blob: bc01585ee8e0f5a86d79d1e7eae5846e9ee08b6a [file] [log] [blame]
/* 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 <ft2build.h>
#include FT_FREETYPE_H
#if 0
// Also include the files by name for build tools which require this.
#include <freetype/freetype.h>
#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<uint8_t*>(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<unsigned>(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<uint8_t*>(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<unsigned>(*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