blob: a9d5abff4e72eefcc4ce79ca4751d6568115fead [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;
18 fKey = NULL;
19}
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() {
reed@google.comac10a2d2010-12-22 21:39:39 +000043 if (NULL == fKey) {
jvanverth733f5f52014-07-11 19:45:16 -070044 fKey = SkNEW_ARGS(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) {
reed@google.comac10a2d2010-12-22 21:39:39 +000067 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
reed@google.com1fcd51e2011-01-05 15:50:27 +000068
commit-bot@chromium.org762cd802014-04-14 22:05:07 +000069 return true;
70}
71
joshualitt6c2c2b02015-07-24 10:37:00 -070072bool GrFontScaler::getPackedGlyphDFBounds(const SkGlyph& glyph, SkIRect* bounds) {
commit-bot@chromium.org762cd802014-04-14 22:05:07 +000073 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
74 bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
75
76 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +000077}
78
bsalomon@google.comc8699ef2012-09-10 13:28:00 +000079namespace {
80// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
81// A8, RGB565, or RGBA8888.
82template <typename INT_TYPE>
83void expand_bits(INT_TYPE* dst,
84 const uint8_t* src,
85 int width,
86 int height,
87 int dstRowBytes,
88 int srcRowBytes) {
89 for (int i = 0; i < height; ++i) {
90 int rowWritesLeft = width;
91 const uint8_t* s = src;
92 INT_TYPE* d = dst;
93 while (rowWritesLeft > 0) {
94 unsigned mask = *s++;
95 for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
96 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +000097 }
98 }
bsalomon@google.comc8699ef2012-09-10 13:28:00 +000099 dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
100 src += srcRowBytes;
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000101 }
102}
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000103}
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000104
joshualitt6c2c2b02015-07-24 10:37:00 -0700105bool GrFontScaler::getPackedGlyphImage(const SkGlyph& glyph, int width, int height, int dstRB,
joshualitt4f19ca32015-07-30 07:59:20 -0700106 GrMaskFormat expectedMaskFormat, void* dst) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000107 SkASSERT(glyph.fWidth == width);
108 SkASSERT(glyph.fHeight == height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000109 const void* src = fStrike->findImage(glyph);
110 if (NULL == src) {
111 return false;
112 }
113
joshualitt4f19ca32015-07-30 07:59:20 -0700114 // crbug:510931
115 // Retrieving the image from the cache can actually change the mask format. This case is very
116 // uncommon so for now we just draw a clear box for these glyphs.
117 if (getPackedGlyphMaskFormat(glyph) != expectedMaskFormat) {
118 const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
119 for (int y = 0; y < height; y++) {
120 sk_bzero(dst, width * bpp);
121 dst = (char*)dst + dstRB;
122 }
123 return true;
124 }
125
reed@google.comac10a2d2010-12-22 21:39:39 +0000126 int srcRB = glyph.rowBytes();
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000127 // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
128 // check the glyph's format, not the strike's format, and to be able to convert to any of the
129 // GrMaskFormats.
130 if (SkMask::kBW_Format == glyph.fMaskFormat) {
131 // expand bits to our mask type
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000132 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000133 switch (this->getMaskFormat()) {
134 case kA8_GrMaskFormat:{
135 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
136 expand_bits(bytes, bits, width, height, dstRB, srcRB);
137 break;
138 }
139 case kA565_GrMaskFormat: {
140 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
141 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
142 break;
143 }
commit-bot@chromium.orgf8cb1842013-12-03 19:45:22 +0000144 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000145 SkFAIL("Invalid GrMaskFormat");
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000146 }
147 } else if (srcRB == dstRB) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000148 memcpy(dst, src, dstRB * height);
149 } else {
reed@google.com98539c62011-03-15 15:40:16 +0000150 const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat());
reed@google.comac10a2d2010-12-22 21:39:39 +0000151 for (int y = 0; y < height; y++) {
reed@google.com98539c62011-03-15 15:40:16 +0000152 memcpy(dst, src, width * bbp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000153 src = (const char*)src + srcRB;
154 dst = (char*)dst + dstRB;
155 }
156 }
157 return true;
158}
159
joshualitt6c2c2b02015-07-24 10:37:00 -0700160bool GrFontScaler::getPackedGlyphDFImage(const SkGlyph& glyph, int width, int height, void* dst) {
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000161 SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width);
162 SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height);
jvanvertha27b82d2015-01-07 10:12:16 -0800163 const void* image = fStrike->findImage(glyph);
164 if (NULL == image) {
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000165 return false;
166 }
jvanvertha27b82d2015-01-07 10:12:16 -0800167 // now generate the distance field
168 SkASSERT(dst);
169 SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
170 if (SkMask::kA8_Format == maskFormat) {
171 // make the distance field from the image
172 SkGenerateDistanceFieldFromA8Image((unsigned char*)dst,
173 (unsigned char*)image,
174 glyph.fWidth, glyph.fHeight,
175 glyph.rowBytes());
176 } else if (SkMask::kBW_Format == maskFormat) {
177 // make the distance field from the image
178 SkGenerateDistanceFieldFromBWImage((unsigned char*)dst,
179 (unsigned char*)image,
180 glyph.fWidth, glyph.fHeight,
181 glyph.rowBytes());
182 } else {
183 return false;
184 }
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000185
186 return true;
187}
188
joshualitt6c2c2b02015-07-24 10:37:00 -0700189const SkPath* GrFontScaler::getGlyphPath(const SkGlyph& glyph) {
190 return fStrike->findPath(glyph);
191}
reed@google.com1fcd51e2011-01-05 15:50:27 +0000192
joshualitt6c2c2b02015-07-24 10:37:00 -0700193const SkGlyph& GrFontScaler::grToSkGlyph(GrGlyph::PackedID id) {
194 return fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(id),
195 GrGlyph::UnpackFixedX(id),
196 GrGlyph::UnpackFixedY(id));
reed@google.comac10a2d2010-12-22 21:39:39 +0000197}