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);
}
Exemple #2
0
//
//	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);
}