blob: b16b498ac1d31bce909c2d218c2d7f91141913c5 [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
9
bsalomon@google.coma3201942012-06-21 19:58:20 +000010#include "GrTemplates.h"
jvanverth733f5f52014-07-11 19:45:16 -070011#include "GrFontScaler.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000012#include "SkDescriptor.h"
commit-bot@chromium.org762cd802014-04-14 22:05:07 +000013#include "SkDistanceFieldGen.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000014#include "SkGlyphCache.h"
15
reed@google.comac10a2d2010-12-22 21:39:39 +000016///////////////////////////////////////////////////////////////////////////////
17
jvanverth733f5f52014-07-11 19:45:16 -070018GrFontDescKey::GrFontDescKey(const SkDescriptor& desc) : fHash(desc.getChecksum()) {
reed@google.comac10a2d2010-12-22 21:39:39 +000019 size_t size = desc.getLength();
20 if (size <= sizeof(fStorage)) {
reed@google.com1fcd51e2011-01-05 15:50:27 +000021 fDesc = GrTCast<SkDescriptor*>(fStorage);
reed@google.comac10a2d2010-12-22 21:39:39 +000022 } else {
23 fDesc = SkDescriptor::Alloc(size);
24 }
25 memcpy(fDesc, &desc, size);
26}
27
jvanverth733f5f52014-07-11 19:45:16 -070028GrFontDescKey::~GrFontDescKey() {
reed@google.com1fcd51e2011-01-05 15:50:27 +000029 if (fDesc != GrTCast<SkDescriptor*>(fStorage)) {
reed@google.comac10a2d2010-12-22 21:39:39 +000030 SkDescriptor::Free(fDesc);
31 }
32}
33
jvanverth733f5f52014-07-11 19:45:16 -070034bool GrFontDescKey::lt(const GrFontDescKey& rh) const {
35 const SkDescriptor* srcDesc = (&rh)->fDesc;
reed@google.comac10a2d2010-12-22 21:39:39 +000036 size_t lenLH = fDesc->getLength();
37 size_t lenRH = srcDesc->getLength();
robertphillips@google.comadacc702013-10-14 21:53:24 +000038 int cmp = memcmp(fDesc, srcDesc, SkTMin<size_t>(lenLH, lenRH));
reed@google.comac10a2d2010-12-22 21:39:39 +000039 if (0 == cmp) {
40 return lenLH < lenRH;
41 } else {
42 return cmp < 0;
43 }
44}
45
jvanverth733f5f52014-07-11 19:45:16 -070046bool GrFontDescKey::eq(const GrFontDescKey& rh) const {
47 const SkDescriptor* srcDesc = (&rh)->fDesc;
reed@google.comac10a2d2010-12-22 21:39:39 +000048 return fDesc->equals(*srcDesc);
49}
50
51///////////////////////////////////////////////////////////////////////////////
52
jvanverth733f5f52014-07-11 19:45:16 -070053GrFontScaler::GrFontScaler(SkGlyphCache* strike) {
reed@google.comac10a2d2010-12-22 21:39:39 +000054 fStrike = strike;
55 fKey = NULL;
56}
57
jvanverth733f5f52014-07-11 19:45:16 -070058GrFontScaler::~GrFontScaler() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000059 SkSafeUnref(fKey);
reed@google.comac10a2d2010-12-22 21:39:39 +000060}
61
jvanverth294c3262014-10-10 11:36:12 -070062GrMaskFormat GrFontScaler::getMaskFormat() const {
reed@google.com98539c62011-03-15 15:40:16 +000063 SkMask::Format format = fStrike->getMaskFormat();
64 switch (format) {
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +000065 case SkMask::kBW_Format:
66 // fall through to kA8 -- we store BW glyphs in our 8-bit cache
reed@google.com98539c62011-03-15 15:40:16 +000067 case SkMask::kA8_Format:
68 return kA8_GrMaskFormat;
69 case SkMask::kLCD16_Format:
70 return kA565_GrMaskFormat;
caryclark@google.com1eeaf0b2011-06-22 13:19:43 +000071 case SkMask::kLCD32_Format:
72 return kA888_GrMaskFormat;
commit-bot@chromium.orgf8cb1842013-12-03 19:45:22 +000073 case SkMask::kARGB32_Format:
74 return kARGB_GrMaskFormat;
reed@google.com98539c62011-03-15 15:40:16 +000075 default:
mtklein@google.com330313a2013-08-22 15:37:26 +000076 SkDEBUGFAIL("unsupported SkMask::Format");
reed@google.com98539c62011-03-15 15:40:16 +000077 return kA8_GrMaskFormat;
78 }
79}
80
jvanverth733f5f52014-07-11 19:45:16 -070081const GrFontDescKey* GrFontScaler::getKey() {
reed@google.comac10a2d2010-12-22 21:39:39 +000082 if (NULL == fKey) {
jvanverth733f5f52014-07-11 19:45:16 -070083 fKey = SkNEW_ARGS(GrFontDescKey, (fStrike->getDescriptor()));
reed@google.comac10a2d2010-12-22 21:39:39 +000084 }
85 return fKey;
86}
87
jvanverth294c3262014-10-10 11:36:12 -070088GrMaskFormat GrFontScaler::getPackedGlyphMaskFormat(GrGlyph::PackedID packed) const {
89 const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
90 GrGlyph::UnpackFixedX(packed),
91 GrGlyph::UnpackFixedY(packed));
92 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
93 switch (format) {
94 case SkMask::kBW_Format:
95 // fall through to kA8 -- we store BW glyphs in our 8-bit cache
96 case SkMask::kA8_Format:
97 return kA8_GrMaskFormat;
98 case SkMask::kLCD16_Format:
99 return kA565_GrMaskFormat;
100 case SkMask::kLCD32_Format:
101 return kA888_GrMaskFormat;
102 case SkMask::kARGB32_Format:
103 return kARGB_GrMaskFormat;
104 default:
105 SkDEBUGFAIL("unsupported SkMask::Format");
106 return kA8_GrMaskFormat;
107 }
108}
109
jvanverth733f5f52014-07-11 19:45:16 -0700110bool GrFontScaler::getPackedGlyphBounds(GrGlyph::PackedID packed, SkIRect* bounds) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000111 const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000112 GrGlyph::UnpackFixedX(packed),
113 GrGlyph::UnpackFixedY(packed));
reed@google.comac10a2d2010-12-22 21:39:39 +0000114 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
reed@google.com1fcd51e2011-01-05 15:50:27 +0000115
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000116 return true;
117}
118
jvanverth733f5f52014-07-11 19:45:16 -0700119bool GrFontScaler::getPackedGlyphDFBounds(GrGlyph::PackedID packed, SkIRect* bounds) {
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000120 const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
121 GrGlyph::UnpackFixedX(packed),
122 GrGlyph::UnpackFixedY(packed));
123 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
124 bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
125
126 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000127}
128
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000129namespace {
130// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
131// A8, RGB565, or RGBA8888.
132template <typename INT_TYPE>
133void expand_bits(INT_TYPE* dst,
134 const uint8_t* src,
135 int width,
136 int height,
137 int dstRowBytes,
138 int srcRowBytes) {
139 for (int i = 0; i < height; ++i) {
140 int rowWritesLeft = width;
141 const uint8_t* s = src;
142 INT_TYPE* d = dst;
143 while (rowWritesLeft > 0) {
144 unsigned mask = *s++;
145 for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
146 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000147 }
148 }
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000149 dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
150 src += srcRowBytes;
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000151 }
152}
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000153}
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000154
jvanverth733f5f52014-07-11 19:45:16 -0700155bool GrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed,
reed@google.comac10a2d2010-12-22 21:39:39 +0000156 int width, int height,
157 int dstRB, void* dst) {
158 const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000159 GrGlyph::UnpackFixedX(packed),
160 GrGlyph::UnpackFixedY(packed));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000161 SkASSERT(glyph.fWidth == width);
162 SkASSERT(glyph.fHeight == height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000163 const void* src = fStrike->findImage(glyph);
164 if (NULL == src) {
165 return false;
166 }
167
168 int srcRB = glyph.rowBytes();
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000169 // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
170 // check the glyph's format, not the strike's format, and to be able to convert to any of the
171 // GrMaskFormats.
172 if (SkMask::kBW_Format == glyph.fMaskFormat) {
173 // expand bits to our mask type
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000174 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000175 switch (this->getMaskFormat()) {
176 case kA8_GrMaskFormat:{
177 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
178 expand_bits(bytes, bits, width, height, dstRB, srcRB);
179 break;
180 }
181 case kA565_GrMaskFormat: {
182 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
183 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
184 break;
185 }
186 case kA888_GrMaskFormat: {
187 uint32_t* rgba8888 = reinterpret_cast<uint32_t*>(dst);
188 expand_bits(rgba8888, bits, width, height, dstRB, srcRB);
189 break;
190 }
commit-bot@chromium.orgf8cb1842013-12-03 19:45:22 +0000191 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000192 SkFAIL("Invalid GrMaskFormat");
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000193 }
194 } else if (srcRB == dstRB) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000195 memcpy(dst, src, dstRB * height);
196 } else {
reed@google.com98539c62011-03-15 15:40:16 +0000197 const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat());
reed@google.comac10a2d2010-12-22 21:39:39 +0000198 for (int y = 0; y < height; y++) {
reed@google.com98539c62011-03-15 15:40:16 +0000199 memcpy(dst, src, width * bbp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000200 src = (const char*)src + srcRB;
201 dst = (char*)dst + dstRB;
202 }
203 }
204 return true;
205}
206
jvanverth733f5f52014-07-11 19:45:16 -0700207bool GrFontScaler::getPackedGlyphDFImage(GrGlyph::PackedID packed,
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000208 int width, int height,
209 void* dst) {
210 const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
211 GrGlyph::UnpackFixedX(packed),
212 GrGlyph::UnpackFixedY(packed));
213 SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width);
214 SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height);
215 const void* src = fStrike->findDistanceField(glyph);
216 if (NULL == src) {
217 return false;
218 }
219
220 memcpy(dst, src, width * height);
221
222 return true;
223}
224
reed@google.com07f3ee12011-05-16 17:21:57 +0000225// we should just return const SkPath* (NULL means false)
jvanverth733f5f52014-07-11 19:45:16 -0700226bool GrFontScaler::getGlyphPath(uint16_t glyphID, SkPath* path) {
reed@google.com1fcd51e2011-01-05 15:50:27 +0000227
reed@google.comac10a2d2010-12-22 21:39:39 +0000228 const SkGlyph& glyph = fStrike->getGlyphIDMetrics(glyphID);
229 const SkPath* skPath = fStrike->findPath(glyph);
230 if (skPath) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000231 *path = *skPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000232 return true;
233 }
234 return false;
235}