Esempio n. 1
0
        public void FlowText(FlowLayoutSource flowSource, FlowLayoutSink flowSink)
        {
            // Reflow all the text, from source to sink.
            if (!isTextAnalysisComplete_)
            {
                throw new Exception("FlowLayout: Text analysis in not complete");
            }

            // Determine the font line height, needed by the flow source.
            FontMetrics fontMetrics = fontFace_.Metrics;
            float       fontHeight  = (fontMetrics.Ascent + fontMetrics.Descent + fontMetrics.LineGap) * fontEmSize_ / fontMetrics.DesignUnitsPerEm;

            // Set initial cluster position to beginning of text.
            ClusterPosition cluster = new ClusterPosition();

            SetClusterPosition(ref cluster, 0);
            RectangleF      rect;
            ClusterPosition nextCluster;

            // Iteratively pull rect's from the source,
            // and push as much text will fit to the sink.
            while (cluster.textPosition < text_.Length)
            {
                // Pull the next rect from the source.
                if (!flowSource.GetNextRect(fontHeight, out rect))
                {
                    break;
                }

                if (rect.Right - rect.Left <= 0)
                {
                    break; // Stop upon reaching zero sized rects.
                }
                // Fit as many clusters between breakpoints that will go in.
                if (!FitText(ref cluster, text_.Length, rect.Right - rect.Left, out nextCluster))
                {
                    break;
                }

                // Push the glyph runs to the sink.
                if (!ProduceGlyphRuns(flowSink, ref rect, ref cluster, ref nextCluster))
                {
                    break;
                }

                cluster = nextCluster;
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CustomLayoutForm"/> class.
        /// </summary>
        public CustomLayoutForm()
        {
            InitializeComponent();

            try
            {
                InitDirect2DAndDirectWrite();
            }
            catch (Exception ex)
            {
                LogException(ex);
                Environment.Exit(1);
            }

            flowLayoutSource = new FlowLayoutSource();
            flowLayoutSink   = new FlowLayoutSink();
            flowLayout       = new FlowLayout(FactoryDWrite);

            SetLayoutText(LayoutText.Latin);
            SetLayoutShape(FlowShape.Circle);

            panel1.Paint  += RenderControlPaint;
            panel1.Resize += RenderControlResize;
        }
Esempio n. 3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CustomLayoutForm"/> class.
        /// </summary>
        public CustomLayoutForm()
        {
            InitializeComponent();

            try
            {
                InitDirect2DAndDirectWrite();
            }
            catch (Exception ex)
            {
                LogException(ex);
                Environment.Exit(1);
            }

            flowLayoutSource = new FlowLayoutSource();
            flowLayoutSink = new FlowLayoutSink();
            flowLayout = new FlowLayout(FactoryDWrite);

            SetLayoutText(LayoutText.Latin);
            SetLayoutShape(FlowShape.Circle);

            panel1.Paint += RenderControlPaint;
            panel1.Resize += RenderControlResize;
        }
Esempio n. 4
0
        protected bool ProduceGlyphRuns(FlowLayoutSink flowSink, ref RectangleF rect, ref ClusterPosition clusterStart, ref ClusterPosition clusterEnd)
        {
            // Produce a series of glyph runs from the given range
            // and send them to the sink. If the entire text fit
            // into the rect, then we'll only pass on a single glyph
            // run.

            ////////////////////////////////////////
            // Figure out how many runs we cross, because this is the number
            // of distinct glyph runs we'll need to reorder visually.

            int runIndexEnd = clusterEnd.runIndex;

            if (clusterEnd.textPosition > runs_[runIndexEnd].textStart)
            {
                ++runIndexEnd; // Only partially cover the run, so round up.
            }
            int[] bidiOrdering = new int[100];
            int   totalRuns    = Math.Min(bidiOrdering.Length, runIndexEnd - clusterStart.runIndex);

            ProduceBidiOrdering(clusterStart.runIndex, totalRuns, bidiOrdering);

            ////////////////////////////////////////
            // Ignore any trailing whitespace

            // Look backward from end until we find non-space.
            int trailingWsPosition;

            for (trailingWsPosition = clusterEnd.textPosition; trailingWsPosition > clusterStart.textPosition; --trailingWsPosition)
            {
                if (!breakpoints_[trailingWsPosition - 1].IsWhitespace)
                {
                    break; // Encountered last significant character.
                }
            }
            // Set the glyph run's ending cluster to the last whitespace.
            ClusterPosition clusterWsEnd = clusterStart;

            SetClusterPosition(ref clusterWsEnd, trailingWsPosition);

            ////////////////////////////////////////
            // Produce justified advances to reduce the jagged edge.
            List <float> justifiedAdvances;

            ProduceJustifiedAdvances(ref rect, ref clusterStart, ref clusterWsEnd, out justifiedAdvances);
            int justificationGlyphStart = GetClusterGlyphStart(ref clusterStart);
            ////////////////////////////////////////
            // Determine starting point for alignment.
            float x = rect.Left;
            float y = rect.Bottom;

            FontMetrics fontMetrics = fontFace_.Metrics;

            float descent = (fontMetrics.Descent * fontEmSize_ / fontMetrics.DesignUnitsPerEm);

            y -= descent;

            if (readingDirection_ == ReadingDirection.RightToLeft)
            {
                // For RTL, we neeed the run width to adjust the origin
                // so it starts on the right side.
                int glyphStart = GetClusterGlyphStart(ref clusterStart);
                int glyphEnd   = GetClusterGlyphStart(ref clusterWsEnd);

                if (glyphStart < glyphEnd)
                {
                    float lineWidth = GetClusterRangeWidth(
                        glyphStart - justificationGlyphStart,
                        glyphEnd - justificationGlyphStart,
                        justifiedAdvances.ToArray()
                        );
                    x = rect.Right - lineWidth;
                }
            }

            ////////////////////////////////////////
            // Send each glyph run to the sink.
            for (int i = 0; i < totalRuns; ++i)
            {
                Run run        = runs_[bidiOrdering[i]];
                int glyphStart = run.glyphStart;
                int glyphEnd   = glyphStart + run.glyphCount;

                // If the run is only partially covered, we'll need to find
                // the subsection of glyphs that were fit.
                if (clusterStart.textPosition > run.textStart)
                {
                    glyphStart = GetClusterGlyphStart(ref clusterStart);
                }
                if (clusterWsEnd.textPosition < run.textStart + run.textLength)
                {
                    glyphEnd = GetClusterGlyphStart(ref clusterWsEnd);
                }
                if ((glyphStart >= glyphEnd) || (run.script.Shapes == ScriptShapes.NoVisual))
                {
                    // The itemizer told us not to draw this character,
                    // either because it was a formatting, control, or other hidden character.
                    continue;
                }

                // The run width is needed to know how far to move forward,
                // and to flip the origin for right-to-left text.
                float runWidth = GetClusterRangeWidth(
                    glyphStart - justificationGlyphStart,
                    glyphEnd - justificationGlyphStart,
                    justifiedAdvances.ToArray()
                    );

                // Flush this glyph run.
                //int glyphCount = glyphEnd - glyphStart;
                int     glyphCount         = justifiedAdvances.Count;
                short[] call_glyphIndices_ = new short[glyphCount];
                Array.Copy(glyphIndices_, glyphStart, call_glyphIndices_, 0, call_glyphIndices_.Length);
                float[] call_justifiedAdvances = new float[justifiedAdvances.Count - (glyphStart - justificationGlyphStart)];
                justifiedAdvances.CopyTo(glyphStart - justificationGlyphStart, call_justifiedAdvances, 0, call_justifiedAdvances.Length);
                GlyphOffset[] call_glyphOffsets_ = new GlyphOffset[glyphCount];
                Array.Copy(glyphOffsets_, glyphStart, call_glyphOffsets_, 0, call_glyphOffsets_.Length);
                flowSink.SetGlyphRun(
                    (run.bidiLevel % 2 != 0) ? (x + runWidth) : (x), // origin starts from right if RTL
                    y,
                    glyphCount,
                    call_glyphIndices_,
                    call_justifiedAdvances,
                    call_glyphOffsets_,
                    fontFace_,
                    fontEmSize_,
                    run.bidiLevel,
                    run.isSideways
                    );

                x += runWidth;
            }
            return(true);
        }
Esempio n. 5
0
        protected bool ProduceGlyphRuns(FlowLayoutSink flowSink, ref RectangleF rect, ref ClusterPosition clusterStart, ref ClusterPosition clusterEnd)
        {
            // Produce a series of glyph runs from the given range
            // and send them to the sink. If the entire text fit
            // into the rect, then we'll only pass on a single glyph
            // run.

            ////////////////////////////////////////
            // Figure out how many runs we cross, because this is the number
            // of distinct glyph runs we'll need to reorder visually.

            int runIndexEnd = clusterEnd.runIndex;
            if (clusterEnd.textPosition > runs_[runIndexEnd].textStart)
                ++runIndexEnd; // Only partially cover the run, so round up.

            int[] bidiOrdering = new int[100];
            int totalRuns = Math.Min(bidiOrdering.Length, runIndexEnd - clusterStart.runIndex);
            ProduceBidiOrdering(clusterStart.runIndex, totalRuns, bidiOrdering);

            ////////////////////////////////////////
            // Ignore any trailing whitespace

            // Look backward from end until we find non-space.
            int trailingWsPosition;
            for (trailingWsPosition = clusterEnd.textPosition; trailingWsPosition > clusterStart.textPosition; --trailingWsPosition)
            {
                if (!breakpoints_[trailingWsPosition - 1].IsWhitespace)
                    break; // Encountered last significant character.
            }
            // Set the glyph run's ending cluster to the last whitespace.
            ClusterPosition clusterWsEnd = clusterStart;
            SetClusterPosition(ref clusterWsEnd, trailingWsPosition);

            ////////////////////////////////////////
            // Produce justified advances to reduce the jagged edge.
            List<float> justifiedAdvances;
            ProduceJustifiedAdvances(ref rect, ref clusterStart, ref clusterWsEnd, out justifiedAdvances);
            int justificationGlyphStart = GetClusterGlyphStart(ref clusterStart);
            ////////////////////////////////////////
            // Determine starting point for alignment.
            float x = rect.Left;
            float y = rect.Bottom;

            FontMetrics fontMetrics = fontFace_.Metrics;

            float descent = (fontMetrics.Descent * fontEmSize_ / fontMetrics.DesignUnitsPerEm);
            y -= descent;

            if (readingDirection_ == ReadingDirection.RightToLeft)
            {
                // For RTL, we neeed the run width to adjust the origin
                // so it starts on the right side.
                int glyphStart = GetClusterGlyphStart(ref clusterStart);
                int glyphEnd = GetClusterGlyphStart(ref clusterWsEnd);

                if (glyphStart < glyphEnd)
                {
                    float lineWidth = GetClusterRangeWidth(
                        glyphStart - justificationGlyphStart,
                        glyphEnd - justificationGlyphStart,
                        justifiedAdvances.ToArray()
                        );
                    x = rect.Right - lineWidth;
                }
            }

            ////////////////////////////////////////
            // Send each glyph run to the sink.
            for (int i = 0; i < totalRuns; ++i)
            {
                Run run = runs_[bidiOrdering[i]];
                int glyphStart = run.glyphStart;
                int glyphEnd = glyphStart + run.glyphCount;

                // If the run is only partially covered, we'll need to find
                // the subsection of glyphs that were fit.
                if (clusterStart.textPosition > run.textStart)
                {
                    glyphStart = GetClusterGlyphStart(ref clusterStart);
                }
                if (clusterWsEnd.textPosition < run.textStart + run.textLength)
                {
                    glyphEnd = GetClusterGlyphStart(ref clusterWsEnd);
                }
                if ((glyphStart >= glyphEnd) || (run.script.Shapes == ScriptShapes.NoVisual))
                {
                    // The itemizer told us not to draw this character,
                    // either because it was a formatting, control, or other hidden character.
                    continue;
                }

                // The run width is needed to know how far to move forward,
                // and to flip the origin for right-to-left text.
                float runWidth = GetClusterRangeWidth(
                                    glyphStart - justificationGlyphStart,
                                    glyphEnd - justificationGlyphStart,
                                    justifiedAdvances.ToArray()
                                    );

                // Flush this glyph run.
                //int glyphCount = glyphEnd - glyphStart;
                int glyphCount = justifiedAdvances.Count;
                short[] call_glyphIndices_ = new short[glyphCount];
                Array.Copy(glyphIndices_, glyphStart, call_glyphIndices_, 0, call_glyphIndices_.Length);
                float[] call_justifiedAdvances = new float[justifiedAdvances.Count - (glyphStart - justificationGlyphStart)];
                justifiedAdvances.CopyTo(glyphStart - justificationGlyphStart, call_justifiedAdvances, 0, call_justifiedAdvances.Length);
                GlyphOffset[] call_glyphOffsets_ = new GlyphOffset[glyphCount];
                Array.Copy(glyphOffsets_, glyphStart, call_glyphOffsets_, 0, call_glyphOffsets_.Length);
                flowSink.SetGlyphRun(
                    (run.bidiLevel % 2 != 0) ? (x + runWidth) : (x), // origin starts from right if RTL
                    y,
                    glyphCount,
                    call_glyphIndices_,
                    call_justifiedAdvances,
                    call_glyphOffsets_,
                    fontFace_,
                    fontEmSize_,
                    run.bidiLevel,
                    run.isSideways
                    );

                x += runWidth;
            }
            return true;
        }
Esempio n. 6
0
        public void FlowText(FlowLayoutSource flowSource, FlowLayoutSink flowSink)
        {
            // Reflow all the text, from source to sink.
            if (!isTextAnalysisComplete_)
                throw new Exception("FlowLayout: Text analysis in not complete");

            // Determine the font line height, needed by the flow source.
            FontMetrics fontMetrics = fontFace_.Metrics;
            float fontHeight = (fontMetrics.Ascent + fontMetrics.Descent + fontMetrics.LineGap) * fontEmSize_ / fontMetrics.DesignUnitsPerEm;

            // Set initial cluster position to beginning of text.
            ClusterPosition cluster = new ClusterPosition();
            SetClusterPosition(ref cluster, 0);
            RectangleF rect;
            ClusterPosition nextCluster;

            // Iteratively pull rect's from the source,
            // and push as much text will fit to the sink.
            while (cluster.textPosition < text_.Length)
            {
                // Pull the next rect from the source.
                if (!flowSource.GetNextRect(fontHeight, out rect))
                    break;

                if (rect.Right - rect.Left <= 0)
                    break; // Stop upon reaching zero sized rects.

                // Fit as many clusters between breakpoints that will go in.
                if (!FitText(ref cluster, text_.Length, rect.Right - rect.Left, out nextCluster))
                    break;

                // Push the glyph runs to the sink.
                if (!ProduceGlyphRuns(flowSink, ref rect, ref cluster, ref nextCluster))
                    break;

                cluster = nextCluster;
            }
        }