1/*
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 */
7
8#include "SkTypes.h"
9#if defined(SK_BUILD_FOR_WIN)
10
11#undef GetGlyphIndices
12
13#include "SkDraw.h"
14#include "SkDWrite.h"
15#include "SkDWriteGeometrySink.h"
16#include "SkEndian.h"
17#include "SkGlyph.h"
18#include "SkHRESULT.h"
19#include "SkMaskGamma.h"
20#include "SkMatrix22.h"
21#include "SkMutex.h"
22#include "SkOTTable_EBLC.h"
23#include "SkOTTable_EBSC.h"
24#include "SkOTTable_gasp.h"
25#include "SkOTTable_maxp.h"
26#include "SkPath.h"
27#include "SkRasterClip.h"
28#include "SkScalerContext.h"
29#include "SkScalerContext_win_dw.h"
30#include "SkSharedMutex.h"
31#include "SkTScopedComPtr.h"
32#include "SkTypeface_win_dw.h"
33
34#include <dwrite.h>
35#include <dwrite_1.h>
36
37/* Note:
38 * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe.
39 * The DWriteFactoryMutex protects the calls that are problematic.
40 */
41static SkSharedMutex DWriteFactoryMutex;
42
43typedef SkAutoSharedMutexShared Shared;
44
45static bool isLCD(const SkScalerContextRec& rec) {
46    return SkMask::kLCD16_Format == rec.fMaskFormat;
47}
48
49static bool is_hinted(DWriteFontTypeface* typeface) {
50    SkAutoExclusive l(DWriteFactoryMutex);
51    AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
52    if (!maxp.fExists) {
53        return false;
54    }
55    if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
56        return false;
57    }
58    if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
59        return false;
60    }
61    return (0 != maxp->version.tt.maxSizeOfInstructions);
62}
63
64/** A GaspRange is inclusive, [min, max]. */
65struct GaspRange {
66    using Behavior = SkOTTableGridAndScanProcedure::GaspRange::behavior;
67    GaspRange(int min, int max, int version, Behavior flags)
68        : fMin(min), fMax(max), fVersion(version), fFlags(flags) { }
69    int fMin;
70    int fMax;
71    int fVersion;
72    Behavior fFlags;
73};
74
75bool get_gasp_range(DWriteFontTypeface* typeface, int size, GaspRange* range) {
76    AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
77    if (!gasp.fExists) {
78        return false;
79    }
80    if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
81        return false;
82    }
83    if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
84        gasp->version != SkOTTableGridAndScanProcedure::version1)
85    {
86        return false;
87    }
88
89    uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
90    if (numRanges > 1024 ||
91        gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
92        sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
93    {
94        return false;
95    }
96
97    const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
98            SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
99    int minPPEM = -1;
100    for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
101        int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
102        if (minPPEM < size && size <= maxPPEM) {
103            range->fMin = minPPEM + 1;
104            range->fMax = maxPPEM;
105            range->fVersion = SkEndian_SwapBE16(gasp->version);
106            range->fFlags = rangeTable->flags;
107            return true;
108        }
109        minPPEM = maxPPEM;
110    }
111    return false;
112}
113/** If the rendering mode for the specified 'size' is gridfit, then place
114 *  the gridfit range into 'range'. Otherwise, leave 'range' alone.
115 */
116static bool is_gridfit_only(GaspRange::Behavior flags) {
117    return flags.raw.value == GaspRange::Behavior::Raw::GridfitMask;
118}
119
120static bool has_bitmap_strike(DWriteFontTypeface* typeface, GaspRange range) {
121    SkAutoExclusive l(DWriteFactoryMutex);
122    {
123        AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
124        if (!eblc.fExists) {
125            return false;
126        }
127        if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
128            return false;
129        }
130        if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
131            return false;
132        }
133
134        uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
135        if (numSizes > 1024 ||
136            eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
137                         sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
138        {
139            return false;
140        }
141
142        const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
143                SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
144        for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
145            if (sizeTable->ppemX == sizeTable->ppemY &&
146                range.fMin <= sizeTable->ppemX && sizeTable->ppemX <= range.fMax)
147            {
148                // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
149                // to determine the actual number of glyphs with bitmaps.
150
151                // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
152
153                // TODO: Ensure that the bitmaps are bi-level?
154                if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
155                    return true;
156                }
157            }
158        }
159    }
160
161    {
162        AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
163        if (!ebsc.fExists) {
164            return false;
165        }
166        if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
167            return false;
168        }
169        if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
170            return false;
171        }
172
173        uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
174        if (numSizes > 1024 ||
175            ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
176                         sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
177        {
178            return false;
179        }
180
181        const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
182                SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
183        for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
184            if (scaleTable->ppemX == scaleTable->ppemY &&
185                range.fMin <= scaleTable->ppemX && scaleTable->ppemX <= range.fMax) {
186                // EBSC tables are normally only found in bitmap only fonts.
187                return true;
188            }
189        }
190    }
191
192    return false;
193}
194
195static bool both_zero(SkScalar a, SkScalar b) {
196    return 0 == a && 0 == b;
197}
198
199// returns false if there is any non-90-rotation or skew
200static bool is_axis_aligned(const SkScalerContextRec& rec) {
201    return 0 == rec.fPreSkewX &&
202           (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
203            both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
204}
205
206SkScalerContext_DW::SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef,
207                                       const SkScalerContextEffects& effects,
208                                       const SkDescriptor* desc)
209        : SkScalerContext(std::move(typefaceRef), effects, desc)
210        , fGlyphCount(-1) {
211
212    DWriteFontTypeface* typeface = this->getDWriteTypeface();
213    fIsColorFont = typeface->fFactory2 &&
214                   typeface->fDWriteFontFace2 &&
215                   typeface->fDWriteFontFace2->IsColorFont();
216
217    // In general, all glyphs should use NATURAL_SYMMETRIC
218    // except when bi-level rendering is requested or there are embedded
219    // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
220    //
221    // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
222    // this. As a result, determine the actual size of the text and then see if
223    // there are any embedded bi-level bitmaps of that size. If there are, then
224    // force bitmaps by requesting bi-level rendering.
225    //
226    // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
227    // square pixels and only uses ppemY. Therefore the transform must track any
228    // non-uniform x-scale.
229    //
230    // Also, rotated glyphs should have the same absolute advance widths as
231    // horizontal glyphs and the subpixel flag should not affect glyph shapes.
232
233    SkVector scale;
234    fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, &scale, &fSkXform);
235
236    fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
237    fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
238    fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
239    fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
240    fXform.dx = 0;
241    fXform.dy = 0;
242
243    // realTextSize is the actual device size we want (as opposed to the size the user requested).
244    // gdiTextSize is the size we request when GDI compatible.
245    // If the scale is negative, this means the matrix will do the flip anyway.
246    const SkScalar realTextSize = scale.fY;
247    // Due to floating point math, the lower bits are suspect. Round carefully.
248    SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
249    if (gdiTextSize == 0) {
250        gdiTextSize = SK_Scalar1;
251    }
252
253    bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
254    bool treatLikeBitmap = false;
255    bool axisAlignedBitmap = false;
256    if (bitmapRequested) {
257        // When embedded bitmaps are requested, treat the entire range like
258        // a bitmap strike if the range is gridfit only and contains a bitmap.
259        int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
260        GaspRange range(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior());
261        if (get_gasp_range(typeface, bitmapPPEM, &range)) {
262            if (!is_gridfit_only(range.fFlags)) {
263                range = GaspRange(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior());
264            }
265        }
266        treatLikeBitmap = has_bitmap_strike(typeface, range);
267
268        axisAlignedBitmap = is_axis_aligned(fRec);
269    }
270
271    GaspRange range(0, 0xFFFF, 0, GaspRange::Behavior());
272
273    // If the user requested aliased, do so with aliased compatible metrics.
274    if (SkMask::kBW_Format == fRec.fMaskFormat) {
275        fTextSizeRender = gdiTextSize;
276        fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
277        fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
278        fTextSizeMeasure = gdiTextSize;
279        fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
280
281    // If we can use a bitmap, use gdi classic rendering and measurement.
282    // This will not always provide a bitmap, but matches expected behavior.
283    } else if (treatLikeBitmap && axisAlignedBitmap) {
284        fTextSizeRender = gdiTextSize;
285        fRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
286        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
287        fTextSizeMeasure = gdiTextSize;
288        fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
289
290    // If rotated but the horizontal text could have used a bitmap,
291    // render high quality rotated glyphs but measure using bitmap metrics.
292    } else if (treatLikeBitmap) {
293        fTextSizeRender = gdiTextSize;
294        fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
295        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
296        fTextSizeMeasure = gdiTextSize;
297        fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
298
299    // If the font has a gasp table version 1, use it to determine symmetric rendering.
300    } else if (get_gasp_range(typeface, SkScalarRoundToInt(gdiTextSize), &range) &&
301               range.fVersion >= 1)
302    {
303        fTextSizeRender = realTextSize;
304        fRenderingMode = range.fFlags.field.SymmetricSmoothing
305                       ? DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
306                       : DWRITE_RENDERING_MODE_NATURAL;
307        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
308        fTextSizeMeasure = realTextSize;
309        fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
310
311    // If the requested size is above 20px or there are no bytecode hints, use symmetric rendering.
312    } else if (realTextSize > SkIntToScalar(20) || !is_hinted(typeface)) {
313        fTextSizeRender = realTextSize;
314        fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
315        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
316        fTextSizeMeasure = realTextSize;
317        fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
318
319    // Fonts with hints, no gasp or gasp version 0, and below 20px get non-symmetric rendering.
320    // Often such fonts have hints which were only tested with GDI ClearType classic.
321    // Some of these fonts rely on drop out control in the y direction in order to be legible.
322    // Tenor Sans
323    //    https://fonts.google.com/specimen/Tenor+Sans
324    // Gill Sans W04
325    //    https://cdn.leagueoflegends.com/lolkit/1.1.9/resources/fonts/gill-sans-w04-book.woff
326    //    https://na.leagueoflegends.com/en/news/game-updates/patch/patch-410-notes
327    // See https://crbug.com/385897
328    } else {
329        fTextSizeRender = gdiTextSize;
330        fRenderingMode = DWRITE_RENDERING_MODE_NATURAL;
331        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
332        fTextSizeMeasure = realTextSize;
333        fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
334    }
335
336    // DirectWrite2 allows for grayscale hinting.
337    fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
338    if (typeface->fFactory2 && typeface->fDWriteFontFace2 &&
339        SkMask::kA8_Format == fRec.fMaskFormat &&
340        !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag))
341    {
342        // DWRITE_TEXTURE_ALIASED_1x1 is now misnamed, it must also be used with grayscale.
343        fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
344        fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
345    }
346
347    // DirectWrite2 allows hinting to be disabled.
348    fGridFitMode = DWRITE_GRID_FIT_MODE_ENABLED;
349    if (fRec.getHinting() == SkPaint::kNo_Hinting) {
350        fGridFitMode = DWRITE_GRID_FIT_MODE_DISABLED;
351        if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) {
352            fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
353        }
354    }
355
356    if (this->isSubpixel()) {
357        fTextSizeMeasure = realTextSize;
358        fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
359    }
360}
361
362SkScalerContext_DW::~SkScalerContext_DW() {
363}
364
365unsigned SkScalerContext_DW::generateGlyphCount() {
366    if (fGlyphCount < 0) {
367        fGlyphCount = this->getDWriteTypeface()->fDWriteFontFace->GetGlyphCount();
368    }
369    return fGlyphCount;
370}
371
372uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
373    uint16_t index = 0;
374    UINT32* uniPtr = reinterpret_cast<UINT32*>(&uni);
375    this->getDWriteTypeface()->fDWriteFontFace->GetGlyphIndices(uniPtr, 1, &index);
376    return index;
377}
378
379void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
380    //Delta is the difference between the right/left side bearing metric
381    //and where the right/left side bearing ends up after hinting.
382    //DirectWrite does not provide this information.
383    glyph->fRsbDelta = 0;
384    glyph->fLsbDelta = 0;
385
386    glyph->fAdvanceX = 0;
387    glyph->fAdvanceY = 0;
388
389    uint16_t glyphId = glyph->getGlyphID();
390    DWRITE_GLYPH_METRICS gm;
391
392    if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
393        DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
394    {
395        SkAutoExclusive l(DWriteFactoryMutex);
396        HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
397                 fTextSizeMeasure,
398                 1.0f, // pixelsPerDip
399                 // This parameter does not act like the lpmat2 parameter to GetGlyphOutlineW.
400                 // If it did then GsA here and G_inv below to mapVectors.
401                 nullptr,
402                 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
403                 &glyphId, 1,
404                 &gm),
405             "Could not get gdi compatible glyph metrics.");
406    } else {
407        SkAutoExclusive l(DWriteFactoryMutex);
408        HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
409             "Could not get design metrics.");
410    }
411
412    DWRITE_FONT_METRICS dwfm;
413    {
414        Shared l(DWriteFactoryMutex);
415        this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm);
416    }
417    SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm;
418
419    SkVector advance = { advanceX, 0 };
420    if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
421        DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
422    {
423        // DirectWrite produced 'compatible' metrics, but while close,
424        // the end result is not always an integer as it would be with GDI.
425        advance.fX = SkScalarRoundToScalar(advance.fX);
426    }
427    fSkXform.mapVectors(&advance, 1);
428
429    glyph->fAdvanceX = SkScalarToFloat(advance.fX);
430    glyph->fAdvanceY = SkScalarToFloat(advance.fY);
431}
432
433HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
434                                           DWRITE_RENDERING_MODE renderingMode,
435                                           DWRITE_TEXTURE_TYPE textureType,
436                                           RECT* bbox)
437{
438    //Measure raster size.
439    fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
440    fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
441
442    FLOAT advance = 0;
443
444    UINT16 glyphId = glyph->getGlyphID();
445
446    DWRITE_GLYPH_OFFSET offset;
447    offset.advanceOffset = 0.0f;
448    offset.ascenderOffset = 0.0f;
449
450    DWRITE_GLYPH_RUN run;
451    run.glyphCount = 1;
452    run.glyphAdvances = &advance;
453    run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
454    run.fontEmSize = SkScalarToFloat(fTextSizeRender);
455    run.bidiLevel = 0;
456    run.glyphIndices = &glyphId;
457    run.isSideways = FALSE;
458    run.glyphOffsets = &offset;
459
460    SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
461    {
462        SkAutoExclusive l(DWriteFactoryMutex);
463        // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
464        if (this->getDWriteTypeface()->fFactory2 &&
465                (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
466                 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
467        {
468            HRM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(
469                    &run,
470                    &fXform,
471                    renderingMode,
472                    fMeasuringMode,
473                    fGridFitMode,
474                    fAntiAliasMode,
475                    0.0f, // baselineOriginX,
476                    0.0f, // baselineOriginY,
477                    &glyphRunAnalysis),
478                "Could not create DW2 glyph run analysis.");
479        } else {
480            HRM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run,
481                    1.0f, // pixelsPerDip,
482                    &fXform,
483                    renderingMode,
484                    fMeasuringMode,
485                    0.0f, // baselineOriginX,
486                    0.0f, // baselineOriginY,
487                    &glyphRunAnalysis),
488                "Could not create glyph run analysis.");
489        }
490    }
491    {
492        Shared l(DWriteFactoryMutex);
493        HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
494            "Could not get texture bounds.");
495    }
496    return S_OK;
497}
498
499/** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
500 *  { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
501 *  for small, but not quite zero, sized glyphs.
502 *  Only set as non-empty if the returned bounds are non-empty.
503 */
504static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) {
505    if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
506        return false;
507    }
508
509    // We're trying to pack left and top into int16_t,
510    // and width and height into uint16_t, after outsetting by 1.
511    if (!SkIRect::MakeXYWH(-32767, -32767, 65535, 65535).contains(
512                SkIRect::MakeLTRB(bbox.left, bbox.top, bbox.right, bbox.bottom))) {
513        return false;
514    }
515
516    glyph->fWidth = SkToU16(bbox.right - bbox.left);
517    glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
518    glyph->fLeft = SkToS16(bbox.left);
519    glyph->fTop = SkToS16(bbox.top);
520    return true;
521}
522
523bool SkScalerContext_DW::isColorGlyph(const SkGlyph& glyph) {
524    SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayer;
525    return getColorGlyphRun(glyph, &colorLayer);
526}
527
528bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph,
529                                          IDWriteColorGlyphRunEnumerator** colorGlyph)
530{
531    FLOAT advance = 0;
532    UINT16 glyphId = glyph.getGlyphID();
533
534    DWRITE_GLYPH_OFFSET offset;
535    offset.advanceOffset = 0.0f;
536    offset.ascenderOffset = 0.0f;
537
538    DWRITE_GLYPH_RUN run;
539    run.glyphCount = 1;
540    run.glyphAdvances = &advance;
541    run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
542    run.fontEmSize = SkScalarToFloat(fTextSizeRender);
543    run.bidiLevel = 0;
544    run.glyphIndices = &glyphId;
545    run.isSideways = FALSE;
546    run.glyphOffsets = &offset;
547
548    HRESULT hr = this->getDWriteTypeface()->fFactory2->TranslateColorGlyphRun(
549        0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph);
550    if (hr == DWRITE_E_NOCOLOR) {
551        return false;
552    }
553    HRBM(hr, "Failed to translate color glyph run");
554    return true;
555}
556
557void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
558    glyph->fWidth = 0;
559    glyph->fHeight = 0;
560    glyph->fLeft = 0;
561    glyph->fTop = 0;
562
563    this->generateAdvance(glyph);
564
565    if (fIsColorFont && isColorGlyph(*glyph)) {
566        glyph->fMaskFormat = SkMask::kARGB32_Format;
567    }
568
569    RECT bbox;
570    HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
571         "Requested bounding box could not be determined.");
572
573    if (glyph_check_and_set_bounds(glyph, bbox)) {
574        return;
575    }
576
577    // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
578    // glyphs of the specified texture type. When this happens, try with the
579    // alternate texture type.
580    if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
581        HRVM(this->getBoundingBox(glyph,
582                                  DWRITE_RENDERING_MODE_ALIASED,
583                                  DWRITE_TEXTURE_ALIASED_1x1,
584                                  &bbox),
585             "Fallback bounding box could not be determined.");
586        if (glyph_check_and_set_bounds(glyph, bbox)) {
587            glyph->fForceBW = 1;
588        }
589    }
590    // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
591    // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
592}
593
594void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
595    if (nullptr == metrics) {
596        return;
597    }
598
599    sk_bzero(metrics, sizeof(*metrics));
600
601    DWRITE_FONT_METRICS dwfm;
602    if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
603        DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
604    {
605        this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleMetrics(
606             fTextSizeRender,
607             1.0f, // pixelsPerDip
608             &fXform,
609             &dwfm);
610    } else {
611        this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm);
612    }
613
614    SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
615
616    metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
617    metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
618    metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
619    metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
620    metrics->fCapHeight = fTextSizeRender * SkIntToScalar(dwfm.capHeight) / upem;
621    metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
622    metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
623    metrics->fStrikeoutThickness = fTextSizeRender * SkIntToScalar(dwfm.strikethroughThickness) / upem;
624    metrics->fStrikeoutPosition = -(fTextSizeRender * SkIntToScalar(dwfm.strikethroughPosition) / upem);
625
626    metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag;
627    metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
628    metrics->fFlags |= SkPaint::FontMetrics::kStrikeoutThicknessIsValid_Flag;
629    metrics->fFlags |= SkPaint::FontMetrics::kStrikeoutPositionIsValid_Flag;
630
631    if (this->getDWriteTypeface()->fDWriteFontFace1.get()) {
632        DWRITE_FONT_METRICS1 dwfm1;
633        this->getDWriteTypeface()->fDWriteFontFace1->GetMetrics(&dwfm1);
634        metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
635        metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
636        metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
637        metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
638
639        metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
640        return;
641    }
642
643    AutoTDWriteTable<SkOTTableHead> head(this->getDWriteTypeface()->fDWriteFontFace.get());
644    if (head.fExists &&
645        head.fSize >= sizeof(SkOTTableHead) &&
646        head->version == SkOTTableHead::version1)
647    {
648        metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
649        metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
650        metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
651        metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
652
653        metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
654        return;
655    }
656
657    metrics->fTop = metrics->fAscent;
658    metrics->fBottom = metrics->fDescent;
659}
660
661///////////////////////////////////////////////////////////////////////////////
662
663#include "SkColorData.h"
664
665static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
666    const int width = glyph.fWidth;
667    const size_t dstRB = (width + 7) >> 3;
668    uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
669
670    int byteCount = width >> 3;
671    int bitCount = width & 7;
672
673    for (int y = 0; y < glyph.fHeight; ++y) {
674        if (byteCount > 0) {
675            for (int i = 0; i < byteCount; ++i) {
676                unsigned byte = 0;
677                byte |= src[0] & (1 << 7);
678                byte |= src[1] & (1 << 6);
679                byte |= src[2] & (1 << 5);
680                byte |= src[3] & (1 << 4);
681                byte |= src[4] & (1 << 3);
682                byte |= src[5] & (1 << 2);
683                byte |= src[6] & (1 << 1);
684                byte |= src[7] & (1 << 0);
685                dst[i] = byte;
686                src += 8;
687            }
688        }
689        if (bitCount > 0) {
690            unsigned byte = 0;
691            unsigned mask = 0x80;
692            for (int i = 0; i < bitCount; i++) {
693                byte |= (src[i]) & mask;
694                mask >>= 1;
695            }
696            dst[byteCount] = byte;
697        }
698        src += bitCount;
699        dst += dstRB;
700    }
701}
702
703template<bool APPLY_PREBLEND>
704static void grayscale_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
705                            const uint8_t* table8) {
706    const size_t dstRB = glyph.rowBytes();
707    const U16CPU width = glyph.fWidth;
708    uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
709
710    for (U16CPU y = 0; y < glyph.fHeight; y++) {
711        for (U16CPU i = 0; i < width; i++) {
712            U8CPU a = *(src++);
713            dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(a, table8);
714        }
715        dst = SkTAddOffset<uint8_t>(dst, dstRB);
716    }
717}
718
719template<bool APPLY_PREBLEND>
720static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
721    const size_t dstRB = glyph.rowBytes();
722    const U16CPU width = glyph.fWidth;
723    uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
724
725    for (U16CPU y = 0; y < glyph.fHeight; y++) {
726        for (U16CPU i = 0; i < width; i++) {
727            U8CPU r = *(src++);
728            U8CPU g = *(src++);
729            U8CPU b = *(src++);
730            dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
731        }
732        dst = SkTAddOffset<uint8_t>(dst, dstRB);
733    }
734}
735
736template<bool APPLY_PREBLEND, bool RGB>
737static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
738                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
739    const size_t dstRB = glyph.rowBytes();
740    const U16CPU width = glyph.fWidth;
741    uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
742
743    for (U16CPU y = 0; y < glyph.fHeight; y++) {
744        for (U16CPU i = 0; i < width; i++) {
745            U8CPU r, g, b;
746            if (RGB) {
747                r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
748                g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
749                b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
750            } else {
751                b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
752                g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
753                r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
754            }
755            dst[i] = SkPack888ToRGB16(r, g, b);
756        }
757        dst = SkTAddOffset<uint16_t>(dst, dstRB);
758    }
759}
760
761const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
762                                           DWRITE_RENDERING_MODE renderingMode,
763                                           DWRITE_TEXTURE_TYPE textureType)
764{
765    int sizeNeeded = glyph.fWidth * glyph.fHeight;
766    if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) {
767        sizeNeeded *= 3;
768    }
769    if (sizeNeeded > fBits.count()) {
770        fBits.setCount(sizeNeeded);
771    }
772
773    // erase
774    memset(fBits.begin(), 0, sizeNeeded);
775
776    fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
777    fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
778
779    FLOAT advance = 0.0f;
780
781    UINT16 index = glyph.getGlyphID();
782
783    DWRITE_GLYPH_OFFSET offset;
784    offset.advanceOffset = 0.0f;
785    offset.ascenderOffset = 0.0f;
786
787    DWRITE_GLYPH_RUN run;
788    run.glyphCount = 1;
789    run.glyphAdvances = &advance;
790    run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
791    run.fontEmSize = SkScalarToFloat(fTextSizeRender);
792    run.bidiLevel = 0;
793    run.glyphIndices = &index;
794    run.isSideways = FALSE;
795    run.glyphOffsets = &offset;
796    {
797        SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
798        {
799            SkAutoExclusive l(DWriteFactoryMutex);
800            // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
801            if (this->getDWriteTypeface()->fFactory2 &&
802                    (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
803                     fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
804            {
805                HRNM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(&run,
806                         &fXform,
807                         renderingMode,
808                         fMeasuringMode,
809                         fGridFitMode,
810                         fAntiAliasMode,
811                         0.0f, // baselineOriginX,
812                         0.0f, // baselineOriginY,
813                         &glyphRunAnalysis),
814                     "Could not create DW2 glyph run analysis.");
815            } else {
816                HRNM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run,
817                         1.0f, // pixelsPerDip,
818                         &fXform,
819                         renderingMode,
820                         fMeasuringMode,
821                         0.0f, // baselineOriginX,
822                         0.0f, // baselineOriginY,
823                         &glyphRunAnalysis),
824                     "Could not create glyph run analysis.");
825            }
826        }
827        //NOTE: this assumes that the glyph has already been measured
828        //with an exact same glyph run analysis.
829        RECT bbox;
830        bbox.left = glyph.fLeft;
831        bbox.top = glyph.fTop;
832        bbox.right = glyph.fLeft + glyph.fWidth;
833        bbox.bottom = glyph.fTop + glyph.fHeight;
834        {
835            Shared l(DWriteFactoryMutex);
836            HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
837                    &bbox,
838                    fBits.begin(),
839                    sizeNeeded),
840                "Could not draw mask.");
841        }
842    }
843    return fBits.begin();
844}
845
846void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) {
847    SkASSERT(isColorGlyph(glyph));
848    SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format);
849
850    memset(glyph.fImage, 0, glyph.computeImageSize());
851
852    SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
853    getColorGlyphRun(glyph, &colorLayers);
854    SkASSERT(colorLayers.get());
855
856    SkMatrix matrix = fSkXform;
857    matrix.postTranslate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop));
858    SkRasterClip rc(SkIRect::MakeWH(glyph.fWidth, glyph.fHeight));
859    SkDraw draw;
860    draw.fDst = SkPixmap(SkImageInfo::MakeN32(glyph.fWidth, glyph.fHeight, kPremul_SkAlphaType),
861                         glyph.fImage,
862                         glyph.ComputeRowBytes(glyph.fWidth, SkMask::Format::kARGB32_Format));
863    draw.fMatrix = &matrix;
864    draw.fRC = &rc;
865
866    SkPaint paint;
867    if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) {
868        paint.setFlags(SkPaint::Flags::kAntiAlias_Flag);
869    }
870
871    BOOL hasNextRun = FALSE;
872    while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
873        const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
874        HRVM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run");
875
876        SkColor color;
877        if (colorGlyph->paletteIndex != 0xffff) {
878            color = SkColorSetARGB(sk_float_round2int(colorGlyph->runColor.a * 255),
879                                   sk_float_round2int(colorGlyph->runColor.r * 255),
880                                   sk_float_round2int(colorGlyph->runColor.g * 255),
881                                   sk_float_round2int(colorGlyph->runColor.b * 255));
882        } else {
883            // If all components of runColor are 0 or (equivalently) paletteIndex is 0xFFFF then
884            // the 'current brush' is used. fRec.getLuminanceColor() is kinda sorta what is wanted
885            // here, but not really, it will often be the wrong value because it wan't designed for
886            // this.
887            // TODO: implement this fully, bug.skia.org/5788
888            color = fRec.getLuminanceColor();
889        }
890        paint.setColor(color);
891
892        SkPath path;
893        SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
894        HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
895             "Could not create geometry to path converter.");
896        {
897            SkAutoExclusive l(DWriteFactoryMutex);
898            HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
899                colorGlyph->glyphRun.fontEmSize,
900                colorGlyph->glyphRun.glyphIndices,
901                colorGlyph->glyphRun.glyphAdvances,
902                colorGlyph->glyphRun.glyphOffsets,
903                colorGlyph->glyphRun.glyphCount,
904                colorGlyph->glyphRun.isSideways,
905                colorGlyph->glyphRun.bidiLevel % 2, //rtl
906                geometryToPath.get()),
907                "Could not create glyph outline.");
908        }
909        draw.drawPath(path, paint, nullptr, true /* pathIsMutable */);
910    }
911}
912
913void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
914    //Create the mask.
915    DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
916    DWRITE_TEXTURE_TYPE textureType = fTextureType;
917    if (glyph.fForceBW) {
918        renderingMode = DWRITE_RENDERING_MODE_ALIASED;
919        textureType = DWRITE_TEXTURE_ALIASED_1x1;
920    }
921
922    if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
923        generateColorGlyphImage(glyph);
924        return;
925    }
926
927    const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
928    if (!bits) {
929        sk_bzero(glyph.fImage, glyph.computeImageSize());
930        return;
931    }
932
933    //Copy the mask into the glyph.
934    const uint8_t* src = (const uint8_t*)bits;
935    if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
936        bilevel_to_bw(src, glyph);
937        const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
938    } else if (!isLCD(fRec)) {
939        if (textureType == DWRITE_TEXTURE_ALIASED_1x1) {
940            if (fPreBlend.isApplicable()) {
941                grayscale_to_a8<true>(src, glyph, fPreBlend.fG);
942            } else {
943                grayscale_to_a8<false>(src, glyph, fPreBlend.fG);
944            }
945        } else {
946            if (fPreBlend.isApplicable()) {
947                rgb_to_a8<true>(src, glyph, fPreBlend.fG);
948            } else {
949                rgb_to_a8<false>(src, glyph, fPreBlend.fG);
950            }
951        }
952    } else {
953        SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat);
954        if (fPreBlend.isApplicable()) {
955            if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
956                rgb_to_lcd16<true, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
957            } else {
958                rgb_to_lcd16<true, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
959            }
960        } else {
961            if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
962                rgb_to_lcd16<false, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
963            } else {
964                rgb_to_lcd16<false, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
965            }
966        }
967    }
968}
969
970void SkScalerContext_DW::generatePath(SkGlyphID glyph, SkPath* path) {
971    SkASSERT(path);
972
973    path->reset();
974
975    SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
976    HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
977         "Could not create geometry to path converter.");
978    UINT16 glyphId = SkTo<UINT16>(glyph);
979    {
980        SkAutoExclusive l(DWriteFactoryMutex);
981        //TODO: convert to<->from DIUs? This would make a difference if hinting.
982        //It may not be needed, it appears that DirectWrite only hints at em size.
983        HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
984             SkScalarToFloat(fTextSizeRender),
985             &glyphId,
986             nullptr, //advances
987             nullptr, //offsets
988             1, //num glyphs
989             FALSE, //sideways
990             FALSE, //rtl
991             geometryToPath.get()),
992             "Could not create glyph outline.");
993    }
994
995    path->transform(fSkXform);
996}
997
998#endif//defined(SK_BUILD_FOR_WIN)
999