180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/* 280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2006-2012 The Android Open Source Project 380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2012 Mozilla Foundation 480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * 580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be 680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file. 780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */ 880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 9924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease#include "SkBitmap.h" 10924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease#include "SkCanvas.h" 11924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease#include "SkColor.h" 1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkColorPriv.h" 1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkFDot6.h" 1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkFontHost_FreeType_common.h" 1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkPath.h" 1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <ft2build.h> 18910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#include FT_FREETYPE_H 1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include FT_BITMAP_H 20910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#include FT_IMAGE_H 21910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#include FT_OUTLINE_H 2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file. 2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include FT_SYNTHESIS_H 2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 25910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger// FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA 26910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger// were introduced in FreeType 2.5.0. 27910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger// The following may be removed once FreeType 2.5.0 is required to build. 28910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#ifndef FT_LOAD_COLOR 29910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger# define FT_LOAD_COLOR ( 1L << 20 ) 30910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger# define FT_PIXEL_MODE_BGRA 7 31910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#endif 32910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 33910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger//#define SK_SHOW_TEXT_BLIT_COVERAGE 34910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) { 3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru switch (format) { 3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case SkMask::kBW_Format: 3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return FT_PIXEL_MODE_MONO; 3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case SkMask::kA8_Format: 4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru default: 4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return FT_PIXEL_MODE_GRAY; 4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////////////// 4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 476699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru// hand-tuned value to reduce outline embolden strength 486699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru#ifndef SK_OUTLINE_EMBOLDEN_DIVISOR 496699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru #ifdef SK_BUILD_FOR_ANDROID 506699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru #define SK_OUTLINE_EMBOLDEN_DIVISOR 34 516699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru #else 526699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru #define SK_OUTLINE_EMBOLDEN_DIVISOR 24 536699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru #endif 546699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru#endif 556699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru 566699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru/////////////////////////////////////////////////////////////////////////////// 576699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru 58910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergerstatic uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) { 59910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#ifdef SK_SHOW_TEXT_BLIT_COVERAGE 60910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger r = SkTMax(r, (U8CPU)0x40); 61910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger g = SkTMax(g, (U8CPU)0x40); 62910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger b = SkTMax(b, (U8CPU)0x40); 63910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#endif 64910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger return SkPack888ToRGB16(r, g, b); 6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic uint16_t grayToRGB16(U8CPU gray) { 68910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#ifdef SK_SHOW_TEXT_BLIT_COVERAGE 69910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger gray = SkTMax(gray, (U8CPU)0x40); 70910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#endif 71910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger return SkPack888ToRGB16(gray, gray, gray); 7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic int bittst(const uint8_t data[], int bitOffset) { 7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(bitOffset >= 0); 7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7); 7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return lowBit & 1; 7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 80910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger/** 81910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * Copies a FT_Bitmap into an SkMask with the same dimensions. 82910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * 83910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_MONO 84910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_GRAY 85910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_LCD 86910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_LCD_V 87910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger */ 8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querutemplate<bool APPLY_PREBLEND> 89910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergerstatic void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR, 90910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) 91910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger{ 92910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(SkMask::kLCD16_Format == mask.fFormat); 93910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) { 94910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(mask.fBounds.width() == bitmap.width); 95910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 96910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) { 97910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(mask.fBounds.height() == bitmap.rows); 9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const uint8_t* src = bitmap.buffer; 101910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage); 102910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const size_t dstRB = mask.fRowBytes; 103910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 104910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const int width = mask.fBounds.width(); 105910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const int height = mask.fBounds.height(); 10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru switch (bitmap.pixel_mode) { 108924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease case FT_PIXEL_MODE_MONO: 109910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int y = height; y --> 0;) { 11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int x = 0; x < width; ++x) { 11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dst[x] = -bittst(src, x); 11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dst = (uint16_t*)((char*)dst + dstRB); 11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru src += bitmap.pitch; 11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 116924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease break; 117924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease case FT_PIXEL_MODE_GRAY: 118910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int y = height; y --> 0;) { 11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int x = 0; x < width; ++x) { 12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dst[x] = grayToRGB16(src[x]); 12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dst = (uint16_t*)((char*)dst + dstRB); 12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru src += bitmap.pitch; 12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 125924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease break; 126910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger case FT_PIXEL_MODE_LCD: 127910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(3 * mask.fBounds.width() == bitmap.width); 128910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int y = height; y --> 0;) { 129910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const uint8_t* triple = src; 130910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (lcdIsBGR) { 13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int x = 0; x < width; x++) { 132910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR), 133910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG), 134910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB)); 135910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger triple += 3; 13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 137910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } else { 138910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int x = 0; x < width; x++) { 139910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR), 140910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG), 141910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB)); 142910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger triple += 3; 14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 145910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger src += bitmap.pitch; 14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dst = (uint16_t*)((char*)dst + dstRB); 14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 148924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease break; 149910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger case FT_PIXEL_MODE_LCD_V: 150910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(3 * mask.fBounds.height() == bitmap.rows); 151910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int y = height; y --> 0;) { 152910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const uint8_t* srcR = src; 153910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const uint8_t* srcG = srcR + bitmap.pitch; 154910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const uint8_t* srcB = srcG + bitmap.pitch; 155910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (lcdIsBGR) { 156910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkTSwap(srcR, srcB); 157910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 158910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int x = 0; x < width; x++) { 159910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR), 160910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG), 161910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB)); 162910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 163910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger src += 3 * bitmap.pitch; 164910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger dst = (uint16_t*)((char*)dst + dstRB); 165910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 166910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger break; 167910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger default: 168910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkDEBUGF(("FT_Pixel_Mode %d", bitmap.pixel_mode)); 169910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16"); 170910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger break; 171924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 172924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease} 173924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease 174910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger/** 175910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * Copies a FT_Bitmap into an SkMask with the same dimensions. 176910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * 177910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * Yes, No, Never Requested, Never Produced 178910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * 179910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * kBW kA8 k3D kARGB32 kLCD16 kLCD32 180910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_MONO Y Y NR N Y NR 181910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_GRAY N Y NR N Y NR 182910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_GRAY2 NP NP NR NP NP NR 183910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_GRAY4 NP NP NR NP NP NR 184910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_LCD NP NP NR NP NP NR 185910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_LCD_V NP NP NR NP NP NR 186910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * FT_PIXEL_MODE_BGRA N N NR Y N NR 187910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * 188910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger * TODO: All of these N need to be Y or otherwise ruled out. 189910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger */ 190910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergerstatic void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) { 191910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(dstMask.fBounds.width() == srcFTBitmap.width); 192910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(dstMask.fBounds.height() == srcFTBitmap.rows); 193910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 194924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer); 195910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode); 196910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // FT_Bitmap::pitch is an int and allowed to be negative. 197910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const int srcPitch = srcFTBitmap.pitch; 198910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const size_t srcRowBytes = SkTAbs(srcPitch); 199910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 200910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint8_t* dst = dstMask.fImage; 201910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat); 202910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const size_t dstRowBytes = dstMask.fRowBytes; 203910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 204910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const size_t width = srcFTBitmap.width; 205910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const size_t height = srcFTBitmap.rows; 206910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 207910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (SkMask::kLCD16_Format == dstFormat) { 208910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger copyFT2LCD16<false>(srcFTBitmap, dstMask, false, NULL, NULL, NULL); 209910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger return; 210910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 211910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 212910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) || 213910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat)) 214910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger { 215910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger size_t commonRowBytes = SkTMin(srcRowBytes, dstRowBytes); 216910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (size_t y = height; y --> 0;) { 217910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger memcpy(dst, src, commonRowBytes); 218910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger src += srcPitch; 219924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease dst += dstRowBytes; 220924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 221910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) { 222910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (size_t y = height; y --> 0;) { 223924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease uint8_t byte = 0; 224924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease int bits = 0; 225924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease const uint8_t* src_row = src; 226924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease uint8_t* dst_row = dst; 227910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (size_t x = width; x --> 0;) { 228910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (0 == bits) { 229924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease byte = *src_row++; 230924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease bits = 8; 231924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 232910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger *dst_row++ = byte & 0x80 ? 0xff : 0x00; 233924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease bits--; 234924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease byte <<= 1; 235924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 236910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger src += srcPitch; 237924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease dst += dstRowBytes; 238924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 239910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) { 240910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // FT_PIXEL_MODE_BGRA is pre-multiplied. 241910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (size_t y = height; y --> 0;) { 242924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease const uint8_t* src_row = src; 243910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst); 244910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (size_t x = 0; x < width; ++x) { 245910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint8_t b = *src_row++; 246910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint8_t g = *src_row++; 247910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint8_t r = *src_row++; 248910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint8_t a = *src_row++; 249910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger *dst_row++ = SkPackARGB32(a, r, g, b); 250910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#ifdef SK_SHOW_TEXT_BLIT_COVERAGE 251910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40); 252910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#endif 253924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 254910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger src += srcPitch; 255924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease dst += dstRowBytes; 256924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 257924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } else { 258910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkDEBUGF(("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat)); 259910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format"); 260924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 261924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease} 262924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease 263910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergerstatic inline int convert_8_to_1(unsigned byte) { 264910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(byte <= 0xFF); 265910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better. 266910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger return (byte >> 6) != 0; 267910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger} 268910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 269910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergerstatic uint8_t pack_8_to_1(const uint8_t alpha[8]) { 270910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger unsigned bits = 0; 271910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int i = 0; i < 8; ++i) { 272910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger bits <<= 1; 273910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger bits |= convert_8_to_1(alpha[i]); 274910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 275910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger return SkToU8(bits); 276910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger} 277910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 278910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergerstatic void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) { 279910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const int height = mask.fBounds.height(); 280910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const int width = mask.fBounds.width(); 281910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const int octs = width >> 3; 282910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const int leftOverBits = width & 7; 283910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 284910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint8_t* dst = mask.fImage; 285910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const int dstPad = mask.fRowBytes - SkAlign8(width)/8; 286910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(dstPad >= 0); 287910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 288910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger const int srcPad = srcRB - width; 289910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(srcPad >= 0); 290910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 291910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int y = 0; y < height; ++y) { 292910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int i = 0; i < octs; ++i) { 293910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger *dst++ = pack_8_to_1(src); 294910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger src += 8; 295910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 296910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (leftOverBits > 0) { 297910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger unsigned bits = 0; 298910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger int shift = 7; 299910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int i = 0; i < leftOverBits; ++i, --shift) { 300910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger bits |= convert_8_to_1(*src++) << shift; 301910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 302910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger *dst++ = bits; 303910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 304910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger src += srcPad; 305910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger dst += dstPad; 306910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 307910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger} 308910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 309910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergerinline SkMask::Format SkMaskFormat_for_SkBitmapConfig(SkBitmap::Config config) { 310910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger switch (config) { 311910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger case SkBitmap::kA8_Config: 312924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease return SkMask::kA8_Format; 313910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger case SkBitmap::kARGB_8888_Config: 314924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease return SkMask::kARGB32_Format; 315924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease default: 316910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkDEBUGFAIL("unsupported SkBitmap::Config"); 317924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease return SkMask::kA8_Format; 318924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 319924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease} 320924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease 321910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergerinline SkBitmap::Config SkBitmapConfig_for_FTPixelMode(FT_Pixel_Mode pixel_mode) { 322924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease switch (pixel_mode) { 323910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger case FT_PIXEL_MODE_MONO: 324924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease case FT_PIXEL_MODE_GRAY: 325924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease return SkBitmap::kA8_Config; 326924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease case FT_PIXEL_MODE_BGRA: 327924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease return SkBitmap::kARGB_8888_Config; 328924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease default: 329924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease SkDEBUGFAIL("unsupported FT_PIXEL_MODE"); 330924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease return SkBitmap::kA8_Config; 331924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 332924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease} 333924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease 334910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenbergerinline SkBitmap::Config SkBitmapConfig_for_SkMaskFormat(SkMask::Format format) { 335924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease switch (format) { 336910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger case SkMask::kBW_Format: 337924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease case SkMask::kA8_Format: 338910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger case SkMask::kLCD16_Format: 339924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease return SkBitmap::kA8_Config; 340924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease case SkMask::kARGB32_Format: 341924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease return SkBitmap::kARGB_8888_Config; 342924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease default: 343910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkDEBUGFAIL("unsupported destination SkBitmap::Config"); 344924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease return SkBitmap::kA8_Config; 34580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 34680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 34780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 348363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph) { 34980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag); 35080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag); 35180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 35280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru switch ( face->glyph->format ) { 35380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case FT_GLYPH_FORMAT_OUTLINE: { 35480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_Outline* outline = &face->glyph->outline; 35580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_BBox bbox; 35680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_Bitmap target; 35780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 358924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease if (fRec.fFlags & SkScalerContext::kEmbolden_Flag && 359924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease !(face->style_flags & FT_STYLE_FLAG_BOLD)) { 36080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru emboldenOutline(face, outline); 36180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 36280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 36380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int dx = 0, dy = 0; 36480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 36580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dx = SkFixedToFDot6(glyph.getSubXFixed()); 36680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dy = SkFixedToFDot6(glyph.getSubYFixed()); 36780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // negate dy since freetype-y-goes-up and skia-y-goes-down 36880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dy = -dy; 36980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 37080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_Outline_Get_CBox(outline, &bbox); 37180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru /* 37280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru what we really want to do for subpixel is 37380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru offset(dx, dy) 37480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru compute_bounds 37580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru offset(bbox & !63) 37680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru but that is two calls to offset, so we do the following, which 37780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru achieves the same thing with only one offset call. 37880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */ 37980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63), 38080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dy - ((bbox.yMin + dy) & ~63)); 38180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 382924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease if (SkMask::kLCD16_Format == glyph.fMaskFormat) { 38380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD); 384910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkMask mask; 385910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger glyph.toMask(&mask); 386363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fPreBlend.isApplicable()) { 387910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger copyFT2LCD16<true>(face->glyph->bitmap, mask, doBGR, 388363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 38980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 390910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger copyFT2LCD16<false>(face->glyph->bitmap, mask, doBGR, 391363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 39280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 39380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 39480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru target.width = glyph.fWidth; 39580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru target.rows = glyph.fHeight; 39680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru target.pitch = glyph.rowBytes(); 39780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage); 398910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger target.pixel_mode = compute_pixel_mode( (SkMask::Format)fRec.fMaskFormat); 39980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru target.num_grays = 256; 40080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 40180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); 40280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_Outline_Get_Bitmap(face->glyph->library, outline, &target); 40380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 40480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } break; 40580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 40680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case FT_GLYPH_FORMAT_BITMAP: { 407910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode); 408910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 409910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 410910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // Assume that the other formats do not exist. 411910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode || 412910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger FT_PIXEL_MODE_GRAY == pixel_mode || 413910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger FT_PIXEL_MODE_BGRA == pixel_mode); 414910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 415910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // These are the only formats this ScalerContext should request. 416910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkASSERT(SkMask::kBW_Format == maskFormat || 417910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkMask::kA8_Format == maskFormat || 418910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkMask::kARGB32_Format == maskFormat || 419910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkMask::kLCD16_Format == maskFormat); 420910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 421910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (fRec.fFlags & SkScalerContext::kEmbolden_Flag && 422910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger !(face->style_flags & FT_STYLE_FLAG_BOLD)) 423910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger { 42480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_GlyphSlot_Own_Bitmap(face->glyph); 425910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap, 426910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger kBitmapEmboldenStrength, 0); 42780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 42880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 429910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // If no scaling needed, directly copy glyph bitmap. 430910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (glyph.fWidth == face->glyph->bitmap.width && 431910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger glyph.fHeight == face->glyph->bitmap.rows && 432910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger glyph.fTop == -face->glyph->bitmap_top && 433910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger glyph.fLeft == face->glyph->bitmap_left) 434910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger { 435910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkMask dstMask; 436910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger glyph.toMask(&dstMask); 437910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger copyFTBitmap(face->glyph->bitmap, dstMask); 438910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger break; 439910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 440910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 441910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // Otherwise, scale the bitmap. 442910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 443910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB) 444910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkBitmap unscaledBitmap; 445910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger unscaledBitmap.setConfig(SkBitmapConfig_for_FTPixelMode(pixel_mode), 446910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger face->glyph->bitmap.width, face->glyph->bitmap.rows); 447910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger unscaledBitmap.allocPixels(); 448910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 449910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkMask unscaledBitmapAlias; 450910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels()); 451910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger unscaledBitmapAlias.fBounds.set(0, 0, unscaledBitmap.width(), unscaledBitmap.height()); 452910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes(); 453910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkBitmapConfig(unscaledBitmap.config()); 454910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias); 455910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 456910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD. 457910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // BW requires an A8 target for resizing, which can then be down sampled. 458910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // LCD should use a 4x A8 target, which will then be down sampled. 459910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // For simplicity, LCD uses A8 and is replicated. 460910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger int bitmapRowBytes = 0; 461910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) { 462910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger bitmapRowBytes = glyph.rowBytes(); 463910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 464910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkBitmap dstBitmap; 465910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger dstBitmap.setConfig(SkBitmapConfig_for_SkMaskFormat(maskFormat), 466910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger glyph.fWidth, glyph.fHeight, bitmapRowBytes); 467910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) { 468910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger dstBitmap.allocPixels(); 46980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 470910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger dstBitmap.setPixels(glyph.fImage); 471910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 472910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 473910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // Scale unscaledBitmap into dstBitmap. 474910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkCanvas canvas(dstBitmap); 475910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger canvas.clear(SK_ColorTRANSPARENT); 476910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger canvas.scale(SkIntToScalar(glyph.fWidth) / SkIntToScalar(face->glyph->bitmap.width), 477910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkIntToScalar(glyph.fHeight) / SkIntToScalar(face->glyph->bitmap.rows)); 478910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkPaint paint; 479910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger paint.setFilterLevel(SkPaint::kLow_FilterLevel); 480910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger canvas.drawBitmap(unscaledBitmap, 0, 0, &paint); 481910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 482910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // If the destination is BW or LCD, convert from A8. 483910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger if (SkMask::kBW_Format == maskFormat) { 484910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // Copy the A8 dstBitmap into the A1 glyph.fImage. 485910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger SkMask dstMask; 486910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger glyph.toMask(&dstMask); 487910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes()); 488910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } else if (SkMask::kLCD16_Format == maskFormat) { 489910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger // Copy the A8 dstBitmap into the LCD16 glyph.fImage. 490910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint8_t* src = dstBitmap.getAddr8(0, 0); 491910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage); 492910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int y = dstBitmap.height(); y --> 0;) { 493910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger for (int x = 0; x < dstBitmap.width(); ++x) { 494910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger dst[x] = grayToRGB16(src[x]); 495910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger } 496910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger dst = (uint16_t*)((char*)dst + glyph.rowBytes()); 497910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger src += dstBitmap.rowBytes(); 498924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease } 49980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 500910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger 50180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } break; 50280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 503924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease default: 504924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease SkDEBUGFAIL("unknown glyph format"); 505924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); 506924ac31ce033167b1d7b4e3ddbb640e706c64cccVictoria Lease return; 50780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 50880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 50980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum, 51080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// it is optional 51180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if defined(SK_GAMMA_APPLY_TO_A8) 512363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) { 51380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage; 51480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned rowBytes = glyph.rowBytes(); 51580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 51680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int y = glyph.fHeight - 1; y >= 0; --y) { 51780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int x = glyph.fWidth - 1; x >= 0; --x) { 518363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dst[x] = fPreBlend.fG[dst[x]]; 51980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 52080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dst += rowBytes; 52180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 52280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 52380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 52480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 52580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 52680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////////////// 52780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 52880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic int move_proc(const FT_Vector* pt, void* ctx) { 52980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPath* path = (SkPath*)ctx; 53080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru path->close(); // to close the previous contour (if any) 53180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru path->moveTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y)); 53280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return 0; 53380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 53480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 53580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic int line_proc(const FT_Vector* pt, void* ctx) { 53680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPath* path = (SkPath*)ctx; 53780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru path->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y)); 53880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return 0; 53980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 54080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 54180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic int quad_proc(const FT_Vector* pt0, const FT_Vector* pt1, 54280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru void* ctx) { 54380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPath* path = (SkPath*)ctx; 54480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru path->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y), 54580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y)); 54680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return 0; 54780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 54880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 54980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic int cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1, 55080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const FT_Vector* pt2, void* ctx) { 55180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPath* path = (SkPath*)ctx; 55280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru path->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y), 55380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y), 55480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y)); 55580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return 0; 55680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 55780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 55880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, 55980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPath* path) 56080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{ 5616699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru if (fRec.fFlags & SkScalerContext::kEmbolden_Flag && !(face->style_flags & FT_STYLE_FLAG_BOLD)) { 56280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru emboldenOutline(face, &face->glyph->outline); 56380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 56480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 56580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_Outline_Funcs funcs; 56680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 56780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru funcs.move_to = move_proc; 56880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru funcs.line_to = line_proc; 56980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru funcs.conic_to = quad_proc; 57080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru funcs.cubic_to = cubic_proc; 57180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru funcs.shift = 0; 57280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru funcs.delta = 0; 57380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 57480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &funcs, path); 57580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 57680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (err != 0) { 57780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru path->reset(); 57880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return; 57980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 58080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 58180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru path->close(); 58280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 58380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 58480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkScalerContext_FreeType_Base::emboldenOutline(FT_Face face, FT_Outline* outline) 58580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{ 58680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_Pos strength; 58780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru strength = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale) 5886699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru / SK_OUTLINE_EMBOLDEN_DIVISOR; 58980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FT_Outline_Embolden(outline, strength); 59080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 591