1635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project/*
2635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved.
3635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
4635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Redistribution and use in source and binary forms, with or without
5635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * modification, are permitted provided that the following conditions are
6635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * met:
7635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
8635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *     * Redistributions of source code must retain the above copyright
9635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * notice, this list of conditions and the following disclaimer.
10635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *     * Redistributions in binary form must reproduce the above
11635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * copyright notice, this list of conditions and the following disclaimer
12635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * in the documentation and/or other materials provided with the
13635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * distribution.
14635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *     * Neither the name of Google Inc. nor the names of its
15635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * contributors may be used to endorse or promote products derived from
16635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * this software without specific prior written permission.
17635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
18635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project */
30635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
31635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "config.h"
32635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "UniscribeHelper.h"
33635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "Font.h"
35635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "FontUtilsChromiumWin.h"
368f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include "PlatformContextSkia.h"
378f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include "SkiaFontWin.h"
388f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include "SkPoint.h"
392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include <windows.h>
40635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <wtf/Assertions.h>
41635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
42635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectnamespace WebCore {
43635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
44635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// HFONT is the 'incarnation' of 'everything' about font, but it's an opaque
45635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// handle and we can't directly query it to make a new HFONT sharing
46635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// its characteristics (height, style, etc) except for family name.
47635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// This function uses GetObject to convert HFONT back to LOGFONT,
48635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// resets the fields of LOGFONT and calculates style to use later
49635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// for the creation of a font identical to HFONT other than family name.
50635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void setLogFontAndStyle(HFONT hfont, LOGFONT *logfont, int *style)
51635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
52635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(hfont && logfont);
53635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!hfont || !logfont)
54635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return;
55635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
56635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    GetObject(hfont, sizeof(LOGFONT), logfont);
57635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We reset these fields to values appropriate for CreateFontIndirect.
58635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // while keeping lfHeight, which is the most important value in creating
59635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // a new font similar to hfont.
60635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    logfont->lfWidth = 0;
61635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    logfont->lfEscapement = 0;
62635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    logfont->lfOrientation = 0;
63635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    logfont->lfCharSet = DEFAULT_CHARSET;
64635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    logfont->lfOutPrecision = OUT_TT_ONLY_PRECIS;
65635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    logfont->lfQuality = DEFAULT_QUALITY;  // Honor user's desktop settings.
66635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    logfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
67635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (style)
68635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        *style = getStyleFromLogfont(logfont);
69635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
70635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
71635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectUniscribeHelper::UniscribeHelper(const UChar* input,
72635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                int inputLength,
73635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                bool isRtl,
74635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                HFONT hfont,
75635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                SCRIPT_CACHE* scriptCache,
762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                SCRIPT_FONTPROPERTIES* fontProperties,
772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                WORD spaceGlyph)
78635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    : m_input(input)
79635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_inputLength(inputLength)
80635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_isRtl(isRtl)
81635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_hfont(hfont)
82635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_scriptCache(scriptCache)
83635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_fontProperties(fontProperties)
842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    , m_spaceGlyph(spaceGlyph)
85635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_directionalOverride(false)
86635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_inhibitLigate(false)
87635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_letterSpacing(0)
88635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_spaceWidth(0)
89635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_wordSpacing(0)
90635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_ascent(0)
918f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    , m_disableFontFallback(false)
928f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
93635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
94635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_logfont.lfFaceName[0] = 0;
95635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
96635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
97635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectUniscribeHelper::~UniscribeHelper()
98635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
99635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
100635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
101635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid UniscribeHelper::initWithOptionalLengthProtection(bool lengthProtection)
102635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
103635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We cap the input length and just don't do anything. We'll allocate a lot
104635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // of things of the size of the number of characters, so the allocated
105635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // memory will be several times the input length. Plus shaping such a large
106635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // buffer may be a form of denial of service. No legitimate text should be
107635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // this long.  It also appears that Uniscribe flatly rejects very long
108635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // strings, so we don't lose anything by doing this.
109635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //
110635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // The input length protection may be disabled by the unit tests to cause
111635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // an error condition.
112635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    static const int kMaxInputLength = 65535;
113635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_inputLength == 0 || (lengthProtection && m_inputLength > kMaxInputLength))
114635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return;
115635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
116635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    fillRuns();
117635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    fillShapes();
118635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    fillScreenOrder();
119635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
120635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
121635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectint UniscribeHelper::width() const
122635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
123635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int width = 0;
124635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (int itemIndex = 0; itemIndex < static_cast<int>(m_runs.size()); itemIndex++)
125635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        width += advanceForItem(itemIndex);
126635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return width;
127635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
128635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
129635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid UniscribeHelper::justify(int additionalSpace)
130635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
131635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Count the total number of glyphs we have so we know how big to make the
132635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // buffers below.
133635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int totalGlyphs = 0;
134635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t run = 0; run < m_runs.size(); run++) {
135635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int runIndex = m_screenOrder[run];
136635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        totalGlyphs += static_cast<int>(m_shapes[runIndex].glyphLength());
137635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
138635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (totalGlyphs == 0)
139635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return;  // Nothing to do.
140635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
141635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We make one big buffer in screen order of all the glyphs we are drawing
142635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // across runs so that the justification function will adjust evenly across
143635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // all glyphs.
144635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    Vector<SCRIPT_VISATTR, 64> visualAttributes;
145635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    visualAttributes.resize(totalGlyphs);
146635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    Vector<int, 64> advances;
147635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    advances.resize(totalGlyphs);
148635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    Vector<int, 64> justify;
149635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    justify.resize(totalGlyphs);
150635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
151635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Build the packed input.
152635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int destIndex = 0;
153635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t run = 0; run < m_runs.size(); run++) {
154635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int runIndex = m_screenOrder[run];
155635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        const Shaping& shaping = m_shapes[runIndex];
156635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
157635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        for (int i = 0; i < shaping.glyphLength(); i++, destIndex++) {
158635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            memcpy(&visualAttributes[destIndex], &shaping.m_visualAttributes[i],
159635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                   sizeof(SCRIPT_VISATTR));
160635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            advances[destIndex] = shaping.m_advance[i];
161635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
162635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
163635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
164635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // The documentation for Scriptjustify is wrong, the parameter is the space
165635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // to add and not the width of the column you want.
166635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    const int minKashida = 1;  // How do we decide what this should be?
167635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ScriptJustify(&visualAttributes[0], &advances[0], totalGlyphs,
168635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                  additionalSpace, minKashida, &justify[0]);
169635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
170635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Now we have to unpack the justification amounts back into the runs so
171635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // the glyph indices match.
172635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int globalGlyphIndex = 0;
173635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t run = 0; run < m_runs.size(); run++) {
174635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int runIndex = m_screenOrder[run];
175635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        Shaping& shaping = m_shapes[runIndex];
176635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
177635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        shaping.m_justify.resize(shaping.glyphLength());
178635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        for (int i = 0; i < shaping.glyphLength(); i++, globalGlyphIndex++)
179635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            shaping.m_justify[i] = justify[globalGlyphIndex];
180635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
181635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
182635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
183635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectint UniscribeHelper::characterToX(int offset) const
184635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
185635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HRESULT hr;
186635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(offset <= m_inputLength);
187635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
188635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Our algorithm is to traverse the items in screen order from left to
189635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // right, adding in each item's screen width until we find the item with
190635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // the requested character in it.
191635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int width = 0;
192635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
193635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Compute the length of this run.
194635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int itemIndex = m_screenOrder[screenIndex];
195635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        const SCRIPT_ITEM& item = m_runs[itemIndex];
196635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        const Shaping& shaping = m_shapes[itemIndex];
197635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int itemLength = shaping.charLength();
198635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
199635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (offset >= item.iCharPos && offset <= item.iCharPos + itemLength) {
200635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Character offset is in this run.
201635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            int charLength = offset - item.iCharPos;
202635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
203635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            int curX = 0;
204635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            hr = ScriptCPtoX(charLength, FALSE, itemLength,
205635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             shaping.glyphLength(),
206635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             &shaping.m_logs[0], &shaping.m_visualAttributes[0],
207635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             shaping.effectiveAdvances(), &item.a, &curX);
208635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (FAILED(hr))
209635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                return 0;
210635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
211635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            width += curX + shaping.m_prePadding;
212635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            ASSERT(width >= 0);
213635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return width;
214635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
215635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
216635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Move to the next item.
217635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        width += advanceForItem(itemIndex);
218635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
219635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(width >= 0);
220635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return width;
221635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
222635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
223635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectint UniscribeHelper::xToCharacter(int x) const
224635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
225635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We iterate in screen order until we find the item with the given pixel
226635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // position in it. When we find that guy, we ask Uniscribe for the
227635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // character index.
228635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HRESULT hr;
229635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
230635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int itemIndex = m_screenOrder[screenIndex];
231635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int itemAdvance = advanceForItem(itemIndex);
232635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
233635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Note that the run may be empty if shaping failed, so we want to skip
234635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // over it.
235635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        const Shaping& shaping = m_shapes[itemIndex];
236635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int itemLength = shaping.charLength();
237635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (x <= itemAdvance && itemLength > 0) {
238635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // The requested offset is within this item.
239635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            const SCRIPT_ITEM& item = m_runs[itemIndex];
240635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
241635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Account for the leading space we've added to this run that
242635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Uniscribe doesn't know about.
243635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            x -= shaping.m_prePadding;
244635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
245635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            int charX = 0;
246635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            int trailing;
247635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            hr = ScriptXtoCP(x, itemLength, shaping.glyphLength(),
248635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             &shaping.m_logs[0], &shaping.m_visualAttributes[0],
249635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             shaping.effectiveAdvances(), &item.a, &charX,
250635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             &trailing);
251635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
252635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // The character offset is within the item. We need to add the
253635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // item's offset to transform it into the space of the TextRun
254635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return charX + item.iCharPos;
255635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
257635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // The offset is beyond this item, account for its length and move on.
258635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        x -= itemAdvance;
259635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
260635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
261635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Error condition, we don't know what to do if we don't have that X
262635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // position in any of our items.
263635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return 0;
264635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
265635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2668f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qianvoid UniscribeHelper::draw(GraphicsContext* graphicsContext,
2678f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                           HDC dc, int x, int y, int from, int to)
268635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
269635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HGDIOBJ oldFont = 0;
270635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int curX = x;
271635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    bool firstRun = true;
2728f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    bool useWindowsDrawing = windowsCanHandleTextDrawing(graphicsContext);
273635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
274635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
275635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int itemIndex = m_screenOrder[screenIndex];
276635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        const SCRIPT_ITEM& item = m_runs[itemIndex];
277635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        const Shaping& shaping = m_shapes[itemIndex];
278635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
279635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Character offsets within this run. THESE MAY NOT BE IN RANGE and may
280635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // be negative, etc. The code below handles this.
281635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int fromChar = from - item.iCharPos;
282635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int toChar = to - item.iCharPos;
283635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
284635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // See if we need to draw any characters in this item.
285635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (shaping.charLength() == 0 ||
286635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            fromChar >= shaping.charLength() || toChar <= 0) {
287635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // No chars in this item to display.
288635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            curX += advanceForItem(itemIndex);
289635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            continue;
290635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
291635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
292635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Compute the starting glyph within this span. |from| and |to| are
293635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // global offsets that may intersect arbitrarily with our local run.
294635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int fromGlyph, afterGlyph;
295635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (item.a.fRTL) {
296635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // To compute the first glyph when going RTL, we use |to|.
297635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (toChar >= shaping.charLength())
298635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // The end of the text is after (to the left) of us.
299635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                fromGlyph = 0;
300635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            else {
301635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // Since |to| is exclusive, the first character we draw on the
302635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // left is actually the one right before (to the right) of
303635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // |to|.
304635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                fromGlyph = shaping.m_logs[toChar - 1];
305635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
306635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
307635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // The last glyph is actually the first character in the range.
308635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (fromChar <= 0) {
309635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // The first character to draw is before (to the right) of this
310635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // span, so draw all the way to the end.
311635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                afterGlyph = shaping.glyphLength();
312635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            } else {
313635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // We want to draw everything up until the character to the
314635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // right of |from|. To the right is - 1, so we look that up
315635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // (remember our character could be more than one glyph, so we
316635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // can't look up our glyph and add one).
317635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                afterGlyph = shaping.m_logs[fromChar - 1];
318635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
319635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        } else {
320635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Easy case, everybody agrees about directions. We only need to
321635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // handle boundary conditions to get a range inclusive at the
322635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // beginning, and exclusive at the ending. We have to do some
323635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // computation to see the glyph one past the end.
324635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar];
325635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (toChar >= shaping.charLength())
326635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                afterGlyph = shaping.glyphLength();
327635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            else
328635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                afterGlyph = shaping.m_logs[toChar];
329635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
330635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
331635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Account for the characters that were skipped in this run. When
332635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // WebKit asks us to draw a subset of the run, it actually tells us
333635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // to draw at the X offset of the beginning of the run, since it
334635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // doesn't know the internal position of any of our characters.
335635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        const int* effectiveAdvances = shaping.effectiveAdvances();
336635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int innerOffset = 0;
337635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        for (int i = 0; i < fromGlyph; i++)
338635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            innerOffset += effectiveAdvances[i];
339635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
340635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Actually draw the glyphs we found.
341635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int glyphCount = afterGlyph - fromGlyph;
342635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (fromGlyph >= 0 && glyphCount > 0) {
3438f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            // Account for the preceding space we need to add to this run. We
344635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // don't need to count for the following space because that will be
345635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // counted in advanceForItem below when we move to the next run.
346635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            innerOffset += shaping.m_prePadding;
347635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
348635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Pass 0 in when there is no justification.
349635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph];
350635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
351231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            if (useWindowsDrawing) {
352231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                if (firstRun) {
353231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                    oldFont = SelectObject(dc, shaping.m_hfont);
354231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                    firstRun = false;
355231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                } else
356231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                    SelectObject(dc, shaping.m_hfont);
357231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            }
358635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
359635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Fonts with different ascents can be used to render different
360635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // runs.  'Across-runs' y-coordinate correction needs to be
361635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // adjusted for each font.
3628f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            bool textOutOk = false;
363635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            for (int executions = 0; executions < 2; ++executions) {
3648f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                if (useWindowsDrawing) {
3658f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                    HRESULT hr = ScriptTextOut(dc, shaping.m_scriptCache,
3668f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                               curX + innerOffset,
3678f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                               y - shaping.m_ascentOffset,
3688f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                               0, 0, &item.a, 0, 0,
3698f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                               &shaping.m_glyphs[fromGlyph],
3708f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                               glyphCount,
3718f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                               &shaping.m_advance[fromGlyph],
3728f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                               justify,
3738f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                               &shaping.m_offsets[fromGlyph]);
3748f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                    textOutOk = (hr == S_OK);
3758f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                } else {
3768f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                    SkPoint origin;
3778f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                    origin.fX = curX + + innerOffset;
378231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                    origin.fY = y + m_ascent;
3798f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                    textOutOk = paintSkiaText(graphicsContext,
3808f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                              shaping.m_hfont,
3818f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                              glyphCount,
3828f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                              &shaping.m_glyphs[fromGlyph],
3838f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                              &shaping.m_advance[fromGlyph],
3848f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                              &shaping.m_offsets[fromGlyph],
3858f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                                              &origin);
3868f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                }
3878f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
3888f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                if (!textOutOk && 0 == executions) {
3898f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                    // If TextOut is called from the renderer it might fail
3908f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                    // because the sandbox is preventing it from opening the
3918f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                    // font files.  If we are running in the renderer,
3928f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                    // TryToPreloadFont is overridden to ask the browser to
3938f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                    // preload the font for us so we can access it.
394635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    tryToPreloadFont(shaping.m_hfont);
395635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    continue;
396635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                }
397635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                break;
398635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
399635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
400635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
401635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        curX += advanceForItem(itemIndex);
402635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
403635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
404635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (oldFont)
405635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        SelectObject(dc, oldFont);
406635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
407635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
408635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectWORD UniscribeHelper::firstGlyphForCharacter(int charOffset) const
409635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
410635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Find the run for the given character.
411635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (int i = 0; i < static_cast<int>(m_runs.size()); i++) {
412635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int firstChar = m_runs[i].iCharPos;
413635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        const Shaping& shaping = m_shapes[i];
414635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int localOffset = charOffset - firstChar;
415635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (localOffset >= 0 && localOffset < shaping.charLength()) {
416635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // The character is in this run, return the first glyph for it
417635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // (should generally be the only glyph). It seems Uniscribe gives
418635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // glyph 0 for empty, which is what we want to return in the
419635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // "missing" case.
420635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            size_t glyphIndex = shaping.m_logs[localOffset];
421635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (glyphIndex >= shaping.m_glyphs.size()) {
422635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // The glyph should be in this run, but the run has too few
423635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // actual characters. This can happen when shaping the run
424635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // fails, in which case, we should have no data in the logs at
425635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // all.
426635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                ASSERT(shaping.m_glyphs.size() == 0);
427635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                return 0;
428635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
429635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return shaping.m_glyphs[glyphIndex];
430635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
431635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
432635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
433635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return 0;
434635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
435635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
436635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid UniscribeHelper::fillRuns()
437635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
438635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HRESULT hr;
439635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_runs.resize(UNISCRIBE_HELPER_STACK_RUNS);
440635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
441635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    SCRIPT_STATE inputState;
442635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.uBidiLevel = m_isRtl;
443635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.fOverrideDirection = m_directionalOverride;
444635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.fInhibitSymSwap = false;
445635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.fCharShape = false;  // Not implemented in Uniscribe
446635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.fDigitSubstitute = false;  // Do we want this for Arabic?
447635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.fInhibitLigate = m_inhibitLigate;
448635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.fDisplayZWG = false;  // Don't draw control characters.
449635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.fArabicNumContext = m_isRtl;  // Do we want this for Arabic?
450635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.fGcpClusters = false;
451635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.fReserved = 0;
452635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    inputState.fEngineReserved = 0;
453635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // The psControl argument to ScriptItemize should be non-0 for RTL text,
454635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // per http://msdn.microsoft.com/en-us/library/ms776532.aspx . So use a
455635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // SCRIPT_CONTROL that is set to all zeros.  Zero as a locale ID means the
456635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // neutral locale per http://msdn.microsoft.com/en-us/library/ms776294.aspx
457635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    static SCRIPT_CONTROL inputControl = {0, // uDefaultLanguage    :16;
458635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                           0, // fContextDigits      :1;
459635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                           0, // fInvertPreBoundDir  :1;
460635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                           0, // fInvertPostBoundDir :1;
461635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                           0, // fLinkStringBefore   :1;
462635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                           0, // fLinkStringAfter    :1;
463635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                           0, // fNeutralOverride    :1;
464635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                           0, // fNumericOverride    :1;
465635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                           0, // fLegacyBidiClass    :1;
466635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                           0, // fMergeNeutralItems  :1;
467635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                           0};// fReserved           :7;
468635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Calling ScriptApplyDigitSubstitution( 0, &inputControl, &inputState)
469635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // here would be appropriate if we wanted to set the language ID, and get
470635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // local digit substitution behavior.  For now, don't do it.
471635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
472635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    while (true) {
473635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int numberOfItems = 0;
474635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
475635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Ideally, we would have a way to know the runs before and after this
476635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // one, and put them into the control parameter of ScriptItemize. This
477635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // would allow us to shape characters properly that cross style
478635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // boundaries (WebKit bug 6148).
479635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        //
480635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // We tell ScriptItemize that the output list of items is one smaller
481635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // than it actually is. According to Mozilla bug 366643, if there is
482635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // not enough room in the array on pre-SP2 systems, ScriptItemize will
483635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // write one past the end of the buffer.
484635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        //
485635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // ScriptItemize is very strange. It will often require a much larger
486635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // ITEM buffer internally than it will give us as output. For example,
487635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // it will say a 16-item buffer is not big enough, and will write
488635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // interesting numbers into all those items. But when we give it a 32
489635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // item buffer and it succeeds, it only has one item output.
490635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        //
491635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // It seems to be doing at least two passes, the first where it puts a
492635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // lot of intermediate data into our items, and the second where it
493635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // collates them.
494635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        hr = ScriptItemize(m_input, m_inputLength,
495635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                           static_cast<int>(m_runs.size()) - 1, &inputControl,
496635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                           &inputState,
497635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                           &m_runs[0], &numberOfItems);
498635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (SUCCEEDED(hr)) {
499635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_runs.resize(numberOfItems);
500635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            break;
501635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
502635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (hr != E_OUTOFMEMORY) {
503635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Some kind of unexpected error.
504635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_runs.resize(0);
505635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            break;
506635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
507635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // There was not enough items for it to write into, expand.
508635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_runs.resize(m_runs.size() * 2);
509635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
510635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
511635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
512635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectbool UniscribeHelper::shape(const UChar* input,
513635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            int itemLength,
514635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            int numGlyphs,
515635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            SCRIPT_ITEM& run,
516635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            Shaping& shaping)
517635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
518635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HFONT hfont = m_hfont;
519635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    SCRIPT_CACHE* scriptCache = m_scriptCache;
520635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties;
521635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int ascent = m_ascent;
5222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    WORD spaceGlyph = m_spaceGlyph;
523635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HDC tempDC = 0;
524635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HGDIOBJ oldFont = 0;
525635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HRESULT hr;
5268f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // When used to fill up glyph pages for simple scripts in non-BMP,
5278f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // we don't want any font fallback in this class. The simple script
5288f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // font path can take care of font fallback.
5298f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    bool lastFallbackTried = m_disableFontFallback;
530635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    bool result;
531635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
532635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int generatedGlyphs = 0;
533635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
534635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // In case HFONT passed in ctor cannot render this run, we have to scan
535635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // other fonts from the beginning of the font list.
536635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    resetFontIndex();
537635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
538635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Compute shapes.
539635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    while (true) {
540635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        shaping.m_logs.resize(itemLength);
541635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        shaping.m_glyphs.resize(numGlyphs);
542635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        shaping.m_visualAttributes.resize(numGlyphs);
543635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
544635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#ifdef PURIFY
545635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // http://code.google.com/p/chromium/issues/detail?id=5309
546635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Purify isn't able to track the assignments that ScriptShape makes to
547635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // shaping.m_glyphs. Consequently, any bytes with value 0xCD that it
548635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // writes, will be considered un-initialized data.
549635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        //
550635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // This hack avoid the false-positive UMRs by marking the buffer as
551635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // initialized.
552635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        //
553635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // FIXME: A better solution would be to use Purify's API and mark only
554635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // the populated range as initialized:
555635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        //
556635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        //     PurifyMarkAsInitialized(
557635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        //         &shaping.m_glyphs[0],
558635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        //         sizeof(shaping.m_glyphs[0] * generatedGlyphs);
5598f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
560635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ZeroMemory(&shaping.m_glyphs[0],
561635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                   sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size());
562635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
563635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
564635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true
565635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // here. Is that what we want? It will display control characters.
566635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        hr = ScriptShape(tempDC, scriptCache, input, itemLength,
567635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                         numGlyphs, &run.a,
568635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                         &shaping.m_glyphs[0], &shaping.m_logs[0],
569635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                         &shaping.m_visualAttributes[0], &generatedGlyphs);
570635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (hr == E_PENDING) {
571635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Allocate the DC.
572635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            tempDC = GetDC(0);
573635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            oldFont = SelectObject(tempDC, hfont);
574635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            continue;
575635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        } else if (hr == E_OUTOFMEMORY) {
576635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            numGlyphs *= 2;
577635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            continue;
5782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(shaping, run, fontProperties)))
579635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            break;
580635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
581635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // The current font can't render this run. clear DC and try
582635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // next font.
583635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (tempDC) {
584635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            SelectObject(tempDC, oldFont);
585635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            ReleaseDC(0, tempDC);
586635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            tempDC = 0;
587635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
588635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
5898f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        if (!m_disableFontFallback &&
5908f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) {
591635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // The primary font does not support this run. Try next font.
592635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // In case of web page rendering, they come from fonts specified in
593635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // CSS stylesheets.
594635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            continue;
595635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        } else if (!lastFallbackTried) {
596635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            lastFallbackTried = true;
597635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
598635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Generate a last fallback font based on the script of
599635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // a character to draw while inheriting size and styles
600635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // from the primary font
601635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (!m_logfont.lfFaceName[0])
602635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                setLogFontAndStyle(m_hfont, &m_logfont, &m_style);
603635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
604635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // TODO(jungshik): generic type should come from webkit for
605635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // UniscribeHelperTextRun (a derived class used in webkit).
606635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            const UChar *family = getFallbackFamily(input, itemLength,
607635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                FontDescription::StandardFamily, 0, 0);
608635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            bool fontOk = getDerivedFontData(family, m_style, &m_logfont,
6092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                             &ascent, &hfont, &scriptCache,
6102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                             &spaceGlyph);
6112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
612635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
613635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (!fontOk) {
614635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // If this GetDerivedFontData is called from the renderer it
615635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // might fail because the sandbox is preventing it from opening
616635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // the font files.  If we are running in the renderer,
617635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // TryToPreloadFont is overridden to ask the browser to preload
618635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // the font for us so we can access it.
619635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                tryToPreloadFont(hfont);
620635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
621635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // Try again.
622635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                fontOk = getDerivedFontData(family, m_style, &m_logfont,
6232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                            &ascent, &hfont, &scriptCache,
6242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                            &spaceGlyph);
625635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                ASSERT(fontOk);
626635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
627635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
628635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // TODO(jungshik) : Currently GetDerivedHFont always returns a
629635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // a valid HFONT, but in the future, I may change it to return 0.
630635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            ASSERT(hfont);
631635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
632635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // We don't need a font_properties for the last resort fallback font
633635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // because we don't have anything more to try and are forced to
634635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // accept empty glyph boxes. If we tried a series of fonts as
635635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // 'last-resort fallback', we'd need it, but currently, we don't.
636635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            continue;
637635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
638635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            run.a.eScript = SCRIPT_UNDEFINED;
639635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            continue;
640635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        } else if (FAILED(hr)) {
641635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Error shaping.
642635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            generatedGlyphs = 0;
643635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            result = false;
644635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            goto cleanup;
645635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
646635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
647635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
648635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Sets Windows font data for this run to those corresponding to
649635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // a font supporting this run. we don't need to store font_properties
650635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // because it's not used elsewhere.
651635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    shaping.m_hfont = hfont;
652635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    shaping.m_scriptCache = scriptCache;
6532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    shaping.m_spaceGlyph = spaceGlyph;
654635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
655635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // The ascent of a font for this run can be different from
656635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // that of the primary font so that we need to keep track of
657635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // the difference per run and take that into account when calling
658635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // ScriptTextOut in |draw|. Otherwise, different runs rendered by
659635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // different fonts would not be aligned vertically.
660635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    shaping.m_ascentOffset = m_ascent ? ascent - m_ascent : 0;
661635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    result = true;
662635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
663635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project  cleanup:
664635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    shaping.m_glyphs.resize(generatedGlyphs);
665635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    shaping.m_visualAttributes.resize(generatedGlyphs);
666635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    shaping.m_advance.resize(generatedGlyphs);
667635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    shaping.m_offsets.resize(generatedGlyphs);
668635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (tempDC) {
669635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        SelectObject(tempDC, oldFont);
670635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ReleaseDC(0, tempDC);
671635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
672635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // On failure, our logs don't mean anything, so zero those out.
673635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!result)
674635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        shaping.m_logs.clear();
675635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
676635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return result;
677635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
678635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
679635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid UniscribeHelper::fillShapes()
680635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
681635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_shapes.resize(m_runs.size());
682635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t i = 0; i < m_runs.size(); i++) {
683635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int startItem = m_runs[i].iCharPos;
684635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int itemLength = m_inputLength - startItem;
685635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (i < m_runs.size() - 1)
686635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            itemLength = m_runs[i + 1].iCharPos - startItem;
687635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
688635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        int numGlyphs;
689635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (itemLength < UNISCRIBE_HELPER_STACK_CHARS) {
690635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // We'll start our buffer sizes with the current stack space
691635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // available in our buffers if the current input fits. As long as
692635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // it doesn't expand past that we'll save a lot of time mallocing.
693635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            numGlyphs = UNISCRIBE_HELPER_STACK_CHARS;
694635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        } else {
695635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // When the input doesn't fit, give up with the stack since it will
696635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // almost surely not be enough room (unless the input actually
697635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // shrinks, which is unlikely) and just start with the length
698635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // recommended by the Uniscribe documentation as a "usually fits"
699635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // size.
700635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            numGlyphs = itemLength * 3 / 2 + 16;
701635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
702635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
703635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Convert a string to a glyph string trying the primary font, fonts in
704635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // the fallback list and then script-specific last resort font.
705635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        Shaping& shaping = m_shapes[i];
706635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], shaping))
707635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            continue;
708635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
7098f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        // At the moment, the only time m_disableFontFallback is set is
7108f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        // when we look up glyph indices for non-BMP code ranges. So,
7118f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        // we can skip the glyph placement. When that becomes not the case
7128f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        // any more, we have to add a new flag to control glyph placement.
7138f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        if (m_disableFontFallback)
7148f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian          continue;
7158f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
716635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Compute placements. Note that offsets is documented incorrectly
717635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // and is actually an array.
718635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
719635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // DC that we lazily create if Uniscribe commands us to.
720635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // (this does not happen often because scriptCache is already
721635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        //  updated when calling ScriptShape).
722635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        HDC tempDC = 0;
723635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        HGDIOBJ oldFont = 0;
724635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        HRESULT hr;
725635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        while (true) {
726635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            shaping.m_prePadding = 0;
727635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            hr = ScriptPlace(tempDC, shaping.m_scriptCache,
728635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             &shaping.m_glyphs[0],
729635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             static_cast<int>(shaping.m_glyphs.size()),
730635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             &shaping.m_visualAttributes[0], &m_runs[i].a,
731635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             &shaping.m_advance[0], &shaping.m_offsets[0],
732635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                             &shaping.m_abc);
733635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (hr != E_PENDING)
734635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                break;
735635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
736635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Allocate the DC and run the loop again.
737635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            tempDC = GetDC(0);
738635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            oldFont = SelectObject(tempDC, shaping.m_hfont);
739635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
740635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
741635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (FAILED(hr)) {
742635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Some error we don't know how to handle. Nuke all of our data
743635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // since we can't deal with partially valid data later.
744635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_runs.clear();
745635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_shapes.clear();
746635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_screenOrder.clear();
747635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
748635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
749635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (tempDC) {
750635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            SelectObject(tempDC, oldFont);
751635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            ReleaseDC(0, tempDC);
752635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
753635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
754635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
755635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    adjustSpaceAdvances();
756635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
757635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_letterSpacing != 0 || m_wordSpacing != 0)
758635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        applySpacing();
759635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
760635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
761635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid UniscribeHelper::fillScreenOrder()
762635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
763635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_screenOrder.resize(m_runs.size());
764635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
765635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We assume that the input has only one text direction in it.
766635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // TODO(brettw) are we sure we want to keep this restriction?
767635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_isRtl) {
768635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++)
769635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_screenOrder[static_cast<int>(m_screenOrder.size()) - i - 1] = i;
770635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    } else {
771635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++)
772635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_screenOrder[i] = i;
773635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
774635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
775635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
776635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid UniscribeHelper::adjustSpaceAdvances()
777635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
778635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_spaceWidth == 0)
779635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return;
780635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
781635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int spaceWidthWithoutLetterSpacing = m_spaceWidth - m_letterSpacing;
782635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
783635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem.
784635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t run = 0; run < m_runs.size(); run++) {
785635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        Shaping& shaping = m_shapes[run];
786635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
7872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        // FIXME: This loop is not UTF-16-safe. Unicode 6.0 has a couple
7882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        // of complex script blocks in Plane 1.
789635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        for (int i = 0; i < shaping.charLength(); i++) {
7902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            UChar c = m_input[m_runs[run].iCharPos + i];
7912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            bool treatAsSpace = Font::treatAsSpace(c);
7922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            if (!treatAsSpace && !Font::treatAsZeroWidthSpaceInComplexScript(c))
793635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                continue;
794635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
795635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            int glyphIndex = shaping.m_logs[i];
796635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            int currentAdvance = shaping.m_advance[glyphIndex];
797635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
7982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            if (treatAsSpace) {
7992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                // currentAdvance does not include additional letter-spacing,
8002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                // but m_spaceWidth does. Here we find out how off we are from
8012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                // the correct width (spaceWidthWithoutLetterSpacing) and
8022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                // just subtract that diff.
8032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                int diff = currentAdvance - spaceWidthWithoutLetterSpacing;
8042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                // The shaping can consist of a run of text, so only subtract
8052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                // the difference in the width of the glyph.
8062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                shaping.m_advance[glyphIndex] -= diff;
8072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                shaping.m_abc.abcB -= diff;
8082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                continue;
8092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            }
8102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
8112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            // For characters treated as zero-width space in complex
8122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            // scripts, set the advance width to zero, adjust
8132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            // |abcB| of the current run accordingly and set
8142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            // the glyph to m_spaceGlyph (invisible).
8152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            shaping.m_advance[glyphIndex] = 0;
8162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            shaping.m_abc.abcB -= currentAdvance;
8172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            shaping.m_offsets[glyphIndex].du = 0;
8182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            shaping.m_offsets[glyphIndex].dv = 0;
8192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            shaping.m_glyphs[glyphIndex] = shaping.m_spaceGlyph;
820635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
821635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
822635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
823635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
824635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid UniscribeHelper::applySpacing()
825635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
826635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t run = 0; run < m_runs.size(); run++) {
827635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        Shaping& shaping = m_shapes[run];
828635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        bool isRtl = m_runs[run].a.fRTL;
829635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
830635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (m_letterSpacing != 0) {
831635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // RTL text gets padded to the left of each character. We increment
832635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // the run's advance to make this happen. This will be balanced out
833635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // by NOT adding additional advance to the last glyph in the run.
834635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (isRtl)
835635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                shaping.m_prePadding += m_letterSpacing;
836635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
837635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Go through all the glyphs in this run and increase the "advance"
838635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // to account for letter spacing. We adjust letter spacing only on
839635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // cluster boundaries.
840635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            //
841635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // This works for most scripts, but may have problems with some
842635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // indic scripts. This behavior is better than Firefox or IE for
843635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Hebrew.
844635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            for (int i = 0; i < shaping.glyphLength(); i++) {
845635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                if (shaping.m_visualAttributes[i].fClusterStart) {
846635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    // Ick, we need to assign the extra space so that the glyph
847635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    // comes first, then is followed by the space. This is
848635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    // opposite for RTL.
849635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    if (isRtl) {
850635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        if (i != shaping.glyphLength() - 1) {
851635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            // All but the last character just get the spacing
852635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            // applied to their advance. The last character
853635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            // doesn't get anything,
854635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            shaping.m_advance[i] += m_letterSpacing;
855635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            shaping.m_abc.abcB += m_letterSpacing;
856635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        }
857635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    } else {
858635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        // LTR case is easier, we just add to the advance.
859635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        shaping.m_advance[i] += m_letterSpacing;
860635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        shaping.m_abc.abcB += m_letterSpacing;
861635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    }
862635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                }
863635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
864635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
865635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
866635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Go through all the characters to find whitespace and insert the
867635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // extra wordspacing amount for the glyphs they correspond to.
868635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (m_wordSpacing != 0) {
869635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            for (int i = 0; i < shaping.charLength(); i++) {
8702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                if (!Font::treatAsSpace(m_input[m_runs[run].iCharPos + i]))
871635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    continue;
872635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
873635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // The char in question is a word separator...
874635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                int glyphIndex = shaping.m_logs[i];
875635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
876635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // Spaces will not have a glyph in Uniscribe, it will just add
877635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // additional advance to the character to the left of the
878635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // space. The space's corresponding glyph will be the character
879635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // following it in reading order.
880635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                if (isRtl) {
881635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    // In RTL, the glyph to the left of the space is the same
882635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    // as the first glyph of the following character, so we can
883635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    // just increment it.
884635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    shaping.m_advance[glyphIndex] += m_wordSpacing;
885635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    shaping.m_abc.abcB += m_wordSpacing;
886635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                } else {
887635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    // LTR is actually more complex here, we apply it to the
888635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    // previous character if there is one, otherwise we have to
889635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    // apply it to the leading space of the run.
890635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    if (glyphIndex == 0)
891635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        shaping.m_prePadding += m_wordSpacing;
892635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    else {
893635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        shaping.m_advance[glyphIndex - 1] += m_wordSpacing;
894635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        shaping.m_abc.abcB += m_wordSpacing;
895635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    }
896635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                }
897635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
898635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }  // m_wordSpacing != 0
899635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
900635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Loop for next run...
901635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
902635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
903635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
904635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// The advance is the ABC width of the run
905635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectint UniscribeHelper::advanceForItem(int itemIndex) const
906635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
907635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int accum = 0;
908635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    const Shaping& shaping = m_shapes[itemIndex];
909635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
910635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (shaping.m_justify.size() == 0) {
911635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Easy case with no justification, the width is just the ABC width of
912635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // the run. (The ABC width is the sum of the advances).
913635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return shaping.m_abc.abcA + shaping.m_abc.abcB +
914635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project               shaping.m_abc.abcC + shaping.m_prePadding;
915635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
916635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
917635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // With justification, we use the justified amounts instead. The
918635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // justification array contains both the advance and the extra space
919635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // added for justification, so is the width we want.
920635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int justification = 0;
921635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t i = 0; i < shaping.m_justify.size(); i++)
922635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        justification += shaping.m_justify[i];
923635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
924635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return shaping.m_prePadding + justification;
925635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
926635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
9272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid
9282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// and blank glyphs. Just because ScriptShape succeeds does not mean
9292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// that a text run is rendered correctly. Some characters may be rendered
9302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// with default/invalid/blank glyphs. Therefore, we need to check if the glyph
9312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// array returned by ScriptShape contains any of those glyphs to make
9322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// sure that the text run is rendered successfully.
9332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// However, we should not subject zero-width characters to this test.
9342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
9352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochbool UniscribeHelper::containsMissingGlyphs(const Shaping& shaping,
9362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                            const SCRIPT_ITEM& run,
9372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                            const SCRIPT_FONTPROPERTIES* properties) const
9382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
9392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    for (int i = 0; i < shaping.charLength(); i++) {
9402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        UChar c = m_input[run.iCharPos + i];
9412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        // Skip zero-width space characters because they're not considered to be missing in a font.
9422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if (Font::treatAsZeroWidthSpaceInComplexScript(c))
9432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            continue;
9442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        int glyphIndex = shaping.m_logs[i];
9452daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        WORD glyph = shaping.m_glyphs[glyphIndex];
9462daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if (glyph == properties->wgDefault
9472daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            || (glyph == properties->wgInvalid && glyph != properties->wgBlank))
9482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            return true;
9492daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }
9502daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return false;
9512daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
9522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
9532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
954635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}  // namespace WebCore
955