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