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