blob: c8412027c04df8cca2ac69c2847ffac1e00f5baf [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
jvanverth733f5f52014-07-11 19:45:16 -07009#include "GrFontScaler.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000010#include "SkDescriptor.h"
commit-bot@chromium.org762cd802014-04-14 22:05:07 +000011#include "SkDistanceFieldGen.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000012#include "SkGlyphCache.h"
13
reed@google.comac10a2d2010-12-22 21:39:39 +000014///////////////////////////////////////////////////////////////////////////////
15
jvanverth733f5f52014-07-11 19:45:16 -070016GrFontScaler::GrFontScaler(SkGlyphCache* strike) {
reed@google.comac10a2d2010-12-22 21:39:39 +000017 fStrike = strike;
halcanary96fcdcc2015-08-27 07:41:13 -070018 fKey = nullptr;
reed@google.comac10a2d2010-12-22 21:39:39 +000019}
20
jvanverth733f5f52014-07-11 19:45:16 -070021GrFontScaler::~GrFontScaler() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000022 SkSafeUnref(fKey);
reed@google.comac10a2d2010-12-22 21:39:39 +000023}
24
jvanverth294c3262014-10-10 11:36:12 -070025GrMaskFormat GrFontScaler::getMaskFormat() const {
reed@google.com98539c62011-03-15 15:40:16 +000026 SkMask::Format format = fStrike->getMaskFormat();
27 switch (format) {
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +000028 case SkMask::kBW_Format:
29 // fall through to kA8 -- we store BW glyphs in our 8-bit cache
reed@google.com98539c62011-03-15 15:40:16 +000030 case SkMask::kA8_Format:
31 return kA8_GrMaskFormat;
32 case SkMask::kLCD16_Format:
33 return kA565_GrMaskFormat;
commit-bot@chromium.orgf8cb1842013-12-03 19:45:22 +000034 case SkMask::kARGB32_Format:
35 return kARGB_GrMaskFormat;
reed@google.com98539c62011-03-15 15:40:16 +000036 default:
mtklein@google.com330313a2013-08-22 15:37:26 +000037 SkDEBUGFAIL("unsupported SkMask::Format");
reed@google.com98539c62011-03-15 15:40:16 +000038 return kA8_GrMaskFormat;
39 }
40}
41
jvanverth733f5f52014-07-11 19:45:16 -070042const GrFontDescKey* GrFontScaler::getKey() {
halcanary96fcdcc2015-08-27 07:41:13 -070043 if (nullptr == fKey) {
halcanary385fe4d2015-08-26 13:07:48 -070044 fKey = new GrFontDescKey(fStrike->getDescriptor());
reed@google.comac10a2d2010-12-22 21:39:39 +000045 }
46 return fKey;
47}
48
joshualitt6c2c2b02015-07-24 10:37:00 -070049GrMaskFormat GrFontScaler::getPackedGlyphMaskFormat(const SkGlyph& glyph) const {
jvanverth294c3262014-10-10 11:36:12 -070050 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
51 switch (format) {
52 case SkMask::kBW_Format:
53 // fall through to kA8 -- we store BW glyphs in our 8-bit cache
54 case SkMask::kA8_Format:
55 return kA8_GrMaskFormat;
56 case SkMask::kLCD16_Format:
57 return kA565_GrMaskFormat;
jvanverth294c3262014-10-10 11:36:12 -070058 case SkMask::kARGB32_Format:
59 return kARGB_GrMaskFormat;
60 default:
61 SkDEBUGFAIL("unsupported SkMask::Format");
62 return kA8_GrMaskFormat;
63 }
64}
65
joshualitt6c2c2b02015-07-24 10:37:00 -070066bool GrFontScaler::getPackedGlyphBounds(const SkGlyph& glyph, SkIRect* bounds) {
joshualitt381b26f2015-07-30 12:43:17 -070067#if 1
68 // crbug:510931
69 // Retrieving the image from the cache can actually change the mask format.
70 fStrike->findImage(glyph);
71#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000072 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
reed@google.com1fcd51e2011-01-05 15:50:27 +000073
commit-bot@chromium.org762cd802014-04-14 22:05:07 +000074 return true;
75}
76
joshualitt6c2c2b02015-07-24 10:37:00 -070077bool GrFontScaler::getPackedGlyphDFBounds(const SkGlyph& glyph, SkIRect* bounds) {
joshualitt381b26f2015-07-30 12:43:17 -070078#if 1
79 // crbug:510931
80 // Retrieving the image from the cache can actually change the mask format.
81 fStrike->findImage(glyph);
82#endif
commit-bot@chromium.org762cd802014-04-14 22:05:07 +000083 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
84 bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
85
86 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +000087}
88
bsalomon@google.comc8699ef2012-09-10 13:28:00 +000089namespace {
90// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
91// A8, RGB565, or RGBA8888.
92template <typename INT_TYPE>
93void expand_bits(INT_TYPE* dst,
94 const uint8_t* src,
95 int width,
96 int height,
97 int dstRowBytes,
98 int srcRowBytes) {
99 for (int i = 0; i < height; ++i) {
100 int rowWritesLeft = width;
101 const uint8_t* s = src;
102 INT_TYPE* d = dst;
103 while (rowWritesLeft > 0) {
104 unsigned mask = *s++;
105 for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
106 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000107 }
108 }
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000109 dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
110 src += srcRowBytes;
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000111 }
112}
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000113}
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000114
joshualitt6c2c2b02015-07-24 10:37:00 -0700115bool GrFontScaler::getPackedGlyphImage(const SkGlyph& glyph, int width, int height, int dstRB,
joshualitt4f19ca32015-07-30 07:59:20 -0700116 GrMaskFormat expectedMaskFormat, void* dst) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000117 SkASSERT(glyph.fWidth == width);
118 SkASSERT(glyph.fHeight == height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000119 const void* src = fStrike->findImage(glyph);
halcanary96fcdcc2015-08-27 07:41:13 -0700120 if (nullptr == src) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000121 return false;
122 }
123
joshualitt4f19ca32015-07-30 07:59:20 -0700124 // crbug:510931
125 // Retrieving the image from the cache can actually change the mask format. This case is very
126 // uncommon so for now we just draw a clear box for these glyphs.
127 if (getPackedGlyphMaskFormat(glyph) != expectedMaskFormat) {
128 const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
129 for (int y = 0; y < height; y++) {
130 sk_bzero(dst, width * bpp);
131 dst = (char*)dst + dstRB;
132 }
133 return true;
134 }
135
reed@google.comac10a2d2010-12-22 21:39:39 +0000136 int srcRB = glyph.rowBytes();
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000137 // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
138 // check the glyph's format, not the strike's format, and to be able to convert to any of the
139 // GrMaskFormats.
140 if (SkMask::kBW_Format == glyph.fMaskFormat) {
141 // expand bits to our mask type
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000142 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
joshualittd1ebe062015-07-31 11:55:29 -0700143 switch (expectedMaskFormat) {
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000144 case kA8_GrMaskFormat:{
145 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
146 expand_bits(bytes, bits, width, height, dstRB, srcRB);
147 break;
148 }
149 case kA565_GrMaskFormat: {
150 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
151 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
152 break;
153 }
commit-bot@chromium.orgf8cb1842013-12-03 19:45:22 +0000154 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000155 SkFAIL("Invalid GrMaskFormat");
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000156 }
157 } else if (srcRB == dstRB) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000158 memcpy(dst, src, dstRB * height);
159 } else {
joshualittd1ebe062015-07-31 11:55:29 -0700160 const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000161 for (int y = 0; y < height; y++) {
reed@google.com98539c62011-03-15 15:40:16 +0000162 memcpy(dst, src, width * bbp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000163 src = (const char*)src + srcRB;
164 dst = (char*)dst + dstRB;
165 }
166 }
167 return true;
168}
169
joshualitt6c2c2b02015-07-24 10:37:00 -0700170bool GrFontScaler::getPackedGlyphDFImage(const SkGlyph& glyph, int width, int height, void* dst) {
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000171 SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width);
172 SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height);
jvanvertha27b82d2015-01-07 10:12:16 -0800173 const void* image = fStrike->findImage(glyph);
halcanary96fcdcc2015-08-27 07:41:13 -0700174 if (nullptr == image) {
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000175 return false;
176 }
jvanvertha27b82d2015-01-07 10:12:16 -0800177 // now generate the distance field
178 SkASSERT(dst);
179 SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
180 if (SkMask::kA8_Format == maskFormat) {
181 // make the distance field from the image
182 SkGenerateDistanceFieldFromA8Image((unsigned char*)dst,
183 (unsigned char*)image,
184 glyph.fWidth, glyph.fHeight,
185 glyph.rowBytes());
186 } else if (SkMask::kBW_Format == maskFormat) {
187 // make the distance field from the image
188 SkGenerateDistanceFieldFromBWImage((unsigned char*)dst,
189 (unsigned char*)image,
190 glyph.fWidth, glyph.fHeight,
191 glyph.rowBytes());
192 } else {
193 return false;
194 }
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000195
196 return true;
197}
198
joshualitt6c2c2b02015-07-24 10:37:00 -0700199const SkPath* GrFontScaler::getGlyphPath(const SkGlyph& glyph) {
200 return fStrike->findPath(glyph);
201}
reed@google.com1fcd51e2011-01-05 15:50:27 +0000202
joshualitt6c2c2b02015-07-24 10:37:00 -0700203const SkGlyph& GrFontScaler::grToSkGlyph(GrGlyph::PackedID id) {
204 return fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(id),
205 GrGlyph::UnpackFixedX(id),
206 GrGlyph::UnpackFixedY(id));
reed@google.comac10a2d2010-12-22 21:39:39 +0000207}