private void PaintLineBackgroundAndExcludeSelectedTextFromClipRegion(DeviceContext deviceContext, PaintOptions paintOptions, ScriptLine* scriptLine, ScriptParagraph* scriptParagraph, int scriptRunIndex, int scriptRunCount, int* visualToLogicalMap, int xStartPosition, int xEndPosition, Rectangle layoutRect, int selectedCharIndex, int selectedCharCount) { IntPtr brush = DeviceContext.GetStockObject(NativeConstants.DC_BRUSH); deviceContext.SetDCBrushColor(paintOptions.SelectedBackgroundColor); int yCurrentBaseline = scriptLine->Y + scriptLine->Ascent; int xCurrentPosition = scriptLine->X; for (int i = 0; i < scriptRunCount; i++) { int logicalScriptRunIndex = visualToLogicalMap[currentLayoutRightToLeft ? scriptRunCount - i - 1 : i]; ScriptRun* scriptRun = scriptParagraph->ScriptRuns + logicalScriptRunIndex + scriptRunIndex; int measuredWidth; switch (scriptRun->RunKind) { case RunKind.Text: { int glyphIndexInParagraph, glyphCount; int truncatedLeadingCharsCount = logicalScriptRunIndex == 0 ? scriptLine->TruncatedLeadingCharsCount : 0; int truncatedTrailingCharsCount = logicalScriptRunIndex == scriptRunCount - 1 ? scriptLine->TruncatedTrailingCharsCount : 0; measuredWidth = MeasureTextScriptRun(scriptParagraph, scriptRun, truncatedLeadingCharsCount, truncatedTrailingCharsCount, out glyphIndexInParagraph, out glyphCount); if (xCurrentPosition + measuredWidth > xStartPosition) { int scriptRunCharIndex = scriptParagraph->CharIndex + scriptRun->CharIndexInParagraph; int leadingCharIndex = scriptRunCharIndex + truncatedLeadingCharsCount; int trailingCharIndex = scriptRunCharIndex + scriptRun->CharCount - truncatedTrailingCharsCount; if (trailingCharIndex >= selectedCharIndex && leadingCharIndex <= selectedCharIndex + selectedCharCount) { int relativePositionOfSelection; if (leadingCharIndex >= selectedCharIndex) { relativePositionOfSelection = 0; } else { relativePositionOfSelection = MeasureTextScriptRun(scriptParagraph, scriptRun, truncatedLeadingCharsCount, truncatedTrailingCharsCount + trailingCharIndex - selectedCharIndex, out glyphIndexInParagraph, out glyphCount); } int measuredWidthOfSelection; if (trailingCharIndex <= selectedCharIndex + selectedCharCount) { measuredWidthOfSelection = measuredWidth - relativePositionOfSelection; } else { measuredWidthOfSelection = MeasureTextScriptRun(scriptParagraph, scriptRun, truncatedLeadingCharsCount + Math.Max(selectedCharIndex - leadingCharIndex, 0), truncatedTrailingCharsCount + trailingCharIndex - selectedCharIndex - selectedCharCount, out glyphIndexInParagraph, out glyphCount); } int x = currentLayoutRightToLeft ? layoutRect.Right - xCurrentPosition - measuredWidth : layoutRect.Left + xCurrentPosition; int y = layoutRect.Top + yCurrentBaseline - scriptRun->Ascent; if (scriptRun->ScriptAnalysis.fRTL) x += measuredWidth - relativePositionOfSelection - measuredWidthOfSelection; else x += relativePositionOfSelection; Rectangle selectedRect = new Rectangle(x, y, measuredWidthOfSelection, scriptRun->Height); deviceContext.FillRect(selectedRect, brush); deviceContext.ExcludeClipRect(selectedRect); } } break; } case RunKind.Object: case RunKind.Tab: { measuredWidth = scriptRun->RunKind == RunKind.Object ? MeasureObjectScriptRun(scriptRun) : MeasureTabScriptRun(scriptRun, GetParagraphStyleAssumingItHasAtLeastOneRun(scriptParagraph), xCurrentPosition, false); if (xCurrentPosition + measuredWidth > xStartPosition) { int leadingCharIndex = scriptParagraph->CharIndex + scriptRun->CharIndexInParagraph; int trailingCharIndex = leadingCharIndex + 1; if (trailingCharIndex >= selectedCharIndex && leadingCharIndex <= selectedCharIndex + selectedCharCount) { int x = currentLayoutRightToLeft ? layoutRect.Right - xCurrentPosition - measuredWidth : layoutRect.Left + xCurrentPosition; int y = layoutRect.Top + yCurrentBaseline - scriptRun->Ascent; Rectangle selectedRect = new Rectangle(x, y, measuredWidth, scriptRun->Height); deviceContext.FillRect(selectedRect, brush); // Don't exclude clip rect for objects and tabs. //deviceContext.ExcludeClipRect(selectedRect); } } break; } default: throw new NotSupportedException(); } xCurrentPosition += measuredWidth; if (xCurrentPosition >= xEndPosition) break; // can't fit any more runs within the clip rectangle } }
private void PaintLineForeground(DeviceContext deviceContext, PaintOptions paintOptions, ScriptLine* scriptLine, ScriptParagraph* scriptParagraph, int scriptRunIndex, int scriptRunCount, int* visualToLogicalMap, int xStartPosition, int xEndPosition, Rectangle layoutRect, bool isSelected, bool skipObjects) { int yCurrentBaseline = scriptLine->Y + scriptLine->Ascent; int xCurrentPosition = scriptLine->X; for (int i = 0; i < scriptRunCount; i++) { int logicalScriptRunIndex = visualToLogicalMap[currentLayoutRightToLeft ? scriptRunCount - i - 1 : i]; ScriptRun* scriptRun = scriptParagraph->ScriptRuns + logicalScriptRunIndex + scriptRunIndex; int measuredWidth; switch (scriptRun->RunKind) { case RunKind.Text: { Style style = document.LookupStyle(scriptRun->StyleIndex); ScriptMetrics scriptMetrics = deviceContext.SelectFont(style.Font); int glyphIndexInParagraph, glyphCount; measuredWidth = MeasureTextScriptRun(scriptParagraph, scriptRun, logicalScriptRunIndex == 0 ? scriptLine->TruncatedLeadingCharsCount : 0, logicalScriptRunIndex == scriptRunCount - 1 ? scriptLine->TruncatedTrailingCharsCount : 0, out glyphIndexInParagraph, out glyphCount); if (glyphCount > 0 && xCurrentPosition + measuredWidth > xStartPosition) { int x = currentLayoutRightToLeft ? layoutRect.Right - xCurrentPosition - measuredWidth : layoutRect.Left + xCurrentPosition; int y = layoutRect.Top + yCurrentBaseline - scriptRun->Ascent; deviceContext.SetTextColor(isSelected ? paintOptions.SelectedTextColor : style.Color); ScriptTextOut(deviceContext.HDC, ref scriptMetrics.ScriptCache, x, y, ExtTextOutOptions.NONE, null, &scriptRun->ScriptAnalysis, scriptParagraph->Glyphs + glyphIndexInParagraph, glyphCount, scriptParagraph->GlyphAdvanceWidths + glyphIndexInParagraph, null, scriptParagraph->GlyphOffsets + glyphIndexInParagraph); } break; } case RunKind.Object: { measuredWidth = MeasureObjectScriptRun(scriptRun); if (!skipObjects && xCurrentPosition + measuredWidth > xStartPosition) { int embeddedObjectCharIndex = scriptRun->CharIndexInParagraph + scriptParagraph->CharIndex; EmbeddedObjectHost embeddedObjectHost; if (embeddedObjectHosts.TryGetValue(embeddedObjectCharIndex, out embeddedObjectHost)) { if (embeddedObjectHost.RequiresPaint) { using (Graphics g = Graphics.FromHdc(deviceContext.HDC)) { Rectangle bounds = GetDrawingBoundsOfEmbeddedObject(embeddedObjectHost, layoutRect.Location); embeddedObjectHost.Paint(g, paintOptions, bounds, currentLayoutRightToLeft); } } } } break; } case RunKind.Tab: { measuredWidth = MeasureTabScriptRun(scriptRun, GetParagraphStyleAssumingItHasAtLeastOneRun(scriptParagraph), xCurrentPosition, false); break; } default: throw new NotSupportedException(); } xCurrentPosition += measuredWidth; if (xCurrentPosition >= xEndPosition) break; // can't fit any more runs within the clip rectangle } }
private void FinishScriptLineLayout(ScriptLine* scriptLine, ScriptParagraph* scriptParagraph, bool mustLayoutObjects) { int ascent = MinimumScriptLineHeight; int descent = 0; ScriptRun* startScriptRun = scriptParagraph->ScriptRuns + scriptLine->ScriptRunIndex; ScriptRun* endScriptRun = startScriptRun + scriptLine->ScriptRunCount; for (ScriptRun* scriptRun = startScriptRun; scriptRun != endScriptRun; scriptRun++) { int scriptRunDescentAndMargin = scriptRun->Descent + scriptRun->BottomMargin; int scriptRunAscentAndMargin = scriptRun->Ascent + scriptRun->TopMargin; if (scriptRunAscentAndMargin > ascent) ascent = scriptRunAscentAndMargin; if (scriptRunDescentAndMargin > descent) descent = scriptRunDescentAndMargin; } int height = ascent + descent; scriptLine->Height = height; scriptLine->Descent = descent; if (mustLayoutObjects) { int xCurrentPosition = scriptLine->X; int scriptRunIndex = scriptLine->ScriptRunIndex; int scriptRunCount = scriptLine->ScriptRunCount; int* visualToLogicalMap = GetTempVisualToLogicalMap( scriptParagraph->ScriptRuns + scriptRunIndex, scriptRunCount); for (int i = 0; i < scriptRunCount; i++) { int logicalScriptRunIndex = visualToLogicalMap[currentLayoutRightToLeft ? scriptRunCount - i - 1 : i]; ScriptRun* scriptRun = scriptParagraph->ScriptRuns + logicalScriptRunIndex + scriptRunIndex; int measuredWidth; switch (scriptRun->RunKind) { case RunKind.Text: { int glyphIndexInParagraph, glyphCount; int truncatedLeadingCharsCount = logicalScriptRunIndex == 0 ? scriptLine->TruncatedLeadingCharsCount : 0; int truncatedTrailingCharsCount = logicalScriptRunIndex == scriptRunCount - 1 ? scriptLine->TruncatedTrailingCharsCount : 0; measuredWidth = MeasureTextScriptRun(scriptParagraph, scriptRun, truncatedLeadingCharsCount, truncatedTrailingCharsCount, out glyphIndexInParagraph, out glyphCount); break; } case RunKind.Object: { measuredWidth = scriptRun->ABC.TotalWidth; EmbeddedObjectHost embeddedObjectHost; int charIndex = scriptRun->CharIndexInParagraph + scriptParagraph->CharIndex; if (embeddedObjectHosts.TryGetValue(charIndex, out embeddedObjectHost)) { embeddedObjectHost.LayoutBounds = new Rectangle( xCurrentPosition + scriptRun->ABC.abcA, scriptLine->Y + scriptLine->Ascent - scriptRun->Ascent, scriptRun->ABC.abcB, scriptRun->Height); pendingEmbeddedObjectHostsToShow.Enqueue(embeddedObjectHost); } break; } case RunKind.Tab: { measuredWidth = scriptRun->ABC.abcB; break; } default: throw new NotSupportedException(); } xCurrentPosition += measuredWidth; } } }