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