1c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com/*
2c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com * Copyright 2006-2012 The Android Open Source Project
3c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com * Copyright 2012 Mozilla Foundation
4c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com *
5c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com * Use of this source code is governed by a BSD-style license that can be
6c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com * found in the LICENSE file.
7c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com */
8c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
9c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#include "SkBitmap.h"
10c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#include "SkCanvas.h"
11c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#include "SkColor.h"
12c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com#include "SkColorPriv.h"
13c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com#include "SkFDot6.h"
14c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com#include "SkFontHost_FreeType_common.h"
15c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com#include "SkPath.h"
16c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
17c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com#include <ft2build.h>
18c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#include FT_FREETYPE_H
19c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com#include FT_BITMAP_H
20c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#include FT_IMAGE_H
21c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#include FT_OUTLINE_H
22c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com// In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
23c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com#include FT_SYNTHESIS_H
24c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
25c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com// FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
26c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com// were introduced in FreeType 2.5.0.
27c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com// The following may be removed once FreeType 2.5.0 is required to build.
28c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#ifndef FT_LOAD_COLOR
29c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#    define FT_LOAD_COLOR ( 1L << 20 )
30c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#    define FT_PIXEL_MODE_BGRA 7
31c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#endif
32c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
33c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com//#define SK_SHOW_TEXT_BLIT_COVERAGE
34c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
35c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.comstatic FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
36c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    switch (format) {
37c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        case SkMask::kBW_Format:
38c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            return FT_PIXEL_MODE_MONO;
39c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        case SkMask::kA8_Format:
40c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        default:
41c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            return FT_PIXEL_MODE_GRAY;
42c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    }
43c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com}
44c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
45c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com///////////////////////////////////////////////////////////////////////////////
46c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
47c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.comstatic uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) {
48c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
49c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    r = SkTMax(r, (U8CPU)0x40);
50c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    g = SkTMax(g, (U8CPU)0x40);
51c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    b = SkTMax(b, (U8CPU)0x40);
52c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#endif
53c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    return SkPack888ToRGB16(r, g, b);
54c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com}
55c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
56c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.comstatic uint16_t grayToRGB16(U8CPU gray) {
57c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
58c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    gray = SkTMax(gray, (U8CPU)0x40);
59c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#endif
60c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    return SkPack888ToRGB16(gray, gray, gray);
61c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com}
62c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
63c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.comstatic int bittst(const uint8_t data[], int bitOffset) {
64c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    SkASSERT(bitOffset >= 0);
65c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
66c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    return lowBit & 1;
67c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com}
68c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
69c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com/**
70c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  Copies a FT_Bitmap into an SkMask with the same dimensions.
71c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *
72c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_MONO
73c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_GRAY
74c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_LCD
75c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_LCD_V
76c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com */
77c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.comtemplate<bool APPLY_PREBLEND>
78c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.comstatic void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR,
79c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
80c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com{
81c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    SkASSERT(SkMask::kLCD16_Format == mask.fFormat);
82c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) {
83c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        SkASSERT(mask.fBounds.width() == bitmap.width);
84c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    }
85c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) {
86c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        SkASSERT(mask.fBounds.height() == bitmap.rows);
87c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    }
88c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
89c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    const uint8_t* src = bitmap.buffer;
90c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage);
91c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const size_t dstRB = mask.fRowBytes;
92c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
93c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const int width = mask.fBounds.width();
94c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const int height = mask.fBounds.height();
95c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
96c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    switch (bitmap.pixel_mode) {
97c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case FT_PIXEL_MODE_MONO:
98c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            for (int y = height; y --> 0;) {
99c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                for (int x = 0; x < width; ++x) {
100c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                    dst[x] = -bittst(src, x);
101c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                }
102c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                dst = (uint16_t*)((char*)dst + dstRB);
103c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                src += bitmap.pitch;
104c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            }
105c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            break;
106c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case FT_PIXEL_MODE_GRAY:
107c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            for (int y = height; y --> 0;) {
108c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                for (int x = 0; x < width; ++x) {
109c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                    dst[x] = grayToRGB16(src[x]);
110c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                }
111c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                dst = (uint16_t*)((char*)dst + dstRB);
112c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                src += bitmap.pitch;
113c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            }
114c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            break;
115c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case FT_PIXEL_MODE_LCD:
116c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkASSERT(3 * mask.fBounds.width() == bitmap.width);
117c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            for (int y = height; y --> 0;) {
118c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                const uint8_t* triple = src;
119c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                if (lcdIsBGR) {
120c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                    for (int x = 0; x < width; x++) {
121c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                        dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
122c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
123c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
124c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                        triple += 3;
125c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                    }
126c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                } else {
127c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    for (int x = 0; x < width; x++) {
128c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                        dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
129c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
130c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                                            sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
131c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                        triple += 3;
132c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                    }
133c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                }
134c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                src += bitmap.pitch;
135c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                dst = (uint16_t*)((char*)dst + dstRB);
136c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            }
137c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            break;
138c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case FT_PIXEL_MODE_LCD_V:
139c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkASSERT(3 * mask.fBounds.height() == bitmap.rows);
140c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            for (int y = height; y --> 0;) {
141c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                const uint8_t* srcR = src;
142c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                const uint8_t* srcG = srcR + bitmap.pitch;
143c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                const uint8_t* srcB = srcG + bitmap.pitch;
144c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                if (lcdIsBGR) {
145c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    SkTSwap(srcR, srcB);
146c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                }
147c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                for (int x = 0; x < width; x++) {
148c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
149c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                                        sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
150c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                                        sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
151c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                }
152c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                src += 3 * bitmap.pitch;
153c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                dst = (uint16_t*)((char*)dst + dstRB);
154c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            }
155c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            break;
156c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        default:
157c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkDEBUGF(("FT_Pixel_Mode %d", bitmap.pixel_mode));
158c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16");
159c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            break;
160c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    }
161c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com}
162c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
163c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com/**
164c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  Copies a FT_Bitmap into an SkMask with the same dimensions.
165c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *
166c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  Yes, No, Never Requested, Never Produced
167c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *
168c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *                        kBW kA8 k3D kARGB32 kLCD16 kLCD32
169c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_MONO     Y   Y  NR     N       Y     NR
170c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_GRAY     N   Y  NR     N       Y     NR
171c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_GRAY2   NP  NP  NR    NP      NP     NR
172c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_GRAY4   NP  NP  NR    NP      NP     NR
173c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_LCD     NP  NP  NR    NP      NP     NR
174c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_LCD_V   NP  NP  NR    NP      NP     NR
175c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  FT_PIXEL_MODE_BGRA     N   N  NR     Y       N     NR
176c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *
177c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com *  TODO: All of these N need to be Y or otherwise ruled out.
178c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com */
179c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.comstatic void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) {
180c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    SkASSERT(dstMask.fBounds.width() == srcFTBitmap.width);
181c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    SkASSERT(dstMask.fBounds.height() == srcFTBitmap.rows);
182c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
183c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
184c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode);
185c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    // FT_Bitmap::pitch is an int and allowed to be negative.
186c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const int srcPitch = srcFTBitmap.pitch;
187c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const size_t srcRowBytes = SkTAbs(srcPitch);
188c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
189c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    uint8_t* dst = dstMask.fImage;
190c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat);
191c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const size_t dstRowBytes = dstMask.fRowBytes;
192c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
193c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const size_t width = srcFTBitmap.width;
194c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const size_t height = srcFTBitmap.rows;
195c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
196c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    if (SkMask::kLCD16_Format == dstFormat) {
197c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        copyFT2LCD16<false>(srcFTBitmap, dstMask, false, NULL, NULL, NULL);
198c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        return;
199c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    }
200c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
201c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) ||
202c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat))
203c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    {
204c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        size_t commonRowBytes = SkTMin(srcRowBytes, dstRowBytes);
205c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        for (size_t y = height; y --> 0;) {
206c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            memcpy(dst, src, commonRowBytes);
207c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            src += srcPitch;
208c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            dst += dstRowBytes;
209c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        }
210c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) {
211c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        for (size_t y = height; y --> 0;) {
212c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            uint8_t byte = 0;
213c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            int bits = 0;
214c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            const uint8_t* src_row = src;
215c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            uint8_t* dst_row = dst;
216c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            for (size_t x = width; x --> 0;) {
217c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                if (0 == bits) {
218c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    byte = *src_row++;
219c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    bits = 8;
220c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                }
221c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                *dst_row++ = byte & 0x80 ? 0xff : 0x00;
222c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                bits--;
223c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                byte <<= 1;
224c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            }
225c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            src += srcPitch;
226c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            dst += dstRowBytes;
227c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        }
228c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) {
229c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        // FT_PIXEL_MODE_BGRA is pre-multiplied.
230c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        for (size_t y = height; y --> 0;) {
231c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            const uint8_t* src_row = src;
232c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst);
233c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            for (size_t x = 0; x < width; ++x) {
234c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                uint8_t b = *src_row++;
235c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                uint8_t g = *src_row++;
236c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                uint8_t r = *src_row++;
237c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                uint8_t a = *src_row++;
238c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                *dst_row++ = SkPackARGB32(a, r, g, b);
239c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
240c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40);
241c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com#endif
242c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            }
243c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            src += srcPitch;
244c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            dst += dstRowBytes;
245c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        }
246c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    } else {
247c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        SkDEBUGF(("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat));
248c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format");
249c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    }
250c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com}
251c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
252c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.comstatic inline int convert_8_to_1(unsigned byte) {
253c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    SkASSERT(byte <= 0xFF);
254c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better.
255c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    return (byte >> 6) != 0;
256c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com}
257c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
258c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.comstatic uint8_t pack_8_to_1(const uint8_t alpha[8]) {
259c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    unsigned bits = 0;
260c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    for (int i = 0; i < 8; ++i) {
261c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        bits <<= 1;
262c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        bits |= convert_8_to_1(alpha[i]);
263c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    }
264c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    return SkToU8(bits);
265c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com}
266c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
267c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.comstatic void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
268c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const int height = mask.fBounds.height();
269c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const int width = mask.fBounds.width();
270c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const int octs = width >> 3;
271c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const int leftOverBits = width & 7;
272c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
273c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    uint8_t* dst = mask.fImage;
274c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
275c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    SkASSERT(dstPad >= 0);
276c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
277c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    const int srcPad = srcRB - width;
278c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    SkASSERT(srcPad >= 0);
279c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
280c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    for (int y = 0; y < height; ++y) {
281c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        for (int i = 0; i < octs; ++i) {
282c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            *dst++ = pack_8_to_1(src);
283c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            src += 8;
284c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        }
285c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        if (leftOverBits > 0) {
286c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            unsigned bits = 0;
287c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            int shift = 7;
288c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            for (int i = 0; i < leftOverBits; ++i, --shift) {
289c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                bits |= convert_8_to_1(*src++) << shift;
290c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            }
291c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            *dst++ = bits;
292c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        }
293c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        src += srcPad;
294c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        dst += dstPad;
295c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    }
296c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com}
297c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
2986c22573edb234ad14df947278cfed010669a39a7reedinline SkMask::Format SkMaskFormat_for_SkColorType(SkColorType colorType) {
2996c22573edb234ad14df947278cfed010669a39a7reed    switch (colorType) {
3006c22573edb234ad14df947278cfed010669a39a7reed        case kAlpha_8_SkColorType:
301c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            return SkMask::kA8_Format;
3026c22573edb234ad14df947278cfed010669a39a7reed        case kN32_SkColorType:
303c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            return SkMask::kARGB32_Format;
304c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        default:
305c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkDEBUGFAIL("unsupported SkBitmap::Config");
306c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            return SkMask::kA8_Format;
307c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    }
308c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com}
309c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
3106c22573edb234ad14df947278cfed010669a39a7reedinline SkColorType SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode) {
311c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    switch (pixel_mode) {
312c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case FT_PIXEL_MODE_MONO:
313c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case FT_PIXEL_MODE_GRAY:
3146c22573edb234ad14df947278cfed010669a39a7reed            return kAlpha_8_SkColorType;
315c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case FT_PIXEL_MODE_BGRA:
3166c22573edb234ad14df947278cfed010669a39a7reed            return kN32_SkColorType;
317c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        default:
318c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
3196c22573edb234ad14df947278cfed010669a39a7reed            return kAlpha_8_SkColorType;
320c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    }
321c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com}
322c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
3236c22573edb234ad14df947278cfed010669a39a7reedinline SkColorType SkColorType_for_SkMaskFormat(SkMask::Format format) {
324c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com    switch (format) {
325c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case SkMask::kBW_Format:
326c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case SkMask::kA8_Format:
327c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case SkMask::kLCD16_Format:
3286c22573edb234ad14df947278cfed010669a39a7reed            return kAlpha_8_SkColorType;
329c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        case SkMask::kARGB32_Format:
3306c22573edb234ad14df947278cfed010669a39a7reed            return kN32_SkColorType;
331c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        default:
332c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkDEBUGFAIL("unsupported destination SkBitmap::Config");
3336c22573edb234ad14df947278cfed010669a39a7reed            return kAlpha_8_SkColorType;
334c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    }
335c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com}
336c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
337a76de72a6036da0a6b051b14411b80941971f881bungeman@google.comvoid SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph) {
338c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
339c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
340c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
341c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    switch ( face->glyph->format ) {
342c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        case FT_GLYPH_FORMAT_OUTLINE: {
343c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            FT_Outline* outline = &face->glyph->outline;
344c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            FT_BBox     bbox;
345c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            FT_Bitmap   target;
346c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
347c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            int dx = 0, dy = 0;
348c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
349c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                dx = SkFixedToFDot6(glyph.getSubXFixed());
350c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                dy = SkFixedToFDot6(glyph.getSubYFixed());
351c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                // negate dy since freetype-y-goes-up and skia-y-goes-down
352c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                dy = -dy;
353c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            }
354c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            FT_Outline_Get_CBox(outline, &bbox);
355c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            /*
356c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                what we really want to do for subpixel is
357c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                    offset(dx, dy)
358c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                    compute_bounds
359c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                    offset(bbox & !63)
360c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                but that is two calls to offset, so we do the following, which
361c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                achieves the same thing with only one offset call.
362c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            */
363c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
364c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                                          dy - ((bbox.yMin + dy) & ~63));
365c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
366c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
367c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD);
368c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                SkMask mask;
369c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                glyph.toMask(&mask);
370a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com                if (fPreBlend.isApplicable()) {
371c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    copyFT2LCD16<true>(face->glyph->bitmap, mask, doBGR,
372a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
373c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                } else {
374c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    copyFT2LCD16<false>(face->glyph->bitmap, mask, doBGR,
375a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
376c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                }
377c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            } else {
378c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                target.width = glyph.fWidth;
379c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                target.rows = glyph.fHeight;
380c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                target.pitch = glyph.rowBytes();
381c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
382c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                target.pixel_mode = compute_pixel_mode( (SkMask::Format)fRec.fMaskFormat);
383c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                target.num_grays = 256;
384c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
385c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
386c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
387c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            }
388c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        } break;
389c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
390c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        case FT_GLYPH_FORMAT_BITMAP: {
391c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
392c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
393c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
394c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // Assume that the other formats do not exist.
395c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
396c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                     FT_PIXEL_MODE_GRAY == pixel_mode ||
397c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                     FT_PIXEL_MODE_BGRA == pixel_mode);
398c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
399c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // These are the only formats this ScalerContext should request.
400c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkASSERT(SkMask::kBW_Format == maskFormat ||
401c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                     SkMask::kA8_Format == maskFormat ||
402c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                     SkMask::kARGB32_Format == maskFormat ||
403c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                     SkMask::kLCD16_Format == maskFormat);
404c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
405c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
406c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                !(face->style_flags & FT_STYLE_FLAG_BOLD))
407c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            {
408c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                FT_GlyphSlot_Own_Bitmap(face->glyph);
409c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap,
410c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                                   kBitmapEmboldenStrength, 0);
411c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            }
412c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
413c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // If no scaling needed, directly copy glyph bitmap.
414c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            if (glyph.fWidth == face->glyph->bitmap.width &&
415c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                glyph.fHeight == face->glyph->bitmap.rows &&
416c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                glyph.fTop == -face->glyph->bitmap_top &&
417c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                glyph.fLeft == face->glyph->bitmap_left)
418c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            {
419c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                SkMask dstMask;
420c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                glyph.toMask(&dstMask);
421c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                copyFTBitmap(face->glyph->bitmap, dstMask);
422c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                break;
423c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            }
424c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
425c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // Otherwise, scale the bitmap.
426c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
427c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
428c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkBitmap unscaledBitmap;
4296c22573edb234ad14df947278cfed010669a39a7reed            unscaledBitmap.allocPixels(SkImageInfo::Make(face->glyph->bitmap.width,
4306c22573edb234ad14df947278cfed010669a39a7reed                                                         face->glyph->bitmap.rows,
4316c22573edb234ad14df947278cfed010669a39a7reed                                                         SkColorType_for_FTPixelMode(pixel_mode),
4326c22573edb234ad14df947278cfed010669a39a7reed                                                         kPremul_SkAlphaType));
433c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
434c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkMask unscaledBitmapAlias;
435c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
436c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            unscaledBitmapAlias.fBounds.set(0, 0, unscaledBitmap.width(), unscaledBitmap.height());
437c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
4386c22573edb234ad14df947278cfed010669a39a7reed            unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkColorType(unscaledBitmap.colorType());
439c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);
440c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
441c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
442c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // BW requires an A8 target for resizing, which can then be down sampled.
443c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // LCD should use a 4x A8 target, which will then be down sampled.
444c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // For simplicity, LCD uses A8 and is replicated.
445c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            int bitmapRowBytes = 0;
446c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
447c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                bitmapRowBytes = glyph.rowBytes();
448c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            }
449c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkBitmap dstBitmap;
4506c22573edb234ad14df947278cfed010669a39a7reed            dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
4516c22573edb234ad14df947278cfed010669a39a7reed                                                SkColorType_for_SkMaskFormat(maskFormat),
4526c22573edb234ad14df947278cfed010669a39a7reed                                                kPremul_SkAlphaType),
4536c22573edb234ad14df947278cfed010669a39a7reed                              bitmapRowBytes);
454c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
455c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                dstBitmap.allocPixels();
456c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            } else {
457c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                dstBitmap.setPixels(glyph.fImage);
458c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            }
459c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
460c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // Scale unscaledBitmap into dstBitmap.
461c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkCanvas canvas(dstBitmap);
462c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            canvas.clear(SK_ColorTRANSPARENT);
463c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            canvas.scale(SkIntToScalar(glyph.fWidth) / SkIntToScalar(face->glyph->bitmap.width),
464c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                         SkIntToScalar(glyph.fHeight) / SkIntToScalar(face->glyph->bitmap.rows));
465c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkPaint paint;
466ef24b7d33826f9e71f01870b3bad9d52f2a8d220djsollen            paint.setFilterLevel(SkPaint::kMedium_FilterLevel);
467c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);
468c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
469c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            // If the destination is BW or LCD, convert from A8.
470c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            if (SkMask::kBW_Format == maskFormat) {
471c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                // Copy the A8 dstBitmap into the A1 glyph.fImage.
472c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                SkMask dstMask;
473c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                glyph.toMask(&dstMask);
474c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
475c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            } else if (SkMask::kLCD16_Format == maskFormat) {
476c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
477c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                uint8_t* src = dstBitmap.getAddr8(0, 0);
478c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
479c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                for (int y = dstBitmap.height(); y --> 0;) {
480c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    for (int x = 0; x < dstBitmap.width(); ++x) {
481c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                        dst[x] = grayToRGB16(src[x]);
482c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    }
483c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    dst = (uint16_t*)((char*)dst + glyph.rowBytes());
484c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                    src += dstBitmap.rowBytes();
485c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com                }
486c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            }
487c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com
488c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        } break;
489c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
490c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com        default:
491c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            SkDEBUGFAIL("unknown glyph format");
492c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
493c9a8a7e23de576ac91e9b34a221382f7c0e69813bungeman@google.com            return;
494c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    }
495c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
496c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
497c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com// it is optional
498c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com#if defined(SK_GAMMA_APPLY_TO_A8)
499a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
500c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
501c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        unsigned rowBytes = glyph.rowBytes();
502d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
503c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        for (int y = glyph.fHeight - 1; y >= 0; --y) {
504c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            for (int x = glyph.fWidth - 1; x >= 0; --x) {
505a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com                dst[x] = fPreBlend.fG[dst[x]];
506c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            }
507c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com            dst += rowBytes;
508c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        }
509c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    }
510c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com#endif
511c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com}
512c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
5138ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com///////////////////////////////////////////////////////////////////////////////
5148ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com
5158ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.comstatic int move_proc(const FT_Vector* pt, void* ctx) {
5168ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    SkPath* path = (SkPath*)ctx;
5178ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    path->close();  // to close the previous contour (if any)
5188ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    path->moveTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
5198ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    return 0;
5208ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com}
5218ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com
5228ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.comstatic int line_proc(const FT_Vector* pt, void* ctx) {
5238ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    SkPath* path = (SkPath*)ctx;
5248ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    path->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
5258ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    return 0;
5268ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com}
5278ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com
5288ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.comstatic int quad_proc(const FT_Vector* pt0, const FT_Vector* pt1,
5298ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com                     void* ctx) {
5308ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    SkPath* path = (SkPath*)ctx;
5318ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    path->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
5328ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com                 SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y));
5338ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    return 0;
5348ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com}
5358ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com
5368ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.comstatic int cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1,
5378ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com                      const FT_Vector* pt2, void* ctx) {
5388ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    SkPath* path = (SkPath*)ctx;
5398ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    path->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
5408ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com                  SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y),
5418ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com                  SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y));
5428ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com    return 0;
5438ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com}
5448ff8a1959f514b969198ec2242c7de57fbf413cdbungeman@google.com
545c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.comvoid SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face,
546c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com                                                      SkPath* path)
547c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com{
548c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    FT_Outline_Funcs    funcs;
549c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
550c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    funcs.move_to   = move_proc;
551c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    funcs.line_to   = line_proc;
552c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    funcs.conic_to  = quad_proc;
553c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    funcs.cubic_to  = cubic_proc;
554c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    funcs.shift     = 0;
555c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    funcs.delta     = 0;
556c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
557c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &funcs, path);
558c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
559c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    if (err != 0) {
560c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        path->reset();
561c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com        return;
562c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    }
563c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com
564c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com    path->close();
565c59b5dac9081e3613ed80d8b6d498e093c03eb87george@mozilla.com}
566