blob: f4e8be808ef21ac2ccfe2e0d92fd31930cdd8a4c [file] [log] [blame]
bungeman@google.come8f05922012-08-16 16:13:40 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Kleinc0bd9f92019-04-23 12:05:21 -05007#include "src/utils/win/SkDWriteNTDDI_VERSION.h"
bungeman@google.come8f05922012-08-16 16:13:40 +00008
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "include/core/SkTypes.h"
Mike Klein8f11d4d2018-01-24 12:42:55 -050010#if defined(SK_BUILD_FOR_WIN)
mtklein1ee76512015-11-02 10:20:27 -080011
bungeman@google.come8f05922012-08-16 16:13:40 +000012#undef GetGlyphIndices
13
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/codec/SkCodec.h"
15#include "include/core/SkFontMetrics.h"
16#include "include/core/SkPath.h"
17#include "include/private/SkMutex.h"
18#include "include/private/SkTo.h"
19#include "src/core/SkDraw.h"
20#include "src/core/SkEndian.h"
21#include "src/core/SkGlyph.h"
22#include "src/core/SkMaskGamma.h"
23#include "src/core/SkRasterClip.h"
24#include "src/core/SkScalerContext.h"
25#include "src/core/SkSharedMutex.h"
26#include "src/ports/SkScalerContext_win_dw.h"
27#include "src/ports/SkTypeface_win_dw.h"
28#include "src/sfnt/SkOTTable_EBLC.h"
29#include "src/sfnt/SkOTTable_EBSC.h"
30#include "src/sfnt/SkOTTable_gasp.h"
31#include "src/sfnt/SkOTTable_maxp.h"
32#include "src/utils/SkMatrix22.h"
33#include "src/utils/win/SkDWrite.h"
34#include "src/utils/win/SkDWriteGeometrySink.h"
35#include "src/utils/win/SkHRESULT.h"
36#include "src/utils/win/SkTScopedComPtr.h"
bungeman@google.come8f05922012-08-16 16:13:40 +000037
38#include <dwrite.h>
Ben Wagnere0c9e002017-03-01 16:08:00 -050039#include <dwrite_1.h>
Ben Wagner297c3c82018-07-19 08:55:10 -040040#include <dwrite_3.h>
bungeman@google.come8f05922012-08-16 16:13:40 +000041
herbc7378af2015-10-21 09:24:37 -070042/* Note:
43 * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe.
44 * The DWriteFactoryMutex protects the calls that are problematic.
45 */
herb6440f0b2015-10-27 14:37:00 -070046static SkSharedMutex DWriteFactoryMutex;
herbc7378af2015-10-21 09:24:37 -070047
Herb Derby209ebc02019-05-13 13:38:09 -040048typedef SkAutoSharedMutexExclusive Exclusive;
herb6440f0b2015-10-27 14:37:00 -070049typedef SkAutoSharedMutexShared Shared;
herbc7378af2015-10-21 09:24:37 -070050
Ben Wagner3e45a2f2017-11-01 11:47:39 -040051static bool isLCD(const SkScalerContextRec& rec) {
reedd54d3fc2014-11-13 14:39:58 -080052 return SkMask::kLCD16_Format == rec.fMaskFormat;
bungeman@google.come8f05922012-08-16 16:13:40 +000053}
54
Ben Wagner9f591342017-04-13 11:02:50 -040055static bool is_hinted(DWriteFontTypeface* typeface) {
Herb Derby209ebc02019-05-13 13:38:09 -040056 Exclusive l(DWriteFactoryMutex);
bungeman761b2502014-06-30 12:19:41 -070057 AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
58 if (!maxp.fExists) {
59 return false;
60 }
61 if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
62 return false;
63 }
64 if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
65 return false;
66 }
Ben Wagner9f591342017-04-13 11:02:50 -040067 return (0 != maxp->version.tt.maxSizeOfInstructions);
bungeman761b2502014-06-30 12:19:41 -070068}
69
Ben Wagner22253062017-03-16 12:38:46 -040070/** A GaspRange is inclusive, [min, max]. */
71struct GaspRange {
72 using Behavior = SkOTTableGridAndScanProcedure::GaspRange::behavior;
Ben Wagner42a2a202017-04-24 12:40:03 -040073 GaspRange(int min, int max, int version, Behavior flags)
74 : fMin(min), fMax(max), fVersion(version), fFlags(flags) { }
Ben Wagner22253062017-03-16 12:38:46 -040075 int fMin;
76 int fMax;
Ben Wagner42a2a202017-04-24 12:40:03 -040077 int fVersion;
Ben Wagner22253062017-03-16 12:38:46 -040078 Behavior fFlags;
bungeman740c3f12014-06-23 08:29:23 -070079};
80
Ben Wagner22253062017-03-16 12:38:46 -040081bool get_gasp_range(DWriteFontTypeface* typeface, int size, GaspRange* range) {
Mike Reedb66fa522017-03-15 23:51:22 +000082 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
83 if (!gasp.fExists) {
Ben Wagner22253062017-03-16 12:38:46 -040084 return false;
Mike Reedb66fa522017-03-15 23:51:22 +000085 }
86 if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
Ben Wagner22253062017-03-16 12:38:46 -040087 return false;
Mike Reedb66fa522017-03-15 23:51:22 +000088 }
89 if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
90 gasp->version != SkOTTableGridAndScanProcedure::version1)
91 {
Ben Wagner22253062017-03-16 12:38:46 -040092 return false;
Mike Reedb66fa522017-03-15 23:51:22 +000093 }
94
95 uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
96 if (numRanges > 1024 ||
97 gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
Ben Wagner22253062017-03-16 12:38:46 -040098 sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
Mike Reedb66fa522017-03-15 23:51:22 +000099 {
Ben Wagner22253062017-03-16 12:38:46 -0400100 return false;
Mike Reedb66fa522017-03-15 23:51:22 +0000101 }
102
103 const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
104 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
105 int minPPEM = -1;
106 for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
107 int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
Ben Wagner34db1ee2017-03-15 15:22:29 -0400108 if (minPPEM < size && size <= maxPPEM) {
Ben Wagner22253062017-03-16 12:38:46 -0400109 range->fMin = minPPEM + 1;
110 range->fMax = maxPPEM;
Ben Wagner42a2a202017-04-24 12:40:03 -0400111 range->fVersion = SkEndian_SwapBE16(gasp->version);
Ben Wagner22253062017-03-16 12:38:46 -0400112 range->fFlags = rangeTable->flags;
113 return true;
Ben Wagnera67615f2017-02-09 13:41:45 -0500114 }
115 minPPEM = maxPPEM;
116 }
117 return false;
118}
Ben Wagner22253062017-03-16 12:38:46 -0400119/** If the rendering mode for the specified 'size' is gridfit, then place
120 * the gridfit range into 'range'. Otherwise, leave 'range' alone.
121 */
122static bool is_gridfit_only(GaspRange::Behavior flags) {
123 return flags.raw.value == GaspRange::Behavior::Raw::GridfitMask;
124}
Ben Wagnera67615f2017-02-09 13:41:45 -0500125
Ben Wagner22253062017-03-16 12:38:46 -0400126static bool has_bitmap_strike(DWriteFontTypeface* typeface, GaspRange range) {
Herb Derby209ebc02019-05-13 13:38:09 -0400127 Exclusive l(DWriteFactoryMutex);
bungeman@google.com058670b2014-05-01 20:39:14 +0000128 {
129 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
130 if (!eblc.fExists) {
131 return false;
132 }
133 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
134 return false;
135 }
136 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
137 return false;
138 }
139
140 uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
bungeman740c3f12014-06-23 08:29:23 -0700141 if (numSizes > 1024 ||
142 eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
bungeman@google.com058670b2014-05-01 20:39:14 +0000143 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
144 {
145 return false;
146 }
147
148 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
149 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
150 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
bungeman740c3f12014-06-23 08:29:23 -0700151 if (sizeTable->ppemX == sizeTable->ppemY &&
Ben Wagner22253062017-03-16 12:38:46 -0400152 range.fMin <= sizeTable->ppemX && sizeTable->ppemX <= range.fMax)
bungeman740c3f12014-06-23 08:29:23 -0700153 {
bungeman@google.com058670b2014-05-01 20:39:14 +0000154 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
155 // to determine the actual number of glyphs with bitmaps.
156
157 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
158
bungeman740c3f12014-06-23 08:29:23 -0700159 // TODO: Ensure that the bitmaps are bi-level?
bungeman@google.com058670b2014-05-01 20:39:14 +0000160 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
161 return true;
162 }
163 }
164 }
165 }
166
167 {
168 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
169 if (!ebsc.fExists) {
170 return false;
171 }
172 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
173 return false;
174 }
175 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
176 return false;
177 }
178
179 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
bungeman740c3f12014-06-23 08:29:23 -0700180 if (numSizes > 1024 ||
181 ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
bungeman@google.com058670b2014-05-01 20:39:14 +0000182 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
183 {
184 return false;
185 }
186
187 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
188 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
189 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
bungeman740c3f12014-06-23 08:29:23 -0700190 if (scaleTable->ppemX == scaleTable->ppemY &&
Ben Wagner22253062017-03-16 12:38:46 -0400191 range.fMin <= scaleTable->ppemX && scaleTable->ppemX <= range.fMax) {
bungeman@google.com058670b2014-05-01 20:39:14 +0000192 // EBSC tables are normally only found in bitmap only fonts.
193 return true;
194 }
195 }
196 }
197
198 return false;
199}
200
bungeman740c3f12014-06-23 08:29:23 -0700201static bool both_zero(SkScalar a, SkScalar b) {
bungeman@google.com058670b2014-05-01 20:39:14 +0000202 return 0 == a && 0 == b;
203}
204
205// returns false if there is any non-90-rotation or skew
Ben Wagner3e45a2f2017-11-01 11:47:39 -0400206static bool is_axis_aligned(const SkScalerContextRec& rec) {
bungeman@google.com058670b2014-05-01 20:39:14 +0000207 return 0 == rec.fPreSkewX &&
bungeman740c3f12014-06-23 08:29:23 -0700208 (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
209 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
bungeman@google.com058670b2014-05-01 20:39:14 +0000210}
211
bungeman7cfd46a2016-10-20 16:06:52 -0400212SkScalerContext_DW::SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef,
reeda9322c22016-04-12 06:47:05 -0700213 const SkScalerContextEffects& effects,
bungeman@google.com6eddc772014-03-31 19:18:07 +0000214 const SkDescriptor* desc)
bungeman7cfd46a2016-10-20 16:06:52 -0400215 : SkScalerContext(std::move(typefaceRef), effects, desc)
bungeman@google.come8f05922012-08-16 16:13:40 +0000216 , fGlyphCount(-1) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000217
bungeman7cfd46a2016-10-20 16:06:52 -0400218 DWriteFontTypeface* typeface = this->getDWriteTypeface();
Ben Wagner22253062017-03-16 12:38:46 -0400219 fIsColorFont = typeface->fFactory2 &&
220 typeface->fDWriteFontFace2 &&
221 typeface->fDWriteFontFace2->IsColorFont();
bungeman73c7c3c2016-06-16 14:41:53 -0700222
Ben Wagner22253062017-03-16 12:38:46 -0400223 // In general, all glyphs should use NATURAL_SYMMETRIC
bungeman@google.com058670b2014-05-01 20:39:14 +0000224 // except when bi-level rendering is requested or there are embedded
225 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
226 //
227 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
228 // this. As a result, determine the actual size of the text and then see if
229 // there are any embedded bi-level bitmaps of that size. If there are, then
230 // force bitmaps by requesting bi-level rendering.
231 //
232 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
233 // square pixels and only uses ppemY. Therefore the transform must track any
234 // non-uniform x-scale.
235 //
236 // Also, rotated glyphs should have the same absolute advance widths as
237 // horizontal glyphs and the subpixel flag should not affect glyph shapes.
bungeman@google.come8f05922012-08-16 16:13:40 +0000238
bungeman5f14c5e2014-12-05 12:26:44 -0800239 SkVector scale;
Ben Wagner1f5f6b82017-04-14 11:39:34 -0400240 fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, &scale, &fSkXform);
bungeman@google.com058670b2014-05-01 20:39:14 +0000241
bungeman5f14c5e2014-12-05 12:26:44 -0800242 fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
243 fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
244 fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
245 fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
246 fXform.dx = 0;
247 fXform.dy = 0;
bungeman@google.com058670b2014-05-01 20:39:14 +0000248
bungeman@google.com058670b2014-05-01 20:39:14 +0000249 // realTextSize is the actual device size we want (as opposed to the size the user requested).
250 // gdiTextSize is the size we request when GDI compatible.
251 // If the scale is negative, this means the matrix will do the flip anyway.
bungeman5f14c5e2014-12-05 12:26:44 -0800252 const SkScalar realTextSize = scale.fY;
bungeman@google.com058670b2014-05-01 20:39:14 +0000253 // Due to floating point math, the lower bits are suspect. Round carefully.
bungeman@google.com7c183512014-05-28 15:40:26 +0000254 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
bungeman@google.com058670b2014-05-01 20:39:14 +0000255 if (gdiTextSize == 0) {
256 gdiTextSize = SK_Scalar1;
257 }
258
bungeman@google.com7c183512014-05-28 15:40:26 +0000259 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
bungeman740c3f12014-06-23 08:29:23 -0700260 bool treatLikeBitmap = false;
bungeman@google.com7c183512014-05-28 15:40:26 +0000261 bool axisAlignedBitmap = false;
262 if (bitmapRequested) {
bungeman740c3f12014-06-23 08:29:23 -0700263 // When embedded bitmaps are requested, treat the entire range like
264 // a bitmap strike if the range is gridfit only and contains a bitmap.
265 int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
Ben Wagner42a2a202017-04-24 12:40:03 -0400266 GaspRange range(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior());
Ben Wagner22253062017-03-16 12:38:46 -0400267 if (get_gasp_range(typeface, bitmapPPEM, &range)) {
268 if (!is_gridfit_only(range.fFlags)) {
Ben Wagner42a2a202017-04-24 12:40:03 -0400269 range = GaspRange(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior());
Ben Wagner22253062017-03-16 12:38:46 -0400270 }
271 }
bungeman740c3f12014-06-23 08:29:23 -0700272 treatLikeBitmap = has_bitmap_strike(typeface, range);
273
274 axisAlignedBitmap = is_axis_aligned(fRec);
bungeman@google.com7c183512014-05-28 15:40:26 +0000275 }
bungeman@google.com058670b2014-05-01 20:39:14 +0000276
Ben Wagner42a2a202017-04-24 12:40:03 -0400277 GaspRange range(0, 0xFFFF, 0, GaspRange::Behavior());
Ben Wagner9f591342017-04-13 11:02:50 -0400278
bungeman@google.com7c183512014-05-28 15:40:26 +0000279 // If the user requested aliased, do so with aliased compatible metrics.
280 if (SkMask::kBW_Format == fRec.fMaskFormat) {
bungeman@google.com058670b2014-05-01 20:39:14 +0000281 fTextSizeRender = gdiTextSize;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000282 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
283 fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
bungeman@google.com058670b2014-05-01 20:39:14 +0000284 fTextSizeMeasure = gdiTextSize;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000285 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
bungemandf1640d2014-06-04 15:19:47 -0700286
bungeman@google.com7c183512014-05-28 15:40:26 +0000287 // If we can use a bitmap, use gdi classic rendering and measurement.
288 // This will not always provide a bitmap, but matches expected behavior.
bungeman740c3f12014-06-23 08:29:23 -0700289 } else if (treatLikeBitmap && axisAlignedBitmap) {
bungeman@google.com7c183512014-05-28 15:40:26 +0000290 fTextSizeRender = gdiTextSize;
Ben Wagner22253062017-03-16 12:38:46 -0400291 fRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
bungeman@google.com7c183512014-05-28 15:40:26 +0000292 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
293 fTextSizeMeasure = gdiTextSize;
294 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
bungemandf1640d2014-06-04 15:19:47 -0700295
bungeman@google.com7c183512014-05-28 15:40:26 +0000296 // If rotated but the horizontal text could have used a bitmap,
297 // render high quality rotated glyphs but measure using bitmap metrics.
bungeman740c3f12014-06-23 08:29:23 -0700298 } else if (treatLikeBitmap) {
bungeman@google.com058670b2014-05-01 20:39:14 +0000299 fTextSizeRender = gdiTextSize;
Ben Wagner22253062017-03-16 12:38:46 -0400300 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000301 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
bungeman@google.com058670b2014-05-01 20:39:14 +0000302 fTextSizeMeasure = gdiTextSize;
303 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
bungeman@google.com7c183512014-05-28 15:40:26 +0000304
Ben Wagner42a2a202017-04-24 12:40:03 -0400305 // If the font has a gasp table version 1, use it to determine symmetric rendering.
306 } else if (get_gasp_range(typeface, SkScalarRoundToInt(gdiTextSize), &range) &&
Ben Wagner42a2a202017-04-24 12:40:03 -0400307 range.fVersion >= 1)
Ben Wagner42a2a202017-04-24 12:40:03 -0400308 {
Ben Wagner9f591342017-04-13 11:02:50 -0400309 fTextSizeRender = realTextSize;
310 fRenderingMode = range.fFlags.field.SymmetricSmoothing
311 ? DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
312 : DWRITE_RENDERING_MODE_NATURAL;
bungeman761b2502014-06-30 12:19:41 -0700313 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
314 fTextSizeMeasure = realTextSize;
315 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
316
Ben Wagner9f591342017-04-13 11:02:50 -0400317 // If the requested size is above 20px or there are no bytecode hints, use symmetric rendering.
318 } else if (realTextSize > SkIntToScalar(20) || !is_hinted(typeface)) {
bungeman@google.com058670b2014-05-01 20:39:14 +0000319 fTextSizeRender = realTextSize;
Ben Wagner9f591342017-04-13 11:02:50 -0400320 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
321 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
322 fTextSizeMeasure = realTextSize;
323 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
324
Ben Wagner42a2a202017-04-24 12:40:03 -0400325 // Fonts with hints, no gasp or gasp version 0, and below 20px get non-symmetric rendering.
326 // Often such fonts have hints which were only tested with GDI ClearType classic.
327 // Some of these fonts rely on drop out control in the y direction in order to be legible.
Ben Wagner9f591342017-04-13 11:02:50 -0400328 // Tenor Sans
329 // https://fonts.google.com/specimen/Tenor+Sans
330 // Gill Sans W04
331 // https://cdn.leagueoflegends.com/lolkit/1.1.9/resources/fonts/gill-sans-w04-book.woff
332 // https://na.leagueoflegends.com/en/news/game-updates/patch/patch-410-notes
333 // See https://crbug.com/385897
334 } else {
335 fTextSizeRender = gdiTextSize;
336 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL;
bungeman@google.com058670b2014-05-01 20:39:14 +0000337 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
338 fTextSizeMeasure = realTextSize;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000339 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
340 }
341
Ben Wagner22253062017-03-16 12:38:46 -0400342 // DirectWrite2 allows for grayscale hinting.
343 fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
Ben Wagner22253062017-03-16 12:38:46 -0400344 if (typeface->fFactory2 && typeface->fDWriteFontFace2 &&
Ben Wagnere0a34e72017-03-17 11:23:32 -0400345 SkMask::kA8_Format == fRec.fMaskFormat &&
346 !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag))
Ben Wagner22253062017-03-16 12:38:46 -0400347 {
348 // DWRITE_TEXTURE_ALIASED_1x1 is now misnamed, it must also be used with grayscale.
349 fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
350 fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
351 }
Ben Wagner22253062017-03-16 12:38:46 -0400352
353 // DirectWrite2 allows hinting to be disabled.
354 fGridFitMode = DWRITE_GRID_FIT_MODE_ENABLED;
Ben Wagner5785e4a2019-05-07 16:50:29 -0400355 if (fRec.getHinting() == SkFontHinting::kNone) {
Ben Wagner22253062017-03-16 12:38:46 -0400356 fGridFitMode = DWRITE_GRID_FIT_MODE_DISABLED;
357 if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) {
358 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
359 }
360 }
361
Ben Wagnerf460eee2019-04-18 16:37:45 -0400362 if (this->isLinearMetrics()) {
bungeman@google.com058670b2014-05-01 20:39:14 +0000363 fTextSizeMeasure = realTextSize;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000364 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
365 }
bungeman@google.come8f05922012-08-16 16:13:40 +0000366}
367
reed@google.com30ddd612013-07-30 17:47:39 +0000368SkScalerContext_DW::~SkScalerContext_DW() {
bungeman@google.come8f05922012-08-16 16:13:40 +0000369}
370
reed@google.com30ddd612013-07-30 17:47:39 +0000371unsigned SkScalerContext_DW::generateGlyphCount() {
bungeman@google.come8f05922012-08-16 16:13:40 +0000372 if (fGlyphCount < 0) {
bungeman7cfd46a2016-10-20 16:06:52 -0400373 fGlyphCount = this->getDWriteTypeface()->fDWriteFontFace->GetGlyphCount();
bungeman@google.come8f05922012-08-16 16:13:40 +0000374 }
375 return fGlyphCount;
376}
377
Ben Wagnere5416452018-08-09 14:03:42 -0400378bool SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000379 glyph->fAdvanceX = 0;
380 glyph->fAdvanceY = 0;
381
382 uint16_t glyphId = glyph->getGlyphID();
383 DWRITE_GLYPH_METRICS gm;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000384
385 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
386 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
387 {
Herb Derby209ebc02019-05-13 13:38:09 -0400388 Exclusive l(DWriteFactoryMutex);
Ben Wagnere5416452018-08-09 14:03:42 -0400389 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
bungeman@google.com058670b2014-05-01 20:39:14 +0000390 fTextSizeMeasure,
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000391 1.0f, // pixelsPerDip
Ben Wagner1f5f6b82017-04-14 11:39:34 -0400392 // This parameter does not act like the lpmat2 parameter to GetGlyphOutlineW.
393 // If it did then GsA here and G_inv below to mapVectors.
394 nullptr,
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000395 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
396 &glyphId, 1,
397 &gm),
398 "Could not get gdi compatible glyph metrics.");
399 } else {
Herb Derby209ebc02019-05-13 13:38:09 -0400400 Exclusive l(DWriteFactoryMutex);
Ben Wagnere5416452018-08-09 14:03:42 -0400401 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000402 "Could not get design metrics.");
403 }
bungeman@google.come8f05922012-08-16 16:13:40 +0000404
405 DWRITE_FONT_METRICS dwfm;
herbc7378af2015-10-21 09:24:37 -0700406 {
herb6440f0b2015-10-27 14:37:00 -0700407 Shared l(DWriteFactoryMutex);
bungeman7cfd46a2016-10-20 16:06:52 -0400408 this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm);
herbc7378af2015-10-21 09:24:37 -0700409 }
Mike Reed8be952a2017-02-13 20:44:33 -0500410 SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000411
Ben Wagner1f5f6b82017-04-14 11:39:34 -0400412 SkVector advance = { advanceX, 0 };
bungeman@google.com058670b2014-05-01 20:39:14 +0000413 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
414 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
415 {
bungeman761b2502014-06-30 12:19:41 -0700416 // DirectWrite produced 'compatible' metrics, but while close,
417 // the end result is not always an integer as it would be with GDI.
Ben Wagner1f5f6b82017-04-14 11:39:34 -0400418 advance.fX = SkScalarRoundToScalar(advance.fX);
bungeman@google.com058670b2014-05-01 20:39:14 +0000419 }
Ben Wagner1f5f6b82017-04-14 11:39:34 -0400420 fSkXform.mapVectors(&advance, 1);
bungeman@google.come8f05922012-08-16 16:13:40 +0000421
Ben Wagner1f5f6b82017-04-14 11:39:34 -0400422 glyph->fAdvanceX = SkScalarToFloat(advance.fX);
423 glyph->fAdvanceY = SkScalarToFloat(advance.fY);
Ben Wagnere5416452018-08-09 14:03:42 -0400424 return true;
bungeman@google.come8f05922012-08-16 16:13:40 +0000425}
426
bungeman683a3762014-08-28 11:42:29 -0700427HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
428 DWRITE_RENDERING_MODE renderingMode,
429 DWRITE_TEXTURE_TYPE textureType,
430 RECT* bbox)
Ben Wagnerb2f7fce2014-08-27 19:17:41 -0400431{
bungeman@google.come8f05922012-08-16 16:13:40 +0000432 //Measure raster size.
433 fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
434 fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
435
436 FLOAT advance = 0;
437
438 UINT16 glyphId = glyph->getGlyphID();
439
440 DWRITE_GLYPH_OFFSET offset;
441 offset.advanceOffset = 0.0f;
442 offset.ascenderOffset = 0.0f;
443
444 DWRITE_GLYPH_RUN run;
445 run.glyphCount = 1;
446 run.glyphAdvances = &advance;
bungeman7cfd46a2016-10-20 16:06:52 -0400447 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
bungeman@google.com058670b2014-05-01 20:39:14 +0000448 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
bungeman@google.come8f05922012-08-16 16:13:40 +0000449 run.bidiLevel = 0;
450 run.glyphIndices = &glyphId;
451 run.isSideways = FALSE;
452 run.glyphOffsets = &offset;
herb6440f0b2015-10-27 14:37:00 -0700453
454 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
herbc7378af2015-10-21 09:24:37 -0700455 {
Herb Derby209ebc02019-05-13 13:38:09 -0400456 Exclusive l(DWriteFactoryMutex);
Ben Wagner22253062017-03-16 12:38:46 -0400457 // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
458 if (this->getDWriteTypeface()->fFactory2 &&
459 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
460 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
461 {
462 HRM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(
463 &run,
464 &fXform,
465 renderingMode,
466 fMeasuringMode,
467 fGridFitMode,
468 fAntiAliasMode,
469 0.0f, // baselineOriginX,
470 0.0f, // baselineOriginY,
471 &glyphRunAnalysis),
472 "Could not create DW2 glyph run analysis.");
473 } else {
474 HRM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run,
475 1.0f, // pixelsPerDip,
476 &fXform,
477 renderingMode,
478 fMeasuringMode,
479 0.0f, // baselineOriginX,
480 0.0f, // baselineOriginY,
481 &glyphRunAnalysis),
482 "Could not create glyph run analysis.");
483 }
herb6440f0b2015-10-27 14:37:00 -0700484 }
485 {
486 Shared l(DWriteFactoryMutex);
herbc7378af2015-10-21 09:24:37 -0700487 HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
488 "Could not get texture bounds.");
489 }
bungeman683a3762014-08-28 11:42:29 -0700490 return S_OK;
Ben Wagnerb2f7fce2014-08-27 19:17:41 -0400491}
492
kulshinc4b09152016-06-01 08:31:28 -0700493bool SkScalerContext_DW::isColorGlyph(const SkGlyph& glyph) {
kulshinc4b09152016-06-01 08:31:28 -0700494 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayer;
Ben Wagnere0c9e002017-03-01 16:08:00 -0500495 return getColorGlyphRun(glyph, &colorLayer);
kulshinc4b09152016-06-01 08:31:28 -0700496}
497
Bruce Wange3986752018-07-15 17:11:25 -0400498bool SkScalerContext_DW::isPngGlyph(const SkGlyph& glyph) {
499 if (!this->getDWriteTypeface()->fDWriteFontFace4) {
500 return false;
501 }
502
503 DWRITE_GLYPH_IMAGE_FORMATS f;
504 IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get();
505 HRBM(fontFace4->GetGlyphImageFormats(glyph.getGlyphID(), 0, UINT32_MAX, &f),
506 "Cannot get glyph image formats.");
507 return f & DWRITE_GLYPH_IMAGE_FORMATS_PNG;
508}
509
kulshinc4b09152016-06-01 08:31:28 -0700510bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph,
511 IDWriteColorGlyphRunEnumerator** colorGlyph)
512{
513 FLOAT advance = 0;
514 UINT16 glyphId = glyph.getGlyphID();
515
516 DWRITE_GLYPH_OFFSET offset;
517 offset.advanceOffset = 0.0f;
518 offset.ascenderOffset = 0.0f;
519
520 DWRITE_GLYPH_RUN run;
521 run.glyphCount = 1;
522 run.glyphAdvances = &advance;
bungeman7cfd46a2016-10-20 16:06:52 -0400523 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
kulshinc4b09152016-06-01 08:31:28 -0700524 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
525 run.bidiLevel = 0;
526 run.glyphIndices = &glyphId;
527 run.isSideways = FALSE;
528 run.glyphOffsets = &offset;
529
Ben Wagner22253062017-03-16 12:38:46 -0400530 HRESULT hr = this->getDWriteTypeface()->fFactory2->TranslateColorGlyphRun(
kulshinc4b09152016-06-01 08:31:28 -0700531 0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph);
532 if (hr == DWRITE_E_NOCOLOR) {
533 return false;
534 }
535 HRBM(hr, "Failed to translate color glyph run");
536 return true;
537}
kulshinc4b09152016-06-01 08:31:28 -0700538
Bruce Wang46f25632018-06-13 13:38:34 -0400539void SkScalerContext_DW::generateColorMetrics(SkGlyph* glyph) {
540 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
541 HRVM(getColorGlyphRun(*glyph, &colorLayers), "Could not get color glyph run");
542 SkASSERT(colorLayers.get());
543
544 SkRect bounds = SkRect::MakeEmpty();
545 BOOL hasNextRun = FALSE;
546 while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
547 const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
548 HRVM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run");
549
550 SkPath path;
551 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
552 HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
553 "Could not create geometry to path converter.");
554 {
Herb Derby209ebc02019-05-13 13:38:09 -0400555 Exclusive l(DWriteFactoryMutex);
Bruce Wang46f25632018-06-13 13:38:34 -0400556 HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
557 colorGlyph->glyphRun.fontEmSize,
558 colorGlyph->glyphRun.glyphIndices,
559 colorGlyph->glyphRun.glyphAdvances,
560 colorGlyph->glyphRun.glyphOffsets,
561 colorGlyph->glyphRun.glyphCount,
562 colorGlyph->glyphRun.isSideways,
563 colorGlyph->glyphRun.bidiLevel % 2, //rtl
564 geometryToPath.get()),
565 "Could not create glyph outline.");
566 }
567 bounds.join(path.getBounds());
568 }
Bruce Wang0bf54082018-07-18 12:36:56 -0400569 SkMatrix matrix = fSkXform;
Bruce Wang0bf54082018-07-18 12:36:56 -0400570 if (this->isSubpixel()) {
571 matrix.postTranslate(SkFixedToScalar(glyph->getSubXFixed()),
572 SkFixedToScalar(glyph->getSubYFixed()));
573 }
Bruce Wang0bf54082018-07-18 12:36:56 -0400574 matrix.mapRect(&bounds);
Bruce Wang46f25632018-06-13 13:38:34 -0400575 // Round float bound values into integer.
576 SkIRect ibounds = bounds.roundOut();
577
578 glyph->fWidth = ibounds.fRight - ibounds.fLeft;
579 glyph->fHeight = ibounds.fBottom - ibounds.fTop;
580 glyph->fLeft = ibounds.fLeft;
581 glyph->fTop = ibounds.fTop;
582}
583
Bruce Wange3986752018-07-15 17:11:25 -0400584namespace {
585struct Context {
586 SkTScopedComPtr<IDWriteFontFace4> fontFace4;
587 void* glyphDataContext;
588 Context(IDWriteFontFace4* face4, void* context)
589 : fontFace4(SkRefComPtr(face4))
590 , glyphDataContext(context)
591 {}
592};
593
594static void ReleaseProc(const void* ptr, void* context) {
595 Context* ctx = (Context*)context;
596 ctx->fontFace4->ReleaseGlyphImageData(ctx->glyphDataContext);
597 delete ctx;
598}
599}
600
601void SkScalerContext_DW::generatePngMetrics(SkGlyph* glyph) {
602 SkASSERT(isPngGlyph(*glyph));
603 SkASSERT(glyph->fMaskFormat == SkMask::Format::kARGB32_Format);
604 SkASSERT(this->getDWriteTypeface()->fDWriteFontFace4);
605
606 IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get();
607 DWRITE_GLYPH_IMAGE_DATA glyphData;
608 void* glyphDataContext;
609 HRVM(fontFace4->GetGlyphImageData(glyph->getGlyphID(),
610 fTextSizeRender,
611 DWRITE_GLYPH_IMAGE_FORMATS_PNG,
612 &glyphData,
613 &glyphDataContext),
614 "Glyph image data could not be acquired.");
615
616 Context* context = new Context(fontFace4, glyphDataContext);
617 sk_sp<SkData> data = SkData::MakeWithProc(glyphData.imageData,
618 glyphData.imageDataSize,
619 &ReleaseProc,
620 context);
621
622 std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(std::move(data));
623 if (!codec) {
624 return;
625 }
626
627 SkImageInfo info = codec->getInfo();
628 SkRect bounds = SkRect::MakeLTRB(SkIntToScalar(info.bounds().fLeft),
629 SkIntToScalar(info.bounds().fTop),
630 SkIntToScalar(info.bounds().fRight),
631 SkIntToScalar(info.bounds().fBottom));
632
633 SkMatrix matrix = fSkXform;
634 SkScalar scale = fTextSizeRender / glyphData.pixelsPerEm;
635 matrix.preScale(scale, scale);
Bruce Wang77bf48a2018-07-18 15:32:08 -0400636 matrix.preTranslate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
Bruce Wange3986752018-07-15 17:11:25 -0400637 if (this->isSubpixel()) {
Bruce Wang77bf48a2018-07-18 15:32:08 -0400638 matrix.postTranslate(SkFixedToScalar(glyph->getSubXFixed()),
639 SkFixedToScalar(glyph->getSubYFixed()));
Bruce Wange3986752018-07-15 17:11:25 -0400640 }
Bruce Wang77bf48a2018-07-18 15:32:08 -0400641 matrix.mapRect(&bounds);
Bruce Wange3986752018-07-15 17:11:25 -0400642 bounds.roundOut();
643
644 glyph->fWidth = bounds.width();
645 glyph->fHeight = bounds.height();
646 glyph->fLeft = bounds.left();
647 glyph->fTop = bounds.top();
648 return;
649}
650
bungeman683a3762014-08-28 11:42:29 -0700651void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
Herb Derby793818b2019-06-25 17:10:11 -0400652
653
654 // GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
655 // { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
656 // for small, but not quite zero, sized glyphs.
657 // Only set as non-empty if the returned bounds are non-empty.
658 auto glyphCheckAndSetBounds = [](SkGlyph* glyph, const RECT& bbox) {
659 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
660 return false;
661 }
662
663 // We're trying to pack left and top into int16_t,
664 // and width and height into uint16_t, after outsetting by 1.
665 if (!SkIRect::MakeXYWH(-32767, -32767, 65535, 65535).contains(
666 SkIRect::MakeLTRB(bbox.left, bbox.top, bbox.right, bbox.bottom))) {
667 return false;
668 }
669
670 glyph->fWidth = SkToU16(bbox.right - bbox.left);
671 glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
672 glyph->fLeft = SkToS16(bbox.left);
673 glyph->fTop = SkToS16(bbox.top);
674 return true;
675 };
676
bungeman683a3762014-08-28 11:42:29 -0700677 glyph->fWidth = 0;
678 glyph->fHeight = 0;
679 glyph->fLeft = 0;
680 glyph->fTop = 0;
Ben Wagnere5416452018-08-09 14:03:42 -0400681 glyph->fMaskFormat = fRec.fMaskFormat;
bungeman683a3762014-08-28 11:42:29 -0700682
Ben Wagnere5416452018-08-09 14:03:42 -0400683 if (!this->generateAdvance(glyph)) {
684 return;
685 }
bungeman683a3762014-08-28 11:42:29 -0700686
kulshinc4b09152016-06-01 08:31:28 -0700687 if (fIsColorFont && isColorGlyph(*glyph)) {
688 glyph->fMaskFormat = SkMask::kARGB32_Format;
Bruce Wang46f25632018-06-13 13:38:34 -0400689 generateColorMetrics(glyph);
690 return;
kulshinc4b09152016-06-01 08:31:28 -0700691 }
kulshinc4b09152016-06-01 08:31:28 -0700692
Bruce Wange3986752018-07-15 17:11:25 -0400693 if (fIsColorFont && isPngGlyph(*glyph)) {
694 glyph->fMaskFormat = SkMask::kARGB32_Format;
695 generatePngMetrics(glyph);
696 return;
697 }
698
bungeman683a3762014-08-28 11:42:29 -0700699 RECT bbox;
700 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
701 "Requested bounding box could not be determined.");
702
Herb Derby793818b2019-06-25 17:10:11 -0400703 if (glyphCheckAndSetBounds(glyph, bbox)) {
bungeman683a3762014-08-28 11:42:29 -0700704 return;
705 }
706
707 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
Ben Wagner79ac5082019-02-04 13:13:17 -0500708 // glyphs of the specified texture type or it is too big for smoothing.
709 // When this happens, try with the alternate texture type.
710 if (DWRITE_TEXTURE_ALIASED_1x1 != fTextureType ||
711 DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE == fAntiAliasMode)
712 {
bungeman683a3762014-08-28 11:42:29 -0700713 HRVM(this->getBoundingBox(glyph,
714 DWRITE_RENDERING_MODE_ALIASED,
715 DWRITE_TEXTURE_ALIASED_1x1,
716 &bbox),
717 "Fallback bounding box could not be determined.");
Herb Derby793818b2019-06-25 17:10:11 -0400718 if (glyphCheckAndSetBounds(glyph, bbox)) {
bungeman683a3762014-08-28 11:42:29 -0700719 glyph->fForceBW = 1;
Ben Wagner968664b2018-12-04 14:06:37 -0500720 glyph->fMaskFormat = SkMask::kBW_Format;
bungeman683a3762014-08-28 11:42:29 -0700721 }
722 }
723 // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
724 // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
bungeman@google.come8f05922012-08-16 16:13:40 +0000725}
726
Mike Reedb5784ac2018-11-12 09:35:15 -0500727void SkScalerContext_DW::generateFontMetrics(SkFontMetrics* metrics) {
halcanary96fcdcc2015-08-27 07:41:13 -0700728 if (nullptr == metrics) {
bungemanf73c2372014-07-23 13:31:06 -0700729 return;
bungeman41078062014-07-07 08:16:37 -0700730 }
bungeman@google.come8f05922012-08-16 16:13:40 +0000731
bungeman41078062014-07-07 08:16:37 -0700732 sk_bzero(metrics, sizeof(*metrics));
bungeman@google.come1b9bad2013-08-27 21:51:37 +0000733
bungeman@google.come8f05922012-08-16 16:13:40 +0000734 DWRITE_FONT_METRICS dwfm;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000735 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
736 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
737 {
bungeman7cfd46a2016-10-20 16:06:52 -0400738 this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleMetrics(
bungeman@google.com058670b2014-05-01 20:39:14 +0000739 fTextSizeRender,
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000740 1.0f, // pixelsPerDip
741 &fXform,
742 &dwfm);
743 } else {
bungeman7cfd46a2016-10-20 16:06:52 -0400744 this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm);
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000745 }
bungeman@google.come8f05922012-08-16 16:13:40 +0000746
bungeman@google.come1b9bad2013-08-27 21:51:37 +0000747 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
commit-bot@chromium.org0bc406d2014-03-01 20:12:26 +0000748
bungemanf73c2372014-07-23 13:31:06 -0700749 metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
bungeman41078062014-07-07 08:16:37 -0700750 metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
bungeman41078062014-07-07 08:16:37 -0700751 metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
752 metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
Koji Ishiia6725fc2017-01-22 02:30:51 +0900753 metrics->fCapHeight = fTextSizeRender * SkIntToScalar(dwfm.capHeight) / upem;
bungeman41078062014-07-07 08:16:37 -0700754 metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
755 metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
Ben Wagner219f3622017-07-17 15:32:25 -0400756 metrics->fStrikeoutThickness = fTextSizeRender * SkIntToScalar(dwfm.strikethroughThickness) / upem;
757 metrics->fStrikeoutPosition = -(fTextSizeRender * SkIntToScalar(dwfm.strikethroughPosition) / upem);
bungeman@google.come8f05922012-08-16 16:13:40 +0000758
Mike Reedb5784ac2018-11-12 09:35:15 -0500759 metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
760 metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
761 metrics->fFlags |= SkFontMetrics::kStrikeoutThicknessIsValid_Flag;
762 metrics->fFlags |= SkFontMetrics::kStrikeoutPositionIsValid_Flag;
bungemanf73c2372014-07-23 13:31:06 -0700763
bungeman7cfd46a2016-10-20 16:06:52 -0400764 if (this->getDWriteTypeface()->fDWriteFontFace1.get()) {
bungemanf73c2372014-07-23 13:31:06 -0700765 DWRITE_FONT_METRICS1 dwfm1;
bungeman7cfd46a2016-10-20 16:06:52 -0400766 this->getDWriteTypeface()->fDWriteFontFace1->GetMetrics(&dwfm1);
bungemanf73c2372014-07-23 13:31:06 -0700767 metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
768 metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
769 metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
770 metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
771
772 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
bungemanf5484442014-09-10 07:49:05 -0700773 return;
bungemanf73c2372014-07-23 13:31:06 -0700774 }
bungemanf5484442014-09-10 07:49:05 -0700775
bungeman7cfd46a2016-10-20 16:06:52 -0400776 AutoTDWriteTable<SkOTTableHead> head(this->getDWriteTypeface()->fDWriteFontFace.get());
bungemanf5484442014-09-10 07:49:05 -0700777 if (head.fExists &&
778 head.fSize >= sizeof(SkOTTableHead) &&
779 head->version == SkOTTableHead::version1)
780 {
781 metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
782 metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
783 metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
784 metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
785
786 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
787 return;
788 }
789
790 metrics->fTop = metrics->fAscent;
791 metrics->fBottom = metrics->fDescent;
bungeman@google.come8f05922012-08-16 16:13:40 +0000792}
793
794///////////////////////////////////////////////////////////////////////////////
795
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500796#include "include/private/SkColorData.h"
bungeman@google.come8f05922012-08-16 16:13:40 +0000797
Herb Derby793818b2019-06-25 17:10:11 -0400798void SkScalerContext_DW::BilevelToBW(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
799 const int width = glyph.width();
bungeman@google.come8f05922012-08-16 16:13:40 +0000800 const size_t dstRB = (width + 7) >> 3;
801 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
802
803 int byteCount = width >> 3;
804 int bitCount = width & 7;
805
Herb Derby793818b2019-06-25 17:10:11 -0400806 for (int y = 0; y < glyph.height(); ++y) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000807 if (byteCount > 0) {
808 for (int i = 0; i < byteCount; ++i) {
809 unsigned byte = 0;
810 byte |= src[0] & (1 << 7);
811 byte |= src[1] & (1 << 6);
812 byte |= src[2] & (1 << 5);
813 byte |= src[3] & (1 << 4);
814 byte |= src[4] & (1 << 3);
815 byte |= src[5] & (1 << 2);
816 byte |= src[6] & (1 << 1);
817 byte |= src[7] & (1 << 0);
818 dst[i] = byte;
819 src += 8;
820 }
821 }
822 if (bitCount > 0) {
823 unsigned byte = 0;
824 unsigned mask = 0x80;
825 for (int i = 0; i < bitCount; i++) {
826 byte |= (src[i]) & mask;
827 mask >>= 1;
828 }
829 dst[byteCount] = byte;
830 }
831 src += bitCount;
832 dst += dstRB;
833 }
834}
835
836template<bool APPLY_PREBLEND>
Herb Derby793818b2019-06-25 17:10:11 -0400837void SkScalerContext_DW::GrayscaleToA8(const uint8_t* SK_RESTRICT src,
838 const SkGlyph& glyph,
839 const uint8_t* table8) {
Ben Wagner22253062017-03-16 12:38:46 -0400840 const size_t dstRB = glyph.rowBytes();
Herb Derby793818b2019-06-25 17:10:11 -0400841 const int width = glyph.width();
Ben Wagner22253062017-03-16 12:38:46 -0400842 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
843
Herb Derby793818b2019-06-25 17:10:11 -0400844 for (int y = 0; y < glyph.height(); y++) {
845 for (int i = 0; i < width; i++) {
Ben Wagner22253062017-03-16 12:38:46 -0400846 U8CPU a = *(src++);
847 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(a, table8);
848 }
849 dst = SkTAddOffset<uint8_t>(dst, dstRB);
850 }
851}
852
853template<bool APPLY_PREBLEND>
Herb Derby793818b2019-06-25 17:10:11 -0400854void SkScalerContext_DW::RGBToA8(const uint8_t* SK_RESTRICT src,
855 const SkGlyph& glyph,
856 const uint8_t* table8) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000857 const size_t dstRB = glyph.rowBytes();
Herb Derby793818b2019-06-25 17:10:11 -0400858 const int width = glyph.width();
bungeman@google.come8f05922012-08-16 16:13:40 +0000859 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
860
Herb Derby793818b2019-06-25 17:10:11 -0400861 for (int y = 0; y < glyph.height(); y++) {
862 for (int i = 0; i < width; i++) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000863 U8CPU r = *(src++);
864 U8CPU g = *(src++);
865 U8CPU b = *(src++);
866 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
867 }
Ben Wagner22253062017-03-16 12:38:46 -0400868 dst = SkTAddOffset<uint8_t>(dst, dstRB);
bungeman@google.come8f05922012-08-16 16:13:40 +0000869 }
870}
871
bungeman12f03122015-03-19 13:57:36 -0700872template<bool APPLY_PREBLEND, bool RGB>
Herb Derby793818b2019-06-25 17:10:11 -0400873void SkScalerContext_DW::RGBToLcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
874 const uint8_t* tableR, const uint8_t* tableG,
875 const uint8_t* tableB) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000876 const size_t dstRB = glyph.rowBytes();
Herb Derby793818b2019-06-25 17:10:11 -0400877 const int width = glyph.width();
bungeman@google.come8f05922012-08-16 16:13:40 +0000878 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
879
Herb Derby793818b2019-06-25 17:10:11 -0400880 for (int y = 0; y < glyph.height(); y++) {
881 for (int i = 0; i < width; i++) {
bungeman12f03122015-03-19 13:57:36 -0700882 U8CPU r, g, b;
883 if (RGB) {
884 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
885 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
886 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
887 } else {
888 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
889 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
890 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
891 }
bungeman@google.come8f05922012-08-16 16:13:40 +0000892 dst[i] = SkPack888ToRGB16(r, g, b);
893 }
Ben Wagner22253062017-03-16 12:38:46 -0400894 dst = SkTAddOffset<uint16_t>(dst, dstRB);
bungeman@google.come8f05922012-08-16 16:13:40 +0000895 }
896}
897
Ben Wagnerb2f7fce2014-08-27 19:17:41 -0400898const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
899 DWRITE_RENDERING_MODE renderingMode,
900 DWRITE_TEXTURE_TYPE textureType)
901{
Herb Derby793818b2019-06-25 17:10:11 -0400902 int sizeNeeded = glyph.width() * glyph.height();
Ben Wagner22253062017-03-16 12:38:46 -0400903 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) {
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000904 sizeNeeded *= 3;
905 }
906 if (sizeNeeded > fBits.count()) {
907 fBits.setCount(sizeNeeded);
908 }
bungeman@google.come8f05922012-08-16 16:13:40 +0000909
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000910 // erase
911 memset(fBits.begin(), 0, sizeNeeded);
912
913 fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
914 fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
915
916 FLOAT advance = 0.0f;
917
918 UINT16 index = glyph.getGlyphID();
919
920 DWRITE_GLYPH_OFFSET offset;
921 offset.advanceOffset = 0.0f;
922 offset.ascenderOffset = 0.0f;
923
924 DWRITE_GLYPH_RUN run;
925 run.glyphCount = 1;
926 run.glyphAdvances = &advance;
bungeman7cfd46a2016-10-20 16:06:52 -0400927 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
bungeman@google.com058670b2014-05-01 20:39:14 +0000928 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000929 run.bidiLevel = 0;
930 run.glyphIndices = &index;
931 run.isSideways = FALSE;
932 run.glyphOffsets = &offset;
herbc7378af2015-10-21 09:24:37 -0700933 {
herb6440f0b2015-10-27 14:37:00 -0700934 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
935 {
Herb Derby209ebc02019-05-13 13:38:09 -0400936 Exclusive l(DWriteFactoryMutex);
Ben Wagner22253062017-03-16 12:38:46 -0400937 // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
938 if (this->getDWriteTypeface()->fFactory2 &&
939 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
940 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
941 {
942 HRNM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(&run,
943 &fXform,
944 renderingMode,
945 fMeasuringMode,
946 fGridFitMode,
947 fAntiAliasMode,
948 0.0f, // baselineOriginX,
949 0.0f, // baselineOriginY,
950 &glyphRunAnalysis),
951 "Could not create DW2 glyph run analysis.");
952 } else {
953 HRNM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run,
954 1.0f, // pixelsPerDip,
955 &fXform,
956 renderingMode,
957 fMeasuringMode,
958 0.0f, // baselineOriginX,
959 0.0f, // baselineOriginY,
960 &glyphRunAnalysis),
961 "Could not create glyph run analysis.");
962 }
herb6440f0b2015-10-27 14:37:00 -0700963 }
herbc7378af2015-10-21 09:24:37 -0700964 //NOTE: this assumes that the glyph has already been measured
965 //with an exact same glyph run analysis.
966 RECT bbox;
Herb Derby793818b2019-06-25 17:10:11 -0400967 bbox.left = glyph.left();
968 bbox.top = glyph.top();
969 bbox.right = glyph.left() + glyph.width();
970 bbox.bottom = glyph.top() + glyph.height();
herb6440f0b2015-10-27 14:37:00 -0700971 {
972 Shared l(DWriteFactoryMutex);
973 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
Ben Wagner22253062017-03-16 12:38:46 -0400974 &bbox,
975 fBits.begin(),
976 sizeNeeded),
herb6440f0b2015-10-27 14:37:00 -0700977 "Could not draw mask.");
978 }
herbc7378af2015-10-21 09:24:37 -0700979 }
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000980 return fBits.begin();
981}
982
kulshinc4b09152016-06-01 08:31:28 -0700983void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) {
984 SkASSERT(isColorGlyph(glyph));
985 SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format);
986
Herb Derby9b06f212019-06-21 14:25:47 -0400987 memset(glyph.fImage, 0, glyph.imageSize());
kulshinc4b09152016-06-01 08:31:28 -0700988
989 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
990 getColorGlyphRun(glyph, &colorLayers);
991 SkASSERT(colorLayers.get());
992
993 SkMatrix matrix = fSkXform;
Herb Derby793818b2019-06-25 17:10:11 -0400994 matrix.postTranslate(-SkIntToScalar(glyph.left()), -SkIntToScalar(glyph.top()));
Bruce Wang0bf54082018-07-18 12:36:56 -0400995 if (this->isSubpixel()) {
996 matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
997 SkFixedToScalar(glyph.getSubYFixed()));
998 }
Herb Derby793818b2019-06-25 17:10:11 -0400999 SkRasterClip rc(SkIRect::MakeWH(glyph.width(), glyph.height()));
kulshinc4b09152016-06-01 08:31:28 -07001000 SkDraw draw;
Herb Derby793818b2019-06-25 17:10:11 -04001001 draw.fDst = SkPixmap(SkImageInfo::MakeN32(glyph.width(), glyph.height(), kPremul_SkAlphaType),
kulshinc4b09152016-06-01 08:31:28 -07001002 glyph.fImage,
Herb Derbyba321b62018-03-12 16:02:29 -04001003 glyph.rowBytesUsingFormat(SkMask::Format::kARGB32_Format));
kulshinc4b09152016-06-01 08:31:28 -07001004 draw.fMatrix = &matrix;
1005 draw.fRC = &rc;
1006
1007 SkPaint paint;
Mike Reedf738d422019-01-16 17:12:15 -05001008 paint.setAntiAlias(fRenderingMode != DWRITE_RENDERING_MODE_ALIASED);
kulshinc4b09152016-06-01 08:31:28 -07001009
1010 BOOL hasNextRun = FALSE;
1011 while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
1012 const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
1013 HRVM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run");
1014
1015 SkColor color;
1016 if (colorGlyph->paletteIndex != 0xffff) {
Mike Reed35ee0e02017-08-06 22:29:57 -04001017 color = SkColorSetARGB(sk_float_round2int(colorGlyph->runColor.a * 255),
1018 sk_float_round2int(colorGlyph->runColor.r * 255),
1019 sk_float_round2int(colorGlyph->runColor.g * 255),
1020 sk_float_round2int(colorGlyph->runColor.b * 255));
kulshinc4b09152016-06-01 08:31:28 -07001021 } else {
1022 // If all components of runColor are 0 or (equivalently) paletteIndex is 0xFFFF then
1023 // the 'current brush' is used. fRec.getLuminanceColor() is kinda sorta what is wanted
1024 // here, but not really, it will often be the wrong value because it wan't designed for
1025 // this.
bungeman5f544342016-09-22 12:32:07 -07001026 // TODO: implement this fully, bug.skia.org/5788
kulshinc4b09152016-06-01 08:31:28 -07001027 color = fRec.getLuminanceColor();
1028 }
1029 paint.setColor(color);
1030
1031 SkPath path;
1032 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1033 HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
1034 "Could not create geometry to path converter.");
1035 {
Herb Derby209ebc02019-05-13 13:38:09 -04001036 Exclusive l(DWriteFactoryMutex);
kulshinc4b09152016-06-01 08:31:28 -07001037 HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
1038 colorGlyph->glyphRun.fontEmSize,
1039 colorGlyph->glyphRun.glyphIndices,
1040 colorGlyph->glyphRun.glyphAdvances,
1041 colorGlyph->glyphRun.glyphOffsets,
1042 colorGlyph->glyphRun.glyphCount,
1043 colorGlyph->glyphRun.isSideways,
1044 colorGlyph->glyphRun.bidiLevel % 2, //rtl
1045 geometryToPath.get()),
1046 "Could not create glyph outline.");
1047 }
1048 draw.drawPath(path, paint, nullptr, true /* pathIsMutable */);
1049 }
1050}
kulshinc4b09152016-06-01 08:31:28 -07001051
Bruce Wange3986752018-07-15 17:11:25 -04001052void SkScalerContext_DW::generatePngGlyphImage(const SkGlyph& glyph) {
1053 SkASSERT(isPngGlyph(glyph));
1054 SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format);
1055 SkASSERT(this->getDWriteTypeface()->fDWriteFontFace4);
1056
1057 IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get();
1058 DWRITE_GLYPH_IMAGE_DATA glyphData;
1059 void* glyphDataContext;
1060 HRVM(fontFace4->GetGlyphImageData(glyph.getGlyphID(),
1061 fTextSizeRender,
1062 DWRITE_GLYPH_IMAGE_FORMATS_PNG,
1063 &glyphData,
1064 &glyphDataContext),
1065 "Glyph image data could not be acquired.");
1066 Context* context = new Context(fontFace4, glyphDataContext);
1067 sk_sp<SkData> data = SkData::MakeWithProc(glyphData.imageData,
1068 glyphData.imageDataSize,
1069 &ReleaseProc,
1070 context);
1071 sk_sp<SkImage> image = SkImage::MakeFromEncoded(std::move(data));
1072
1073 SkBitmap dstBitmap;
Herb Derby793818b2019-06-25 17:10:11 -04001074 dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(),
Bruce Wange3986752018-07-15 17:11:25 -04001075 kN32_SkColorType,
1076 kPremul_SkAlphaType),
1077 glyph.rowBytes());
1078 dstBitmap.setPixels(glyph.fImage);
1079
1080 SkCanvas canvas(dstBitmap);
1081 canvas.clear(SK_ColorTRANSPARENT);
Herb Derby793818b2019-06-25 17:10:11 -04001082 canvas.translate(-glyph.left(), -glyph.top());
Bruce Wange3986752018-07-15 17:11:25 -04001083 if (this->isSubpixel()) {
1084 canvas.translate(SkFixedToScalar(glyph.getSubXFixed()),
1085 SkFixedToScalar(glyph.getSubYFixed()));
1086 }
1087 canvas.concat(fSkXform);
1088 SkScalar ratio = fTextSizeRender / glyphData.pixelsPerEm;
1089 canvas.scale(ratio, ratio);
Bruce Wang77bf48a2018-07-18 15:32:08 -04001090 canvas.translate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
Bruce Wange3986752018-07-15 17:11:25 -04001091 canvas.drawImage(image, 0, 0, nullptr);
1092}
1093
bungeman@google.comd715aaa2014-04-09 15:35:03 +00001094void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
bungeman@google.come8f05922012-08-16 16:13:40 +00001095 //Create the mask.
Ben Wagnerb2f7fce2014-08-27 19:17:41 -04001096 DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
1097 DWRITE_TEXTURE_TYPE textureType = fTextureType;
1098 if (glyph.fForceBW) {
1099 renderingMode = DWRITE_RENDERING_MODE_ALIASED;
1100 textureType = DWRITE_TEXTURE_ALIASED_1x1;
1101 }
kulshinc4b09152016-06-01 08:31:28 -07001102
kulshinc4b09152016-06-01 08:31:28 -07001103 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
Bruce Wange3986752018-07-15 17:11:25 -04001104 if (fIsColorFont) {
1105 if (isColorGlyph(glyph)) {
1106 generateColorGlyphImage(glyph);
1107 return;
1108 } else if (isPngGlyph(glyph)) {
1109 generatePngGlyphImage(glyph);
1110 return;
1111 }
1112 }
1113 SkDEBUGFAIL("Could not generate image from the given color font format.");
kulshinc4b09152016-06-01 08:31:28 -07001114 return;
1115 }
kulshinc4b09152016-06-01 08:31:28 -07001116
Ben Wagnerb2f7fce2014-08-27 19:17:41 -04001117 const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
bungeman@google.come8f05922012-08-16 16:13:40 +00001118 if (!bits) {
Herb Derby9b06f212019-06-21 14:25:47 -04001119 sk_bzero(glyph.fImage, glyph.imageSize());
bungeman@google.come8f05922012-08-16 16:13:40 +00001120 return;
1121 }
1122
1123 //Copy the mask into the glyph.
bungeman@google.come8f05922012-08-16 16:13:40 +00001124 const uint8_t* src = (const uint8_t*)bits;
Ben Wagnerb2f7fce2014-08-27 19:17:41 -04001125 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
Ben Wagner968664b2018-12-04 14:06:37 -05001126 SkASSERT(SkMask::kBW_Format == glyph.fMaskFormat);
1127 SkASSERT(DWRITE_TEXTURE_ALIASED_1x1 == textureType);
Herb Derby793818b2019-06-25 17:10:11 -04001128 BilevelToBW(src, glyph);
bungeman@google.comd715aaa2014-04-09 15:35:03 +00001129 } else if (!isLCD(fRec)) {
Ben Wagner22253062017-03-16 12:38:46 -04001130 if (textureType == DWRITE_TEXTURE_ALIASED_1x1) {
1131 if (fPreBlend.isApplicable()) {
Herb Derby793818b2019-06-25 17:10:11 -04001132 GrayscaleToA8<true>(src, glyph, fPreBlend.fG);
Ben Wagner22253062017-03-16 12:38:46 -04001133 } else {
Herb Derby793818b2019-06-25 17:10:11 -04001134 GrayscaleToA8<false>(src, glyph, fPreBlend.fG);
Ben Wagner22253062017-03-16 12:38:46 -04001135 }
bungeman@google.come8f05922012-08-16 16:13:40 +00001136 } else {
Ben Wagner22253062017-03-16 12:38:46 -04001137 if (fPreBlend.isApplicable()) {
Herb Derby793818b2019-06-25 17:10:11 -04001138 RGBToA8<true>(src, glyph, fPreBlend.fG);
Ben Wagner22253062017-03-16 12:38:46 -04001139 } else {
Herb Derby793818b2019-06-25 17:10:11 -04001140 RGBToA8<false>(src, glyph, fPreBlend.fG);
Ben Wagner22253062017-03-16 12:38:46 -04001141 }
bungeman@google.come8f05922012-08-16 16:13:40 +00001142 }
reedd54d3fc2014-11-13 14:39:58 -08001143 } else {
1144 SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat);
bungeman@google.coma76de722012-10-26 19:35:54 +00001145 if (fPreBlend.isApplicable()) {
bungeman12f03122015-03-19 13:57:36 -07001146 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
Herb Derby793818b2019-06-25 17:10:11 -04001147 RGBToLcd16<true, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman12f03122015-03-19 13:57:36 -07001148 } else {
Herb Derby793818b2019-06-25 17:10:11 -04001149 RGBToLcd16<true, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman12f03122015-03-19 13:57:36 -07001150 }
bungeman@google.come8f05922012-08-16 16:13:40 +00001151 } else {
bungeman12f03122015-03-19 13:57:36 -07001152 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
Herb Derby793818b2019-06-25 17:10:11 -04001153 RGBToLcd16<false, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman12f03122015-03-19 13:57:36 -07001154 } else {
Herb Derby793818b2019-06-25 17:10:11 -04001155 RGBToLcd16<false, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman12f03122015-03-19 13:57:36 -07001156 }
bungeman@google.come8f05922012-08-16 16:13:40 +00001157 }
bungeman@google.come8f05922012-08-16 16:13:40 +00001158 }
1159}
1160
Ben Wagner5ddb3082018-03-29 11:18:06 -04001161bool SkScalerContext_DW::generatePath(SkGlyphID glyph, SkPath* path) {
dcheng2f19b552015-07-07 19:35:53 -07001162 SkASSERT(path);
bungeman@google.come8f05922012-08-16 16:13:40 +00001163
1164 path->reset();
1165
1166 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
Ben Wagner5ddb3082018-03-29 11:18:06 -04001167 HRBM(SkDWriteGeometrySink::Create(path, &geometryToPath),
bungeman@google.come8f05922012-08-16 16:13:40 +00001168 "Could not create geometry to path converter.");
Ben Wagner6e9ac122016-11-11 14:31:06 -05001169 UINT16 glyphId = SkTo<UINT16>(glyph);
herbc7378af2015-10-21 09:24:37 -07001170 {
Herb Derby209ebc02019-05-13 13:38:09 -04001171 Exclusive l(DWriteFactoryMutex);
herbc7378af2015-10-21 09:24:37 -07001172 //TODO: convert to<->from DIUs? This would make a difference if hinting.
1173 //It may not be needed, it appears that DirectWrite only hints at em size.
Ben Wagner5ddb3082018-03-29 11:18:06 -04001174 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
bungeman7cfd46a2016-10-20 16:06:52 -04001175 SkScalarToFloat(fTextSizeRender),
1176 &glyphId,
1177 nullptr, //advances
1178 nullptr, //offsets
1179 1, //num glyphs
1180 FALSE, //sideways
1181 FALSE, //rtl
1182 geometryToPath.get()),
1183 "Could not create glyph outline.");
herbc7378af2015-10-21 09:24:37 -07001184 }
bungeman@google.com091f51b2013-01-10 18:56:18 +00001185
bungeman@google.com058670b2014-05-01 20:39:14 +00001186 path->transform(fSkXform);
Ben Wagner5ddb3082018-03-29 11:18:06 -04001187 return true;
bungeman@google.come8f05922012-08-16 16:13:40 +00001188}
mtklein1ee76512015-11-02 10:20:27 -08001189
Mike Klein8f11d4d2018-01-24 12:42:55 -05001190#endif//defined(SK_BUILD_FOR_WIN)