void UniscribeHelper::draw(GraphicsContext* graphicsContext, HDC dc, int x, int y, int from, int to) { HGDIOBJ oldFont = 0; int curX = x; bool firstRun = true; bool useWindowsDrawing = windowsCanHandleTextDrawing(graphicsContext); for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) { int itemIndex = m_screenOrder[screenIndex]; const SCRIPT_ITEM& item = m_runs[itemIndex]; const Shaping& shaping = m_shapes[itemIndex]; // Character offsets within this run. THESE MAY NOT BE IN RANGE and may // be negative, etc. The code below handles this. int fromChar = from - item.iCharPos; int toChar = to - item.iCharPos; // See if we need to draw any characters in this item. if (shaping.charLength() == 0 || fromChar >= shaping.charLength() || toChar <= 0) { // No chars in this item to display. curX += advanceForItem(itemIndex); continue; } // Compute the starting glyph within this span. |from| and |to| are // global offsets that may intersect arbitrarily with our local run. int fromGlyph, afterGlyph; if (item.a.fRTL) { // To compute the first glyph when going RTL, we use |to|. if (toChar >= shaping.charLength()) // The end of the text is after (to the left) of us. fromGlyph = 0; else { // Since |to| is exclusive, the first character we draw on the // left is actually the one right before (to the right) of // |to|. fromGlyph = shaping.m_logs[toChar - 1]; } // The last glyph is actually the first character in the range. if (fromChar <= 0) { // The first character to draw is before (to the right) of this // span, so draw all the way to the end. afterGlyph = shaping.glyphLength(); } else { // We want to draw everything up until the character to the // right of |from|. To the right is - 1, so we look that up // (remember our character could be more than one glyph, so we // can't look up our glyph and add one). afterGlyph = shaping.m_logs[fromChar - 1]; } } else { // Easy case, everybody agrees about directions. We only need to // handle boundary conditions to get a range inclusive at the // beginning, and exclusive at the ending. We have to do some // computation to see the glyph one past the end. fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar]; if (toChar >= shaping.charLength()) afterGlyph = shaping.glyphLength(); else afterGlyph = shaping.m_logs[toChar]; } // Account for the characters that were skipped in this run. When // WebKit asks us to draw a subset of the run, it actually tells us // to draw at the X offset of the beginning of the run, since it // doesn't know the internal position of any of our characters. const int* effectiveAdvances = shaping.effectiveAdvances(); int innerOffset = 0; for (int i = 0; i < fromGlyph; i++) innerOffset += effectiveAdvances[i]; // Actually draw the glyphs we found. int glyphCount = afterGlyph - fromGlyph; if (fromGlyph >= 0 && glyphCount > 0) { // Account for the preceding space we need to add to this run. We // don't need to count for the following space because that will be // counted in advanceForItem below when we move to the next run. innerOffset += shaping.m_prePadding; // Pass 0 in when there is no justification. const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph]; if (useWindowsDrawing) { if (firstRun) { oldFont = SelectObject(dc, shaping.m_hfont); firstRun = false; } else SelectObject(dc, shaping.m_hfont); } // Fonts with different ascents can be used to render different // runs. 'Across-runs' y-coordinate correction needs to be // adjusted for each font. bool textOutOk = false; for (int executions = 0; executions < 2; ++executions) { if (useWindowsDrawing) { HRESULT hr = ScriptTextOut(dc, shaping.m_scriptCache, curX + innerOffset, y - shaping.m_ascentOffset, 0, 0, &item.a, 0, 0, &shaping.m_glyphs[fromGlyph], glyphCount, &shaping.m_advance[fromGlyph], justify, &shaping.m_offsets[fromGlyph]); ASSERT(S_OK == hr); textOutOk = (hr == S_OK); } else { SkPoint origin; origin.fX = curX + + innerOffset; origin.fY = y + m_ascent; textOutOk = paintSkiaText(graphicsContext, shaping.m_hfont, glyphCount, &shaping.m_glyphs[fromGlyph], &shaping.m_advance[fromGlyph], &shaping.m_offsets[fromGlyph], &origin); } if (!textOutOk && 0 == executions) { // If TextOut is called from the renderer it might fail // because the sandbox is preventing it from opening the // font files. If we are running in the renderer, // TryToPreloadFont is overridden to ask the browser to // preload the font for us so we can access it. tryToPreloadFont(shaping.m_hfont); continue; } break; } } curX += advanceForItem(itemIndex); } if (oldFont) SelectObject(dc, oldFont); }
// // PaintItemRunForeground // // Output a whole ITEM_RUN of text. Use clusterList and attrList // to break the glyphs into whole-cluster runs before calling ScriptTextOut // // We don't attempt to interpolate colours over each cluster. If there // is more than one ATTR per cluster then tough - only one gets used and // whole clusters (even if they contain multiple glyphs) get painted in // a single colour // static void PaintItemRunForeground ( USPDATA * uspData, USPFONT * uspFont, ITEM_RUN * itemRun, HDC hdc, int xpos, int ypos, RECT * bounds, BOOL forcesel ) { HRESULT hr; int i, lasti, g; int glyphIdx1; int glyphIdx2; int runWidth; int runDir = 1; UINT oldMode; // make pointers to the run's various glyph buffers ATTR * attrList = uspData->attrList + itemRun->charPos; WORD * clusterList = uspData->clusterList + itemRun->charPos; WORD * glyphList = uspData->glyphList + itemRun->glyphPos; int * widthList = uspData->widthList + itemRun->glyphPos; GOFFSET * offsetList = uspData->offsetList + itemRun->glyphPos; // right-left runs can be drawn backwards for simplicity if(itemRun->analysis.fRTL) { oldMode = SetTextAlign(hdc, TA_RIGHT); xpos += itemRun->width; runDir = -1; } // loop over all the logical character-positions for(lasti = 0, i = 0; i <= itemRun->len; i++) { // find a change in attribute if(i == itemRun->len || attrList[i].fg != attrList[lasti].fg ) { // scan forward to locate end of cluster (we must always // handle whole-clusters because the attr[] might fall in the middle) for( ; i < itemRun->len; i++) if(clusterList[i - 1] != clusterList[i]) break; // locate glyph-positions for the cluster [i,lasti] GetGlyphClusterIndices(itemRun, clusterList, i, lasti, &glyphIdx1, &glyphIdx2); // measure the width (in pixels) of the run for(runWidth = 0, g = glyphIdx1; g <= glyphIdx2; g++) runWidth += widthList[g]; // only need the text colour as we are drawing transparently SetTextColor(hdc, forcesel ? uspData->selFG : attrList[lasti].fg); // // Finally output the run of glyphs // hr = ScriptTextOut( hdc, &uspFont->scriptCache, xpos, ypos, 0, NULL, &itemRun->analysis, 0, 0, glyphList + glyphIdx1, glyphIdx2 - glyphIdx1 + 1, widthList + glyphIdx1, 0, offsetList + glyphIdx1 ); // +ve/-ve depending on run direction xpos += runWidth * runDir; lasti = i; } } // restore the mapping mode if(itemRun->analysis.fRTL) oldMode = SetTextAlign(hdc, oldMode); }