Home | History | Annotate | Download | only in chromium
      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     bool useWindowsDrawing = windowsCanHandleTextDrawing(graphicsContext);
    273 
    274     for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
    275         int itemIndex = m_screenOrder[screenIndex];
    276         const SCRIPT_ITEM& item = m_runs[itemIndex];
    277         const Shaping& shaping = m_shapes[itemIndex];
    278 
    279         // Character offsets within this run. THESE MAY NOT BE IN RANGE and may
    280         // be negative, etc. The code below handles this.
    281         int fromChar = from - item.iCharPos;
    282         int toChar = to - item.iCharPos;
    283 
    284         // See if we need to draw any characters in this item.
    285         if (shaping.charLength() == 0 ||
    286             fromChar >= shaping.charLength() || toChar <= 0) {
    287             // No chars in this item to display.
    288             curX += advanceForItem(itemIndex);
    289             continue;
    290         }
    291 
    292         // Compute the starting glyph within this span. |from| and |to| are
    293         // global offsets that may intersect arbitrarily with our local run.
    294         int fromGlyph, afterGlyph;
    295         if (item.a.fRTL) {
    296             // To compute the first glyph when going RTL, we use |to|.
    297             if (toChar >= shaping.charLength())
    298                 // The end of the text is after (to the left) of us.
    299                 fromGlyph = 0;
    300             else {
    301                 // Since |to| is exclusive, the first character we draw on the
    302                 // left is actually the one right before (to the right) of
    303                 // |to|.
    304                 fromGlyph = shaping.m_logs[toChar - 1];
    305             }
    306 
    307             // The last glyph is actually the first character in the range.
    308             if (fromChar <= 0) {
    309                 // The first character to draw is before (to the right) of this
    310                 // span, so draw all the way to the end.
    311                 afterGlyph = shaping.glyphLength();
    312             } else {
    313                 // We want to draw everything up until the character to the
    314                 // right of |from|. To the right is - 1, so we look that up
    315                 // (remember our character could be more than one glyph, so we
    316                 // can't look up our glyph and add one).
    317                 afterGlyph = shaping.m_logs[fromChar - 1];
    318             }
    319         } else {
    320             // Easy case, everybody agrees about directions. We only need to
    321             // handle boundary conditions to get a range inclusive at the
    322             // beginning, and exclusive at the ending. We have to do some
    323             // computation to see the glyph one past the end.
    324             fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar];
    325             if (toChar >= shaping.charLength())
    326                 afterGlyph = shaping.glyphLength();
    327             else
    328                 afterGlyph = shaping.m_logs[toChar];
    329         }
    330 
    331         // Account for the characters that were skipped in this run. When
    332         // WebKit asks us to draw a subset of the run, it actually tells us
    333         // to draw at the X offset of the beginning of the run, since it
    334         // doesn't know the internal position of any of our characters.
    335         const int* effectiveAdvances = shaping.effectiveAdvances();
    336         int innerOffset = 0;
    337         for (int i = 0; i < fromGlyph; i++)
    338             innerOffset += effectiveAdvances[i];
    339 
    340         // Actually draw the glyphs we found.
    341         int glyphCount = afterGlyph - fromGlyph;
    342         if (fromGlyph >= 0 && glyphCount > 0) {
    343             // Account for the preceding space we need to add to this run. We
    344             // don't need to count for the following space because that will be
    345             // counted in advanceForItem below when we move to the next run.
    346             innerOffset += shaping.m_prePadding;
    347 
    348             // Pass 0 in when there is no justification.
    349             const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph];
    350 
    351             if (useWindowsDrawing) {
    352                 if (firstRun) {
    353                     oldFont = SelectObject(dc, shaping.m_hfont);
    354                     firstRun = false;
    355                 } else
    356                     SelectObject(dc, shaping.m_hfont);
    357             }
    358 
    359             // Fonts with different ascents can be used to render different
    360             // runs.  'Across-runs' y-coordinate correction needs to be
    361             // adjusted for each font.
    362             bool textOutOk = false;
    363             for (int executions = 0; executions < 2; ++executions) {
    364                 if (useWindowsDrawing) {
    365                     HRESULT hr = ScriptTextOut(dc, shaping.m_scriptCache,
    366                                                curX + innerOffset,
    367                                                y - shaping.m_ascentOffset,
    368                                                0, 0, &item.a, 0, 0,
    369                                                &shaping.m_glyphs[fromGlyph],
    370                                                glyphCount,
    371                                                &shaping.m_advance[fromGlyph],
    372                                                justify,
    373                                                &shaping.m_offsets[fromGlyph]);
    374                     textOutOk = (hr == S_OK);
    375                 } else {
    376                     SkPoint origin;
    377                     origin.fX = curX + + innerOffset;
    378                     origin.fY = y + m_ascent;
    379                     textOutOk = paintSkiaText(graphicsContext,
    380                                               shaping.m_hfont,
    381                                               glyphCount,
    382                                               &shaping.m_glyphs[fromGlyph],
    383                                               &shaping.m_advance[fromGlyph],
    384                                               &shaping.m_offsets[fromGlyph],
    385                                               &origin);
    386                 }
    387 
    388                 if (!textOutOk && 0 == executions) {
    389                     // If TextOut is called from the renderer it might fail
    390                     // because the sandbox is preventing it from opening the
    391                     // font files.  If we are running in the renderer,
    392                     // TryToPreloadFont is overridden to ask the browser to
    393                     // preload the font for us so we can access it.
    394                     tryToPreloadFont(shaping.m_hfont);
    395                     continue;
    396                 }
    397                 break;
    398             }
    399         }
    400 
    401         curX += advanceForItem(itemIndex);
    402     }
    403 
    404     if (oldFont)
    405         SelectObject(dc, oldFont);
    406 }
    407 
    408 WORD UniscribeHelper::firstGlyphForCharacter(int charOffset) const
    409 {
    410     // Find the run for the given character.
    411     for (int i = 0; i < static_cast<int>(m_runs.size()); i++) {
    412         int firstChar = m_runs[i].iCharPos;
    413         const Shaping& shaping = m_shapes[i];
    414         int localOffset = charOffset - firstChar;
    415         if (localOffset >= 0 && localOffset < shaping.charLength()) {
    416             // The character is in this run, return the first glyph for it
    417             // (should generally be the only glyph). It seems Uniscribe gives
    418             // glyph 0 for empty, which is what we want to return in the
    419             // "missing" case.
    420             size_t glyphIndex = shaping.m_logs[localOffset];
    421             if (glyphIndex >= shaping.m_glyphs.size()) {
    422                 // The glyph should be in this run, but the run has too few
    423                 // actual characters. This can happen when shaping the run
    424                 // fails, in which case, we should have no data in the logs at
    425                 // all.
    426                 ASSERT(shaping.m_glyphs.size() == 0);
    427                 return 0;
    428             }
    429             return shaping.m_glyphs[glyphIndex];
    430         }
    431     }
    432 
    433     return 0;
    434 }
    435 
    436 void UniscribeHelper::fillRuns()
    437 {
    438     HRESULT hr;
    439     m_runs.resize(UNISCRIBE_HELPER_STACK_RUNS);
    440 
    441     SCRIPT_STATE inputState;
    442     inputState.uBidiLevel = m_isRtl;
    443     inputState.fOverrideDirection = m_directionalOverride;
    444     inputState.fInhibitSymSwap = false;
    445     inputState.fCharShape = false;  // Not implemented in Uniscribe
    446     inputState.fDigitSubstitute = false;  // Do we want this for Arabic?
    447     inputState.fInhibitLigate = m_inhibitLigate;
    448     inputState.fDisplayZWG = false;  // Don't draw control characters.
    449     inputState.fArabicNumContext = m_isRtl;  // Do we want this for Arabic?
    450     inputState.fGcpClusters = false;
    451     inputState.fReserved = 0;
    452     inputState.fEngineReserved = 0;
    453     // The psControl argument to ScriptItemize should be non-0 for RTL text,
    454     // per http://msdn.microsoft.com/en-us/library/ms776532.aspx . So use a
    455     // SCRIPT_CONTROL that is set to all zeros.  Zero as a locale ID means the
    456     // neutral locale per http://msdn.microsoft.com/en-us/library/ms776294.aspx
    457     static SCRIPT_CONTROL inputControl = {0, // uDefaultLanguage    :16;
    458                                            0, // fContextDigits      :1;
    459                                            0, // fInvertPreBoundDir  :1;
    460                                            0, // fInvertPostBoundDir :1;
    461                                            0, // fLinkStringBefore   :1;
    462                                            0, // fLinkStringAfter    :1;
    463                                            0, // fNeutralOverride    :1;
    464                                            0, // fNumericOverride    :1;
    465                                            0, // fLegacyBidiClass    :1;
    466                                            0, // fMergeNeutralItems  :1;
    467                                            0};// fReserved           :7;
    468     // Calling ScriptApplyDigitSubstitution( 0, &inputControl, &inputState)
    469     // here would be appropriate if we wanted to set the language ID, and get
    470     // local digit substitution behavior.  For now, don't do it.
    471 
    472     while (true) {
    473         int numberOfItems = 0;
    474 
    475         // Ideally, we would have a way to know the runs before and after this
    476         // one, and put them into the control parameter of ScriptItemize. This
    477         // would allow us to shape characters properly that cross style
    478         // boundaries (WebKit bug 6148).
    479         //
    480         // We tell ScriptItemize that the output list of items is one smaller
    481         // than it actually is. According to Mozilla bug 366643, if there is
    482         // not enough room in the array on pre-SP2 systems, ScriptItemize will
    483         // write one past the end of the buffer.
    484         //
    485         // ScriptItemize is very strange. It will often require a much larger
    486         // ITEM buffer internally than it will give us as output. For example,
    487         // it will say a 16-item buffer is not big enough, and will write
    488         // interesting numbers into all those items. But when we give it a 32
    489         // item buffer and it succeeds, it only has one item output.
    490         //
    491         // It seems to be doing at least two passes, the first where it puts a
    492         // lot of intermediate data into our items, and the second where it
    493         // collates them.
    494         hr = ScriptItemize(m_input, m_inputLength,
    495                            static_cast<int>(m_runs.size()) - 1, &inputControl,
    496                            &inputState,
    497                            &m_runs[0], &numberOfItems);
    498         if (SUCCEEDED(hr)) {
    499             m_runs.resize(numberOfItems);
    500             break;
    501         }
    502         if (hr != E_OUTOFMEMORY) {
    503             // Some kind of unexpected error.
    504             m_runs.resize(0);
    505             break;
    506         }
    507         // There was not enough items for it to write into, expand.
    508         m_runs.resize(m_runs.size() * 2);
    509     }
    510 }
    511 
    512 bool UniscribeHelper::shape(const UChar* input,
    513                             int itemLength,
    514                             int numGlyphs,
    515                             SCRIPT_ITEM& run,
    516                             Shaping& shaping)
    517 {
    518     HFONT hfont = m_hfont;
    519     SCRIPT_CACHE* scriptCache = m_scriptCache;
    520     SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties;
    521     int ascent = m_ascent;
    522     WORD spaceGlyph = m_spaceGlyph;
    523     HDC tempDC = 0;
    524     HGDIOBJ oldFont = 0;
    525     HRESULT hr;
    526     // When used to fill up glyph pages for simple scripts in non-BMP,
    527     // we don't want any font fallback in this class. The simple script
    528     // font path can take care of font fallback.
    529     bool lastFallbackTried = m_disableFontFallback;
    530     bool result;
    531 
    532     int generatedGlyphs = 0;
    533 
    534     // In case HFONT passed in ctor cannot render this run, we have to scan
    535     // other fonts from the beginning of the font list.
    536     resetFontIndex();
    537 
    538     // Compute shapes.
    539     while (true) {
    540         shaping.m_logs.resize(itemLength);
    541         shaping.m_glyphs.resize(numGlyphs);
    542         shaping.m_visualAttributes.resize(numGlyphs);
    543 
    544 #ifdef PURIFY
    545         // http://code.google.com/p/chromium/issues/detail?id=5309
    546         // Purify isn't able to track the assignments that ScriptShape makes to
    547         // shaping.m_glyphs. Consequently, any bytes with value 0xCD that it
    548         // writes, will be considered un-initialized data.
    549         //
    550         // This hack avoid the false-positive UMRs by marking the buffer as
    551         // initialized.
    552         //
    553         // FIXME: A better solution would be to use Purify's API and mark only
    554         // the populated range as initialized:
    555         //
    556         //     PurifyMarkAsInitialized(
    557         //         &shaping.m_glyphs[0],
    558         //         sizeof(shaping.m_glyphs[0] * generatedGlyphs);
    559 
    560         ZeroMemory(&shaping.m_glyphs[0],
    561                    sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size());
    562 #endif
    563 
    564         // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true
    565         // here. Is that what we want? It will display control characters.
    566         hr = ScriptShape(tempDC, scriptCache, input, itemLength,
    567                          numGlyphs, &run.a,
    568                          &shaping.m_glyphs[0], &shaping.m_logs[0],
    569                          &shaping.m_visualAttributes[0], &generatedGlyphs);
    570         if (hr == E_PENDING) {
    571             // Allocate the DC.
    572             tempDC = GetDC(0);
    573             oldFont = SelectObject(tempDC, hfont);
    574             continue;
    575         } else if (hr == E_OUTOFMEMORY) {
    576             numGlyphs *= 2;
    577             continue;
    578         } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(shaping, run, fontProperties)))
    579             break;
    580 
    581         // The current font can't render this run. clear DC and try
    582         // next font.
    583         if (tempDC) {
    584             SelectObject(tempDC, oldFont);
    585             ReleaseDC(0, tempDC);
    586             tempDC = 0;
    587         }
    588 
    589         if (!m_disableFontFallback &&
    590             nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) {
    591             // The primary font does not support this run. Try next font.
    592             // In case of web page rendering, they come from fonts specified in
    593             // CSS stylesheets.
    594             continue;
    595         } else if (!lastFallbackTried) {
    596             lastFallbackTried = true;
    597 
    598             // Generate a last fallback font based on the script of
    599             // a character to draw while inheriting size and styles
    600             // from the primary font
    601             if (!m_logfont.lfFaceName[0])
    602                 setLogFontAndStyle(m_hfont, &m_logfont, &m_style);
    603 
    604             // TODO(jungshik): generic type should come from webkit for
    605             // UniscribeHelperTextRun (a derived class used in webkit).
    606             const UChar *family = getFallbackFamily(input, itemLength,
    607                 FontDescription::StandardFamily, 0, 0);
    608             bool fontOk = getDerivedFontData(family, m_style, &m_logfont,
    609                                              &ascent, &hfont, &scriptCache,
    610                                              &spaceGlyph);
    611 
    612 
    613             if (!fontOk) {
    614                 // If this GetDerivedFontData is called from the renderer it
    615                 // might fail because the sandbox is preventing it from opening
    616                 // the font files.  If we are running in the renderer,
    617                 // TryToPreloadFont is overridden to ask the browser to preload
    618                 // the font for us so we can access it.
    619                 tryToPreloadFont(hfont);
    620 
    621                 // Try again.
    622                 fontOk = getDerivedFontData(family, m_style, &m_logfont,
    623                                             &ascent, &hfont, &scriptCache,
    624                                             &spaceGlyph);
    625                 ASSERT(fontOk);
    626             }
    627 
    628             // TODO(jungshik) : Currently GetDerivedHFont always returns a
    629             // a valid HFONT, but in the future, I may change it to return 0.
    630             ASSERT(hfont);
    631 
    632             // We don't need a font_properties for the last resort fallback font
    633             // because we don't have anything more to try and are forced to
    634             // accept empty glyph boxes. If we tried a series of fonts as
    635             // 'last-resort fallback', we'd need it, but currently, we don't.
    636             continue;
    637         } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
    638             run.a.eScript = SCRIPT_UNDEFINED;
    639             continue;
    640         } else if (FAILED(hr)) {
    641             // Error shaping.
    642             generatedGlyphs = 0;
    643             result = false;
    644             goto cleanup;
    645         }
    646     }
    647 
    648     // Sets Windows font data for this run to those corresponding to
    649     // a font supporting this run. we don't need to store font_properties
    650     // because it's not used elsewhere.
    651     shaping.m_hfont = hfont;
    652     shaping.m_scriptCache = scriptCache;
    653     shaping.m_spaceGlyph = spaceGlyph;
    654 
    655     // The ascent of a font for this run can be different from
    656     // that of the primary font so that we need to keep track of
    657     // the difference per run and take that into account when calling
    658     // ScriptTextOut in |draw|. Otherwise, different runs rendered by
    659     // different fonts would not be aligned vertically.
    660     shaping.m_ascentOffset = m_ascent ? ascent - m_ascent : 0;
    661     result = true;
    662 
    663   cleanup:
    664     shaping.m_glyphs.resize(generatedGlyphs);
    665     shaping.m_visualAttributes.resize(generatedGlyphs);
    666     shaping.m_advance.resize(generatedGlyphs);
    667     shaping.m_offsets.resize(generatedGlyphs);
    668     if (tempDC) {
    669         SelectObject(tempDC, oldFont);
    670         ReleaseDC(0, tempDC);
    671     }
    672     // On failure, our logs don't mean anything, so zero those out.
    673     if (!result)
    674         shaping.m_logs.clear();
    675 
    676     return result;
    677 }
    678 
    679 void UniscribeHelper::fillShapes()
    680 {
    681     m_shapes.resize(m_runs.size());
    682     for (size_t i = 0; i < m_runs.size(); i++) {
    683         int startItem = m_runs[i].iCharPos;
    684         int itemLength = m_inputLength - startItem;
    685         if (i < m_runs.size() - 1)
    686             itemLength = m_runs[i + 1].iCharPos - startItem;
    687 
    688         int numGlyphs;
    689         if (itemLength < UNISCRIBE_HELPER_STACK_CHARS) {
    690             // We'll start our buffer sizes with the current stack space
    691             // available in our buffers if the current input fits. As long as
    692             // it doesn't expand past that we'll save a lot of time mallocing.
    693             numGlyphs = UNISCRIBE_HELPER_STACK_CHARS;
    694         } else {
    695             // When the input doesn't fit, give up with the stack since it will
    696             // almost surely not be enough room (unless the input actually
    697             // shrinks, which is unlikely) and just start with the length
    698             // recommended by the Uniscribe documentation as a "usually fits"
    699             // size.
    700             numGlyphs = itemLength * 3 / 2 + 16;
    701         }
    702 
    703         // Convert a string to a glyph string trying the primary font, fonts in
    704         // the fallback list and then script-specific last resort font.
    705         Shaping& shaping = m_shapes[i];
    706         if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], shaping))
    707             continue;
    708 
    709         // At the moment, the only time m_disableFontFallback is set is
    710         // when we look up glyph indices for non-BMP code ranges. So,
    711         // we can skip the glyph placement. When that becomes not the case
    712         // any more, we have to add a new flag to control glyph placement.
    713         if (m_disableFontFallback)
    714           continue;
    715 
    716         // Compute placements. Note that offsets is documented incorrectly
    717         // and is actually an array.
    718 
    719         // DC that we lazily create if Uniscribe commands us to.
    720         // (this does not happen often because scriptCache is already
    721         //  updated when calling ScriptShape).
    722         HDC tempDC = 0;
    723         HGDIOBJ oldFont = 0;
    724         HRESULT hr;
    725         while (true) {
    726             shaping.m_prePadding = 0;
    727             hr = ScriptPlace(tempDC, shaping.m_scriptCache,
    728                              &shaping.m_glyphs[0],
    729                              static_cast<int>(shaping.m_glyphs.size()),
    730                              &shaping.m_visualAttributes[0], &m_runs[i].a,
    731                              &shaping.m_advance[0], &shaping.m_offsets[0],
    732                              &shaping.m_abc);
    733             if (hr != E_PENDING)
    734                 break;
    735 
    736             // Allocate the DC and run the loop again.
    737             tempDC = GetDC(0);
    738             oldFont = SelectObject(tempDC, shaping.m_hfont);
    739         }
    740 
    741         if (FAILED(hr)) {
    742             // Some error we don't know how to handle. Nuke all of our data
    743             // since we can't deal with partially valid data later.
    744             m_runs.clear();
    745             m_shapes.clear();
    746             m_screenOrder.clear();
    747         }
    748 
    749         if (tempDC) {
    750             SelectObject(tempDC, oldFont);
    751             ReleaseDC(0, tempDC);
    752         }
    753     }
    754 
    755     adjustSpaceAdvances();
    756 
    757     if (m_letterSpacing != 0 || m_wordSpacing != 0)
    758         applySpacing();
    759 }
    760 
    761 void UniscribeHelper::fillScreenOrder()
    762 {
    763     m_screenOrder.resize(m_runs.size());
    764 
    765     // We assume that the input has only one text direction in it.
    766     // TODO(brettw) are we sure we want to keep this restriction?
    767     if (m_isRtl) {
    768         for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++)
    769             m_screenOrder[static_cast<int>(m_screenOrder.size()) - i - 1] = i;
    770     } else {
    771         for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++)
    772             m_screenOrder[i] = i;
    773     }
    774 }
    775 
    776 void UniscribeHelper::adjustSpaceAdvances()
    777 {
    778     if (m_spaceWidth == 0)
    779         return;
    780 
    781     int spaceWidthWithoutLetterSpacing = m_spaceWidth - m_letterSpacing;
    782 
    783     // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem.
    784     for (size_t run = 0; run < m_runs.size(); run++) {
    785         Shaping& shaping = m_shapes[run];
    786 
    787         // FIXME: This loop is not UTF-16-safe. Unicode 6.0 has a couple
    788         // of complex script blocks in Plane 1.
    789         for (int i = 0; i < shaping.charLength(); i++) {
    790             UChar c = m_input[m_runs[run].iCharPos + i];
    791             bool treatAsSpace = Font::treatAsSpace(c);
    792             if (!treatAsSpace && !Font::treatAsZeroWidthSpaceInComplexScript(c))
    793                 continue;
    794 
    795             int glyphIndex = shaping.m_logs[i];
    796             int currentAdvance = shaping.m_advance[glyphIndex];
    797 
    798             if (treatAsSpace) {
    799                 // currentAdvance does not include additional letter-spacing,
    800                 // but m_spaceWidth does. Here we find out how off we are from
    801                 // the correct width (spaceWidthWithoutLetterSpacing) and
    802                 // just subtract that diff.
    803                 int diff = currentAdvance - spaceWidthWithoutLetterSpacing;
    804                 // The shaping can consist of a run of text, so only subtract
    805                 // the difference in the width of the glyph.
    806                 shaping.m_advance[glyphIndex] -= diff;
    807                 shaping.m_abc.abcB -= diff;
    808                 continue;
    809             }
    810 
    811             // For characters treated as zero-width space in complex
    812             // scripts, set the advance width to zero, adjust
    813             // |abcB| of the current run accordingly and set
    814             // the glyph to m_spaceGlyph (invisible).
    815             shaping.m_advance[glyphIndex] = 0;
    816             shaping.m_abc.abcB -= currentAdvance;
    817             shaping.m_offsets[glyphIndex].du = 0;
    818             shaping.m_offsets[glyphIndex].dv = 0;
    819             shaping.m_glyphs[glyphIndex] = shaping.m_spaceGlyph;
    820         }
    821     }
    822 }
    823 
    824 void UniscribeHelper::applySpacing()
    825 {
    826     for (size_t run = 0; run < m_runs.size(); run++) {
    827         Shaping& shaping = m_shapes[run];
    828         bool isRtl = m_runs[run].a.fRTL;
    829 
    830         if (m_letterSpacing != 0) {
    831             // RTL text gets padded to the left of each character. We increment
    832             // the run's advance to make this happen. This will be balanced out
    833             // by NOT adding additional advance to the last glyph in the run.
    834             if (isRtl)
    835                 shaping.m_prePadding += m_letterSpacing;
    836 
    837             // Go through all the glyphs in this run and increase the "advance"
    838             // to account for letter spacing. We adjust letter spacing only on
    839             // cluster boundaries.
    840             //
    841             // This works for most scripts, but may have problems with some
    842             // indic scripts. This behavior is better than Firefox or IE for
    843             // Hebrew.
    844             for (int i = 0; i < shaping.glyphLength(); i++) {
    845                 if (shaping.m_visualAttributes[i].fClusterStart) {
    846                     // Ick, we need to assign the extra space so that the glyph
    847                     // comes first, then is followed by the space. This is
    848                     // opposite for RTL.
    849                     if (isRtl) {
    850                         if (i != shaping.glyphLength() - 1) {
    851                             // All but the last character just get the spacing
    852                             // applied to their advance. The last character
    853                             // doesn't get anything,
    854                             shaping.m_advance[i] += m_letterSpacing;
    855                             shaping.m_abc.abcB += m_letterSpacing;
    856                         }
    857                     } else {
    858                         // LTR case is easier, we just add to the advance.
    859                         shaping.m_advance[i] += m_letterSpacing;
    860                         shaping.m_abc.abcB += m_letterSpacing;
    861                     }
    862                 }
    863             }
    864         }
    865 
    866         // Go through all the characters to find whitespace and insert the
    867         // extra wordspacing amount for the glyphs they correspond to.
    868         if (m_wordSpacing != 0) {
    869             for (int i = 0; i < shaping.charLength(); i++) {
    870                 if (!Font::treatAsSpace(m_input[m_runs[run].iCharPos + i]))
    871                     continue;
    872 
    873                 // The char in question is a word separator...
    874                 int glyphIndex = shaping.m_logs[i];
    875 
    876                 // Spaces will not have a glyph in Uniscribe, it will just add
    877                 // additional advance to the character to the left of the
    878                 // space. The space's corresponding glyph will be the character
    879                 // following it in reading order.
    880                 if (isRtl) {
    881                     // In RTL, the glyph to the left of the space is the same
    882                     // as the first glyph of the following character, so we can
    883                     // just increment it.
    884                     shaping.m_advance[glyphIndex] += m_wordSpacing;
    885                     shaping.m_abc.abcB += m_wordSpacing;
    886                 } else {
    887                     // LTR is actually more complex here, we apply it to the
    888                     // previous character if there is one, otherwise we have to
    889                     // apply it to the leading space of the run.
    890                     if (glyphIndex == 0)
    891                         shaping.m_prePadding += m_wordSpacing;
    892                     else {
    893                         shaping.m_advance[glyphIndex - 1] += m_wordSpacing;
    894                         shaping.m_abc.abcB += m_wordSpacing;
    895                     }
    896                 }
    897             }
    898         }  // m_wordSpacing != 0
    899 
    900         // Loop for next run...
    901     }
    902 }
    903 
    904 // The advance is the ABC width of the run
    905 int UniscribeHelper::advanceForItem(int itemIndex) const
    906 {
    907     int accum = 0;
    908     const Shaping& shaping = m_shapes[itemIndex];
    909 
    910     if (shaping.m_justify.size() == 0) {
    911         // Easy case with no justification, the width is just the ABC width of
    912         // the run. (The ABC width is the sum of the advances).
    913         return shaping.m_abc.abcA + shaping.m_abc.abcB +
    914                shaping.m_abc.abcC + shaping.m_prePadding;
    915     }
    916 
    917     // With justification, we use the justified amounts instead. The
    918     // justification array contains both the advance and the extra space
    919     // added for justification, so is the width we want.
    920     int justification = 0;
    921     for (size_t i = 0; i < shaping.m_justify.size(); i++)
    922         justification += shaping.m_justify[i];
    923 
    924     return shaping.m_prePadding + justification;
    925 }
    926 
    927 // SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid
    928 // and blank glyphs. Just because ScriptShape succeeds does not mean
    929 // that a text run is rendered correctly. Some characters may be rendered
    930 // with default/invalid/blank glyphs. Therefore, we need to check if the glyph
    931 // array returned by ScriptShape contains any of those glyphs to make
    932 // sure that the text run is rendered successfully.
    933 // However, we should not subject zero-width characters to this test.
    934 
    935 bool UniscribeHelper::containsMissingGlyphs(const Shaping& shaping,
    936                                             const SCRIPT_ITEM& run,
    937                                             const SCRIPT_FONTPROPERTIES* properties) const
    938 {
    939     for (int i = 0; i < shaping.charLength(); i++) {
    940         UChar c = m_input[run.iCharPos + i];
    941         // Skip zero-width space characters because they're not considered to be missing in a font.
    942         if (Font::treatAsZeroWidthSpaceInComplexScript(c))
    943             continue;
    944         int glyphIndex = shaping.m_logs[i];
    945         WORD glyph = shaping.m_glyphs[glyphIndex];
    946         if (glyph == properties->wgDefault
    947             || (glyph == properties->wgInvalid && glyph != properties->wgBlank))
    948             return true;
    949     }
    950     return false;
    951 }
    952 
    953 
    954 }  // namespace WebCore
    955