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_WIN32)
10
11#undef GetGlyphIndices
12
13#include "SkDWrite.h"
14#include "SkDWriteGeometrySink.h"
15#include "SkEndian.h"
16#include "SkGlyph.h"
17#include "SkHRESULT.h"
18#include "SkMaskGamma.h"
19#include "SkMatrix22.h"
20#include "SkMutex.h"
21#include "SkOTTable_EBLC.h"
22#include "SkOTTable_EBSC.h"
23#include "SkOTTable_gasp.h"
24#include "SkOTTable_maxp.h"
25#include "SkPath.h"
26#include "SkScalerContext.h"
27#include "SkScalerContext_win_dw.h"
28#include "SkSharedMutex.h"
29#include "SkTScopedComPtr.h"
30#include "SkTypeface_win_dw.h"
31
32#include <dwrite.h>
33#if SK_HAS_DWRITE_1_H
34#  include <dwrite_1.h>
35#endif
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 SkAutoTExclusive<SkSharedMutex> Exclusive;
44typedef SkAutoSharedMutexShared Shared;
45
46static bool isLCD(const SkScalerContext::Rec& rec) {
47    return SkMask::kLCD16_Format == rec.fMaskFormat;
48}
49
50static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) {
51    Exclusive l(DWriteFactoryMutex);
52    AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
53    if (!maxp.fExists) {
54        return false;
55    }
56    if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
57        return false;
58    }
59    if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
60        return false;
61    }
62
63    if (0 == maxp->version.tt.maxSizeOfInstructions) {
64        // No hints.
65        return false;
66    }
67
68    AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
69    return !gasp.fExists;
70}
71
72/** A PPEMRange is inclusive, [min, max]. */
73struct PPEMRange {
74    int min;
75    int max;
76};
77
78/** If the rendering mode for the specified 'size' is gridfit, then place
79 *  the gridfit range into 'range'. Otherwise, leave 'range' alone.
80 */
81static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) {
82    AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
83    if (!gasp.fExists) {
84        return;
85    }
86    if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
87        return;
88    }
89    if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
90        gasp->version != SkOTTableGridAndScanProcedure::version1)
91    {
92        return;
93    }
94
95    uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
96    if (numRanges > 1024 ||
97        gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
98                     sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
99    {
100        return;
101    }
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);
108        // Test that the size is in range and the range is gridfit only.
109        if (minPPEM < size && size <= maxPPEM &&
110            rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask)
111        {
112            range->min = minPPEM + 1;
113            range->max = maxPPEM;
114            return;
115        }
116        minPPEM = maxPPEM;
117    }
118}
119
120static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) {
121    Exclusive 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.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max)
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.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max) {
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 SkScalerContext::Rec& 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(DWriteFontTypeface* typeface,
207                                       const SkDescriptor* desc)
208        : SkScalerContext(typeface, desc)
209        , fTypeface(SkRef(typeface))
210        , fGlyphCount(-1) {
211
212    // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC
213    // except when bi-level rendering is requested or there are embedded
214    // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
215    //
216    // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
217    // this. As a result, determine the actual size of the text and then see if
218    // there are any embedded bi-level bitmaps of that size. If there are, then
219    // force bitmaps by requesting bi-level rendering.
220    //
221    // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
222    // square pixels and only uses ppemY. Therefore the transform must track any
223    // non-uniform x-scale.
224    //
225    // Also, rotated glyphs should have the same absolute advance widths as
226    // horizontal glyphs and the subpixel flag should not affect glyph shapes.
227
228    SkVector scale;
229    SkMatrix GsA;
230    fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale,
231                         &scale, &fSkXform, &GsA, &fG_inv);
232
233    fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
234    fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
235    fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
236    fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
237    fXform.dx = 0;
238    fXform.dy = 0;
239
240    fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX));
241    fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
242    fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX));
243    fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY));
244    fGsA.dx = 0;
245    fGsA.dy = 0;
246
247    // realTextSize is the actual device size we want (as opposed to the size the user requested).
248    // gdiTextSize is the size we request when GDI compatible.
249    // If the scale is negative, this means the matrix will do the flip anyway.
250    const SkScalar realTextSize = scale.fY;
251    // Due to floating point math, the lower bits are suspect. Round carefully.
252    SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
253    if (gdiTextSize == 0) {
254        gdiTextSize = SK_Scalar1;
255    }
256
257    bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
258    bool treatLikeBitmap = false;
259    bool axisAlignedBitmap = false;
260    if (bitmapRequested) {
261        // When embedded bitmaps are requested, treat the entire range like
262        // a bitmap strike if the range is gridfit only and contains a bitmap.
263        int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
264        PPEMRange range = { bitmapPPEM, bitmapPPEM };
265        expand_range_if_gridfit_only(typeface, bitmapPPEM, &range);
266        treatLikeBitmap = has_bitmap_strike(typeface, range);
267
268        axisAlignedBitmap = is_axis_aligned(fRec);
269    }
270
271    // If the user requested aliased, do so with aliased compatible metrics.
272    if (SkMask::kBW_Format == fRec.fMaskFormat) {
273        fTextSizeRender = gdiTextSize;
274        fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
275        fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
276        fTextSizeMeasure = gdiTextSize;
277        fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
278
279    // If we can use a bitmap, use gdi classic rendering and measurement.
280    // This will not always provide a bitmap, but matches expected behavior.
281    } else if (treatLikeBitmap && axisAlignedBitmap) {
282        fTextSizeRender = gdiTextSize;
283        fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
284        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
285        fTextSizeMeasure = gdiTextSize;
286        fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
287
288    // If rotated but the horizontal text could have used a bitmap,
289    // render high quality rotated glyphs but measure using bitmap metrics.
290    } else if (treatLikeBitmap) {
291        fTextSizeRender = gdiTextSize;
292        fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
293        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
294        fTextSizeMeasure = gdiTextSize;
295        fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
296
297    // Fonts that have hints but no gasp table get non-symmetric rendering.
298    // Usually such fonts have low quality hints which were never tested
299    // with anything but GDI ClearType classic. Such fonts often rely on
300    // drop out control in the y direction in order to be legible.
301    } else if (is_hinted_without_gasp(typeface)) {
302        fTextSizeRender = gdiTextSize;
303        fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
304        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
305        fTextSizeMeasure = realTextSize;
306        fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
307
308    // The normal case is to use natural symmetric rendering and linear metrics.
309    } else {
310        fTextSizeRender = realTextSize;
311        fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
312        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
313        fTextSizeMeasure = realTextSize;
314        fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
315    }
316
317    if (this->isSubpixel()) {
318        fTextSizeMeasure = realTextSize;
319        fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
320    }
321}
322
323SkScalerContext_DW::~SkScalerContext_DW() {
324}
325
326unsigned SkScalerContext_DW::generateGlyphCount() {
327    if (fGlyphCount < 0) {
328        fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
329    }
330    return fGlyphCount;
331}
332
333uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
334    uint16_t index = 0;
335    fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
336    return index;
337}
338
339void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
340    //Delta is the difference between the right/left side bearing metric
341    //and where the right/left side bearing ends up after hinting.
342    //DirectWrite does not provide this information.
343    glyph->fRsbDelta = 0;
344    glyph->fLsbDelta = 0;
345
346    glyph->fAdvanceX = 0;
347    glyph->fAdvanceY = 0;
348
349    uint16_t glyphId = glyph->getGlyphID();
350    DWRITE_GLYPH_METRICS gm;
351
352    if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
353        DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
354    {
355        Exclusive l(DWriteFactoryMutex);
356        HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
357                 fTextSizeMeasure,
358                 1.0f, // pixelsPerDip
359                 &fGsA,
360                 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
361                 &glyphId, 1,
362                 &gm),
363             "Could not get gdi compatible glyph metrics.");
364    } else {
365        Exclusive l(DWriteFactoryMutex);
366        HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
367             "Could not get design metrics.");
368    }
369
370    DWRITE_FONT_METRICS dwfm;
371    {
372        Shared l(DWriteFactoryMutex);
373        fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
374    }
375    SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
376                                       SkIntToScalar(gm.advanceWidth),
377                                       SkIntToScalar(dwfm.designUnitsPerEm));
378
379    SkVector vecs[1] = { { advanceX, 0 } };
380    if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
381        DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
382    {
383        // DirectWrite produced 'compatible' metrics, but while close,
384        // the end result is not always an integer as it would be with GDI.
385        vecs[0].fX = SkScalarRoundToScalar(advanceX);
386        fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
387    } else {
388        fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
389    }
390
391    glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
392    glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
393}
394
395HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
396                                           DWRITE_RENDERING_MODE renderingMode,
397                                           DWRITE_TEXTURE_TYPE textureType,
398                                           RECT* bbox)
399{
400    //Measure raster size.
401    fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
402    fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
403
404    FLOAT advance = 0;
405
406    UINT16 glyphId = glyph->getGlyphID();
407
408    DWRITE_GLYPH_OFFSET offset;
409    offset.advanceOffset = 0.0f;
410    offset.ascenderOffset = 0.0f;
411
412    DWRITE_GLYPH_RUN run;
413    run.glyphCount = 1;
414    run.glyphAdvances = &advance;
415    run.fontFace = fTypeface->fDWriteFontFace.get();
416    run.fontEmSize = SkScalarToFloat(fTextSizeRender);
417    run.bidiLevel = 0;
418    run.glyphIndices = &glyphId;
419    run.isSideways = FALSE;
420    run.glyphOffsets = &offset;
421
422    SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
423    {
424        Exclusive l(DWriteFactoryMutex);
425        HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(
426            &run,
427            1.0f, // pixelsPerDip,
428            &fXform,
429            renderingMode,
430            fMeasuringMode,
431            0.0f, // baselineOriginX,
432            0.0f, // baselineOriginY,
433            &glyphRunAnalysis),
434            "Could not create glyph run analysis.");
435    }
436    {
437        Shared l(DWriteFactoryMutex);
438        HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
439            "Could not get texture bounds.");
440    }
441    return S_OK;
442}
443
444/** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
445 *  { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
446 *  for small, but not quite zero, sized glyphs.
447 *  Only set as non-empty if the returned bounds are non-empty.
448 */
449static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) {
450    if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
451        return false;
452    }
453    glyph->fWidth = SkToU16(bbox.right - bbox.left);
454    glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
455    glyph->fLeft = SkToS16(bbox.left);
456    glyph->fTop = SkToS16(bbox.top);
457    return true;
458}
459
460void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
461    glyph->fWidth = 0;
462    glyph->fHeight = 0;
463    glyph->fLeft = 0;
464    glyph->fTop = 0;
465
466    this->generateAdvance(glyph);
467
468    RECT bbox;
469    HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
470         "Requested bounding box could not be determined.");
471
472    if (glyph_check_and_set_bounds(glyph, bbox)) {
473        return;
474    }
475
476    // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
477    // glyphs of the specified texture type. When this happens, try with the
478    // alternate texture type.
479    if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
480        HRVM(this->getBoundingBox(glyph,
481                                  DWRITE_RENDERING_MODE_ALIASED,
482                                  DWRITE_TEXTURE_ALIASED_1x1,
483                                  &bbox),
484             "Fallback bounding box could not be determined.");
485        if (glyph_check_and_set_bounds(glyph, bbox)) {
486            glyph->fForceBW = 1;
487        }
488    }
489    // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
490    // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
491}
492
493void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
494    if (nullptr == metrics) {
495        return;
496    }
497
498    sk_bzero(metrics, sizeof(*metrics));
499
500    DWRITE_FONT_METRICS dwfm;
501    if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
502        DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
503    {
504        fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
505             fTextSizeRender,
506             1.0f, // pixelsPerDip
507             &fXform,
508             &dwfm);
509    } else {
510        fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
511    }
512
513    SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
514
515    metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
516    metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
517    metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
518    metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
519    metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
520    metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
521
522    metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
523    metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
524
525#if SK_HAS_DWRITE_1_H
526    if (fTypeface->fDWriteFontFace1.get()) {
527        DWRITE_FONT_METRICS1 dwfm1;
528        fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1);
529        metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
530        metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
531        metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
532        metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
533
534        metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
535        return;
536    }
537#else
538#  pragma message("No dwrite_1.h is available, font metrics may be affected.")
539#endif
540
541    AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get());
542    if (head.fExists &&
543        head.fSize >= sizeof(SkOTTableHead) &&
544        head->version == SkOTTableHead::version1)
545    {
546        metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
547        metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
548        metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
549        metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
550
551        metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
552        return;
553    }
554
555    metrics->fTop = metrics->fAscent;
556    metrics->fBottom = metrics->fDescent;
557}
558
559///////////////////////////////////////////////////////////////////////////////
560
561#include "SkColorPriv.h"
562
563static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
564    const int width = glyph.fWidth;
565    const size_t dstRB = (width + 7) >> 3;
566    uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
567
568    int byteCount = width >> 3;
569    int bitCount = width & 7;
570
571    for (int y = 0; y < glyph.fHeight; ++y) {
572        if (byteCount > 0) {
573            for (int i = 0; i < byteCount; ++i) {
574                unsigned byte = 0;
575                byte |= src[0] & (1 << 7);
576                byte |= src[1] & (1 << 6);
577                byte |= src[2] & (1 << 5);
578                byte |= src[3] & (1 << 4);
579                byte |= src[4] & (1 << 3);
580                byte |= src[5] & (1 << 2);
581                byte |= src[6] & (1 << 1);
582                byte |= src[7] & (1 << 0);
583                dst[i] = byte;
584                src += 8;
585            }
586        }
587        if (bitCount > 0) {
588            unsigned byte = 0;
589            unsigned mask = 0x80;
590            for (int i = 0; i < bitCount; i++) {
591                byte |= (src[i]) & mask;
592                mask >>= 1;
593            }
594            dst[byteCount] = byte;
595        }
596        src += bitCount;
597        dst += dstRB;
598    }
599}
600
601template<bool APPLY_PREBLEND>
602static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
603    const size_t dstRB = glyph.rowBytes();
604    const U16CPU width = glyph.fWidth;
605    uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
606
607    for (U16CPU y = 0; y < glyph.fHeight; y++) {
608        for (U16CPU i = 0; i < width; i++) {
609            U8CPU r = *(src++);
610            U8CPU g = *(src++);
611            U8CPU b = *(src++);
612            dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
613        }
614        dst = (uint8_t*)((char*)dst + dstRB);
615    }
616}
617
618template<bool APPLY_PREBLEND, bool RGB>
619static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
620                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
621    const size_t dstRB = glyph.rowBytes();
622    const U16CPU width = glyph.fWidth;
623    uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
624
625    for (U16CPU y = 0; y < glyph.fHeight; y++) {
626        for (U16CPU i = 0; i < width; i++) {
627            U8CPU r, g, b;
628            if (RGB) {
629                r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
630                g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
631                b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
632            } else {
633                b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
634                g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
635                r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
636            }
637            dst[i] = SkPack888ToRGB16(r, g, b);
638        }
639        dst = (uint16_t*)((char*)dst + dstRB);
640    }
641}
642
643const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
644                                           DWRITE_RENDERING_MODE renderingMode,
645                                           DWRITE_TEXTURE_TYPE textureType)
646{
647    int sizeNeeded = glyph.fWidth * glyph.fHeight;
648    if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) {
649        sizeNeeded *= 3;
650    }
651    if (sizeNeeded > fBits.count()) {
652        fBits.setCount(sizeNeeded);
653    }
654
655    // erase
656    memset(fBits.begin(), 0, sizeNeeded);
657
658    fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
659    fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
660
661    FLOAT advance = 0.0f;
662
663    UINT16 index = glyph.getGlyphID();
664
665    DWRITE_GLYPH_OFFSET offset;
666    offset.advanceOffset = 0.0f;
667    offset.ascenderOffset = 0.0f;
668
669    DWRITE_GLYPH_RUN run;
670    run.glyphCount = 1;
671    run.glyphAdvances = &advance;
672    run.fontFace = fTypeface->fDWriteFontFace.get();
673    run.fontEmSize = SkScalarToFloat(fTextSizeRender);
674    run.bidiLevel = 0;
675    run.glyphIndices = &index;
676    run.isSideways = FALSE;
677    run.glyphOffsets = &offset;
678    {
679
680        SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
681        {
682            Exclusive l(DWriteFactoryMutex);
683            HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
684                1.0f, // pixelsPerDip,
685                &fXform,
686                renderingMode,
687                fMeasuringMode,
688                0.0f, // baselineOriginX,
689                0.0f, // baselineOriginY,
690                &glyphRunAnalysis),
691                "Could not create glyph run analysis.");
692        }
693        //NOTE: this assumes that the glyph has already been measured
694        //with an exact same glyph run analysis.
695        RECT bbox;
696        bbox.left = glyph.fLeft;
697        bbox.top = glyph.fTop;
698        bbox.right = glyph.fLeft + glyph.fWidth;
699        bbox.bottom = glyph.fTop + glyph.fHeight;
700        {
701            Shared l(DWriteFactoryMutex);
702            HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
703                &bbox,
704                fBits.begin(),
705                sizeNeeded),
706                "Could not draw mask.");
707        }
708    }
709    return fBits.begin();
710}
711
712void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
713    //Create the mask.
714    DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
715    DWRITE_TEXTURE_TYPE textureType = fTextureType;
716    if (glyph.fForceBW) {
717        renderingMode = DWRITE_RENDERING_MODE_ALIASED;
718        textureType = DWRITE_TEXTURE_ALIASED_1x1;
719    }
720    const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
721    if (!bits) {
722        sk_bzero(glyph.fImage, glyph.computeImageSize());
723        return;
724    }
725
726    //Copy the mask into the glyph.
727    const uint8_t* src = (const uint8_t*)bits;
728    if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
729        bilevel_to_bw(src, glyph);
730        const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
731    } else if (!isLCD(fRec)) {
732        if (fPreBlend.isApplicable()) {
733            rgb_to_a8<true>(src, glyph, fPreBlend.fG);
734        } else {
735            rgb_to_a8<false>(src, glyph, fPreBlend.fG);
736        }
737    } else {
738        SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat);
739        if (fPreBlend.isApplicable()) {
740            if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
741                rgb_to_lcd16<true, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
742            } else {
743                rgb_to_lcd16<true, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
744            }
745        } else {
746            if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
747                rgb_to_lcd16<false, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
748            } else {
749                rgb_to_lcd16<false, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
750            }
751        }
752    }
753}
754
755void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
756    SkASSERT(path);
757
758    path->reset();
759
760    SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
761    HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
762         "Could not create geometry to path converter.");
763    uint16_t glyphId = glyph.getGlyphID();
764    {
765        Exclusive l(DWriteFactoryMutex);
766        //TODO: convert to<->from DIUs? This would make a difference if hinting.
767        //It may not be needed, it appears that DirectWrite only hints at em size.
768        HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
769            &glyphId,
770            nullptr, //advances
771            nullptr, //offsets
772            1, //num glyphs
773            FALSE, //sideways
774            FALSE, //rtl
775            geometryToPath.get()),
776            "Could not create glyph outline.");
777    }
778
779    path->transform(fSkXform);
780}
781
782#endif//defined(SK_BUILD_FOR_WIN32)
783