Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(973)

Unified Diff: src/ports/SkFontHost_FreeType_common.cpp

Issue 23684041: improve bitmap font support (FreeType only) (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Correct selection logic, remove debug code. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« gm/coloremoji.cpp ('K') | « src/ports/SkFontHost_FreeType.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ports/SkFontHost_FreeType_common.cpp
===================================================================
--- src/ports/SkFontHost_FreeType_common.cpp (revision 12480)
+++ src/ports/SkFontHost_FreeType_common.cpp (working copy)
@@ -6,17 +6,32 @@
* found in the LICENSE file.
*/
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkFDot6.h"
#include "SkFontHost_FreeType_common.h"
#include "SkPath.h"
#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_BITMAP_H
+#include FT_IMAGE_H
#include FT_OUTLINE_H
-#include FT_BITMAP_H
// In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
#include FT_SYNTHESIS_H
+// FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
+// were introduced in FreeType 2.5.0.
+// The following may be removed once FreeType 2.5.0 is required to build.
+#ifndef FT_LOAD_COLOR
+# define FT_LOAD_COLOR ( 1L << 20 )
+# define FT_PIXEL_MODE_BGRA 7
+#endif
+
+//#define SK_SHOW_TEXT_BLIT_COVERAGE
+
static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
switch (format) {
case SkMask::kBW_Format:
@@ -29,13 +44,20 @@
///////////////////////////////////////////////////////////////////////////////
-static uint16_t packTriple(unsigned r, unsigned g, unsigned b) {
- return SkPackRGB16(r >> 3, g >> 2, b >> 3);
+static uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) {
+#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
+ r = SkTMax(r, (U8CPU)0x40);
+ g = SkTMax(g, (U8CPU)0x40);
+ b = SkTMax(b, (U8CPU)0x40);
+#endif
+ return SkPack888ToRGB16(r, g, b);
}
static uint16_t grayToRGB16(U8CPU gray) {
- SkASSERT(gray <= 255);
- return SkPackRGB16(gray >> 3, gray >> 2, gray >> 3);
+#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
+ gray = SkTMax(gray, (U8CPU)0x40);
+#endif
+ return SkPack888ToRGB16(gray, gray, gray);
}
static int bittst(const uint8_t data[], int bitOffset) {
@@ -44,81 +66,274 @@
return lowBit & 1;
}
+/**
+ * Copies a FT_Bitmap into an SkMask with the same dimensions.
+ *
+ * FT_PIXEL_MODE_MONO
+ * FT_PIXEL_MODE_GRAY
+ * FT_PIXEL_MODE_LCD
+ * FT_PIXEL_MODE_LCD_V
+ */
template<bool APPLY_PREBLEND>
-static void copyFT2LCD16(const SkGlyph& glyph, const FT_Bitmap& bitmap,
- int lcdIsBGR, bool lcdIsVert, const uint8_t* tableR,
- const uint8_t* tableG, const uint8_t* tableB) {
- if (lcdIsVert) {
- SkASSERT(3 * glyph.fHeight == bitmap.rows);
- } else {
- SkASSERT(glyph.fHeight == bitmap.rows);
+static void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR,
+ const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
+{
+ SkASSERT(SkMask::kLCD16_Format == mask.fFormat);
+ if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) {
+ SkASSERT(mask.fBounds.width() == bitmap.width);
}
+ if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) {
+ SkASSERT(mask.fBounds.height() == bitmap.rows);
+ }
- uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
- const size_t dstRB = glyph.rowBytes();
- const int width = glyph.fWidth;
const uint8_t* src = bitmap.buffer;
+ uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage);
+ const size_t dstRB = mask.fRowBytes;
+ const int width = mask.fBounds.width();
+ const int height = mask.fBounds.height();
+
switch (bitmap.pixel_mode) {
- case FT_PIXEL_MODE_MONO: {
- for (int y = 0; y < glyph.fHeight; ++y) {
+ case FT_PIXEL_MODE_MONO:
+ for (int y = height; y --> 0;) {
for (int x = 0; x < width; ++x) {
dst[x] = -bittst(src, x);
}
dst = (uint16_t*)((char*)dst + dstRB);
src += bitmap.pitch;
}
- } break;
- case FT_PIXEL_MODE_GRAY: {
- for (int y = 0; y < glyph.fHeight; ++y) {
+ break;
+ case FT_PIXEL_MODE_GRAY:
+ for (int y = height; y --> 0;) {
for (int x = 0; x < width; ++x) {
dst[x] = grayToRGB16(src[x]);
}
dst = (uint16_t*)((char*)dst + dstRB);
src += bitmap.pitch;
}
- } break;
- default: {
- SkASSERT(lcdIsVert || (glyph.fWidth * 3 == bitmap.width));
- for (int y = 0; y < glyph.fHeight; y++) {
- if (lcdIsVert) { // vertical stripes
- const uint8_t* srcR = src;
- const uint8_t* srcG = srcR + bitmap.pitch;
- const uint8_t* srcB = srcG + bitmap.pitch;
- if (lcdIsBGR) {
- SkTSwap(srcR, srcB);
+ break;
+ case FT_PIXEL_MODE_LCD:
+ SkASSERT(3 * mask.fBounds.width() == bitmap.width);
+ for (int y = height; y --> 0;) {
+ const uint8_t* triple = src;
+ if (lcdIsBGR) {
+ for (int x = 0; x < width; x++) {
+ dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
+ sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
+ sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
+ triple += 3;
}
+ } else {
for (int x = 0; x < width; x++) {
- dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
- sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
- sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
+ dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
+ sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
+ sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
+ triple += 3;
}
- src += 3 * bitmap.pitch;
- } else { // horizontal stripes
- const uint8_t* triple = src;
- if (lcdIsBGR) {
- for (int x = 0; x < width; x++) {
- dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
- sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
- sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
- triple += 3;
- }
- } else {
- for (int x = 0; x < width; x++) {
- dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
- sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
- sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
- triple += 3;
- }
- }
- src += bitmap.pitch;
}
+ src += bitmap.pitch;
dst = (uint16_t*)((char*)dst + dstRB);
}
- } break;
+ break;
+ case FT_PIXEL_MODE_LCD_V:
+ SkASSERT(3 * mask.fBounds.height() == bitmap.rows);
+ for (int y = height; y --> 0;) {
+ const uint8_t* srcR = src;
+ const uint8_t* srcG = srcR + bitmap.pitch;
+ const uint8_t* srcB = srcG + bitmap.pitch;
+ if (lcdIsBGR) {
+ SkTSwap(srcR, srcB);
+ }
+ for (int x = 0; x < width; x++) {
+ dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
+ sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
+ sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
+ }
+ src += 3 * bitmap.pitch;
+ dst = (uint16_t*)((char*)dst + dstRB);
+ }
+ break;
+ default:
+ SkDEBUGF(("FT_Pixel_Mode %d", bitmap.pixel_mode));
+ SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16");
+ break;
}
}
+/**
+ * Copies a FT_Bitmap into an SkMask with the same dimensions.
+ *
+ * Yes, No, Never Requested, Never Produced
+ *
+ * kBW kA8 k3D kARGB32 kLCD16 kLCD32
+ * FT_PIXEL_MODE_MONO Y Y NR N Y NR
+ * FT_PIXEL_MODE_GRAY N Y NR N Y NR
+ * FT_PIXEL_MODE_GRAY2 NP NP NR NP NP NR
+ * FT_PIXEL_MODE_GRAY4 NP NP NR NP NP NR
+ * FT_PIXEL_MODE_LCD NP NP NR NP NP NR
+ * FT_PIXEL_MODE_LCD_V NP NP NR NP NP NR
+ * FT_PIXEL_MODE_BGRA N N NR Y N NR
+ *
+ * TODO: All of these N need to be Y or otherwise ruled out.
+ */
+static void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) {
+ SkASSERT(dstMask.fBounds.width() == srcFTBitmap.width);
+ SkASSERT(dstMask.fBounds.height() == srcFTBitmap.rows);
+
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
+ const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode);
+ // FT_Bitmap::pitch is an int and allowed to be negative.
+ const int srcPitch = srcFTBitmap.pitch;
+ const size_t srcRowBytes = SkTAbs(srcPitch);
+
+ uint8_t* dst = dstMask.fImage;
+ const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat);
+ const size_t dstRowBytes = dstMask.fRowBytes;
+
+ const size_t width = srcFTBitmap.width;
+ const size_t height = srcFTBitmap.rows;
+
+ if (SkMask::kLCD16_Format == dstFormat) {
+ copyFT2LCD16<false>(srcFTBitmap, dstMask, false, NULL, NULL, NULL);
+ return;
+ }
+
+ if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) ||
+ (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat))
+ {
+ size_t commonRowBytes = SkTMin(srcRowBytes, dstRowBytes);
+ for (size_t y = height; y --> 0;) {
+ memcpy(dst, src, commonRowBytes);
+ src += srcPitch;
+ dst += dstRowBytes;
+ }
+ } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) {
+ for (size_t y = height; y --> 0;) {
+ uint8_t byte = 0;
+ int bits = 0;
+ const uint8_t* src_row = src;
+ uint8_t* dst_row = dst;
+ for (size_t x = width; x --> 0;) {
+ if (0 == bits) {
+ byte = *src_row++;
+ bits = 8;
+ }
+ *dst_row++ = byte & 0x80 ? 0xff : 0x00;
+ bits--;
+ byte <<= 1;
+ }
+ src += srcPitch;
+ dst += dstRowBytes;
+ }
+ } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) {
+ // FT_PIXEL_MODE_BGRA is pre-multiplied.
+ for (size_t y = height; y --> 0;) {
+ const uint8_t* src_row = src;
+ SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst);
+ for (size_t x = 0; x < width; ++x) {
+ uint8_t b = *src_row++;
+ uint8_t g = *src_row++;
+ uint8_t r = *src_row++;
+ uint8_t a = *src_row++;
+ *dst_row++ = SkPackARGB32(a, r, g, b);
+#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
+ *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40);
+#endif
+ }
+ src += srcPitch;
+ dst += dstRowBytes;
+ }
+ } else {
+ SkDEBUGF(("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat));
+ SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format");
+ }
+}
+
+static inline int convert_8_to_1(unsigned byte) {
+ SkASSERT(byte <= 0xFF);
+ // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better.
+ return (byte >> 6) != 0;
+}
+
+static uint8_t pack_8_to_1(const uint8_t alpha[8]) {
+ unsigned bits = 0;
+ for (int i = 0; i < 8; ++i) {
+ bits <<= 1;
+ bits |= convert_8_to_1(alpha[i]);
+ }
+ return SkToU8(bits);
+}
+
+static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
+ const int height = mask.fBounds.height();
+ const int width = mask.fBounds.width();
+ const int octs = width >> 3;
+ const int leftOverBits = width & 7;
+
+ uint8_t* dst = mask.fImage;
+ const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
+ SkASSERT(dstPad >= 0);
+
+ const int srcPad = srcRB - width;
+ SkASSERT(srcPad >= 0);
+
+ for (int y = 0; y < height; ++y) {
+ for (int i = 0; i < octs; ++i) {
+ *dst++ = pack_8_to_1(src);
+ src += 8;
+ }
+ if (leftOverBits > 0) {
+ unsigned bits = 0;
+ int shift = 7;
+ for (int i = 0; i < leftOverBits; ++i, --shift) {
+ bits |= convert_8_to_1(*src++) << shift;
+ }
+ *dst++ = bits;
+ }
+ src += srcPad;
+ dst += dstPad;
+ }
+}
+
+inline SkMask::Format SkMaskFormat_for_SkBitmapConfig(SkBitmap::Config config) {
+ switch (config) {
+ case SkBitmap::kA8_Config:
+ return SkMask::kA8_Format;
+ case SkBitmap::kARGB_8888_Config:
+ return SkMask::kARGB32_Format;
+ default:
+ SkDEBUGFAIL("unsupported SkBitmap::Config");
+ return SkMask::kA8_Format;
+ }
+}
+
+inline SkBitmap::Config SkBitmapConfig_for_FTPixelMode(FT_Pixel_Mode pixel_mode) {
+ switch (pixel_mode) {
+ case FT_PIXEL_MODE_MONO:
+ case FT_PIXEL_MODE_GRAY:
+ return SkBitmap::kA8_Config;
+ case FT_PIXEL_MODE_BGRA:
+ return SkBitmap::kARGB_8888_Config;
+ default:
+ SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
+ return SkBitmap::kA8_Config;
+ }
+}
+
+inline SkBitmap::Config SkBitmapConfig_for_SkMaskFormat(SkMask::Format format) {
+ switch (format) {
+ case SkMask::kBW_Format:
+ case SkMask::kA8_Format:
+ case SkMask::kLCD16_Format:
+ return SkBitmap::kA8_Config;
+ case SkMask::kARGB32_Format:
+ return SkBitmap::kARGB_8888_Config;
+ default:
+ SkDEBUGFAIL("unsupported destination SkBitmap::Config");
+ return SkBitmap::kA8_Config;
+ }
+}
+
void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph) {
const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
@@ -129,7 +344,8 @@
FT_BBox bbox;
FT_Bitmap target;
- if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) {
+ if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
+ !(face->style_flags & FT_STYLE_FLAG_BOLD)) {
emboldenOutline(face, outline);
}
@@ -154,11 +370,13 @@
if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD);
+ SkMask mask;
+ glyph.toMask(&mask);
if (fPreBlend.isApplicable()) {
- copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert,
+ copyFT2LCD16<true>(face->glyph->bitmap, mask, doBGR,
fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
} else {
- copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVert,
+ copyFT2LCD16<false>(face->glyph->bitmap, mask, doBGR,
fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
}
} else {
@@ -166,8 +384,7 @@
target.rows = glyph.fHeight;
target.pitch = glyph.rowBytes();
target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
- target.pixel_mode = compute_pixel_mode(
- (SkMask::Format)fRec.fMaskFormat);
+ target.pixel_mode = compute_pixel_mode( (SkMask::Format)fRec.fMaskFormat);
target.num_grays = 256;
memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
@@ -176,71 +393,106 @@
} break;
case FT_GLYPH_FORMAT_BITMAP: {
- if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) {
+ FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
+ SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
+
+ // Assume that the other formats do not exist.
+ SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
+ FT_PIXEL_MODE_GRAY == pixel_mode ||
+ FT_PIXEL_MODE_BGRA == pixel_mode);
+
+ // These are the only formats this ScalerContext should request.
+ SkASSERT(SkMask::kBW_Format == maskFormat ||
+ SkMask::kA8_Format == maskFormat ||
+ SkMask::kARGB32_Format == maskFormat ||
+ SkMask::kLCD16_Format == maskFormat);
+
+ if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
+ !(face->style_flags & FT_STYLE_FLAG_BOLD))
+ {
FT_GlyphSlot_Own_Bitmap(face->glyph);
- FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap, kBitmapEmboldenStrength, 0);
+ FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap,
+ kBitmapEmboldenStrength, 0);
}
- SkASSERT_CONTINUE(glyph.fWidth == face->glyph->bitmap.width);
- SkASSERT_CONTINUE(glyph.fHeight == face->glyph->bitmap.rows);
- SkASSERT_CONTINUE(glyph.fTop == -face->glyph->bitmap_top);
- SkASSERT_CONTINUE(glyph.fLeft == face->glyph->bitmap_left);
- const uint8_t* src = (const uint8_t*)face->glyph->bitmap.buffer;
- uint8_t* dst = (uint8_t*)glyph.fImage;
+ // If no scaling needed, directly copy glyph bitmap.
+ if (glyph.fWidth == face->glyph->bitmap.width &&
+ glyph.fHeight == face->glyph->bitmap.rows &&
+ glyph.fTop == -face->glyph->bitmap_top &&
+ glyph.fLeft == face->glyph->bitmap_left)
+ {
+ SkMask dstMask;
+ glyph.toMask(&dstMask);
+ copyFTBitmap(face->glyph->bitmap, dstMask);
+ break;
+ }
- if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ||
- (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO &&
- glyph.fMaskFormat == SkMask::kBW_Format)) {
- unsigned srcRowBytes = face->glyph->bitmap.pitch;
- unsigned dstRowBytes = glyph.rowBytes();
- unsigned minRowBytes = SkMin32(srcRowBytes, dstRowBytes);
- unsigned extraRowBytes = dstRowBytes - minRowBytes;
+ // Otherwise, scale the bitmap.
- for (int y = face->glyph->bitmap.rows - 1; y >= 0; --y) {
- memcpy(dst, src, minRowBytes);
- memset(dst + minRowBytes, 0, extraRowBytes);
- src += srcRowBytes;
- dst += dstRowBytes;
- }
- } else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO &&
- glyph.fMaskFormat == SkMask::kA8_Format) {
- for (int y = 0; y < face->glyph->bitmap.rows; ++y) {
- uint8_t byte = 0;
- int bits = 0;
- const uint8_t* src_row = src;
- uint8_t* dst_row = dst;
+ // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
+ SkBitmap unscaledBitmap;
+ unscaledBitmap.setConfig(SkBitmapConfig_for_FTPixelMode(pixel_mode),
+ face->glyph->bitmap.width, face->glyph->bitmap.rows);
+ unscaledBitmap.allocPixels();
- for (int x = 0; x < face->glyph->bitmap.width; ++x) {
- if (!bits) {
- byte = *src_row++;
- bits = 8;
- }
+ SkMask unscaledBitmapAlias;
+ unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
+ unscaledBitmapAlias.fBounds.set(0, 0, unscaledBitmap.width(), unscaledBitmap.height());
+ unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
+ unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkBitmapConfig(unscaledBitmap.config());
+ copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);
- *dst_row++ = byte & 0x80 ? 0xff : 0;
- bits--;
- byte <<= 1;
+ // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
+ // BW requires an A8 target for resizing, which can then be down sampled.
+ // LCD should use a 4x A8 target, which will then be down sampled.
+ // For simplicity, LCD uses A8 and is replicated.
+ int bitmapRowBytes = 0;
+ if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
+ bitmapRowBytes = glyph.rowBytes();
+ }
+ SkBitmap dstBitmap;
+ dstBitmap.setConfig(SkBitmapConfig_for_SkMaskFormat(maskFormat),
+ glyph.fWidth, glyph.fHeight, bitmapRowBytes);
+ if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
+ dstBitmap.allocPixels();
+ } else {
+ dstBitmap.setPixels(glyph.fImage);
+ }
+
+ // Scale unscaledBitmap into dstBitmap.
+ SkCanvas canvas(dstBitmap);
+ canvas.clear(SK_ColorTRANSPARENT);
+ canvas.scale(SkIntToScalar(glyph.fWidth) / SkIntToScalar(face->glyph->bitmap.width),
+ SkIntToScalar(glyph.fHeight) / SkIntToScalar(face->glyph->bitmap.rows));
+ SkPaint paint;
+ paint.setFilterLevel(SkPaint::kLow_FilterLevel);
+ canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);
+
+ // If the destination is BW or LCD, convert from A8.
+ if (SkMask::kBW_Format == maskFormat) {
+ // Copy the A8 dstBitmap into the A1 glyph.fImage.
+ SkMask dstMask;
+ glyph.toMask(&dstMask);
+ packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
+ } else if (SkMask::kLCD16_Format == maskFormat) {
+ // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
+ uint8_t* src = dstBitmap.getAddr8(0, 0);
+ uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
+ for (int y = dstBitmap.height(); y --> 0;) {
+ for (int x = 0; x < dstBitmap.width(); ++x) {
+ dst[x] = grayToRGB16(src[x]);
}
-
- src += face->glyph->bitmap.pitch;
- dst += glyph.rowBytes();
+ dst = (uint16_t*)((char*)dst + glyph.rowBytes());
+ src += dstBitmap.rowBytes();
}
- } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
- if (fPreBlend.isApplicable()) {
- copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert,
- fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
- } else {
- copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVert,
- fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
- }
- } else {
- SkDEBUGFAIL("unknown glyph bitmap transform needed");
}
+
} break;
- default:
- SkDEBUGFAIL("unknown glyph format");
- memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
- return;
+ default:
+ SkDEBUGFAIL("unknown glyph format");
+ memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
+ return;
}
// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
« gm/coloremoji.cpp ('K') | « src/ports/SkFontHost_FreeType.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698