1/* libs/graphics/ports/SkFontHost_FreeType_Subpixel.cpp 2** 3** Copyright 2009, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18/* This file contains functions for converting Freetype's subpixel output 19 formats into the format used by SkMask for subpixel masks. See the comments 20 in SkMask.h for details on the format. 21*/ 22 23#include "SkColorPriv.h" 24#include "SkFontHost.h" 25#include "SkMask.h" 26#include "SkScalerContext.h" 27 28#include <ft2build.h> 29#include FT_FREETYPE_H 30 31#if 0 32// Also include the files by name for build tools which require this. 33#include <freetype/freetype.h> 34#endif 35 36namespace skia_freetype_support { 37 38void CopyFreetypeBitmapToLCDMask(const SkGlyph& dest, const FT_Bitmap& source) 39{ 40 // |source| has three alpha values per pixel and has an extra column at the 41 // left and right edges. 42 43 // ----- <--- a single pixel in the output 44 // source .oOo.. |.oO|o.. 45 // .OOO.. ----- 46 // .oOo.. --> .OO O.. 47 // .oO o.. 48 49 uint8_t* output = reinterpret_cast<uint8_t*>(dest.fImage); 50 const unsigned outputPitch = SkAlign4((source.width / 3) - 2); 51 const uint8_t* input = source.buffer; 52 53 // First we calculate the A8 mask. 54 for (int y = 0; y < source.rows; ++y) { 55 const uint8_t* inputRow = input; 56 uint8_t* outputRow = output; 57 inputRow += 3; // skip the extra column on the left 58 for (int x = 3; x < source.width - 3; x += 3) { 59 const uint8_t averageAlpha = (static_cast<unsigned>(inputRow[0]) + inputRow[1] + inputRow[2] + 1) / 3; 60 *outputRow++ = averageAlpha; 61 inputRow += 3; 62 } 63 64 input += source.pitch; 65 output += outputPitch; 66 } 67 68 // Align the 32-bit plane on a word boundary 69 uint32_t* output32 = (uint32_t*) SkAlign4((uintptr_t) output); 70 71 // Now we build the 32-bit alpha mask and RGB order correct. 72 const int isBGR = SkFontHost::GetSubpixelOrder() == SkFontHost::kBGR_LCDOrder; 73 input = source.buffer; 74 75 for (int y = 0; y < source.rows; ++y) { 76 const uint8_t* inputRow = input; 77 for (int x = 0; x < source.width; x += 3) { 78 const uint8_t alphaRed = isBGR ? inputRow[2] : inputRow[0]; 79 const uint8_t alphaGreen = inputRow[1]; 80 const uint8_t alphaBlue = isBGR ? inputRow[0] : inputRow[2]; 81 const uint8_t maxAlpha = SkMax32(alphaRed, SkMax32(alphaGreen, alphaBlue)); 82 *output32++ = SkPackARGB32(maxAlpha, alphaRed, alphaGreen, alphaBlue); 83 84 inputRow += 3; 85 } 86 87 input += source.pitch; 88 } 89} 90 91void CopyFreetypeBitmapToVerticalLCDMask(const SkGlyph& dest, const FT_Bitmap& source) 92{ 93 // |source| has three times as many rows as normal, and an extra triple on the 94 // top and bottom. 95 96 // source .oOo.. |.|oOo.. 97 // .OOO.. --> |.|OOO.. 98 // .oOo.. |.|oOo.. 99 // ^ 100 // |-------- A single pixel in the output 101 102 uint8_t* output = reinterpret_cast<uint8_t*>(dest.fImage); 103 const unsigned outputPitch = dest.rowBytes(); 104 const uint8_t* input = source.buffer; 105 106 // First we calculate the A8 mask. 107 input += 3 * source.pitch; // skip the extra at the beginning 108 for (int y = 3; y < source.rows - 3; y += 3) { 109 const uint8_t* inputRow = input; 110 uint8_t* outputRow = output; 111 for (int x = 0; x < source.width; ++x) { 112 const uint8_t averageAlpha = (static_cast<unsigned>(*inputRow) + inputRow[source.pitch] + inputRow[source.pitch * 2] + 1) / 3; 113 *outputRow++ = averageAlpha; 114 inputRow++; 115 } 116 117 input += source.pitch * 3; 118 output += outputPitch; 119 } 120 121 // Align the 32-bit plane on a word boundary 122 uint32_t* output32 = (uint32_t*) SkAlign4((uintptr_t) output); 123 124 // Now we build the 32-bit alpha mask and RGB order correct. 125 const int isBGR = SkFontHost::GetSubpixelOrder() == SkFontHost::kBGR_LCDOrder; 126 input = source.buffer; 127 128 for (int y = 0; y < source.rows; y += 3) { 129 const uint8_t* inputRow = input; 130 for (int x = 0; x < source.width; ++x) { 131 const uint8_t alphaRed = isBGR ? inputRow[source.pitch * 2] : inputRow[0]; 132 const uint8_t alphaGreen = inputRow[source.pitch]; 133 const uint8_t alphaBlue = isBGR ? inputRow[0] : inputRow[2 * source.pitch]; 134 const uint8_t maxAlpha = SkMax32(alphaRed, SkMax32(alphaGreen, alphaBlue)); 135 *output32++ = SkPackARGB32(maxAlpha, alphaRed, alphaGreen, alphaBlue); 136 inputRow++; 137 } 138 139 input += source.pitch * 3; 140 } 141} 142 143} // namespace skia_freetype_support 144