14dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com/*
24dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com * Copyright 2006-2012 The Android Open Source Project
34dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com * Copyright 2012 Mozilla Foundation
44dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com *
54dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com * Use of this source code is governed by a BSD-style license that can be
64dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com * found in the LICENSE file.
74dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com */
84dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
9b314e5855948322329b8c779065a71473ac5705abungeman@google.com#include "SkBitmap.h"
10b314e5855948322329b8c779065a71473ac5705abungeman@google.com#include "SkCanvas.h"
11b314e5855948322329b8c779065a71473ac5705abungeman@google.com#include "SkColor.h"
124dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com#include "SkColorPriv.h"
134dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com#include "SkFDot6.h"
144dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com#include "SkFontHost_FreeType_common.h"
154dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com#include "SkPath.h"
164dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
174dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com#include <ft2build.h>
18b314e5855948322329b8c779065a71473ac5705abungeman@google.com#include FT_FREETYPE_H
194dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com#include FT_BITMAP_H
20b314e5855948322329b8c779065a71473ac5705abungeman@google.com#include FT_IMAGE_H
21b314e5855948322329b8c779065a71473ac5705abungeman@google.com#include FT_OUTLINE_H
224dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com// In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
234dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com#include FT_SYNTHESIS_H
244dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
25b314e5855948322329b8c779065a71473ac5705abungeman@google.com// FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
26b314e5855948322329b8c779065a71473ac5705abungeman@google.com// were introduced in FreeType 2.5.0.
27b314e5855948322329b8c779065a71473ac5705abungeman@google.com// The following may be removed once FreeType 2.5.0 is required to build.
28b314e5855948322329b8c779065a71473ac5705abungeman@google.com#ifndef FT_LOAD_COLOR
29b314e5855948322329b8c779065a71473ac5705abungeman@google.com#    define FT_LOAD_COLOR ( 1L << 20 )
30b314e5855948322329b8c779065a71473ac5705abungeman@google.com#    define FT_PIXEL_MODE_BGRA 7
31b314e5855948322329b8c779065a71473ac5705abungeman@google.com#endif
32b314e5855948322329b8c779065a71473ac5705abungeman@google.com
33b314e5855948322329b8c779065a71473ac5705abungeman@google.com//#define SK_SHOW_TEXT_BLIT_COVERAGE
34b314e5855948322329b8c779065a71473ac5705abungeman@google.com
354dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.comstatic FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
364dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    switch (format) {
374dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        case SkMask::kBW_Format:
384dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            return FT_PIXEL_MODE_MONO;
394dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        case SkMask::kA8_Format:
404dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        default:
414dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            return FT_PIXEL_MODE_GRAY;
424dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    }
434dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com}
444dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
454dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com///////////////////////////////////////////////////////////////////////////////
464dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
47b314e5855948322329b8c779065a71473ac5705abungeman@google.comstatic uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) {
48b314e5855948322329b8c779065a71473ac5705abungeman@google.com#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
49b314e5855948322329b8c779065a71473ac5705abungeman@google.com    r = SkTMax(r, (U8CPU)0x40);
50b314e5855948322329b8c779065a71473ac5705abungeman@google.com    g = SkTMax(g, (U8CPU)0x40);
51b314e5855948322329b8c779065a71473ac5705abungeman@google.com    b = SkTMax(b, (U8CPU)0x40);
52b314e5855948322329b8c779065a71473ac5705abungeman@google.com#endif
53b314e5855948322329b8c779065a71473ac5705abungeman@google.com    return SkPack888ToRGB16(r, g, b);
544dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com}
554dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
564dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.comstatic uint16_t grayToRGB16(U8CPU gray) {
57b314e5855948322329b8c779065a71473ac5705abungeman@google.com#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
58b314e5855948322329b8c779065a71473ac5705abungeman@google.com    gray = SkTMax(gray, (U8CPU)0x40);
59b314e5855948322329b8c779065a71473ac5705abungeman@google.com#endif
60b314e5855948322329b8c779065a71473ac5705abungeman@google.com    return SkPack888ToRGB16(gray, gray, gray);
614dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com}
624dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
634dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.comstatic int bittst(const uint8_t data[], int bitOffset) {
644dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    SkASSERT(bitOffset >= 0);
654dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
664dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    return lowBit & 1;
674dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com}
684dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
69b314e5855948322329b8c779065a71473ac5705abungeman@google.com/**
70b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  Copies a FT_Bitmap into an SkMask with the same dimensions.
71b314e5855948322329b8c779065a71473ac5705abungeman@google.com *
72b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_MONO
73b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_GRAY
74b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_LCD
75b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_LCD_V
76b314e5855948322329b8c779065a71473ac5705abungeman@google.com */
774dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.comtemplate<bool APPLY_PREBLEND>
78b314e5855948322329b8c779065a71473ac5705abungeman@google.comstatic void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR,
79b314e5855948322329b8c779065a71473ac5705abungeman@google.com                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
80b314e5855948322329b8c779065a71473ac5705abungeman@google.com{
81b314e5855948322329b8c779065a71473ac5705abungeman@google.com    SkASSERT(SkMask::kLCD16_Format == mask.fFormat);
82b314e5855948322329b8c779065a71473ac5705abungeman@google.com    if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) {
83b314e5855948322329b8c779065a71473ac5705abungeman@google.com        SkASSERT(mask.fBounds.width() == bitmap.width);
84b314e5855948322329b8c779065a71473ac5705abungeman@google.com    }
85b314e5855948322329b8c779065a71473ac5705abungeman@google.com    if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) {
86b314e5855948322329b8c779065a71473ac5705abungeman@google.com        SkASSERT(mask.fBounds.height() == bitmap.rows);
874dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    }
884dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
894dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    const uint8_t* src = bitmap.buffer;
90b314e5855948322329b8c779065a71473ac5705abungeman@google.com    uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage);
91b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const size_t dstRB = mask.fRowBytes;
92b314e5855948322329b8c779065a71473ac5705abungeman@google.com
93b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const int width = mask.fBounds.width();
94b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const int height = mask.fBounds.height();
954dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
964dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    switch (bitmap.pixel_mode) {
97b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case FT_PIXEL_MODE_MONO:
98b314e5855948322329b8c779065a71473ac5705abungeman@google.com            for (int y = height; y --> 0;) {
994dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                for (int x = 0; x < width; ++x) {
1004dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                    dst[x] = -bittst(src, x);
1014dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                }
1024dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                dst = (uint16_t*)((char*)dst + dstRB);
1034dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                src += bitmap.pitch;
1044dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            }
105b314e5855948322329b8c779065a71473ac5705abungeman@google.com            break;
106b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case FT_PIXEL_MODE_GRAY:
107b314e5855948322329b8c779065a71473ac5705abungeman@google.com            for (int y = height; y --> 0;) {
1084dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                for (int x = 0; x < width; ++x) {
1094dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                    dst[x] = grayToRGB16(src[x]);
1104dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                }
1114dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                dst = (uint16_t*)((char*)dst + dstRB);
1124dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                src += bitmap.pitch;
1134dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            }
114b314e5855948322329b8c779065a71473ac5705abungeman@google.com            break;
115b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case FT_PIXEL_MODE_LCD:
116b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkASSERT(3 * mask.fBounds.width() == bitmap.width);
117b314e5855948322329b8c779065a71473ac5705abungeman@google.com            for (int y = height; y --> 0;) {
118b314e5855948322329b8c779065a71473ac5705abungeman@google.com                const uint8_t* triple = src;
119b314e5855948322329b8c779065a71473ac5705abungeman@google.com                if (lcdIsBGR) {
1204dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                    for (int x = 0; x < width; x++) {
121b314e5855948322329b8c779065a71473ac5705abungeman@google.com                        dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
122b314e5855948322329b8c779065a71473ac5705abungeman@google.com                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
123b314e5855948322329b8c779065a71473ac5705abungeman@google.com                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
124b314e5855948322329b8c779065a71473ac5705abungeman@google.com                        triple += 3;
1254dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                    }
126b314e5855948322329b8c779065a71473ac5705abungeman@google.com                } else {
127b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    for (int x = 0; x < width; x++) {
128b314e5855948322329b8c779065a71473ac5705abungeman@google.com                        dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
129b314e5855948322329b8c779065a71473ac5705abungeman@google.com                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
130b314e5855948322329b8c779065a71473ac5705abungeman@google.com                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
131b314e5855948322329b8c779065a71473ac5705abungeman@google.com                        triple += 3;
1324dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                    }
1334dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                }
134b314e5855948322329b8c779065a71473ac5705abungeman@google.com                src += bitmap.pitch;
1354dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                dst = (uint16_t*)((char*)dst + dstRB);
1364dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            }
137b314e5855948322329b8c779065a71473ac5705abungeman@google.com            break;
138b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case FT_PIXEL_MODE_LCD_V:
139b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkASSERT(3 * mask.fBounds.height() == bitmap.rows);
140b314e5855948322329b8c779065a71473ac5705abungeman@google.com            for (int y = height; y --> 0;) {
141b314e5855948322329b8c779065a71473ac5705abungeman@google.com                const uint8_t* srcR = src;
142b314e5855948322329b8c779065a71473ac5705abungeman@google.com                const uint8_t* srcG = srcR + bitmap.pitch;
143b314e5855948322329b8c779065a71473ac5705abungeman@google.com                const uint8_t* srcB = srcG + bitmap.pitch;
144b314e5855948322329b8c779065a71473ac5705abungeman@google.com                if (lcdIsBGR) {
145b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    SkTSwap(srcR, srcB);
146b314e5855948322329b8c779065a71473ac5705abungeman@google.com                }
147b314e5855948322329b8c779065a71473ac5705abungeman@google.com                for (int x = 0; x < width; x++) {
148b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
149b314e5855948322329b8c779065a71473ac5705abungeman@google.com                                        sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
150b314e5855948322329b8c779065a71473ac5705abungeman@google.com                                        sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
151b314e5855948322329b8c779065a71473ac5705abungeman@google.com                }
152b314e5855948322329b8c779065a71473ac5705abungeman@google.com                src += 3 * bitmap.pitch;
153b314e5855948322329b8c779065a71473ac5705abungeman@google.com                dst = (uint16_t*)((char*)dst + dstRB);
154b314e5855948322329b8c779065a71473ac5705abungeman@google.com            }
155b314e5855948322329b8c779065a71473ac5705abungeman@google.com            break;
156b314e5855948322329b8c779065a71473ac5705abungeman@google.com        default:
157b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkDEBUGF(("FT_Pixel_Mode %d", bitmap.pixel_mode));
158b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16");
159b314e5855948322329b8c779065a71473ac5705abungeman@google.com            break;
160b314e5855948322329b8c779065a71473ac5705abungeman@google.com    }
161b314e5855948322329b8c779065a71473ac5705abungeman@google.com}
162b314e5855948322329b8c779065a71473ac5705abungeman@google.com
163b314e5855948322329b8c779065a71473ac5705abungeman@google.com/**
164b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  Copies a FT_Bitmap into an SkMask with the same dimensions.
165b314e5855948322329b8c779065a71473ac5705abungeman@google.com *
166b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  Yes, No, Never Requested, Never Produced
167b314e5855948322329b8c779065a71473ac5705abungeman@google.com *
168b314e5855948322329b8c779065a71473ac5705abungeman@google.com *                        kBW kA8 k3D kARGB32 kLCD16 kLCD32
169b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_MONO     Y   Y  NR     N       Y     NR
170b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_GRAY     N   Y  NR     N       Y     NR
171b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_GRAY2   NP  NP  NR    NP      NP     NR
172b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_GRAY4   NP  NP  NR    NP      NP     NR
173b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_LCD     NP  NP  NR    NP      NP     NR
174b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_LCD_V   NP  NP  NR    NP      NP     NR
175b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  FT_PIXEL_MODE_BGRA     N   N  NR     Y       N     NR
176b314e5855948322329b8c779065a71473ac5705abungeman@google.com *
177b314e5855948322329b8c779065a71473ac5705abungeman@google.com *  TODO: All of these N need to be Y or otherwise ruled out.
178b314e5855948322329b8c779065a71473ac5705abungeman@google.com */
179b314e5855948322329b8c779065a71473ac5705abungeman@google.comstatic void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) {
180b314e5855948322329b8c779065a71473ac5705abungeman@google.com    SkASSERT(dstMask.fBounds.width() == srcFTBitmap.width);
181b314e5855948322329b8c779065a71473ac5705abungeman@google.com    SkASSERT(dstMask.fBounds.height() == srcFTBitmap.rows);
182b314e5855948322329b8c779065a71473ac5705abungeman@google.com
183b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
184b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode);
185b314e5855948322329b8c779065a71473ac5705abungeman@google.com    // FT_Bitmap::pitch is an int and allowed to be negative.
186b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const int srcPitch = srcFTBitmap.pitch;
187b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const size_t srcRowBytes = SkTAbs(srcPitch);
188b314e5855948322329b8c779065a71473ac5705abungeman@google.com
189b314e5855948322329b8c779065a71473ac5705abungeman@google.com    uint8_t* dst = dstMask.fImage;
190b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat);
191b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const size_t dstRowBytes = dstMask.fRowBytes;
192b314e5855948322329b8c779065a71473ac5705abungeman@google.com
193b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const size_t width = srcFTBitmap.width;
194b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const size_t height = srcFTBitmap.rows;
195b314e5855948322329b8c779065a71473ac5705abungeman@google.com
196b314e5855948322329b8c779065a71473ac5705abungeman@google.com    if (SkMask::kLCD16_Format == dstFormat) {
197b314e5855948322329b8c779065a71473ac5705abungeman@google.com        copyFT2LCD16<false>(srcFTBitmap, dstMask, false, NULL, NULL, NULL);
198b314e5855948322329b8c779065a71473ac5705abungeman@google.com        return;
199b314e5855948322329b8c779065a71473ac5705abungeman@google.com    }
200b314e5855948322329b8c779065a71473ac5705abungeman@google.com
201b314e5855948322329b8c779065a71473ac5705abungeman@google.com    if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) ||
202b314e5855948322329b8c779065a71473ac5705abungeman@google.com        (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat))
203b314e5855948322329b8c779065a71473ac5705abungeman@google.com    {
204b314e5855948322329b8c779065a71473ac5705abungeman@google.com        size_t commonRowBytes = SkTMin(srcRowBytes, dstRowBytes);
205b314e5855948322329b8c779065a71473ac5705abungeman@google.com        for (size_t y = height; y --> 0;) {
206b314e5855948322329b8c779065a71473ac5705abungeman@google.com            memcpy(dst, src, commonRowBytes);
207b314e5855948322329b8c779065a71473ac5705abungeman@google.com            src += srcPitch;
208b314e5855948322329b8c779065a71473ac5705abungeman@google.com            dst += dstRowBytes;
209b314e5855948322329b8c779065a71473ac5705abungeman@google.com        }
210b314e5855948322329b8c779065a71473ac5705abungeman@google.com    } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) {
211b314e5855948322329b8c779065a71473ac5705abungeman@google.com        for (size_t y = height; y --> 0;) {
212b314e5855948322329b8c779065a71473ac5705abungeman@google.com            uint8_t byte = 0;
213b314e5855948322329b8c779065a71473ac5705abungeman@google.com            int bits = 0;
214b314e5855948322329b8c779065a71473ac5705abungeman@google.com            const uint8_t* src_row = src;
215b314e5855948322329b8c779065a71473ac5705abungeman@google.com            uint8_t* dst_row = dst;
216b314e5855948322329b8c779065a71473ac5705abungeman@google.com            for (size_t x = width; x --> 0;) {
217b314e5855948322329b8c779065a71473ac5705abungeman@google.com                if (0 == bits) {
218b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    byte = *src_row++;
219b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    bits = 8;
220b314e5855948322329b8c779065a71473ac5705abungeman@google.com                }
221b314e5855948322329b8c779065a71473ac5705abungeman@google.com                *dst_row++ = byte & 0x80 ? 0xff : 0x00;
222b314e5855948322329b8c779065a71473ac5705abungeman@google.com                bits--;
223b314e5855948322329b8c779065a71473ac5705abungeman@google.com                byte <<= 1;
224b314e5855948322329b8c779065a71473ac5705abungeman@google.com            }
225b314e5855948322329b8c779065a71473ac5705abungeman@google.com            src += srcPitch;
226b314e5855948322329b8c779065a71473ac5705abungeman@google.com            dst += dstRowBytes;
227b314e5855948322329b8c779065a71473ac5705abungeman@google.com        }
228b314e5855948322329b8c779065a71473ac5705abungeman@google.com    } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) {
229b314e5855948322329b8c779065a71473ac5705abungeman@google.com        // FT_PIXEL_MODE_BGRA is pre-multiplied.
230b314e5855948322329b8c779065a71473ac5705abungeman@google.com        for (size_t y = height; y --> 0;) {
231b314e5855948322329b8c779065a71473ac5705abungeman@google.com            const uint8_t* src_row = src;
232b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst);
233b314e5855948322329b8c779065a71473ac5705abungeman@google.com            for (size_t x = 0; x < width; ++x) {
234b314e5855948322329b8c779065a71473ac5705abungeman@google.com                uint8_t b = *src_row++;
235b314e5855948322329b8c779065a71473ac5705abungeman@google.com                uint8_t g = *src_row++;
236b314e5855948322329b8c779065a71473ac5705abungeman@google.com                uint8_t r = *src_row++;
237b314e5855948322329b8c779065a71473ac5705abungeman@google.com                uint8_t a = *src_row++;
238b314e5855948322329b8c779065a71473ac5705abungeman@google.com                *dst_row++ = SkPackARGB32(a, r, g, b);
239b314e5855948322329b8c779065a71473ac5705abungeman@google.com#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
240b314e5855948322329b8c779065a71473ac5705abungeman@google.com                *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40);
241b314e5855948322329b8c779065a71473ac5705abungeman@google.com#endif
242b314e5855948322329b8c779065a71473ac5705abungeman@google.com            }
243b314e5855948322329b8c779065a71473ac5705abungeman@google.com            src += srcPitch;
244b314e5855948322329b8c779065a71473ac5705abungeman@google.com            dst += dstRowBytes;
245b314e5855948322329b8c779065a71473ac5705abungeman@google.com        }
246b314e5855948322329b8c779065a71473ac5705abungeman@google.com    } else {
247b314e5855948322329b8c779065a71473ac5705abungeman@google.com        SkDEBUGF(("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat));
248b314e5855948322329b8c779065a71473ac5705abungeman@google.com        SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format");
249b314e5855948322329b8c779065a71473ac5705abungeman@google.com    }
250b314e5855948322329b8c779065a71473ac5705abungeman@google.com}
251b314e5855948322329b8c779065a71473ac5705abungeman@google.com
252b314e5855948322329b8c779065a71473ac5705abungeman@google.comstatic inline int convert_8_to_1(unsigned byte) {
253b314e5855948322329b8c779065a71473ac5705abungeman@google.com    SkASSERT(byte <= 0xFF);
254b314e5855948322329b8c779065a71473ac5705abungeman@google.com    // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better.
255b314e5855948322329b8c779065a71473ac5705abungeman@google.com    return (byte >> 6) != 0;
256b314e5855948322329b8c779065a71473ac5705abungeman@google.com}
257b314e5855948322329b8c779065a71473ac5705abungeman@google.com
258b314e5855948322329b8c779065a71473ac5705abungeman@google.comstatic uint8_t pack_8_to_1(const uint8_t alpha[8]) {
259b314e5855948322329b8c779065a71473ac5705abungeman@google.com    unsigned bits = 0;
260b314e5855948322329b8c779065a71473ac5705abungeman@google.com    for (int i = 0; i < 8; ++i) {
261b314e5855948322329b8c779065a71473ac5705abungeman@google.com        bits <<= 1;
262b314e5855948322329b8c779065a71473ac5705abungeman@google.com        bits |= convert_8_to_1(alpha[i]);
263b314e5855948322329b8c779065a71473ac5705abungeman@google.com    }
264b314e5855948322329b8c779065a71473ac5705abungeman@google.com    return SkToU8(bits);
265b314e5855948322329b8c779065a71473ac5705abungeman@google.com}
266b314e5855948322329b8c779065a71473ac5705abungeman@google.com
267b314e5855948322329b8c779065a71473ac5705abungeman@google.comstatic void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
268b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const int height = mask.fBounds.height();
269b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const int width = mask.fBounds.width();
270b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const int octs = width >> 3;
271b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const int leftOverBits = width & 7;
272b314e5855948322329b8c779065a71473ac5705abungeman@google.com
273b314e5855948322329b8c779065a71473ac5705abungeman@google.com    uint8_t* dst = mask.fImage;
274b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
275b314e5855948322329b8c779065a71473ac5705abungeman@google.com    SkASSERT(dstPad >= 0);
276b314e5855948322329b8c779065a71473ac5705abungeman@google.com
277b314e5855948322329b8c779065a71473ac5705abungeman@google.com    const int srcPad = srcRB - width;
278b314e5855948322329b8c779065a71473ac5705abungeman@google.com    SkASSERT(srcPad >= 0);
279b314e5855948322329b8c779065a71473ac5705abungeman@google.com
280b314e5855948322329b8c779065a71473ac5705abungeman@google.com    for (int y = 0; y < height; ++y) {
281b314e5855948322329b8c779065a71473ac5705abungeman@google.com        for (int i = 0; i < octs; ++i) {
282b314e5855948322329b8c779065a71473ac5705abungeman@google.com            *dst++ = pack_8_to_1(src);
283b314e5855948322329b8c779065a71473ac5705abungeman@google.com            src += 8;
284b314e5855948322329b8c779065a71473ac5705abungeman@google.com        }
285b314e5855948322329b8c779065a71473ac5705abungeman@google.com        if (leftOverBits > 0) {
286b314e5855948322329b8c779065a71473ac5705abungeman@google.com            unsigned bits = 0;
287b314e5855948322329b8c779065a71473ac5705abungeman@google.com            int shift = 7;
288b314e5855948322329b8c779065a71473ac5705abungeman@google.com            for (int i = 0; i < leftOverBits; ++i, --shift) {
289b314e5855948322329b8c779065a71473ac5705abungeman@google.com                bits |= convert_8_to_1(*src++) << shift;
290b314e5855948322329b8c779065a71473ac5705abungeman@google.com            }
291b314e5855948322329b8c779065a71473ac5705abungeman@google.com            *dst++ = bits;
292b314e5855948322329b8c779065a71473ac5705abungeman@google.com        }
293b314e5855948322329b8c779065a71473ac5705abungeman@google.com        src += srcPad;
294b314e5855948322329b8c779065a71473ac5705abungeman@google.com        dst += dstPad;
295b314e5855948322329b8c779065a71473ac5705abungeman@google.com    }
296b314e5855948322329b8c779065a71473ac5705abungeman@google.com}
297b314e5855948322329b8c779065a71473ac5705abungeman@google.com
298b314e5855948322329b8c779065a71473ac5705abungeman@google.cominline SkMask::Format SkMaskFormat_for_SkBitmapConfig(SkBitmap::Config config) {
299b314e5855948322329b8c779065a71473ac5705abungeman@google.com    switch (config) {
300b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case SkBitmap::kA8_Config:
301b314e5855948322329b8c779065a71473ac5705abungeman@google.com            return SkMask::kA8_Format;
302b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case SkBitmap::kARGB_8888_Config:
303b314e5855948322329b8c779065a71473ac5705abungeman@google.com            return SkMask::kARGB32_Format;
304b314e5855948322329b8c779065a71473ac5705abungeman@google.com        default:
305b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkDEBUGFAIL("unsupported SkBitmap::Config");
306b314e5855948322329b8c779065a71473ac5705abungeman@google.com            return SkMask::kA8_Format;
307b314e5855948322329b8c779065a71473ac5705abungeman@google.com    }
308b314e5855948322329b8c779065a71473ac5705abungeman@google.com}
309b314e5855948322329b8c779065a71473ac5705abungeman@google.com
310b314e5855948322329b8c779065a71473ac5705abungeman@google.cominline SkBitmap::Config SkBitmapConfig_for_FTPixelMode(FT_Pixel_Mode pixel_mode) {
311b314e5855948322329b8c779065a71473ac5705abungeman@google.com    switch (pixel_mode) {
312b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case FT_PIXEL_MODE_MONO:
313b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case FT_PIXEL_MODE_GRAY:
314b314e5855948322329b8c779065a71473ac5705abungeman@google.com            return SkBitmap::kA8_Config;
315b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case FT_PIXEL_MODE_BGRA:
316b314e5855948322329b8c779065a71473ac5705abungeman@google.com            return SkBitmap::kARGB_8888_Config;
317b314e5855948322329b8c779065a71473ac5705abungeman@google.com        default:
318b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
319b314e5855948322329b8c779065a71473ac5705abungeman@google.com            return SkBitmap::kA8_Config;
320b314e5855948322329b8c779065a71473ac5705abungeman@google.com    }
321b314e5855948322329b8c779065a71473ac5705abungeman@google.com}
322b314e5855948322329b8c779065a71473ac5705abungeman@google.com
323b314e5855948322329b8c779065a71473ac5705abungeman@google.cominline SkBitmap::Config SkBitmapConfig_for_SkMaskFormat(SkMask::Format format) {
324b314e5855948322329b8c779065a71473ac5705abungeman@google.com    switch (format) {
325b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case SkMask::kBW_Format:
326b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case SkMask::kA8_Format:
327b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case SkMask::kLCD16_Format:
328b314e5855948322329b8c779065a71473ac5705abungeman@google.com            return SkBitmap::kA8_Config;
329b314e5855948322329b8c779065a71473ac5705abungeman@google.com        case SkMask::kARGB32_Format:
330b314e5855948322329b8c779065a71473ac5705abungeman@google.com            return SkBitmap::kARGB_8888_Config;
331b314e5855948322329b8c779065a71473ac5705abungeman@google.com        default:
332b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkDEBUGFAIL("unsupported destination SkBitmap::Config");
333b314e5855948322329b8c779065a71473ac5705abungeman@google.com            return SkBitmap::kA8_Config;
3344dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    }
3354dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com}
3364dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
337ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.comvoid SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph) {
3384dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
3394dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
3404dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
3414dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    switch ( face->glyph->format ) {
3424dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        case FT_GLYPH_FORMAT_OUTLINE: {
3434dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            FT_Outline* outline = &face->glyph->outline;
3444dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            FT_BBox     bbox;
3454dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            FT_Bitmap   target;
3464dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
347b314e5855948322329b8c779065a71473ac5705abungeman@google.com            if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
348b314e5855948322329b8c779065a71473ac5705abungeman@google.com                !(face->style_flags & FT_STYLE_FLAG_BOLD)) {
3494dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                emboldenOutline(face, outline);
3504dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            }
3514dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
3524dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            int dx = 0, dy = 0;
3534dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
3544dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                dx = SkFixedToFDot6(glyph.getSubXFixed());
3554dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                dy = SkFixedToFDot6(glyph.getSubYFixed());
3564dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                // negate dy since freetype-y-goes-up and skia-y-goes-down
3574dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                dy = -dy;
3584dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            }
3594dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            FT_Outline_Get_CBox(outline, &bbox);
3604dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            /*
3614dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                what we really want to do for subpixel is
3624dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                    offset(dx, dy)
3634dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                    compute_bounds
3644dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                    offset(bbox & !63)
3654dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                but that is two calls to offset, so we do the following, which
3664dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                achieves the same thing with only one offset call.
3674dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            */
3684dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
3694dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                                          dy - ((bbox.yMin + dy) & ~63));
3704dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
3714dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
3724dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD);
373b314e5855948322329b8c779065a71473ac5705abungeman@google.com                SkMask mask;
374b314e5855948322329b8c779065a71473ac5705abungeman@google.com                glyph.toMask(&mask);
375ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                if (fPreBlend.isApplicable()) {
376b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    copyFT2LCD16<true>(face->glyph->bitmap, mask, doBGR,
377ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
3784dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                } else {
379b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    copyFT2LCD16<false>(face->glyph->bitmap, mask, doBGR,
380ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
3814dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                }
3824dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            } else {
3834dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                target.width = glyph.fWidth;
3844dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                target.rows = glyph.fHeight;
3854dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                target.pitch = glyph.rowBytes();
3864dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
387b314e5855948322329b8c779065a71473ac5705abungeman@google.com                target.pixel_mode = compute_pixel_mode( (SkMask::Format)fRec.fMaskFormat);
3884dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                target.num_grays = 256;
3894dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
3904dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
3914dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
3924dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            }
3934dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        } break;
3944dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
3954dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        case FT_GLYPH_FORMAT_BITMAP: {
396b314e5855948322329b8c779065a71473ac5705abungeman@google.com            FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
397b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
398b314e5855948322329b8c779065a71473ac5705abungeman@google.com
399b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // Assume that the other formats do not exist.
400b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
401b314e5855948322329b8c779065a71473ac5705abungeman@google.com                     FT_PIXEL_MODE_GRAY == pixel_mode ||
402b314e5855948322329b8c779065a71473ac5705abungeman@google.com                     FT_PIXEL_MODE_BGRA == pixel_mode);
403b314e5855948322329b8c779065a71473ac5705abungeman@google.com
404b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // These are the only formats this ScalerContext should request.
405b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkASSERT(SkMask::kBW_Format == maskFormat ||
406b314e5855948322329b8c779065a71473ac5705abungeman@google.com                     SkMask::kA8_Format == maskFormat ||
407b314e5855948322329b8c779065a71473ac5705abungeman@google.com                     SkMask::kARGB32_Format == maskFormat ||
408b314e5855948322329b8c779065a71473ac5705abungeman@google.com                     SkMask::kLCD16_Format == maskFormat);
409b314e5855948322329b8c779065a71473ac5705abungeman@google.com
410b314e5855948322329b8c779065a71473ac5705abungeman@google.com            if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
411b314e5855948322329b8c779065a71473ac5705abungeman@google.com                !(face->style_flags & FT_STYLE_FLAG_BOLD))
412b314e5855948322329b8c779065a71473ac5705abungeman@google.com            {
4134dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                FT_GlyphSlot_Own_Bitmap(face->glyph);
414b314e5855948322329b8c779065a71473ac5705abungeman@google.com                FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap,
415b314e5855948322329b8c779065a71473ac5705abungeman@google.com                                   kBitmapEmboldenStrength, 0);
4164dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            }
4174dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
418b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // If no scaling needed, directly copy glyph bitmap.
419b314e5855948322329b8c779065a71473ac5705abungeman@google.com            if (glyph.fWidth == face->glyph->bitmap.width &&
420b314e5855948322329b8c779065a71473ac5705abungeman@google.com                glyph.fHeight == face->glyph->bitmap.rows &&
421b314e5855948322329b8c779065a71473ac5705abungeman@google.com                glyph.fTop == -face->glyph->bitmap_top &&
422b314e5855948322329b8c779065a71473ac5705abungeman@google.com                glyph.fLeft == face->glyph->bitmap_left)
423b314e5855948322329b8c779065a71473ac5705abungeman@google.com            {
424b314e5855948322329b8c779065a71473ac5705abungeman@google.com                SkMask dstMask;
425b314e5855948322329b8c779065a71473ac5705abungeman@google.com                glyph.toMask(&dstMask);
426b314e5855948322329b8c779065a71473ac5705abungeman@google.com                copyFTBitmap(face->glyph->bitmap, dstMask);
427b314e5855948322329b8c779065a71473ac5705abungeman@google.com                break;
428b314e5855948322329b8c779065a71473ac5705abungeman@google.com            }
429b314e5855948322329b8c779065a71473ac5705abungeman@google.com
430b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // Otherwise, scale the bitmap.
431b314e5855948322329b8c779065a71473ac5705abungeman@google.com
432b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
433b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkBitmap unscaledBitmap;
434b314e5855948322329b8c779065a71473ac5705abungeman@google.com            unscaledBitmap.setConfig(SkBitmapConfig_for_FTPixelMode(pixel_mode),
435b314e5855948322329b8c779065a71473ac5705abungeman@google.com                                     face->glyph->bitmap.width, face->glyph->bitmap.rows);
436b314e5855948322329b8c779065a71473ac5705abungeman@google.com            unscaledBitmap.allocPixels();
437b314e5855948322329b8c779065a71473ac5705abungeman@google.com
438b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkMask unscaledBitmapAlias;
439b314e5855948322329b8c779065a71473ac5705abungeman@google.com            unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
440b314e5855948322329b8c779065a71473ac5705abungeman@google.com            unscaledBitmapAlias.fBounds.set(0, 0, unscaledBitmap.width(), unscaledBitmap.height());
441b314e5855948322329b8c779065a71473ac5705abungeman@google.com            unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
442b314e5855948322329b8c779065a71473ac5705abungeman@google.com            unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkBitmapConfig(unscaledBitmap.config());
443b314e5855948322329b8c779065a71473ac5705abungeman@google.com            copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);
444b314e5855948322329b8c779065a71473ac5705abungeman@google.com
445b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
446b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // BW requires an A8 target for resizing, which can then be down sampled.
447b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // LCD should use a 4x A8 target, which will then be down sampled.
448b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // For simplicity, LCD uses A8 and is replicated.
449b314e5855948322329b8c779065a71473ac5705abungeman@google.com            int bitmapRowBytes = 0;
450b314e5855948322329b8c779065a71473ac5705abungeman@google.com            if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
451b314e5855948322329b8c779065a71473ac5705abungeman@google.com                bitmapRowBytes = glyph.rowBytes();
452b314e5855948322329b8c779065a71473ac5705abungeman@google.com            }
453b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkBitmap dstBitmap;
454b314e5855948322329b8c779065a71473ac5705abungeman@google.com            dstBitmap.setConfig(SkBitmapConfig_for_SkMaskFormat(maskFormat),
455b314e5855948322329b8c779065a71473ac5705abungeman@google.com                                glyph.fWidth, glyph.fHeight, bitmapRowBytes);
456b314e5855948322329b8c779065a71473ac5705abungeman@google.com            if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
457b314e5855948322329b8c779065a71473ac5705abungeman@google.com                dstBitmap.allocPixels();
4584dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            } else {
459b314e5855948322329b8c779065a71473ac5705abungeman@google.com                dstBitmap.setPixels(glyph.fImage);
460b314e5855948322329b8c779065a71473ac5705abungeman@google.com            }
461b314e5855948322329b8c779065a71473ac5705abungeman@google.com
462b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // Scale unscaledBitmap into dstBitmap.
463b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkCanvas canvas(dstBitmap);
464b314e5855948322329b8c779065a71473ac5705abungeman@google.com            canvas.clear(SK_ColorTRANSPARENT);
465b314e5855948322329b8c779065a71473ac5705abungeman@google.com            canvas.scale(SkIntToScalar(glyph.fWidth) / SkIntToScalar(face->glyph->bitmap.width),
466b314e5855948322329b8c779065a71473ac5705abungeman@google.com                         SkIntToScalar(glyph.fHeight) / SkIntToScalar(face->glyph->bitmap.rows));
467b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkPaint paint;
468b314e5855948322329b8c779065a71473ac5705abungeman@google.com            paint.setFilterLevel(SkPaint::kLow_FilterLevel);
469b314e5855948322329b8c779065a71473ac5705abungeman@google.com            canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);
470b314e5855948322329b8c779065a71473ac5705abungeman@google.com
471b314e5855948322329b8c779065a71473ac5705abungeman@google.com            // If the destination is BW or LCD, convert from A8.
472b314e5855948322329b8c779065a71473ac5705abungeman@google.com            if (SkMask::kBW_Format == maskFormat) {
473b314e5855948322329b8c779065a71473ac5705abungeman@google.com                // Copy the A8 dstBitmap into the A1 glyph.fImage.
474b314e5855948322329b8c779065a71473ac5705abungeman@google.com                SkMask dstMask;
475b314e5855948322329b8c779065a71473ac5705abungeman@google.com                glyph.toMask(&dstMask);
476b314e5855948322329b8c779065a71473ac5705abungeman@google.com                packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
477b314e5855948322329b8c779065a71473ac5705abungeman@google.com            } else if (SkMask::kLCD16_Format == maskFormat) {
478b314e5855948322329b8c779065a71473ac5705abungeman@google.com                // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
479b314e5855948322329b8c779065a71473ac5705abungeman@google.com                uint8_t* src = dstBitmap.getAddr8(0, 0);
480b314e5855948322329b8c779065a71473ac5705abungeman@google.com                uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
481b314e5855948322329b8c779065a71473ac5705abungeman@google.com                for (int y = dstBitmap.height(); y --> 0;) {
482b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    for (int x = 0; x < dstBitmap.width(); ++x) {
483b314e5855948322329b8c779065a71473ac5705abungeman@google.com                        dst[x] = grayToRGB16(src[x]);
484b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    }
485b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    dst = (uint16_t*)((char*)dst + glyph.rowBytes());
486b314e5855948322329b8c779065a71473ac5705abungeman@google.com                    src += dstBitmap.rowBytes();
487b314e5855948322329b8c779065a71473ac5705abungeman@google.com                }
4884dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            }
489b314e5855948322329b8c779065a71473ac5705abungeman@google.com
4904dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        } break;
4914dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
492b314e5855948322329b8c779065a71473ac5705abungeman@google.com        default:
493b314e5855948322329b8c779065a71473ac5705abungeman@google.com            SkDEBUGFAIL("unknown glyph format");
494b314e5855948322329b8c779065a71473ac5705abungeman@google.com            memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
495b314e5855948322329b8c779065a71473ac5705abungeman@google.com            return;
4964dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    }
4974dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
4984dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
4994dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com// it is optional
5004dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com#if defined(SK_GAMMA_APPLY_TO_A8)
501ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
5024dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
5034dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        unsigned rowBytes = glyph.rowBytes();
504dfb3e3c0faadabc131ac1532e29ca71667328513rmistry@google.com
5054dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        for (int y = glyph.fHeight - 1; y >= 0; --y) {
5064dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            for (int x = glyph.fWidth - 1; x >= 0; --x) {
507ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                dst[x] = fPreBlend.fG[dst[x]];
5084dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            }
5094dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com            dst += rowBytes;
5104dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        }
5114dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    }
5124dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com#endif
5134dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com}
5144dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
515fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com///////////////////////////////////////////////////////////////////////////////
516fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com
517fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.comstatic int move_proc(const FT_Vector* pt, void* ctx) {
518fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    SkPath* path = (SkPath*)ctx;
519fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    path->close();  // to close the previous contour (if any)
520fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    path->moveTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
521fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    return 0;
522fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com}
523fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com
524fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.comstatic int line_proc(const FT_Vector* pt, void* ctx) {
525fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    SkPath* path = (SkPath*)ctx;
526fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    path->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
527fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    return 0;
528fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com}
529fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com
530fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.comstatic int quad_proc(const FT_Vector* pt0, const FT_Vector* pt1,
531fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com                     void* ctx) {
532fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    SkPath* path = (SkPath*)ctx;
533fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    path->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
534fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com                 SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y));
535fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    return 0;
536fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com}
537fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com
538fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.comstatic int cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1,
539fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com                      const FT_Vector* pt2, void* ctx) {
540fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    SkPath* path = (SkPath*)ctx;
541fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    path->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
542fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com                  SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y),
543fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com                  SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y));
544fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com    return 0;
545fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com}
546fb631c1a394164e84d25a5bf0f285950ef1f238bbungeman@google.com
5474dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.comvoid SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face,
5484dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com                                                      SkPath* path)
5494dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com{
5504dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) {
5514dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        emboldenOutline(face, &face->glyph->outline);
5524dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    }
5534dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
5544dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    FT_Outline_Funcs    funcs;
5554dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
5564dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    funcs.move_to   = move_proc;
5574dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    funcs.line_to   = line_proc;
5584dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    funcs.conic_to  = quad_proc;
5594dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    funcs.cubic_to  = cubic_proc;
5604dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    funcs.shift     = 0;
5614dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    funcs.delta     = 0;
5624dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
5634dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &funcs, path);
5644dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
5654dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    if (err != 0) {
5664dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        path->reset();
5674dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com        return;
5684dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    }
5694dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
5704dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    path->close();
5714dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com}
5724dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com
5734dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.comvoid SkScalerContext_FreeType_Base::emboldenOutline(FT_Face face, FT_Outline* outline)
5744dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com{
5754dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    FT_Pos strength;
5764dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    strength = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale)
5774dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com               / 24;
5784dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com    FT_Outline_Embolden(outline, strength);
5794dd9bf317ea9ba973ee05d201a682b2ea5fa7e87george@mozilla.com}
580