[chromium] Convert uses of GetDC to HWndDC.
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / UniscribeHelper.cpp
1 /*
2  * Copyright (c) 2006, 2007, 2008, 2009, 2012 Google Inc. All rights reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "UniscribeHelper.h"
33
34 #include "Font.h"
35 #include "FontUtilsChromiumWin.h"
36 #include "HWndDC.h"
37 #include "PlatformContextSkia.h"
38 #include "SkiaFontWin.h"
39 #include "SkPoint.h"
40 #include <windows.h>
41 #include <wtf/Assertions.h>
42
43 namespace WebCore {
44
45 // The function types for ScriptItemizeOpenType() and ScriptShapeOpenType().
46 // We want to use these functions for OpenType feature support, but we can't
47 // call them directly because usp10.dll does not always have them.
48 // Instead, we use GetProcAddress() to check whether we can actually use these
49 // function. If we can't use these functions, we substitute ScriptItemze() and
50 // ScriptShape().
51 typedef HRESULT (WINAPI *ScriptItemizeOpenTypeFunc)(const WCHAR*, int, int,
52                                                     const SCRIPT_CONTROL*,
53                                                     const SCRIPT_STATE*,
54                                                     SCRIPT_ITEM*,
55                                                     OPENTYPE_TAG*, int*);
56 typedef HRESULT (WINAPI *ScriptShapeOpenTypeFunc)(HDC, SCRIPT_CACHE*,
57                                                   SCRIPT_ANALYSIS*,
58                                                   OPENTYPE_TAG, OPENTYPE_TAG,
59                                                   int*, TEXTRANGE_PROPERTIES**,
60                                                   int, const WCHAR*, int, int,
61                                                   WORD*, SCRIPT_CHARPROP*,
62                                                   WORD*, SCRIPT_GLYPHPROP*,
63                                                   int*);
64
65 static ScriptItemizeOpenTypeFunc gScriptItemizeOpenTypeFunc = 0;
66 static ScriptShapeOpenTypeFunc gScriptShapeOpenTypeFunc = 0;
67 static bool gOpenTypeFunctionsLoaded = false;
68
69 static void loadOpenTypeFunctions()
70 {
71     HMODULE hModule = GetModuleHandle(L"usp10");
72     if (hModule) {
73         gScriptItemizeOpenTypeFunc = reinterpret_cast<ScriptItemizeOpenTypeFunc>(GetProcAddress(hModule, "ScriptItemizeOpenType"));
74         gScriptShapeOpenTypeFunc = reinterpret_cast<ScriptShapeOpenTypeFunc>(GetProcAddress(hModule, "ScriptShapeOpenType"));
75     }
76     if (!gScriptItemizeOpenTypeFunc || !gScriptShapeOpenTypeFunc) {
77         gScriptItemizeOpenTypeFunc = 0;
78         gScriptShapeOpenTypeFunc = 0;
79     }
80     gOpenTypeFunctionsLoaded = true;
81 }
82
83 // HFONT is the 'incarnation' of 'everything' about font, but it's an opaque
84 // handle and we can't directly query it to make a new HFONT sharing
85 // its characteristics (height, style, etc) except for family name.
86 // This function uses GetObject to convert HFONT back to LOGFONT,
87 // resets the fields of LOGFONT and calculates style to use later
88 // for the creation of a font identical to HFONT other than family name.
89 static void setLogFontAndStyle(HFONT hfont, LOGFONT *logfont, int *style)
90 {
91     ASSERT(hfont && logfont);
92     if (!hfont || !logfont)
93         return;
94
95     GetObject(hfont, sizeof(LOGFONT), logfont);
96     // We reset these fields to values appropriate for CreateFontIndirect.
97     // while keeping lfHeight, which is the most important value in creating
98     // a new font similar to hfont.
99     logfont->lfWidth = 0;
100     logfont->lfEscapement = 0;
101     logfont->lfOrientation = 0;
102     logfont->lfCharSet = DEFAULT_CHARSET;
103     logfont->lfOutPrecision = OUT_TT_ONLY_PRECIS;
104     logfont->lfQuality = DEFAULT_QUALITY;  // Honor user's desktop settings.
105     logfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
106     if (style)
107         *style = getStyleFromLogfont(logfont);
108 }
109
110 // This memory DC will NOT be released but it's OK
111 // since we want to keep it for the whole life span of the process.
112 HDC UniscribeHelper::m_cachedDC = 0;
113
114 static bool canUseGlyphIndex(const SCRIPT_ITEM& run)
115 {
116     // On early version of Uniscribe, ScriptShape() sets run.a.fNoGlyphIndex
117     // to TRUE when it can't shape the run with glyph indexes. This could
118     // occur when we use CFF webfonts(See http://crbug.com/39017).
119     // We don't use the font in that case and try to use fallback fonts.
120     return !run.a.fNoGlyphIndex;
121 }
122
123 UniscribeHelper::UniscribeHelper(const UChar* input,
124                                 int inputLength,
125                                 bool isRtl,
126                                 HFONT hfont,
127                                 SCRIPT_CACHE* scriptCache,
128                                 SCRIPT_FONTPROPERTIES* fontProperties,
129                                 WORD spaceGlyph)
130     : m_input(input)
131     , m_inputLength(inputLength)
132     , m_isRtl(isRtl)
133     , m_hfont(hfont)
134     , m_scriptCache(scriptCache)
135     , m_fontProperties(fontProperties)
136     , m_spaceGlyph(spaceGlyph)
137     , m_directionalOverride(false)
138     , m_inhibitLigate(false)
139     , m_letterSpacing(0)
140     , m_spaceWidth(0)
141     , m_wordSpacing(0)
142     , m_ascent(0)
143     , m_disableFontFallback(false)
144
145 {
146     m_logfont.lfFaceName[0] = 0;
147     if (!gOpenTypeFunctionsLoaded)
148         loadOpenTypeFunctions();
149 }
150
151 UniscribeHelper::~UniscribeHelper()
152 {
153 }
154
155 void UniscribeHelper::initWithOptionalLengthProtection(bool lengthProtection)
156 {
157     // We cap the input length and just don't do anything. We'll allocate a lot
158     // of things of the size of the number of characters, so the allocated
159     // memory will be several times the input length. Plus shaping such a large
160     // buffer may be a form of denial of service. No legitimate text should be
161     // this long.  It also appears that Uniscribe flatly rejects very long
162     // strings, so we don't lose anything by doing this.
163     //
164     // The input length protection may be disabled by the unit tests to cause
165     // an error condition.
166     static const int kMaxInputLength = 65535;
167     if (m_inputLength == 0 || (lengthProtection && m_inputLength > kMaxInputLength))
168         return;
169
170     fillRuns();
171     fillShapes();
172     fillScreenOrder();
173 }
174
175 int UniscribeHelper::width() const
176 {
177     int width = 0;
178     for (int itemIndex = 0; itemIndex < static_cast<int>(m_runs.size()); itemIndex++)
179         width += advanceForItem(itemIndex);
180     return width;
181 }
182
183 void UniscribeHelper::justify(int additionalSpace)
184 {
185     // Count the total number of glyphs we have so we know how big to make the
186     // buffers below.
187     int totalGlyphs = 0;
188     for (size_t run = 0; run < m_runs.size(); run++) {
189         int runIndex = m_screenOrder[run];
190         totalGlyphs += static_cast<int>(m_shapes[runIndex].glyphLength());
191     }
192     if (totalGlyphs == 0)
193         return;  // Nothing to do.
194
195     // We make one big buffer in screen order of all the glyphs we are drawing
196     // across runs so that the justification function will adjust evenly across
197     // all glyphs.
198     Vector<SCRIPT_VISATTR, 64> visualAttributes;
199     visualAttributes.resize(totalGlyphs);
200     Vector<int, 64> advances;
201     advances.resize(totalGlyphs);
202     Vector<int, 64> justify;
203     justify.resize(totalGlyphs);
204
205     // Build the packed input.
206     int destIndex = 0;
207     for (size_t run = 0; run < m_runs.size(); run++) {
208         int runIndex = m_screenOrder[run];
209         const Shaping& shaping = m_shapes[runIndex];
210
211         for (int i = 0; i < shaping.glyphLength(); i++, destIndex++) {
212             memcpy(&visualAttributes[destIndex], &shaping.m_visualAttributes[i],
213                    sizeof(SCRIPT_VISATTR));
214             advances[destIndex] = shaping.m_advance[i];
215         }
216     }
217
218     // The documentation for Scriptjustify is wrong, the parameter is the space
219     // to add and not the width of the column you want.
220     const int minKashida = 1;  // How do we decide what this should be?
221     ScriptJustify(&visualAttributes[0], &advances[0], totalGlyphs,
222                   additionalSpace, minKashida, &justify[0]);
223
224     // Now we have to unpack the justification amounts back into the runs so
225     // the glyph indices match.
226     int globalGlyphIndex = 0;
227     for (size_t run = 0; run < m_runs.size(); run++) {
228         int runIndex = m_screenOrder[run];
229         Shaping& shaping = m_shapes[runIndex];
230
231         shaping.m_justify.resize(shaping.glyphLength());
232         for (int i = 0; i < shaping.glyphLength(); i++, globalGlyphIndex++)
233             shaping.m_justify[i] = justify[globalGlyphIndex];
234     }
235 }
236
237 int UniscribeHelper::characterToX(int offset) const
238 {
239     HRESULT hr;
240     ASSERT(offset <= m_inputLength);
241
242     // Our algorithm is to traverse the items in screen order from left to
243     // right, adding in each item's screen width until we find the item with
244     // the requested character in it.
245     int width = 0;
246     for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
247         // Compute the length of this run.
248         int itemIndex = m_screenOrder[screenIndex];
249         const SCRIPT_ITEM& item = m_runs[itemIndex];
250         const Shaping& shaping = m_shapes[itemIndex];
251         int itemLength = shaping.charLength();
252
253         if (offset >= item.iCharPos && offset <= item.iCharPos + itemLength) {
254             // Character offset is in this run.
255             int charLength = offset - item.iCharPos;
256
257             int curX = 0;
258             hr = ScriptCPtoX(charLength, FALSE, itemLength,
259                              shaping.glyphLength(),
260                              &shaping.m_logs[0], &shaping.m_visualAttributes[0],
261                              shaping.effectiveAdvances(), &item.a, &curX);
262             if (FAILED(hr))
263                 return 0;
264
265             width += curX + shaping.m_prePadding;
266             ASSERT(width >= 0);
267             return width;
268         }
269
270         // Move to the next item.
271         width += advanceForItem(itemIndex);
272     }
273     ASSERT(width >= 0);
274     return width;
275 }
276
277 int UniscribeHelper::xToCharacter(int x) const
278 {
279     // We iterate in screen order until we find the item with the given pixel
280     // position in it. When we find that guy, we ask Uniscribe for the
281     // character index.
282     HRESULT hr;
283     for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
284         int itemIndex = m_screenOrder[screenIndex];
285         int itemAdvance = advanceForItem(itemIndex);
286
287         // Note that the run may be empty if shaping failed, so we want to skip
288         // over it.
289         const Shaping& shaping = m_shapes[itemIndex];
290         int itemLength = shaping.charLength();
291         if (x <= itemAdvance && itemLength > 0) {
292             // The requested offset is within this item.
293             const SCRIPT_ITEM& item = m_runs[itemIndex];
294
295             // Account for the leading space we've added to this run that
296             // Uniscribe doesn't know about.
297             x -= shaping.m_prePadding;
298
299             int charX = 0;
300             int trailing;
301             hr = ScriptXtoCP(x, itemLength, shaping.glyphLength(),
302                              &shaping.m_logs[0], &shaping.m_visualAttributes[0],
303                              shaping.effectiveAdvances(), &item.a, &charX,
304                              &trailing);
305
306             // The character offset is within the item. We need to add the
307             // item's offset to transform it into the space of the TextRun
308             return charX + item.iCharPos;
309         }
310
311         // The offset is beyond this item, account for its length and move on.
312         x -= itemAdvance;
313     }
314
315     // Error condition, we don't know what to do if we don't have that X
316     // position in any of our items.
317     return 0;
318 }
319
320 void UniscribeHelper::draw(GraphicsContext* graphicsContext,
321                            HDC dc, int x, int y, int from, int to)
322 {
323     HGDIOBJ oldFont = 0;
324     int curX = x;
325     bool firstRun = true;
326 #if !USE(SKIA_TEXT)
327     bool useWindowsDrawing = windowsCanHandleTextDrawing(graphicsContext);
328 #endif
329
330     for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
331         int itemIndex = m_screenOrder[screenIndex];
332         const SCRIPT_ITEM& item = m_runs[itemIndex];
333         const Shaping& shaping = m_shapes[itemIndex];
334
335         // Character offsets within this run. THESE MAY NOT BE IN RANGE and may
336         // be negative, etc. The code below handles this.
337         int fromChar = from - item.iCharPos;
338         int toChar = to - item.iCharPos;
339
340         // See if we need to draw any characters in this item.
341         if (shaping.charLength() == 0 ||
342             fromChar >= shaping.charLength() || toChar <= 0) {
343             // No chars in this item to display.
344             curX += advanceForItem(itemIndex);
345             continue;
346         }
347
348         // Compute the starting glyph within this span. |from| and |to| are
349         // global offsets that may intersect arbitrarily with our local run.
350         int fromGlyph, afterGlyph;
351         if (item.a.fRTL) {
352             // To compute the first glyph when going RTL, we use |to|.
353             if (toChar >= shaping.charLength())
354                 // The end of the text is after (to the left) of us.
355                 fromGlyph = 0;
356             else {
357                 // Since |to| is exclusive, the first character we draw on the
358                 // left is actually the one right before (to the right) of
359                 // |to|.
360                 fromGlyph = shaping.m_logs[toChar - 1];
361             }
362
363             // The last glyph is actually the first character in the range.
364             if (fromChar <= 0) {
365                 // The first character to draw is before (to the right) of this
366                 // span, so draw all the way to the end.
367                 afterGlyph = shaping.glyphLength();
368             } else {
369                 // We want to draw everything up until the character to the
370                 // right of |from|. To the right is - 1, so we look that up
371                 // (remember our character could be more than one glyph, so we
372                 // can't look up our glyph and add one).
373                 afterGlyph = shaping.m_logs[fromChar - 1];
374             }
375         } else {
376             // Easy case, everybody agrees about directions. We only need to
377             // handle boundary conditions to get a range inclusive at the
378             // beginning, and exclusive at the ending. We have to do some
379             // computation to see the glyph one past the end.
380             fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar];
381             if (toChar >= shaping.charLength())
382                 afterGlyph = shaping.glyphLength();
383             else
384                 afterGlyph = shaping.m_logs[toChar];
385         }
386
387         // Account for the characters that were skipped in this run. When
388         // WebKit asks us to draw a subset of the run, it actually tells us
389         // to draw at the X offset of the beginning of the run, since it
390         // doesn't know the internal position of any of our characters.
391         const int* effectiveAdvances = shaping.effectiveAdvances();
392         int innerOffset = 0;
393         for (int i = 0; i < fromGlyph; i++)
394             innerOffset += effectiveAdvances[i];
395
396         // Actually draw the glyphs we found.
397         int glyphCount = afterGlyph - fromGlyph;
398         if (fromGlyph >= 0 && glyphCount > 0) {
399             // Account for the preceding space we need to add to this run. We
400             // don't need to count for the following space because that will be
401             // counted in advanceForItem below when we move to the next run.
402             innerOffset += shaping.m_prePadding;
403
404             // Pass 0 in when there is no justification.
405             const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph];
406
407 #if USE(SKIA_TEXT)
408             const int* advances = shaping.m_justify.size() ?
409                                       &shaping.m_justify[fromGlyph]
410                                     : &shaping.m_advance[fromGlyph];
411 #else
412             if (useWindowsDrawing) {
413                 if (firstRun) {
414                     oldFont = SelectObject(dc, shaping.m_hfont);
415                     firstRun = false;
416                 } else
417                     SelectObject(dc, shaping.m_hfont);
418             }
419
420 #endif
421             // Fonts with different ascents can be used to render different
422             // runs.  'Across-runs' y-coordinate correction needs to be
423             // adjusted for each font.
424             bool textOutOk = false;
425             for (int executions = 0; executions < 2; ++executions) {
426 #if USE(SKIA_TEXT)
427                 SkPoint origin;
428                 origin.fX = curX + + innerOffset;
429                 origin.fY = y + m_ascent;
430                 paintSkiaText(graphicsContext,
431                               shaping.m_hfont,
432                               glyphCount,
433                               &shaping.m_glyphs[fromGlyph],
434                               advances,
435                               &shaping.m_offsets[fromGlyph],
436                               &origin);
437                 textOutOk = true;
438 #else
439                 if (useWindowsDrawing) {
440                     HRESULT hr = ScriptTextOut(dc, shaping.m_scriptCache,
441                                                curX + innerOffset,
442                                                y - shaping.m_ascentOffset,
443                                                0, 0, &item.a, 0, 0,
444                                                &shaping.m_glyphs[fromGlyph],
445                                                glyphCount,
446                                                &shaping.m_advance[fromGlyph],
447                                                justify,
448                                                &shaping.m_offsets[fromGlyph]);
449                     textOutOk = (hr == S_OK);
450                 } else {
451                     SkPoint origin;
452                     origin.fX = curX + + innerOffset;
453                     origin.fY = y + m_ascent;
454                     paintSkiaText(graphicsContext,
455                                   shaping.m_hfont,
456                                   glyphCount,
457                                   &shaping.m_glyphs[fromGlyph],
458                                   &shaping.m_advance[fromGlyph],
459                                   &shaping.m_offsets[fromGlyph],
460                                   &origin);
461                     textOutOk = true;
462                 }
463 #endif
464
465                 if (!textOutOk && 0 == executions) {
466                     // If TextOut is called from the renderer it might fail
467                     // because the sandbox is preventing it from opening the
468                     // font files.  If we are running in the renderer,
469                     // TryToPreloadFont is overridden to ask the browser to
470                     // preload the font for us so we can access it.
471                     tryToPreloadFont(shaping.m_hfont);
472                     continue;
473                 }
474                 break;
475             }
476         }
477
478         curX += advanceForItem(itemIndex);
479     }
480
481     if (oldFont)
482         SelectObject(dc, oldFont);
483 }
484
485 WORD UniscribeHelper::firstGlyphForCharacter(int charOffset) const
486 {
487     // Find the run for the given character.
488     for (int i = 0; i < static_cast<int>(m_runs.size()); i++) {
489         int firstChar = m_runs[i].iCharPos;
490         const Shaping& shaping = m_shapes[i];
491         int localOffset = charOffset - firstChar;
492         if (localOffset >= 0 && localOffset < shaping.charLength()) {
493             // The character is in this run, return the first glyph for it
494             // (should generally be the only glyph). It seems Uniscribe gives
495             // glyph 0 for empty, which is what we want to return in the
496             // "missing" case.
497             size_t glyphIndex = shaping.m_logs[localOffset];
498             if (glyphIndex >= shaping.m_glyphs.size()) {
499                 // The glyph should be in this run, but the run has too few
500                 // actual characters. This can happen when shaping the run
501                 // fails, in which case, we should have no data in the logs at
502                 // all.
503                 ASSERT(shaping.m_glyphs.size() == 0);
504                 return 0;
505             }
506             return shaping.m_glyphs[glyphIndex];
507         }
508     }
509
510     return 0;
511 }
512
513 void UniscribeHelper::fillRuns()
514 {
515     HRESULT hr;
516     m_runs.resize(cUniscribeHelperStackRuns);
517     m_scriptTags.resize(cUniscribeHelperStackRuns);
518
519     SCRIPT_STATE inputState;
520     inputState.uBidiLevel = m_isRtl;
521     inputState.fOverrideDirection = m_directionalOverride;
522     inputState.fInhibitSymSwap = false;
523     inputState.fCharShape = false;  // Not implemented in Uniscribe
524     inputState.fDigitSubstitute = false;  // Do we want this for Arabic?
525     inputState.fInhibitLigate = m_inhibitLigate;
526     inputState.fDisplayZWG = false;  // Don't draw control characters.
527     inputState.fArabicNumContext = m_isRtl;  // Do we want this for Arabic?
528     inputState.fGcpClusters = false;
529     inputState.fReserved = 0;
530     inputState.fEngineReserved = 0;
531     // The psControl argument to ScriptItemize should be non-0 for RTL text,
532     // per http://msdn.microsoft.com/en-us/library/ms776532.aspx . So use a
533     // SCRIPT_CONTROL that is set to all zeros.  Zero as a locale ID means the
534     // neutral locale per http://msdn.microsoft.com/en-us/library/ms776294.aspx
535     static SCRIPT_CONTROL inputControl = {0, // uDefaultLanguage    :16;
536                                            0, // fContextDigits      :1;
537                                            0, // fInvertPreBoundDir  :1;
538                                            0, // fInvertPostBoundDir :1;
539                                            0, // fLinkStringBefore   :1;
540                                            0, // fLinkStringAfter    :1;
541                                            0, // fNeutralOverride    :1;
542                                            0, // fNumericOverride    :1;
543                                            0, // fLegacyBidiClass    :1;
544                                            1, // fMergeNeutralItems  :1;
545                                            0};// fReserved           :7;
546     // Calling ScriptApplyDigitSubstitution( 0, &inputControl, &inputState)
547     // here would be appropriate if we wanted to set the language ID, and get
548     // local digit substitution behavior.  For now, don't do it.
549
550     while (true) {
551         int numberOfItems = 0;
552
553         // Ideally, we would have a way to know the runs before and after this
554         // one, and put them into the control parameter of ScriptItemize. This
555         // would allow us to shape characters properly that cross style
556         // boundaries (WebKit bug 6148).
557         //
558         // We tell ScriptItemize that the output list of items is one smaller
559         // than it actually is. According to Mozilla bug 366643, if there is
560         // not enough room in the array on pre-SP2 systems, ScriptItemize will
561         // write one past the end of the buffer.
562         //
563         // ScriptItemize is very strange. It will often require a much larger
564         // ITEM buffer internally than it will give us as output. For example,
565         // it will say a 16-item buffer is not big enough, and will write
566         // interesting numbers into all those items. But when we give it a 32
567         // item buffer and it succeeds, it only has one item output.
568         //
569         // It seems to be doing at least two passes, the first where it puts a
570         // lot of intermediate data into our items, and the second where it
571         // collates them.
572         if (gScriptItemizeOpenTypeFunc) {
573             hr = gScriptItemizeOpenTypeFunc(m_input, m_inputLength,
574                                             static_cast<int>(m_runs.size()) - 1,
575                                             &inputControl, &inputState,
576                                             &m_runs[0], &m_scriptTags[0],
577                                             &numberOfItems);
578         } else {
579             hr = ScriptItemize(m_input, m_inputLength,
580                                static_cast<int>(m_runs.size()) - 1,
581                                &inputControl, &inputState, &m_runs[0],
582                                &numberOfItems);
583         }
584         if (SUCCEEDED(hr)) {
585             m_runs.resize(numberOfItems);
586             break;
587         }
588         if (hr != E_OUTOFMEMORY) {
589             // Some kind of unexpected error.
590             m_runs.resize(0);
591             break;
592         }
593         // There was not enough items for it to write into, expand.
594         m_runs.resize(m_runs.size() * 2);
595         m_scriptTags.resize(m_runs.size());
596     }
597 }
598
599 bool UniscribeHelper::shape(const UChar* input,
600                             int itemLength,
601                             int numGlyphs,
602                             SCRIPT_ITEM& run,
603                             OPENTYPE_TAG scriptTag,
604                             Shaping& shaping)
605 {
606     HFONT hfont = m_hfont;
607     SCRIPT_CACHE* scriptCache = m_scriptCache;
608     SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties;
609     Vector<SCRIPT_CHARPROP, cUniscribeHelperStackChars> charProps;
610     Vector<SCRIPT_GLYPHPROP, cUniscribeHelperStackChars> glyphProps;
611     int ascent = m_ascent;
612     WORD spaceGlyph = m_spaceGlyph;
613     HRESULT hr;
614     // When used to fill up glyph pages for simple scripts in non-BMP,
615     // we don't want any font fallback in this class. The simple script
616     // font path can take care of font fallback.
617     bool lastFallbackTried = m_disableFontFallback;
618     bool result;
619
620     int generatedGlyphs = 0;
621
622     // In case HFONT passed in ctor cannot render this run, we have to scan
623     // other fonts from the beginning of the font list.
624     resetFontIndex();
625
626     // Compute shapes.
627     while (true) {
628         shaping.m_logs.resize(itemLength);
629         shaping.m_glyphs.resize(numGlyphs);
630         shaping.m_visualAttributes.resize(numGlyphs);
631         charProps.resize(itemLength);
632         glyphProps.resize(numGlyphs);
633         run.a.fNoGlyphIndex = FALSE;
634
635 #ifdef PURIFY
636         // http://code.google.com/p/chromium/issues/detail?id=5309
637         // Purify isn't able to track the assignments that ScriptShape makes to
638         // shaping.m_glyphs. Consequently, any bytes with value 0xCD that it
639         // writes, will be considered un-initialized data.
640         //
641         // This hack avoid the false-positive UMRs by marking the buffer as
642         // initialized.
643         //
644         // FIXME: A better solution would be to use Purify's API and mark only
645         // the populated range as initialized:
646         //
647         //     PurifyMarkAsInitialized(
648         //         &shaping.m_glyphs[0],
649         //         sizeof(shaping.m_glyphs[0] * generatedGlyphs);
650
651         ZeroMemory(&shaping.m_glyphs[0],
652                    sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size());
653 #endif
654         // If our DC is already created, select the font in it so we can use it now.
655         // Otherwise, we'll create it as needed afterward...
656         if (m_cachedDC)
657             SelectObject(m_cachedDC, hfont);
658
659         // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true
660         // here. Is that what we want? It will display control characters.
661         if (gScriptShapeOpenTypeFunc) {
662             TEXTRANGE_PROPERTIES* rangeProps = m_featureRecords.size() ? &m_rangeProperties : 0;
663             hr = gScriptShapeOpenTypeFunc(m_cachedDC, scriptCache, &run.a,
664                                           scriptTag, 0, &itemLength,
665                                           &rangeProps, rangeProps ? 1 : 0,
666                                           input, itemLength, numGlyphs,
667                                           &shaping.m_logs[0], &charProps[0],
668                                           &shaping.m_glyphs[0], &glyphProps[0],
669                                           &generatedGlyphs);
670         } else {
671             hr = ScriptShape(m_cachedDC, scriptCache, input, itemLength,
672                              numGlyphs, &run.a,
673                              &shaping.m_glyphs[0], &shaping.m_logs[0],
674                              &shaping.m_visualAttributes[0], &generatedGlyphs);
675         }
676         // We receive E_PENDING when we need to try again with a Drawing Context,
677         // but we don't want to retry again if we already tried with non-zero DC.
678         if (hr == E_PENDING && !m_cachedDC) {
679             EnsureCachedDCCreated();
680             continue;
681         }
682         if (hr == E_OUTOFMEMORY) {
683             numGlyphs *= 2;
684             continue;
685         }
686         if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(shaping, run, fontProperties) && canUseGlyphIndex(run)))
687             break;
688
689         // The current font can't render this run, try next font.
690         if (!m_disableFontFallback &&
691             nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) {
692             // The primary font does not support this run. Try next font.
693             // In case of web page rendering, they come from fonts specified in
694             // CSS stylesheets.
695             continue;
696         } else if (!lastFallbackTried) {
697             lastFallbackTried = true;
698
699             // Generate a last fallback font based on the script of
700             // a character to draw while inheriting size and styles
701             // from the primary font
702             if (!m_logfont.lfFaceName[0])
703                 setLogFontAndStyle(m_hfont, &m_logfont, &m_style);
704
705             // TODO(jungshik): generic type should come from webkit for
706             // UniscribeHelperTextRun (a derived class used in webkit).
707             const UChar *family = getFallbackFamily(input, itemLength,
708                 FontDescription::StandardFamily, 0, 0);
709             bool fontOk = getDerivedFontData(family, m_style, &m_logfont,
710                                              &ascent, &hfont, &scriptCache,
711                                              &spaceGlyph);
712                                               
713
714             if (!fontOk) {
715                 // If this GetDerivedFontData is called from the renderer it
716                 // might fail because the sandbox is preventing it from opening
717                 // the font files.  If we are running in the renderer,
718                 // TryToPreloadFont is overridden to ask the browser to preload
719                 // the font for us so we can access it.
720                 tryToPreloadFont(hfont);
721
722                 // Try again.
723                 fontOk = getDerivedFontData(family, m_style, &m_logfont,
724                                             &ascent, &hfont, &scriptCache,
725                                             &spaceGlyph);
726                 ASSERT(fontOk);
727             }
728
729             // TODO(jungshik) : Currently GetDerivedHFont always returns a
730             // a valid HFONT, but in the future, I may change it to return 0.
731             ASSERT(hfont);
732
733             // We don't need a font_properties for the last resort fallback font
734             // because we don't have anything more to try and are forced to
735             // accept empty glyph boxes. If we tried a series of fonts as
736             // 'last-resort fallback', we'd need it, but currently, we don't.
737             continue;
738         } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
739             run.a.eScript = SCRIPT_UNDEFINED;
740             continue;
741         } else if (FAILED(hr)) {
742             // Error shaping.
743             generatedGlyphs = 0;
744             result = false;
745             goto cleanup;
746         }
747     }
748
749     // Sets Windows font data for this run to those corresponding to
750     // a font supporting this run. we don't need to store font_properties
751     // because it's not used elsewhere.
752     shaping.m_hfont = hfont;
753     shaping.m_scriptCache = scriptCache;
754     shaping.m_spaceGlyph = spaceGlyph;
755
756     // The ascent of a font for this run can be different from
757     // that of the primary font so that we need to keep track of
758     // the difference per run and take that into account when calling
759     // ScriptTextOut in |draw|. Otherwise, different runs rendered by
760     // different fonts would not be aligned vertically.
761     shaping.m_ascentOffset = m_ascent ? ascent - m_ascent : 0;
762     result = true;
763
764   cleanup:
765     shaping.m_glyphs.resize(generatedGlyphs);
766     shaping.m_visualAttributes.resize(generatedGlyphs);
767     // If we use ScriptShapeOpenType(), visual attributes information for each
768     // characters are stored in |glyphProps[i].sva|.
769     if (gScriptShapeOpenTypeFunc) {
770         for (int i = 0; i < generatedGlyphs; ++i)
771             memcpy(&shaping.m_visualAttributes[i], &glyphProps[i].sva, sizeof(SCRIPT_VISATTR));
772     }
773     shaping.m_advance.resize(generatedGlyphs);
774     shaping.m_offsets.resize(generatedGlyphs);
775
776     // On failure, our logs don't mean anything, so zero those out.
777     if (!result)
778         shaping.m_logs.clear();
779
780     return result;
781 }
782
783 void UniscribeHelper::EnsureCachedDCCreated()
784 {
785     if (m_cachedDC)
786         return;
787     // Allocate a memory DC that is compatible with the Desktop DC since we don't have any window,
788     // and we don't want to use the Desktop DC directly since it can have nasty side effects
789     // as identified in Chrome Issue http://crbug.com/59315.
790     HWndDC screenDC(0);
791     m_cachedDC = ::CreateCompatibleDC(screenDC);
792     ASSERT(m_cachedDC);
793 }
794
795 void UniscribeHelper::fillShapes()
796 {
797     m_shapes.resize(m_runs.size());
798     for (size_t i = 0; i < m_runs.size(); i++) {
799         int startItem = m_runs[i].iCharPos;
800         int itemLength = m_inputLength - startItem;
801         if (i < m_runs.size() - 1)
802             itemLength = m_runs[i + 1].iCharPos - startItem;
803
804         int numGlyphs;
805         if (itemLength < cUniscribeHelperStackChars) {
806             // We'll start our buffer sizes with the current stack space
807             // available in our buffers if the current input fits. As long as
808             // it doesn't expand past that we'll save a lot of time mallocing.
809             numGlyphs = cUniscribeHelperStackChars;
810         } else {
811             // When the input doesn't fit, give up with the stack since it will
812             // almost surely not be enough room (unless the input actually
813             // shrinks, which is unlikely) and just start with the length
814             // recommended by the Uniscribe documentation as a "usually fits"
815             // size.
816             numGlyphs = itemLength * 3 / 2 + 16;
817         }
818
819         // Convert a string to a glyph string trying the primary font, fonts in
820         // the fallback list and then script-specific last resort font.
821         Shaping& shaping = m_shapes[i];
822         if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], m_scriptTags[i], shaping))
823             continue;
824
825         // At the moment, the only time m_disableFontFallback is set is
826         // when we look up glyph indices for non-BMP code ranges. So,
827         // we can skip the glyph placement. When that becomes not the case
828         // any more, we have to add a new flag to control glyph placement.
829         if (m_disableFontFallback)
830           continue;
831
832         // Compute placements. Note that offsets is documented incorrectly
833         // and is actually an array.
834         EnsureCachedDCCreated();
835         SelectObject(m_cachedDC, shaping.m_hfont);
836         shaping.m_prePadding = 0;
837         if (FAILED(ScriptPlace(m_cachedDC, shaping.m_scriptCache,
838                                &shaping.m_glyphs[0],
839                                static_cast<int>(shaping.m_glyphs.size()),
840                                &shaping.m_visualAttributes[0], &m_runs[i].a,
841                                &shaping.m_advance[0], &shaping.m_offsets[0],
842                                &shaping.m_abc))) {
843             // Some error we don't know how to handle. Nuke all of our data
844             // since we can't deal with partially valid data later.
845             m_runs.clear();
846             m_scriptTags.clear();
847             m_shapes.clear();
848             m_screenOrder.clear();
849         }
850     }
851
852     adjustSpaceAdvances();
853
854     if (m_letterSpacing != 0 || m_wordSpacing != 0)
855         applySpacing();
856 }
857
858 void UniscribeHelper::fillScreenOrder()
859 {
860     m_screenOrder.resize(m_runs.size());
861
862     // We assume that the input has only one text direction in it.
863     // TODO(brettw) are we sure we want to keep this restriction?
864     if (m_isRtl) {
865         for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++)
866             m_screenOrder[static_cast<int>(m_screenOrder.size()) - i - 1] = i;
867     } else {
868         for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++)
869             m_screenOrder[i] = i;
870     }
871 }
872
873 void UniscribeHelper::adjustSpaceAdvances()
874 {
875     if (m_spaceWidth == 0)
876         return;
877
878     int spaceWidthWithoutLetterSpacing = m_spaceWidth - m_letterSpacing;
879
880     // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem.
881     for (size_t run = 0; run < m_runs.size(); run++) {
882         Shaping& shaping = m_shapes[run];
883
884         // FIXME: This loop is not UTF-16-safe. Unicode 6.0 has a couple
885         // of complex script blocks in Plane 1.
886         for (int i = 0; i < shaping.charLength(); i++) {
887             UChar c = m_input[m_runs[run].iCharPos + i];
888             bool treatAsSpace = Font::treatAsSpace(c);
889             if (!treatAsSpace && !Font::treatAsZeroWidthSpaceInComplexScript(c))
890                 continue;
891
892             int glyphIndex = shaping.m_logs[i];
893             int currentAdvance = shaping.m_advance[glyphIndex];
894
895             if (treatAsSpace) {
896                 // currentAdvance does not include additional letter-spacing,
897                 // but m_spaceWidth does. Here we find out how off we are from
898                 // the correct width (spaceWidthWithoutLetterSpacing) and
899                 // just subtract that diff.
900                 int diff = currentAdvance - spaceWidthWithoutLetterSpacing;
901                 // The shaping can consist of a run of text, so only subtract
902                 // the difference in the width of the glyph.
903                 shaping.m_advance[glyphIndex] -= diff;
904                 shaping.m_abc.abcB -= diff;
905                 continue;
906             }
907
908             // For characters treated as zero-width space in complex
909             // scripts, set the advance width to zero, adjust
910             // |abcB| of the current run accordingly and set 
911             // the glyph to m_spaceGlyph (invisible).
912             shaping.m_advance[glyphIndex] = 0;
913             shaping.m_abc.abcB -= currentAdvance;
914             shaping.m_offsets[glyphIndex].du = 0;
915             shaping.m_offsets[glyphIndex].dv = 0;
916             shaping.m_glyphs[glyphIndex] = shaping.m_spaceGlyph;
917         }
918     }
919 }
920
921 void UniscribeHelper::applySpacing()
922 {
923     for (size_t run = 0; run < m_runs.size(); run++) {
924         Shaping& shaping = m_shapes[run];
925         bool isRtl = m_runs[run].a.fRTL;
926
927         if (m_letterSpacing != 0) {
928             // RTL text gets padded to the left of each character. We increment
929             // the run's advance to make this happen. This will be balanced out
930             // by NOT adding additional advance to the last glyph in the run.
931             if (isRtl)
932                 shaping.m_prePadding += m_letterSpacing;
933
934             // Go through all the glyphs in this run and increase the "advance"
935             // to account for letter spacing. We adjust letter spacing only on
936             // cluster boundaries.
937             //
938             // This works for most scripts, but may have problems with some
939             // indic scripts. This behavior is better than Firefox or IE for
940             // Hebrew.
941             for (int i = 0; i < shaping.glyphLength(); i++) {
942                 if (shaping.m_visualAttributes[i].fClusterStart) {
943                     // Ick, we need to assign the extra space so that the glyph
944                     // comes first, then is followed by the space. This is
945                     // opposite for RTL.
946                     if (isRtl) {
947                         if (i != shaping.glyphLength() - 1) {
948                             // All but the last character just get the spacing
949                             // applied to their advance. The last character
950                             // doesn't get anything,
951                             shaping.m_advance[i] += m_letterSpacing;
952                             shaping.m_abc.abcB += m_letterSpacing;
953                         }
954                     } else {
955                         // LTR case is easier, we just add to the advance.
956                         shaping.m_advance[i] += m_letterSpacing;
957                         shaping.m_abc.abcB += m_letterSpacing;
958                     }
959                 }
960             }
961         }
962
963         // Go through all the characters to find whitespace and insert the
964         // extra wordspacing amount for the glyphs they correspond to.
965         if (m_wordSpacing != 0) {
966             for (int i = 0; i < shaping.charLength(); i++) {
967                 if (!Font::treatAsSpace(m_input[m_runs[run].iCharPos + i]))
968                     continue;
969
970                 // The char in question is a word separator...
971                 int glyphIndex = shaping.m_logs[i];
972
973                 // Spaces will not have a glyph in Uniscribe, it will just add
974                 // additional advance to the character to the left of the
975                 // space. The space's corresponding glyph will be the character
976                 // following it in reading order.
977                 if (isRtl) {
978                     // In RTL, the glyph to the left of the space is the same
979                     // as the first glyph of the following character, so we can
980                     // just increment it.
981                     shaping.m_advance[glyphIndex] += m_wordSpacing;
982                     shaping.m_abc.abcB += m_wordSpacing;
983                 } else {
984                     // LTR is actually more complex here, we apply it to the
985                     // previous character if there is one, otherwise we have to
986                     // apply it to the leading space of the run.
987                     if (glyphIndex == 0)
988                         shaping.m_prePadding += m_wordSpacing;
989                     else {
990                         shaping.m_advance[glyphIndex - 1] += m_wordSpacing;
991                         shaping.m_abc.abcB += m_wordSpacing;
992                     }
993                 }
994             }
995         }  // m_wordSpacing != 0
996
997         // Loop for next run...
998     }
999 }
1000
1001 // The advance is the ABC width of the run
1002 int UniscribeHelper::advanceForItem(int itemIndex) const
1003 {
1004     int accum = 0;
1005     const Shaping& shaping = m_shapes[itemIndex];
1006
1007     if (shaping.m_justify.size() == 0) {
1008         // Easy case with no justification, the width is just the ABC width of
1009         // the run. (The ABC width is the sum of the advances).
1010         return shaping.m_abc.abcA + shaping.m_abc.abcB +
1011                shaping.m_abc.abcC + shaping.m_prePadding;
1012     }
1013
1014     // With justification, we use the justified amounts instead. The
1015     // justification array contains both the advance and the extra space
1016     // added for justification, so is the width we want.
1017     int justification = 0;
1018     for (size_t i = 0; i < shaping.m_justify.size(); i++)
1019         justification += shaping.m_justify[i];
1020
1021     return shaping.m_prePadding + justification;
1022 }
1023
1024 // SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid
1025 // and blank glyphs. Just because ScriptShape succeeds does not mean
1026 // that a text run is rendered correctly. Some characters may be rendered
1027 // with default/invalid/blank glyphs. Therefore, we need to check if the glyph
1028 // array returned by ScriptShape contains any of those glyphs to make
1029 // sure that the text run is rendered successfully.
1030 // However, we should not subject zero-width characters to this test.
1031
1032 bool UniscribeHelper::containsMissingGlyphs(const Shaping& shaping,
1033                                             const SCRIPT_ITEM& run,
1034                                             const SCRIPT_FONTPROPERTIES* properties) const
1035 {
1036     for (int i = 0; i < shaping.charLength(); i++) {
1037         UChar c = m_input[run.iCharPos + i];
1038         // Skip zero-width space characters because they're not considered to be missing in a font.
1039         if (Font::treatAsZeroWidthSpaceInComplexScript(c))
1040             continue;
1041         int glyphIndex = shaping.m_logs[i];
1042         WORD glyph = shaping.m_glyphs[glyphIndex];
1043         if (glyph == properties->wgDefault
1044             || (glyph == properties->wgInvalid && glyph != properties->wgBlank))
1045             return true;
1046     }
1047     return false;
1048 }
1049
1050 static OPENTYPE_TAG convertFeatureTag(const String& tag)
1051 {
1052     return ((tag[0] & 0xFF) | ((tag[1] & 0xFF) << 8) | ((tag[2] & 0xFF) << 16) | ((tag[3] & 0xFF) << 24));
1053 }
1054
1055 void UniscribeHelper::setRangeProperties(const FontFeatureSettings* featureSettings)
1056 {
1057     if (!featureSettings || !featureSettings->size()) {
1058         m_featureRecords.resize(0);
1059         return;
1060     }
1061
1062     m_featureRecords.resize(featureSettings->size());
1063     for (unsigned i = 0; i < featureSettings->size(); ++i) {
1064         m_featureRecords[i].lParameter = featureSettings->at(i).value();
1065         m_featureRecords[i].tagFeature = convertFeatureTag(featureSettings->at(i).tag());
1066     }
1067     m_rangeProperties.potfRecords = &m_featureRecords[0];
1068     m_rangeProperties.cotfRecords = m_featureRecords.size();
1069 }
1070
1071 }  // namespace WebCore