示例#1
0
        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
            }
        }
示例#2
0
        /// <summary>
        /// Analyzes a <see cref="Paragraph" /> to populate a <see cref="ScriptParagraph"/>.
        /// </summary>
        private void AnalyzeParagraph(DeviceContext deviceContext, Paragraph* paragraph, ScriptParagraph* scriptParagraph)
        {
            int paragraphCharIndex = paragraph->CharIndex;
            int paragraphCharCount = paragraph->CharCount;

            scriptParagraph->CharIndex = paragraphCharIndex;
            scriptParagraph->CharCount = paragraphCharCount;
            scriptParagraph->ScriptRunCount = 0;
            scriptParagraph->GlyphCount = 0;

            Run* runZero = document.GetRunZero();
            Run* runs = runZero + paragraph->RunIndex;
            int runCount = paragraph->RunCount;

            // Skip paragraphs with no runs (this is the sentinel at end of document)
            if (runCount == 0)
            {
                return;
            }

            // Handle paragraphs with exactly one empty run (simple newline)
            Debug.Assert(paragraphCharCount != 0, "A paragraph with at least one run should always have at least one character.");

            char* charZero = document.GetCharZero();
            char* chars = charZero + paragraphCharIndex;

            // Step 1. Itemize the script items within the paragraph.
            //         Each script item represents a chunk of text (such as a word)
            //         for Unicode rendering purposes.
            scriptParagraph->EnsureCharCapacity(paragraphCharCount);

            SCRIPT_ITEM* tempScriptItems;
            int tempScriptItemCount;
            ScriptItemize(chars, paragraphCharCount, currentLayoutRightToLeft, tempScriptItemBuffer, out tempScriptItems, out tempScriptItemCount);

            // Step 2. Compute logical attributes for characters in the paragraph for word-break purposes.
            ScriptBreak(scriptParagraph, chars, tempScriptItems, tempScriptItemCount);

            // Step 3. Split the Runs on SCRIPT_ITEM boundaries to produce ScriptRuns.
            SplitScriptRuns(scriptParagraph, runs, runCount, tempScriptItems, tempScriptItemCount);

            // Step 4. Shape and Place glyphs and Measure embedded objects one run at a time.
            //         We do this in linear order because it is simpler and we do not care about
            //         visual order until later when we pack runs into lines and draw them.
            ScriptRun* scriptRun = scriptParagraph->ScriptRuns;
            ScriptRun* endScriptRun = scriptRun + scriptParagraph->ScriptRunCount;
            for (; scriptRun != endScriptRun; scriptRun++)
            {
                Style scriptRunStyle = document.LookupStyle(scriptRun->StyleIndex);

                switch (scriptRun->RunKind)
                {
                    case RunKind.Text:
                    {
                        // Fill in basic metrics.
                        ScriptMetrics scriptMetrics = deviceContext.SelectFont(scriptRunStyle.Font);
                        scriptRun->Height = scriptMetrics.Height;
                        scriptRun->Descent = scriptMetrics.Descent;
                        scriptRun->TopMargin = 0;
                        scriptRun->BottomMargin = 0;

                        // Set glyphs.
                        ScriptShapeAndPlace(deviceContext.HDC, ref scriptMetrics.ScriptCache, scriptParagraph, scriptRun, chars);
                        break;
                    }

                    case RunKind.Object:
                    {
                        // No glyphs for an embedded object.
                        scriptRun->GlyphCount = 0;
                        scriptRun->GlyphIndexInParagraph = 0;

                        // Fill in object measurements.
                        int charIndex = scriptRun->CharIndexInParagraph + paragraphCharIndex;
                        EmbeddedObjectHost embeddedObjectHost;
                        EmbeddedObjectMeasurements embeddedObjectMeasurements;
                        if (embeddedObjectHosts.TryGetValue(charIndex, out embeddedObjectHost))
                            embeddedObjectMeasurements = embeddedObjectHost.Measure();
                        else
                            embeddedObjectMeasurements = EmbeddedObjectHost.CreateDefaultEmbeddedObjectMeasurements();

                        scriptRun->Height = embeddedObjectMeasurements.Size.Height;
                        scriptRun->Descent = embeddedObjectMeasurements.Descent;
                        scriptRun->TopMargin = embeddedObjectMeasurements.Margin.Top;
                        scriptRun->BottomMargin = embeddedObjectMeasurements.Margin.Bottom;
                        scriptRun->ABC.abcA = embeddedObjectMeasurements.Margin.Left;
                        scriptRun->ABC.abcB = embeddedObjectMeasurements.Size.Width;
                        scriptRun->ABC.abcC = embeddedObjectMeasurements.Margin.Right;

                        // Change the logical attributes of the character so that an object behaves like
                        // a word rather than whitespace when performing word wrap.
                        scriptParagraph->CharLogicalAttributes[scriptRun->CharIndexInParagraph].SetfSoftBreakfCharStopAndfWordStop();
                        break;
                    }

                    case RunKind.Tab:
                    {
                        // No glyphs for a tab.
                        scriptRun->GlyphCount = 0;
                        scriptRun->GlyphIndexInParagraph = 0;

                        // Use same metrics as inline text.
                        ScriptMetrics scriptMetrics = deviceContext.SelectFont(scriptRunStyle.Font);
                        scriptRun->Height = scriptMetrics.Height;
                        scriptRun->Descent = scriptMetrics.Descent;
                        scriptRun->TopMargin = 0;
                        scriptRun->BottomMargin = 0;
                        scriptRun->ABC.abcA = 0;
                        scriptRun->ABC.abcB = -1; // will be filled in when the TAB is measured
                        scriptRun->ABC.abcC = 0;

                        // Change the logical attributes of the character to make it whitespace since Uniscribe
                        // does not consider a TAB to be whitespace.
                        scriptParagraph->CharLogicalAttributes[scriptRun->CharIndexInParagraph].SetfWhiteSpace();
                        break;
                    }
                }
            }
        }