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