/* libs/graphics/ports/SkFontHost_FreeType_Subpixel.cpp ** ** Copyright 2009, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ /* This file contains functions for converting Freetype's subpixel output formats into the format used by SkMask for subpixel masks. See the comments in SkMask.h for details on the format. */ #include "SkColorPriv.h" #include "SkFontHost.h" #include "SkMask.h" #include "SkScalerContext.h" #include #include FT_FREETYPE_H #if 0 // Also include the files by name for build tools which require this. #include #endif namespace skia_freetype_support { void CopyFreetypeBitmapToLCDMask(const SkGlyph& dest, const FT_Bitmap& source) { // |source| has three alpha values per pixel and has an extra column at the // left and right edges. // ----- <--- a single pixel in the output // source .oOo.. |.oO|o.. // .OOO.. ----- // .oOo.. --> .OO O.. // .oO o.. uint8_t* output = reinterpret_cast(dest.fImage); const unsigned outputPitch = SkAlign4((source.width / 3) - 2); const uint8_t* input = source.buffer; // First we calculate the A8 mask. for (int y = 0; y < source.rows; ++y) { const uint8_t* inputRow = input; uint8_t* outputRow = output; inputRow += 3; // skip the extra column on the left for (int x = 3; x < source.width - 3; x += 3) { const uint8_t averageAlpha = (static_cast(inputRow[0]) + inputRow[1] + inputRow[2] + 1) / 3; *outputRow++ = averageAlpha; inputRow += 3; } input += source.pitch; output += outputPitch; } // Align the 32-bit plane on a word boundary uint32_t* output32 = (uint32_t*) SkAlign4((uintptr_t) output); // Now we build the 32-bit alpha mask and RGB order correct. const int isBGR = SkFontHost::GetSubpixelOrder() == SkFontHost::kBGR_LCDOrder; input = source.buffer; for (int y = 0; y < source.rows; ++y) { const uint8_t* inputRow = input; for (int x = 0; x < source.width; x += 3) { const uint8_t alphaRed = isBGR ? inputRow[2] : inputRow[0]; const uint8_t alphaGreen = inputRow[1]; const uint8_t alphaBlue = isBGR ? inputRow[0] : inputRow[2]; const uint8_t maxAlpha = SkMax32(alphaRed, SkMax32(alphaGreen, alphaBlue)); *output32++ = SkPackARGB32(maxAlpha, alphaRed, alphaGreen, alphaBlue); inputRow += 3; } input += source.pitch; } } void CopyFreetypeBitmapToVerticalLCDMask(const SkGlyph& dest, const FT_Bitmap& source) { // |source| has three times as many rows as normal, and an extra triple on the // top and bottom. // source .oOo.. |.|oOo.. // .OOO.. --> |.|OOO.. // .oOo.. |.|oOo.. // ^ // |-------- A single pixel in the output uint8_t* output = reinterpret_cast(dest.fImage); const unsigned outputPitch = dest.rowBytes(); const uint8_t* input = source.buffer; // First we calculate the A8 mask. input += 3 * source.pitch; // skip the extra at the beginning for (int y = 3; y < source.rows - 3; y += 3) { const uint8_t* inputRow = input; uint8_t* outputRow = output; for (int x = 0; x < source.width; ++x) { const uint8_t averageAlpha = (static_cast(*inputRow) + inputRow[source.pitch] + inputRow[source.pitch * 2] + 1) / 3; *outputRow++ = averageAlpha; inputRow++; } input += source.pitch * 3; output += outputPitch; } // Align the 32-bit plane on a word boundary uint32_t* output32 = (uint32_t*) SkAlign4((uintptr_t) output); // Now we build the 32-bit alpha mask and RGB order correct. const int isBGR = SkFontHost::GetSubpixelOrder() == SkFontHost::kBGR_LCDOrder; input = source.buffer; for (int y = 0; y < source.rows; y += 3) { const uint8_t* inputRow = input; for (int x = 0; x < source.width; ++x) { const uint8_t alphaRed = isBGR ? inputRow[source.pitch * 2] : inputRow[0]; const uint8_t alphaGreen = inputRow[source.pitch]; const uint8_t alphaBlue = isBGR ? inputRow[0] : inputRow[2 * source.pitch]; const uint8_t maxAlpha = SkMax32(alphaRed, SkMax32(alphaGreen, alphaBlue)); *output32++ = SkPackARGB32(maxAlpha, alphaRed, alphaGreen, alphaBlue); inputRow++; } input += source.pitch * 3; } } } // namespace skia_freetype_support