blob: 84fd58133c634f4936a5aae256280cfeeb575b2d [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,
106 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
114 int srcRB = glyph.rowBytes();
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000115 // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
116 // check the glyph's format, not the strike's format, and to be able to convert to any of the
117 // GrMaskFormats.
118 if (SkMask::kBW_Format == glyph.fMaskFormat) {
119 // expand bits to our mask type
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000120 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000121 switch (this->getMaskFormat()) {
122 case kA8_GrMaskFormat:{
123 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
124 expand_bits(bytes, bits, width, height, dstRB, srcRB);
125 break;
126 }
127 case kA565_GrMaskFormat: {
128 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
129 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
130 break;
131 }
commit-bot@chromium.orgf8cb1842013-12-03 19:45:22 +0000132 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000133 SkFAIL("Invalid GrMaskFormat");
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000134 }
135 } else if (srcRB == dstRB) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000136 memcpy(dst, src, dstRB * height);
137 } else {
reed@google.com98539c62011-03-15 15:40:16 +0000138 const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat());
reed@google.comac10a2d2010-12-22 21:39:39 +0000139 for (int y = 0; y < height; y++) {
reed@google.com98539c62011-03-15 15:40:16 +0000140 memcpy(dst, src, width * bbp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000141 src = (const char*)src + srcRB;
142 dst = (char*)dst + dstRB;
143 }
144 }
145 return true;
146}
147
joshualitt6c2c2b02015-07-24 10:37:00 -0700148bool GrFontScaler::getPackedGlyphDFImage(const SkGlyph& glyph, int width, int height, void* dst) {
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000149 SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width);
150 SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height);
jvanvertha27b82d2015-01-07 10:12:16 -0800151 const void* image = fStrike->findImage(glyph);
152 if (NULL == image) {
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000153 return false;
154 }
jvanvertha27b82d2015-01-07 10:12:16 -0800155 // now generate the distance field
156 SkASSERT(dst);
157 SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
158 if (SkMask::kA8_Format == maskFormat) {
159 // make the distance field from the image
160 SkGenerateDistanceFieldFromA8Image((unsigned char*)dst,
161 (unsigned char*)image,
162 glyph.fWidth, glyph.fHeight,
163 glyph.rowBytes());
164 } else if (SkMask::kBW_Format == maskFormat) {
165 // make the distance field from the image
166 SkGenerateDistanceFieldFromBWImage((unsigned char*)dst,
167 (unsigned char*)image,
168 glyph.fWidth, glyph.fHeight,
169 glyph.rowBytes());
170 } else {
171 return false;
172 }
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000173
174 return true;
175}
176
joshualitt6c2c2b02015-07-24 10:37:00 -0700177const SkPath* GrFontScaler::getGlyphPath(const SkGlyph& glyph) {
178 return fStrike->findPath(glyph);
179}
reed@google.com1fcd51e2011-01-05 15:50:27 +0000180
joshualitt6c2c2b02015-07-24 10:37:00 -0700181const SkGlyph& GrFontScaler::grToSkGlyph(GrGlyph::PackedID id) {
182 return fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(id),
183 GrGlyph::UnpackFixedX(id),
184 GrGlyph::UnpackFixedY(id));
reed@google.comac10a2d2010-12-22 21:39:39 +0000185}