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