1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2006-2012 The Android Open Source Project
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2012 Mozilla Foundation
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkBitmap.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkCanvas.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkColor.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkColorData.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkFDot6.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkFontHost_FreeType_common.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPath.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <ft2build.h>
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include FT_FREETYPE_H
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include FT_BITMAP_H
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include FT_IMAGE_H
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include FT_OUTLINE_H
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include FT_SYNTHESIS_H
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// were introduced in FreeType 2.5.0.
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// The following may be removed once FreeType 2.5.0 is required to build.
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifndef FT_LOAD_COLOR
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#    define FT_LOAD_COLOR ( 1L << 20 )
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#    define FT_PIXEL_MODE_BGRA 7
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//#define SK_SHOW_TEXT_BLIT_COVERAGE
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst char* SkTraceFtrGetError(int e) {
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch ((FT_Error)e) {
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #undef FTERRORS_H_
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #define FT_ERRORDEF( e, v, s ) case v: return s;
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #define FT_ERROR_START_LIST
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #define FT_ERROR_END_LIST
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #include FT_ERRORS_H
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #undef FT_ERRORDEF
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #undef FT_ERROR_START_LIST
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        #undef FT_ERROR_END_LIST
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default: return "";
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif  // SK_DEBUG
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace {
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotFT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (format) {
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case SkMask::kBW_Format:
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return FT_PIXEL_MODE_MONO;
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case SkMask::kA8_Format:
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return FT_PIXEL_MODE_GRAY;
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotuint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) {
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    r = SkTMax(r, (U8CPU)0x40);
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    g = SkTMax(g, (U8CPU)0x40);
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    b = SkTMax(b, (U8CPU)0x40);
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkPack888ToRGB16(r, g, b);
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotuint16_t grayToRGB16(U8CPU gray) {
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    gray = SkTMax(gray, (U8CPU)0x40);
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkPack888ToRGB16(gray, gray, gray);
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint bittst(const uint8_t data[], int bitOffset) {
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(bitOffset >= 0);
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return lowBit & 1;
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/**
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  Copies a FT_Bitmap into an SkMask with the same dimensions.
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_MONO
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_GRAY
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_LCD
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_LCD_V
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate<bool APPLY_PREBLEND>
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR,
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                  const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot{
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(SkMask::kLCD16_Format == mask.fFormat);
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) {
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(mask.fBounds.width() == static_cast<int>(bitmap.width));
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) {
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(mask.fBounds.height() == static_cast<int>(bitmap.rows));
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const uint8_t* src = bitmap.buffer;
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage);
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const size_t dstRB = mask.fRowBytes;
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int width = mask.fBounds.width();
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int height = mask.fBounds.height();
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (bitmap.pixel_mode) {
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FT_PIXEL_MODE_MONO:
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int y = height; y --> 0;) {
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                for (int x = 0; x < width; ++x) {
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    dst[x] = -bittst(src, x);
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dst = (uint16_t*)((char*)dst + dstRB);
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                src += bitmap.pitch;
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FT_PIXEL_MODE_GRAY:
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int y = height; y --> 0;) {
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                for (int x = 0; x < width; ++x) {
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    dst[x] = grayToRGB16(src[x]);
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dst = (uint16_t*)((char*)dst + dstRB);
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                src += bitmap.pitch;
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FT_PIXEL_MODE_LCD:
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(3 * mask.fBounds.width() == static_cast<int>(bitmap.width));
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int y = height; y --> 0;) {
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const uint8_t* triple = src;
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (lcdIsBGR) {
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    for (int x = 0; x < width; x++) {
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        triple += 3;
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else {
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    for (int x = 0; x < width; x++) {
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        triple += 3;
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                src += bitmap.pitch;
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dst = (uint16_t*)((char*)dst + dstRB);
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FT_PIXEL_MODE_LCD_V:
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(3 * mask.fBounds.height() == static_cast<int>(bitmap.rows));
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int y = height; y --> 0;) {
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const uint8_t* srcR = src;
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const uint8_t* srcG = srcR + bitmap.pitch;
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const uint8_t* srcB = srcG + bitmap.pitch;
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (lcdIsBGR) {
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkTSwap(srcR, srcB);
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                for (int x = 0; x < width; x++) {
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                        sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                        sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                src += 3 * bitmap.pitch;
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dst = (uint16_t*)((char*)dst + dstRB);
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDEBUGF(("FT_Pixel_Mode %d", bitmap.pixel_mode));
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16");
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/**
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  Copies a FT_Bitmap into an SkMask with the same dimensions.
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  Yes, No, Never Requested, Never Produced
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *                        kBW kA8 k3D kARGB32 kLCD16
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_MONO     Y   Y  NR     N       Y
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_GRAY     N   Y  NR     N       Y
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_GRAY2   NP  NP  NR    NP      NP
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_GRAY4   NP  NP  NR    NP      NP
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_LCD     NP  NP  NR    NP      NP
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_LCD_V   NP  NP  NR    NP      NP
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  FT_PIXEL_MODE_BGRA     N   N  NR     Y       N
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  TODO: All of these N need to be Y or otherwise ruled out.
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) {
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERTF(dstMask.fBounds.width() == static_cast<int>(srcFTBitmap.width),
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              "dstMask.fBounds.width() = %d\n"
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              "static_cast<int>(srcFTBitmap.width) = %d",
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              dstMask.fBounds.width(),
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              static_cast<int>(srcFTBitmap.width)
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    );
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERTF(dstMask.fBounds.height() == static_cast<int>(srcFTBitmap.rows),
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              "dstMask.fBounds.height() = %d\n"
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              "static_cast<int>(srcFTBitmap.rows) = %d",
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              dstMask.fBounds.height(),
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              static_cast<int>(srcFTBitmap.rows)
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    );
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode);
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // FT_Bitmap::pitch is an int and allowed to be negative.
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int srcPitch = srcFTBitmap.pitch;
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const size_t srcRowBytes = SkTAbs(srcPitch);
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint8_t* dst = dstMask.fImage;
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat);
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const size_t dstRowBytes = dstMask.fRowBytes;
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const size_t width = srcFTBitmap.width;
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const size_t height = srcFTBitmap.rows;
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkMask::kLCD16_Format == dstFormat) {
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        copyFT2LCD16<false>(srcFTBitmap, dstMask, false, nullptr, nullptr, nullptr);
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) ||
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat))
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    {
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t commonRowBytes = SkTMin(srcRowBytes, dstRowBytes);
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (size_t y = height; y --> 0;) {
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            memcpy(dst, src, commonRowBytes);
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            src += srcPitch;
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            dst += dstRowBytes;
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) {
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (size_t y = height; y --> 0;) {
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint8_t byte = 0;
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int bits = 0;
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const uint8_t* src_row = src;
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint8_t* dst_row = dst;
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (size_t x = width; x --> 0;) {
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (0 == bits) {
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    byte = *src_row++;
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    bits = 8;
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                *dst_row++ = byte & 0x80 ? 0xff : 0x00;
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                bits--;
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                byte <<= 1;
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            src += srcPitch;
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            dst += dstRowBytes;
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) {
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // FT_PIXEL_MODE_BGRA is pre-multiplied.
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (size_t y = height; y --> 0;) {
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const uint8_t* src_row = src;
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst);
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (size_t x = 0; x < width; ++x) {
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint8_t b = *src_row++;
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint8_t g = *src_row++;
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint8_t r = *src_row++;
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint8_t a = *src_row++;
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                *dst_row++ = SkPackARGB32(a, r, g, b);
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40);
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            src += srcPitch;
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            dst += dstRowBytes;
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDEBUGF(("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat));
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format");
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotinline int convert_8_to_1(unsigned byte) {
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(byte <= 0xFF);
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better.
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return (byte >> 6) != 0;
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotuint8_t pack_8_to_1(const uint8_t alpha[8]) {
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    unsigned bits = 0;
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < 8; ++i) {
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bits <<= 1;
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bits |= convert_8_to_1(alpha[i]);
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkToU8(bits);
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int height = mask.fBounds.height();
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int width = mask.fBounds.width();
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int octs = width >> 3;
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int leftOverBits = width & 7;
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint8_t* dst = mask.fImage;
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(dstPad >= 0);
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int srcPad = srcRB - width;
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(srcPad >= 0);
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int y = 0; y < height; ++y) {
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = 0; i < octs; ++i) {
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *dst++ = pack_8_to_1(src);
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            src += 8;
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (leftOverBits > 0) {
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            unsigned bits = 0;
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int shift = 7;
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int i = 0; i < leftOverBits; ++i, --shift) {
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                bits |= convert_8_to_1(*src++) << shift;
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *dst++ = bits;
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        src += srcPad;
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        dst += dstPad;
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotinline SkMask::Format SkMaskFormat_for_SkColorType(SkColorType colorType) {
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (colorType) {
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kAlpha_8_SkColorType:
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return SkMask::kA8_Format;
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kN32_SkColorType:
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return SkMask::kARGB32_Format;
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDEBUGFAIL("unsupported SkBitmap::Config");
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return SkMask::kA8_Format;
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotinline SkColorType SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode) {
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (pixel_mode) {
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FT_PIXEL_MODE_MONO:
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FT_PIXEL_MODE_GRAY:
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return kAlpha_8_SkColorType;
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FT_PIXEL_MODE_BGRA:
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return kN32_SkColorType;
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return kAlpha_8_SkColorType;
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotinline SkColorType SkColorType_for_SkMaskFormat(SkMask::Format format) {
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (format) {
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case SkMask::kBW_Format:
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case SkMask::kA8_Format:
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case SkMask::kLCD16_Format:
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return kAlpha_8_SkColorType;
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case SkMask::kARGB32_Format:
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return kN32_SkColorType;
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDEBUGFAIL("unsupported destination SkBitmap::Config");
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return kAlpha_8_SkColorType;
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}  // namespace
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkScalerContext_FreeType_Base::generateGlyphImage(
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FT_Face face,
369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkGlyph& glyph,
370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkMatrix& bitmapTransform)
371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot{
372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch ( face->glyph->format ) {
376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FT_GLYPH_FORMAT_OUTLINE: {
377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            FT_Outline* outline = &face->glyph->outline;
378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int dx = 0, dy = 0;
380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dx = SkFixedToFDot6(glyph.getSubXFixed());
382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dy = SkFixedToFDot6(glyph.getSubYFixed());
383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // negate dy since freetype-y-goes-up and skia-y-goes-down
384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dy = -dy;
385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FT_Outline_Translate(outline, dx, dy);
391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FT_Error err = FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V :
392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                     FT_RENDER_MODE_LCD);
393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (err) {
394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SK_TRACEFTR(err, "Could not render glyph %x.", face->glyph);
395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return;
396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkMask mask;
399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                glyph.toMask(&mask);
400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                memset(mask.fImage, 0x80, mask.fBounds.height() * mask.fRowBytes);
402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FT_GlyphSlotRec& ftGlyph = *face->glyph;
404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!SkIRect::Intersects(mask.fBounds,
406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         SkIRect::MakeXYWH( ftGlyph.bitmap_left,
407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                           -ftGlyph.bitmap_top,
408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                            ftGlyph.bitmap.width,
409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                            ftGlyph.bitmap.rows)))
410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                {
411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return;
412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // If the FT_Bitmap extent is larger, discard bits of the bitmap outside the mask.
415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // If the SkMask extent is larger, shrink mask to fit bitmap (clearing discarded).
416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                unsigned char* origBuffer = ftGlyph.bitmap.buffer;
417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // First align the top left (origin).
418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (-ftGlyph.bitmap_top < mask.fBounds.fTop) {
419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    int32_t topDiff = mask.fBounds.fTop - (-ftGlyph.bitmap_top);
420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ftGlyph.bitmap.buffer += ftGlyph.bitmap.pitch * topDiff;
421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ftGlyph.bitmap.rows -= topDiff;
422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ftGlyph.bitmap_top = -mask.fBounds.fTop;
423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (ftGlyph.bitmap_left < mask.fBounds.fLeft) {
425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    int32_t leftDiff = mask.fBounds.fLeft - ftGlyph.bitmap_left;
426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ftGlyph.bitmap.buffer += leftDiff;
427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ftGlyph.bitmap.width -= leftDiff;
428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ftGlyph.bitmap_left = mask.fBounds.fLeft;
429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (mask.fBounds.fTop < -ftGlyph.bitmap_top) {
431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    mask.fImage += mask.fRowBytes * (-ftGlyph.bitmap_top - mask.fBounds.fTop);
432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    mask.fBounds.fTop = -ftGlyph.bitmap_top;
433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (mask.fBounds.fLeft < ftGlyph.bitmap_left) {
435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    mask.fImage += sizeof(uint16_t) * (ftGlyph.bitmap_left - mask.fBounds.fLeft);
436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    mask.fBounds.fLeft = ftGlyph.bitmap_left;
437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // Origins aligned, clean up the width and height.
439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                int ftVertScale = (doVert ? 3 : 1);
440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                int ftHoriScale = (doVert ? 1 : 3);
441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (mask.fBounds.height() * ftVertScale < SkToInt(ftGlyph.bitmap.rows)) {
442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ftGlyph.bitmap.rows = mask.fBounds.height() * ftVertScale;
443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (mask.fBounds.width() * ftHoriScale < SkToInt(ftGlyph.bitmap.width)) {
445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ftGlyph.bitmap.width = mask.fBounds.width() * ftHoriScale;
446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (SkToInt(ftGlyph.bitmap.rows) < mask.fBounds.height() * ftVertScale) {
448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    mask.fBounds.fBottom = mask.fBounds.fTop + ftGlyph.bitmap.rows / ftVertScale;
449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (SkToInt(ftGlyph.bitmap.width) < mask.fBounds.width() * ftHoriScale) {
451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    mask.fBounds.fRight = mask.fBounds.fLeft + ftGlyph.bitmap.width / ftHoriScale;
452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (fPreBlend.isApplicable()) {
454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    copyFT2LCD16<true>(ftGlyph.bitmap, mask, doBGR,
455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else {
457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    copyFT2LCD16<false>(ftGlyph.bitmap, mask, doBGR,
458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // Restore the buffer pointer so FreeType can properly free it.
461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ftGlyph.bitmap.buffer = origBuffer;
462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FT_BBox     bbox;
464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FT_Bitmap   target;
465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FT_Outline_Get_CBox(outline, &bbox);
466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                /*
467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    what we really want to do for subpixel is
468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        offset(dx, dy)
469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        compute_bounds
470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        offset(bbox & !63)
471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    but that is two calls to offset, so we do the following, which
472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    achieves the same thing with only one offset call.
473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                */
474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                              dy - ((bbox.yMin + dy) & ~63));
476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                target.width = glyph.fWidth;
478fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                target.rows = glyph.fHeight;
479fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                target.pitch = glyph.rowBytes();
480fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
481fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                target.pixel_mode = compute_pixel_mode( (SkMask::Format)fRec.fMaskFormat);
482fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                target.num_grays = 256;
483fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
484fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
485fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
486fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                for (int y = 0; y < glyph.fHeight; ++y) {
487fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    for (int x = 0; x < glyph.fWidth; ++x) {
488fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        uint8_t& a = ((uint8_t*)glyph.fImage)[(glyph.rowBytes() * y) + x];
489fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        a = SkTMax<uint8_t>(a, 0x20);
490fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
491fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
492fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
493fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
494fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } break;
495fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
496fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FT_GLYPH_FORMAT_BITMAP: {
497fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
498fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
499fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
500fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Assume that the other formats do not exist.
501fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
502fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     FT_PIXEL_MODE_GRAY == pixel_mode ||
503fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     FT_PIXEL_MODE_BGRA == pixel_mode);
504fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
505fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // These are the only formats this ScalerContext should request.
506fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(SkMask::kBW_Format == maskFormat ||
507fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     SkMask::kA8_Format == maskFormat ||
508fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     SkMask::kARGB32_Format == maskFormat ||
509fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     SkMask::kLCD16_Format == maskFormat);
510fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
511fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // If no scaling needed, directly copy glyph bitmap.
512fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (bitmapTransform.isIdentity()) {
513fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkMask dstMask;
514fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                glyph.toMask(&dstMask);
515fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                copyFTBitmap(face->glyph->bitmap, dstMask);
516fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
517fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
518fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
519fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Otherwise, scale the bitmap.
520fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
521fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
522fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkBitmap unscaledBitmap;
523fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // TODO: mark this as sRGB when the blits will be sRGB.
524fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            unscaledBitmap.allocPixels(SkImageInfo::Make(face->glyph->bitmap.width,
525fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         face->glyph->bitmap.rows,
526fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         SkColorType_for_FTPixelMode(pixel_mode),
527fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         kPremul_SkAlphaType));
528fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
529fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkMask unscaledBitmapAlias;
530fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
531fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            unscaledBitmapAlias.fBounds.set(0, 0, unscaledBitmap.width(), unscaledBitmap.height());
532fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
533fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkColorType(unscaledBitmap.colorType());
534fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);
535fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
536fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
537fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // BW requires an A8 target for resizing, which can then be down sampled.
538fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // LCD should use a 4x A8 target, which will then be down sampled.
539fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // For simplicity, LCD uses A8 and is replicated.
540fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int bitmapRowBytes = 0;
541fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
542fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                bitmapRowBytes = glyph.rowBytes();
543fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
544fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkBitmap dstBitmap;
545fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // TODO: mark this as sRGB when the blits will be sRGB.
546fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
547fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                SkColorType_for_SkMaskFormat(maskFormat),
548fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                kPremul_SkAlphaType),
549fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              bitmapRowBytes);
550fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
551fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dstBitmap.allocPixels();
552fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
553fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dstBitmap.setPixels(glyph.fImage);
554fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
555fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
556fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Scale unscaledBitmap into dstBitmap.
557fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkCanvas canvas(dstBitmap);
558fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
559fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            canvas.clear(0x33FF0000);
560fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else
561fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            canvas.clear(SK_ColorTRANSPARENT);
562fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
563fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            canvas.translate(-glyph.fLeft, -glyph.fTop);
564fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            canvas.concat(bitmapTransform);
565fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            canvas.translate(face->glyph->bitmap_left, -face->glyph->bitmap_top);
566fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
567fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkPaint paint;
568fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Using kMedium FilterQuality will cause mipmaps to be generated. Use
569fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // kLow when the results will be roughly the same in order to avoid
570fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // the mipmap generation cost.
571fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // See skbug.com/6967
572fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (bitmapTransform.getMinScale() < 0.5) {
573fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                paint.setFilterQuality(kMedium_SkFilterQuality);
574fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
575fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                paint.setFilterQuality(kLow_SkFilterQuality);
576fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
577fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);
578fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
579fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // If the destination is BW or LCD, convert from A8.
580fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (SkMask::kBW_Format == maskFormat) {
581fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // Copy the A8 dstBitmap into the A1 glyph.fImage.
582fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkMask dstMask;
583fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                glyph.toMask(&dstMask);
584fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
585fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else if (SkMask::kLCD16_Format == maskFormat) {
586fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
587fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint8_t* src = dstBitmap.getAddr8(0, 0);
588fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
589fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                for (int y = dstBitmap.height(); y --> 0;) {
590fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    for (int x = 0; x < dstBitmap.width(); ++x) {
591fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        dst[x] = grayToRGB16(src[x]);
592fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
593fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    dst = (uint16_t*)((char*)dst + glyph.rowBytes());
594fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    src += dstBitmap.rowBytes();
595fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
596fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
597fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
598fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } break;
599fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
600fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
601fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDEBUGFAIL("unknown glyph format");
602fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
603fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
604fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
605fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
606fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
607fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// it is optional
608fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if defined(SK_GAMMA_APPLY_TO_A8)
609fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
610fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
611fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        unsigned rowBytes = glyph.rowBytes();
612fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
613fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int y = glyph.fHeight - 1; y >= 0; --y) {
614fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int x = glyph.fWidth - 1; x >= 0; --x) {
615fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dst[x] = fPreBlend.fG[dst[x]];
616fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
617fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            dst += rowBytes;
618fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
619fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
620fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
621fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
622fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
623fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////
624fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
625fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace {
626fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
627fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint move_proc(const FT_Vector* pt, void* ctx) {
628fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath* path = (SkPath*)ctx;
629fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    path->close();  // to close the previous contour (if any)
630fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    path->moveTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
631fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return 0;
632fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
633fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
634fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint line_proc(const FT_Vector* pt, void* ctx) {
635fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath* path = (SkPath*)ctx;
636fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    path->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
637fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return 0;
638fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
639fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
640fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint quad_proc(const FT_Vector* pt0, const FT_Vector* pt1,
641fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     void* ctx) {
642fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath* path = (SkPath*)ctx;
643fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    path->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
644fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                 SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y));
645fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return 0;
646fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
647fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
648fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1,
649fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                      const FT_Vector* pt2, void* ctx) {
650fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath* path = (SkPath*)ctx;
651fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    path->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
652fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                  SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y),
653fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                  SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y));
654fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return 0;
655fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
656fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
657fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}  // namespace
658fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
659fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, SkPath* path) {
660fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FT_Outline_Funcs    funcs;
661fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
662fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    funcs.move_to   = move_proc;
663fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    funcs.line_to   = line_proc;
664fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    funcs.conic_to  = quad_proc;
665fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    funcs.cubic_to  = cubic_proc;
666fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    funcs.shift     = 0;
667fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    funcs.delta     = 0;
668fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
669fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &funcs, path);
670fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
671fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (err != 0) {
672fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        path->reset();
673fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
674fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
675fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
676fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    path->close();
677fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
678