1e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com/*
2e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com * Copyright 2011 Google Inc.
3e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com *
4e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com * Use of this source code is governed by a BSD-style license that can be
5e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com * found in the LICENSE file.
6e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com */
7e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
8e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkTypes.h"
9e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#undef GetGlyphIndices
10e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
1172cf4fcafa54cfa04c5ec7cb8eaa3acb144712ddbungeman@google.com#include "SkDWrite.h"
12e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkDWriteGeometrySink.h"
13e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkEndian.h"
14e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkGlyph.h"
15e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkHRESULT.h"
16e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkMaskGamma.h"
17058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com#include "SkMatrix22.h"
18058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com#include "SkOTTable_EBLC.h"
19058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com#include "SkOTTable_EBSC.h"
20740c3f17f7f37fca5268b60a83448953f075d8d1bungeman#include "SkOTTable_gasp.h"
21761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman#include "SkOTTable_maxp.h"
22e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkPath.h"
2351daa25a2b16bca578e78b7ea1e5815b9abb8b0bbungeman#include "SkScalerContext.h"
2451daa25a2b16bca578e78b7ea1e5815b9abb8b0bbungeman#include "SkScalerContext_win_dw.h"
25e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkTScopedComPtr.h"
2651daa25a2b16bca578e78b7ea1e5815b9abb8b0bbungeman#include "SkTypeface_win_dw.h"
27e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
28e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include <dwrite.h>
29f548444684b9c96f7717aebe645944af4f95d650bungeman#if SK_HAS_DWRITE_1_H
30f548444684b9c96f7717aebe645944af4f95d650bungeman#  include <dwrite_1.h>
31f548444684b9c96f7717aebe645944af4f95d650bungeman#endif
32e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
33e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comstatic bool isLCD(const SkScalerContext::Rec& rec) {
34e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    return SkMask::kLCD16_Format == rec.fMaskFormat ||
35e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com           SkMask::kLCD32_Format == rec.fMaskFormat;
36e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
37e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
38761b2509d59787a8920b2e98911cff9f88e0eb4ebungemanstatic bool is_hinted_without_gasp(DWriteFontTypeface* typeface) {
39761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
40761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    if (!maxp.fExists) {
41761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        return false;
42761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    }
43761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
44761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        return false;
45761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    }
46761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
47761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        return false;
48761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    }
49761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman
50761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    if (0 == maxp->version.tt.maxSizeOfInstructions) {
51761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        // No hints.
52761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        return false;
53761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    }
54761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman
55761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
56761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    return !gasp.fExists;
57761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman}
58761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman
59740c3f17f7f37fca5268b60a83448953f075d8d1bungeman/** A PPEMRange is inclusive, [min, max]. */
60740c3f17f7f37fca5268b60a83448953f075d8d1bungemanstruct PPEMRange {
61740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    int min;
62740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    int max;
63740c3f17f7f37fca5268b60a83448953f075d8d1bungeman};
64740c3f17f7f37fca5268b60a83448953f075d8d1bungeman
65740c3f17f7f37fca5268b60a83448953f075d8d1bungeman/** If the rendering mode for the specified 'size' is gridfit, then place
66740c3f17f7f37fca5268b60a83448953f075d8d1bungeman *  the gridfit range into 'range'. Otherwise, leave 'range' alone.
67740c3f17f7f37fca5268b60a83448953f075d8d1bungeman */
68740c3f17f7f37fca5268b60a83448953f075d8d1bungemanstatic void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) {
69740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
70740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    if (!gasp.fExists) {
71740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        return;
72740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    }
73740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
74740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        return;
75740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    }
76740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
77740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        gasp->version != SkOTTableGridAndScanProcedure::version1)
78740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    {
79c83780c9ec9fb7dc46abed71a64d83ec0ce7a274Ben Wagner        return;
80740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    }
81740c3f17f7f37fca5268b60a83448953f075d8d1bungeman
82740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
83740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    if (numRanges > 1024 ||
84740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
85740c3f17f7f37fca5268b60a83448953f075d8d1bungeman                     sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
86740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    {
87740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        return;
88740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    }
89740c3f17f7f37fca5268b60a83448953f075d8d1bungeman
90740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
91740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
92740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    int minPPEM = -1;
93740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
94740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
95740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        // Test that the size is in range and the range is gridfit only.
96740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        if (minPPEM < size && size <= maxPPEM &&
97740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask)
98740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        {
99740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            range->min = minPPEM + 1;
100740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            range->max = maxPPEM;
101740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            return;
102740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        }
103740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        minPPEM = maxPPEM;
104740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    }
105740c3f17f7f37fca5268b60a83448953f075d8d1bungeman}
106740c3f17f7f37fca5268b60a83448953f075d8d1bungeman
107740c3f17f7f37fca5268b60a83448953f075d8d1bungemanstatic bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) {
108058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    {
109058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
110058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        if (!eblc.fExists) {
111058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com            return false;
112058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        }
113058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
114058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com            return false;
115058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        }
116058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
117058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com            return false;
118058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        }
119058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
120058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
121740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        if (numSizes > 1024 ||
122740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
123058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                         sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
124058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        {
125058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com            return false;
126058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        }
127058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
128058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
129058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
130058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
131740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            if (sizeTable->ppemX == sizeTable->ppemY &&
132740c3f17f7f37fca5268b60a83448953f075d8d1bungeman                range.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max)
133740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            {
134058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
135058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                // to determine the actual number of glyphs with bitmaps.
136058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
137058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
138058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
139740c3f17f7f37fca5268b60a83448953f075d8d1bungeman                // TODO: Ensure that the bitmaps are bi-level?
140058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
141058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                    return true;
142058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                }
143058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com            }
144058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        }
145058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    }
146058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
147058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    {
148058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
149058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        if (!ebsc.fExists) {
150058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com            return false;
151058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        }
152058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
153058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com            return false;
154058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        }
155058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
156058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com            return false;
157058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        }
158058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
159058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
160740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        if (numSizes > 1024 ||
161740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
162058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                         sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
163058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        {
164058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com            return false;
165058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        }
166058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
167058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
168058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
169058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
170740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            if (scaleTable->ppemX == scaleTable->ppemY &&
171740c3f17f7f37fca5268b60a83448953f075d8d1bungeman                range.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max) {
172058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                // EBSC tables are normally only found in bitmap only fonts.
173058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                return true;
174058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com            }
175058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        }
176058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    }
177058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
178058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    return false;
179058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com}
180058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
181740c3f17f7f37fca5268b60a83448953f075d8d1bungemanstatic bool both_zero(SkScalar a, SkScalar b) {
182058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    return 0 == a && 0 == b;
183058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com}
184058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
185058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com// returns false if there is any non-90-rotation or skew
186740c3f17f7f37fca5268b60a83448953f075d8d1bungemanstatic bool is_axis_aligned(const SkScalerContext::Rec& rec) {
187058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    return 0 == rec.fPreSkewX &&
188740c3f17f7f37fca5268b60a83448953f075d8d1bungeman           (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
189740c3f17f7f37fca5268b60a83448953f075d8d1bungeman            both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
190058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com}
191058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
19230ddd615c447fed73286151b463af20d309c85f1reed@google.comSkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
1936eddc77f6a0078570471277954c07d73b3a921d8bungeman@google.com                                       const SkDescriptor* desc)
1940da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com        : SkScalerContext(typeface, desc)
1950da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com        , fTypeface(SkRef(typeface))
196e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        , fGlyphCount(-1) {
197e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
198058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC
199058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // except when bi-level rendering is requested or there are embedded
200058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
201058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    //
202058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
203058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // this. As a result, determine the actual size of the text and then see if
204058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // there are any embedded bi-level bitmaps of that size. If there are, then
205058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // force bitmaps by requesting bi-level rendering.
206058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    //
207058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
208058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // square pixels and only uses ppemY. Therefore the transform must track any
209058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // non-uniform x-scale.
210058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    //
211058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // Also, rotated glyphs should have the same absolute advance widths as
212058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // horizontal glyphs and the subpixel flag should not affect glyph shapes.
213058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
214058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // A is the total matrix.
215058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    SkMatrix A;
216058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fRec.getSingleMatrix(&A);
217058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
218058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // h is where A maps the horizontal baseline.
219058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    SkPoint h = SkPoint::Make(SK_Scalar1, 0);
220058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    A.mapPoints(&h, 1);
221058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
222058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
223058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    SkMatrix G;
224058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    SkComputeGivensRotation(h, &G);
225058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
226058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // GA is the matrix A with rotation removed.
227058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    SkMatrix GA(G);
228058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    GA.preConcat(A);
229058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
230058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // realTextSize is the actual device size we want (as opposed to the size the user requested).
231058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // gdiTextSize is the size we request when GDI compatible.
232058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // If the scale is negative, this means the matrix will do the flip anyway.
233058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
234058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // Due to floating point math, the lower bits are suspect. Round carefully.
2357c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
236058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    if (gdiTextSize == 0) {
237058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        gdiTextSize = SK_Scalar1;
238058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    }
239058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
2407c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
241740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    bool treatLikeBitmap = false;
2427c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    bool axisAlignedBitmap = false;
2437c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    if (bitmapRequested) {
244740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        // When embedded bitmaps are requested, treat the entire range like
245740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        // a bitmap strike if the range is gridfit only and contains a bitmap.
246740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
247740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        PPEMRange range = { bitmapPPEM, bitmapPPEM };
248740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        expand_range_if_gridfit_only(typeface, bitmapPPEM, &range);
249740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        treatLikeBitmap = has_bitmap_strike(typeface, range);
250740c3f17f7f37fca5268b60a83448953f075d8d1bungeman
251740c3f17f7f37fca5268b60a83448953f075d8d1bungeman        axisAlignedBitmap = is_axis_aligned(fRec);
2527c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    }
253058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
2547c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    // If the user requested aliased, do so with aliased compatible metrics.
2557c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    if (SkMask::kBW_Format == fRec.fMaskFormat) {
256058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fTextSizeRender = gdiTextSize;
257d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
258d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
259058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fTextSizeMeasure = gdiTextSize;
260058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
261df1640d413c16abf4527960642aca41581808699bungeman
2627c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    // If we can use a bitmap, use gdi classic rendering and measurement.
2637c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    // This will not always provide a bitmap, but matches expected behavior.
264740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    } else if (treatLikeBitmap && axisAlignedBitmap) {
2657c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com        fTextSizeRender = gdiTextSize;
2667c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com        fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
2677c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
2687c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com        fTextSizeMeasure = gdiTextSize;
2697c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com        fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
270df1640d413c16abf4527960642aca41581808699bungeman
2717c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    // If rotated but the horizontal text could have used a bitmap,
2727c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    // render high quality rotated glyphs but measure using bitmap metrics.
273740c3f17f7f37fca5268b60a83448953f075d8d1bungeman    } else if (treatLikeBitmap) {
274058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fTextSizeRender = gdiTextSize;
275058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
276058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
277058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fTextSizeMeasure = gdiTextSize;
278d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
2797c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com
280761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    // Fonts that have hints but no gasp table get non-symmetric rendering.
281761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    // Usually such fonts have low quality hints which were never tested
282761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    // with anything but GDI ClearType classic. Such fonts often rely on
283761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    // drop out control in the y direction in order to be legible.
284761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman    } else if (is_hinted_without_gasp(typeface)) {
285761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        fTextSizeRender = gdiTextSize;
286761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
287761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
288761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        fTextSizeMeasure = realTextSize;
289761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
290761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman
2917c18351d1f9f8fe4c5cbebf1852cd4f7bb5e026fbungeman@google.com    // The normal case is to use natural symmetric rendering and linear metrics.
292d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    } else {
293058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fTextSizeRender = realTextSize;
294d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
295d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
296058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fTextSizeMeasure = realTextSize;
297d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
298d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    }
299d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com
300d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    if (this->isSubpixel()) {
301058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fTextSizeMeasure = realTextSize;
302d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
303d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    }
304058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
305058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // Remove the realTextSize, as that is the text height scale currently in A.
306058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    SkScalar scale = SkScalarInvert(realTextSize);
307058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
308058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // fSkXform is the total matrix A without the text height scale.
309058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fSkXform = A;
310058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fSkXform.preScale(scale, scale); //remove the text height scale.
311058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
312058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
313058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
314058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
315058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
316058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fXform.dx = 0;
317058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fXform.dy = 0;
318058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
319058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // GsA is the non-rotational part of A without the text height scale.
320058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    SkMatrix GsA(GA);
321058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    GsA.preScale(scale, scale); //remove text height scale, G is rotational so reorders with scale.
322058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
323058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX));
324058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
325058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX));
326058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY));
327e4ae0bc5caeed52e07c7e5939fa4ac38d9e408abbungeman@google.com    fGsA.dx = 0;
328e4ae0bc5caeed52e07c7e5939fa4ac38d9e408abbungeman@google.com    fGsA.dy = 0;
329058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com
330058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
331058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
332058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                  -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
333058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                  G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
334e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
335e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
33630ddd615c447fed73286151b463af20d309c85f1reed@google.comSkScalerContext_DW::~SkScalerContext_DW() {
337e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
338e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
33930ddd615c447fed73286151b463af20d309c85f1reed@google.comunsigned SkScalerContext_DW::generateGlyphCount() {
340e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    if (fGlyphCount < 0) {
341e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
342e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
343e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    return fGlyphCount;
344e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
345e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
34630ddd615c447fed73286151b463af20d309c85f1reed@google.comuint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
347e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    uint16_t index = 0;
348e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
349e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    return index;
350e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
351e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
35230ddd615c447fed73286151b463af20d309c85f1reed@google.comvoid SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
353e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    //Delta is the difference between the right/left side bearing metric
354e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    //and where the right/left side bearing ends up after hinting.
355e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    //DirectWrite does not provide this information.
356e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    glyph->fRsbDelta = 0;
357e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    glyph->fLsbDelta = 0;
358d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
359e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    glyph->fAdvanceX = 0;
360e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    glyph->fAdvanceY = 0;
361e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
362e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    uint16_t glyphId = glyph->getGlyphID();
363e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    DWRITE_GLYPH_METRICS gm;
364d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com
365d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
366d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
367d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    {
368d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
369058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                 fTextSizeMeasure,
370d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                 1.0f, // pixelsPerDip
371058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com                 &fGsA,
372d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
373d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                 &glyphId, 1,
374d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                 &gm),
375d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com             "Could not get gdi compatible glyph metrics.");
376d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    } else {
377d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
378d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com             "Could not get design metrics.");
379d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    }
380e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
381e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    DWRITE_FONT_METRICS dwfm;
382e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
383058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
384e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                                       SkIntToScalar(gm.advanceWidth),
385e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                                       SkIntToScalar(dwfm.designUnitsPerEm));
386d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
387e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    SkVector vecs[1] = { { advanceX, 0 } };
388058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
389058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
390058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    {
391761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        // DirectWrite produced 'compatible' metrics, but while close,
392761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        // the end result is not always an integer as it would be with GDI.
393761b2509d59787a8920b2e98911cff9f88e0eb4ebungeman        vecs[0].fX = SkScalarRoundToScalar(advanceX);
394058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
395058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    } else {
396058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com        fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
397058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    }
398e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
399e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
400e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
401e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
402e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
403683a37692bc67ef1144922b73a1e871e7e1e842ebungemanHRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
404683a37692bc67ef1144922b73a1e871e7e1e842ebungeman                                           DWRITE_RENDERING_MODE renderingMode,
405683a37692bc67ef1144922b73a1e871e7e1e842ebungeman                                           DWRITE_TEXTURE_TYPE textureType,
406683a37692bc67ef1144922b73a1e871e7e1e842ebungeman                                           RECT* bbox)
407b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner{
408e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    //Measure raster size.
409e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
410e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
411e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
412e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    FLOAT advance = 0;
413e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
414e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    UINT16 glyphId = glyph->getGlyphID();
415e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
416e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    DWRITE_GLYPH_OFFSET offset;
417e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    offset.advanceOffset = 0.0f;
418e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    offset.ascenderOffset = 0.0f;
419e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
420e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    DWRITE_GLYPH_RUN run;
421e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    run.glyphCount = 1;
422e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    run.glyphAdvances = &advance;
423e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    run.fontFace = fTypeface->fDWriteFontFace.get();
424058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    run.fontEmSize = SkScalarToFloat(fTextSizeRender);
425e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    run.bidiLevel = 0;
426e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    run.glyphIndices = &glyphId;
427e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    run.isSideways = FALSE;
428e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    run.glyphOffsets = &offset;
429e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
430e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
431683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(
432683a37692bc67ef1144922b73a1e871e7e1e842ebungeman            &run,
433683a37692bc67ef1144922b73a1e871e7e1e842ebungeman            1.0f, // pixelsPerDip,
434683a37692bc67ef1144922b73a1e871e7e1e842ebungeman            &fXform,
435683a37692bc67ef1144922b73a1e871e7e1e842ebungeman            renderingMode,
436683a37692bc67ef1144922b73a1e871e7e1e842ebungeman            fMeasuringMode,
437683a37692bc67ef1144922b73a1e871e7e1e842ebungeman            0.0f, // baselineOriginX,
438683a37692bc67ef1144922b73a1e871e7e1e842ebungeman            0.0f, // baselineOriginY,
439683a37692bc67ef1144922b73a1e871e7e1e842ebungeman            &glyphRunAnalysis),
440683a37692bc67ef1144922b73a1e871e7e1e842ebungeman        "Could not create glyph run analysis.");
441683a37692bc67ef1144922b73a1e871e7e1e842ebungeman
442683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
443683a37692bc67ef1144922b73a1e871e7e1e842ebungeman        "Could not get texture bounds.");
444683a37692bc67ef1144922b73a1e871e7e1e842ebungeman
445683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    return S_OK;
446683a37692bc67ef1144922b73a1e871e7e1e842ebungeman}
447683a37692bc67ef1144922b73a1e871e7e1e842ebungeman
448683a37692bc67ef1144922b73a1e871e7e1e842ebungeman/** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
449683a37692bc67ef1144922b73a1e871e7e1e842ebungeman *  { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
450683a37692bc67ef1144922b73a1e871e7e1e842ebungeman *  for small, but not quite zero, sized glyphs.
451683a37692bc67ef1144922b73a1e871e7e1e842ebungeman *  Only set as non-empty if the returned bounds are non-empty.
452683a37692bc67ef1144922b73a1e871e7e1e842ebungeman */
453683a37692bc67ef1144922b73a1e871e7e1e842ebungemanstatic bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) {
454683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
455683a37692bc67ef1144922b73a1e871e7e1e842ebungeman        return false;
456683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    }
457683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    glyph->fWidth = SkToU16(bbox.right - bbox.left);
458683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
459683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    glyph->fLeft = SkToS16(bbox.left);
460683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    glyph->fTop = SkToS16(bbox.top);
461683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    return true;
462b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner}
463b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner
464b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagnervoid SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
465b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    glyph->fWidth = 0;
466683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    glyph->fHeight = 0;
467683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    glyph->fLeft = 0;
468683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    glyph->fTop = 0;
469b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner
470b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    this->generateAdvance(glyph);
471b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner
472b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    RECT bbox;
473683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
474683a37692bc67ef1144922b73a1e871e7e1e842ebungeman         "Requested bounding box could not be determined.");
475683a37692bc67ef1144922b73a1e871e7e1e842ebungeman
476683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    if (glyph_check_and_set_bounds(glyph, bbox)) {
477683a37692bc67ef1144922b73a1e871e7e1e842ebungeman        return;
478683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    }
479b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner
480b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
481b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    // glyphs of the specified texture type. When this happens, try with the
482b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    // alternate texture type.
483683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
484683a37692bc67ef1144922b73a1e871e7e1e842ebungeman        HRVM(this->getBoundingBox(glyph,
485683a37692bc67ef1144922b73a1e871e7e1e842ebungeman                                  DWRITE_RENDERING_MODE_ALIASED,
486683a37692bc67ef1144922b73a1e871e7e1e842ebungeman                                  DWRITE_TEXTURE_ALIASED_1x1,
487683a37692bc67ef1144922b73a1e871e7e1e842ebungeman                                  &bbox),
488683a37692bc67ef1144922b73a1e871e7e1e842ebungeman             "Fallback bounding box could not be determined.");
489683a37692bc67ef1144922b73a1e871e7e1e842ebungeman        if (glyph_check_and_set_bounds(glyph, bbox)) {
490683a37692bc67ef1144922b73a1e871e7e1e842ebungeman            glyph->fForceBW = 1;
491b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner        }
492b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    }
493683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
494683a37692bc67ef1144922b73a1e871e7e1e842ebungeman    // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
495e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
496e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
497410780677af260e32948b02c0725ef6ad761260cbungemanvoid SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
498410780677af260e32948b02c0725ef6ad761260cbungeman    if (NULL == metrics) {
499f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman        return;
500e1b9bad0711e557e45fee109fb492d19e35e1d38bungeman@google.com    }
501e1b9bad0711e557e45fee109fb492d19e35e1d38bungeman@google.com
502410780677af260e32948b02c0725ef6ad761260cbungeman    sk_bzero(metrics, sizeof(*metrics));
503410780677af260e32948b02c0725ef6ad761260cbungeman
504e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    DWRITE_FONT_METRICS dwfm;
505d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
506d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
507d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    {
508d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
509058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com             fTextSizeRender,
510d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com             1.0f, // pixelsPerDip
511d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com             &fXform,
512d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com             &dwfm);
513d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    } else {
514d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
515d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    }
516e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
517e1b9bad0711e557e45fee109fb492d19e35e1d38bungeman@google.com    SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
518e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
519f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman    metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
520410780677af260e32948b02c0725ef6ad761260cbungeman    metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
521410780677af260e32948b02c0725ef6ad761260cbungeman    metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
522410780677af260e32948b02c0725ef6ad761260cbungeman    metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
523410780677af260e32948b02c0725ef6ad761260cbungeman    metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
524410780677af260e32948b02c0725ef6ad761260cbungeman    metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
525410780677af260e32948b02c0725ef6ad761260cbungeman
526410780677af260e32948b02c0725ef6ad761260cbungeman    metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
527410780677af260e32948b02c0725ef6ad761260cbungeman    metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
528f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman
529f548444684b9c96f7717aebe645944af4f95d650bungeman#if SK_HAS_DWRITE_1_H
53049f085dddff10473b6ebf832a974288300224e60bsalomon    if (fTypeface->fDWriteFontFace1.get()) {
531f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman        DWRITE_FONT_METRICS1 dwfm1;
532f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman        fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1);
533f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman        metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
534f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman        metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
535f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman        metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
536f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman        metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
537f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman
538f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman        metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
539f548444684b9c96f7717aebe645944af4f95d650bungeman        return;
540f548444684b9c96f7717aebe645944af4f95d650bungeman    }
541f548444684b9c96f7717aebe645944af4f95d650bungeman#else
542f548444684b9c96f7717aebe645944af4f95d650bungeman#  pragma message("No dwrite_1.h is available, font metrics may be affected.")
543f548444684b9c96f7717aebe645944af4f95d650bungeman#endif
544f548444684b9c96f7717aebe645944af4f95d650bungeman
545f548444684b9c96f7717aebe645944af4f95d650bungeman    AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get());
546f548444684b9c96f7717aebe645944af4f95d650bungeman    if (head.fExists &&
547f548444684b9c96f7717aebe645944af4f95d650bungeman        head.fSize >= sizeof(SkOTTableHead) &&
548f548444684b9c96f7717aebe645944af4f95d650bungeman        head->version == SkOTTableHead::version1)
549f548444684b9c96f7717aebe645944af4f95d650bungeman    {
550f548444684b9c96f7717aebe645944af4f95d650bungeman        metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
551f548444684b9c96f7717aebe645944af4f95d650bungeman        metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
552f548444684b9c96f7717aebe645944af4f95d650bungeman        metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
553f548444684b9c96f7717aebe645944af4f95d650bungeman        metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
554f548444684b9c96f7717aebe645944af4f95d650bungeman
555f548444684b9c96f7717aebe645944af4f95d650bungeman        metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
556f548444684b9c96f7717aebe645944af4f95d650bungeman        return;
557f73c237291bb1fc698f688d8a9b1cdd23838ed18bungeman    }
558f548444684b9c96f7717aebe645944af4f95d650bungeman
559f548444684b9c96f7717aebe645944af4f95d650bungeman    metrics->fTop = metrics->fAscent;
560f548444684b9c96f7717aebe645944af4f95d650bungeman    metrics->fBottom = metrics->fDescent;
561e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
562e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
563e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com///////////////////////////////////////////////////////////////////////////////
564e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
565e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkColorPriv.h"
566e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
567e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comstatic void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
568e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const int width = glyph.fWidth;
569e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const size_t dstRB = (width + 7) >> 3;
570e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
571e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
572e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    int byteCount = width >> 3;
573e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    int bitCount = width & 7;
574e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
575e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    for (int y = 0; y < glyph.fHeight; ++y) {
576e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        if (byteCount > 0) {
577e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            for (int i = 0; i < byteCount; ++i) {
578e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                unsigned byte = 0;
579e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                byte |= src[0] & (1 << 7);
580e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                byte |= src[1] & (1 << 6);
581e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                byte |= src[2] & (1 << 5);
582e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                byte |= src[3] & (1 << 4);
583e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                byte |= src[4] & (1 << 3);
584e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                byte |= src[5] & (1 << 2);
585e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                byte |= src[6] & (1 << 1);
586e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                byte |= src[7] & (1 << 0);
587e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                dst[i] = byte;
588e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                src += 8;
589e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            }
590e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
591e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        if (bitCount > 0) {
592e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            unsigned byte = 0;
593e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            unsigned mask = 0x80;
594e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            for (int i = 0; i < bitCount; i++) {
595e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                byte |= (src[i]) & mask;
596e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                mask >>= 1;
597e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            }
598e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            dst[byteCount] = byte;
599e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
600e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        src += bitCount;
601e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        dst += dstRB;
602e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
603e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
604e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
605e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comtemplate<bool APPLY_PREBLEND>
606e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comstatic void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
607e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const size_t dstRB = glyph.rowBytes();
608e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const U16CPU width = glyph.fWidth;
609e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
610e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
611e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    for (U16CPU y = 0; y < glyph.fHeight; y++) {
612e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        for (U16CPU i = 0; i < width; i++) {
613e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            U8CPU r = *(src++);
614e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            U8CPU g = *(src++);
615e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            U8CPU b = *(src++);
616e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
617e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
618e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        dst = (uint8_t*)((char*)dst + dstRB);
619e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
620e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
621e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
622e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comtemplate<bool APPLY_PREBLEND>
623e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comstatic void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
624e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
625e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const size_t dstRB = glyph.rowBytes();
626e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const U16CPU width = glyph.fWidth;
627e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
628e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
629e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    for (U16CPU y = 0; y < glyph.fHeight; y++) {
630e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        for (U16CPU i = 0; i < width; i++) {
631e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
632e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
633e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
634e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            dst[i] = SkPack888ToRGB16(r, g, b);
635e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
636e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        dst = (uint16_t*)((char*)dst + dstRB);
637e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
638e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
639e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
640e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comtemplate<bool APPLY_PREBLEND>
641e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comstatic void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
642e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
643e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const size_t dstRB = glyph.rowBytes();
644e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const U16CPU width = glyph.fWidth;
645e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage);
646e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
647e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    for (U16CPU y = 0; y < glyph.fHeight; y++) {
648e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        for (U16CPU i = 0; i < width; i++) {
649e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
650e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
651e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
652e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            dst[i] = SkPackARGB32(0xFF, r, g, b);
653e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
654e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        dst = (SkPMColor*)((char*)dst + dstRB);
655e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
656e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
657e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
658b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagnerconst void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
659b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner                                           DWRITE_RENDERING_MODE renderingMode,
660b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner                                           DWRITE_TEXTURE_TYPE textureType)
661b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner{
662d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    int sizeNeeded = glyph.fWidth * glyph.fHeight;
663b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) {
664d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        sizeNeeded *= 3;
665d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    }
666d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    if (sizeNeeded > fBits.count()) {
667d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        fBits.setCount(sizeNeeded);
668d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    }
669d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com
670d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    // erase
671d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    memset(fBits.begin(), 0, sizeNeeded);
672d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com
673d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
674d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
675d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com
676d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    FLOAT advance = 0.0f;
677d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com
678d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    UINT16 index = glyph.getGlyphID();
679d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com
680d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    DWRITE_GLYPH_OFFSET offset;
681d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    offset.advanceOffset = 0.0f;
682d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    offset.ascenderOffset = 0.0f;
683e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
684d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    DWRITE_GLYPH_RUN run;
685d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    run.glyphCount = 1;
686d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    run.glyphAdvances = &advance;
687d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    run.fontFace = fTypeface->fDWriteFontFace.get();
688058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    run.fontEmSize = SkScalarToFloat(fTextSizeRender);
689d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    run.bidiLevel = 0;
690d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    run.glyphIndices = &index;
691d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    run.isSideways = FALSE;
692d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    run.glyphOffsets = &offset;
693d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com
694d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
695d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
696d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                                          1.0f, // pixelsPerDip,
697d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                                          &fXform,
698b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner                                          renderingMode,
699d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                                          fMeasuringMode,
700d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                                          0.0f, // baselineOriginX,
701d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                                          0.0f, // baselineOriginY,
702d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                                          &glyphRunAnalysis),
703d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com         "Could not create glyph run analysis.");
704d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com
705d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    //NOTE: this assumes that the glyph has already been measured
706d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    //with an exact same glyph run analysis.
707d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    RECT bbox;
708d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    bbox.left = glyph.fLeft;
709d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    bbox.top = glyph.fTop;
710d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    bbox.right = glyph.fLeft + glyph.fWidth;
711d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    bbox.bottom = glyph.fTop + glyph.fHeight;
712b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
713d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                                              &bbox,
714d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                                              fBits.begin(),
715d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com                                              sizeNeeded),
716d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com         "Could not draw mask.");
717d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    return fBits.begin();
718d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com}
719d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com
720d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.comvoid SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
721e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    //Create the mask.
722b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
723b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    DWRITE_TEXTURE_TYPE textureType = fTextureType;
724b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    if (glyph.fForceBW) {
725b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner        renderingMode = DWRITE_RENDERING_MODE_ALIASED;
726b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner        textureType = DWRITE_TEXTURE_ALIASED_1x1;
727b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    }
728b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
729e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    if (!bits) {
730e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        sk_bzero(glyph.fImage, glyph.computeImageSize());
731e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        return;
732e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
733e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
734e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    //Copy the mask into the glyph.
735e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const uint8_t* src = (const uint8_t*)bits;
736b2f7fce9e034c3b6749e75a129e7836df3529706Ben Wagner    if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
737e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        bilevel_to_bw(src, glyph);
738d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com        const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
739d715aaa33fc52d36f566caf941787a2cca24d85bbungeman@google.com    } else if (!isLCD(fRec)) {
740a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com        if (fPreBlend.isApplicable()) {
741a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            rgb_to_a8<true>(src, glyph, fPreBlend.fG);
742e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        } else {
743a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            rgb_to_a8<false>(src, glyph, fPreBlend.fG);
744e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
745e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
746a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com        if (fPreBlend.isApplicable()) {
747a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
748e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        } else {
749a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
750e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
751e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    } else {
752e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
753a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com        if (fPreBlend.isApplicable()) {
754a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
755e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        } else {
756a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
757e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
758e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
759e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
760e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
76130ddd615c447fed73286151b463af20d309c85f1reed@google.comvoid SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
762e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    SkASSERT(&glyph && path);
763e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
764e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    path->reset();
765e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
766e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
767e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
768e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com         "Could not create geometry to path converter.");
769e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    uint16_t glyphId = glyph.getGlyphID();
770e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    //TODO: convert to<->from DIUs? This would make a difference if hinting.
771e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    //It may not be needed, it appears that DirectWrite only hints at em size.
772058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
773e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                                       &glyphId,
774e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                                       NULL, //advances
775e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                                       NULL, //offsets
776e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                                       1, //num glyphs
777e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                                       FALSE, //sideways
778e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                                       FALSE, //rtl
779e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com                                       geometryToPath.get()),
780e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com         "Could not create glyph outline.");
781091f51b794e62942db47ccef6fef143ad1590d12bungeman@google.com
782058670b1e52910e61d9de294a46b5023ed6dd964bungeman@google.com    path->transform(fSkXform);
783e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
784