Beispiel #1
0
        //------------------------------------------------------
        //
        //  Protected Methods
        //
        //------------------------------------------------------

        #region Protected Methods

        /// <summary>
        /// Render override to render the composition adorner here.
        /// </summary>
        protected override void OnRender(DrawingContext drawingContext)
        {
            // Get the matrix from AdornedElement to the visual parent to get the transformed
            // start/end point
            Visual parent2d = VisualTreeHelper.GetParent(this.AdornedElement) as Visual;

            if (parent2d == null)
            {
                return;
            }

            GeneralTransform transform = AdornedElement.TransformToAncestor(parent2d);

            if (transform == null)
            {
                return;
            }

            // Please note that we do the highlight adornment for the CONVERTED text only
            // for Simplified Chinese IMEs. Doing this uniformly across all IMEs wasnt possible
            // because it was noted that some of them (viz. Japanese) werent being consistent
            // about this attribute.

            bool isChinesePinyin = chinesePinyin.Equals(InputLanguageManager.Current.CurrentInputLanguage.IetfLanguageTag);

            // Render the each of the composition string attribute from the attribute ranges.
            for (int i = 0; i < _attributeRanges.Count; i++)
            {
                DoubleCollection dashArray;

                // Get the composition attribute range from the attribute range lists
                AttributeRange attributeRange = (AttributeRange)_attributeRanges[i];

                // Skip the rendering composition lines if the composition line doesn't exist.
                if (attributeRange.CompositionLines.Count == 0)
                {
                    continue;
                }

                // Set the line bold and squiggle
                bool lineBold            = attributeRange.TextServicesDisplayAttribute.IsBoldLine ? true : false;
                bool squiggle            = false;
                bool hasVirtualSelection = (attributeRange.TextServicesDisplayAttribute.AttrInfo & UnsafeNativeMethods.TF_DA_ATTR_INFO.TF_ATTR_TARGET_CONVERTED) != 0;

                Brush  selectionBrush   = null;
                double selectionOpacity = -1;
                Pen    selectionPen     = null;

                if (isChinesePinyin && hasVirtualSelection)
                {
                    DependencyObject owner = _textView.TextContainer.Parent;
                    selectionBrush   = (Brush)owner.GetValue(TextBoxBase.SelectionBrushProperty);
                    selectionOpacity = (double)owner.GetValue(TextBoxBase.SelectionOpacityProperty);
                }

                // Set the line height and cluse gap value that base on the ratio of text height
                double height     = attributeRange.Height;
                double lineHeight = height * (lineBold ? BoldLineHeightRatio : NormalLineHeightRatio);
                double clauseGap  = height * ClauseGapRatio;

                // Create Pen for drawing the composition lines with the specified line color
                Pen pen = new Pen(new SolidColorBrush(Colors.Black), lineHeight);

                // Set the pen style that based on IME's composition line style
                switch (attributeRange.TextServicesDisplayAttribute.LineStyle)
                {
                case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_DOT:
                    // Add the dot length and specify the start/end line cap as the round
                    dashArray = new DoubleCollection();
                    dashArray.Add(DotLength);
                    dashArray.Add(DotLength);

                    pen.DashStyle    = new DashStyle(dashArray, 0);
                    pen.DashCap      = System.Windows.Media.PenLineCap.Round;
                    pen.StartLineCap = System.Windows.Media.PenLineCap.Round;
                    pen.EndLineCap   = System.Windows.Media.PenLineCap.Round;

                    // Update the line height for the dot line. Dot line will be more thickness than
                    // other line to show it clearly.
                    lineHeight = height * (lineBold ? BoldDotLineHeightRatio : NormalDotLineHeightRatio);

                    break;

                case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_DASH:
                    double dashLength    = height * (lineBold ? BoldDashRatio : NormalDashRatio);
                    double dashGapLength = height * (lineBold ? BoldDashGapRatio : NormalDashGapRatio);

                    // Add the dash and dash gap legth
                    dashArray = new DoubleCollection();
                    dashArray.Add(dashLength);
                    dashArray.Add(dashGapLength);

                    pen.DashStyle    = new DashStyle(dashArray, 0);
                    pen.DashCap      = System.Windows.Media.PenLineCap.Round;
                    pen.StartLineCap = System.Windows.Media.PenLineCap.Round;
                    pen.EndLineCap   = System.Windows.Media.PenLineCap.Round;

                    break;

                case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_SOLID:
                    pen.StartLineCap = System.Windows.Media.PenLineCap.Round;
                    pen.EndLineCap   = System.Windows.Media.PenLineCap.Round;

                    break;

                case UnsafeNativeMethods.TF_DA_LINESTYLE.TF_LS_SQUIGGLE:
                    squiggle = true;
                    break;
                }

                double halfLineHeight = lineHeight / 2;

                // Draw the each of the composition line
                for (int j = 0; j < attributeRange.CompositionLines.Count; j++)
                {
                    CompositionLine compositionLine = (CompositionLine)attributeRange.CompositionLines[j];

                    // Get the start/end point for composition adorner.
                    // Currently Text doesn't aware of the spaceroom for the drawing of the composition
                    // adorner(like as normal/bold dot/line/squggle), so we should draw the composition adorners
                    // to the closest area of the bottom text.
                    Point startPoint = new Point(compositionLine.StartPoint.X + clauseGap, compositionLine.StartPoint.Y - halfLineHeight);
                    Point endPoint   = new Point(compositionLine.EndPoint.X - clauseGap, compositionLine.EndPoint.Y - halfLineHeight);

                    // Apply composition line color which is actually the foreground of text as well
                    pen.Brush = new SolidColorBrush(compositionLine.LineColor);

                    // Apply matrix to start/end point
                    //
                    transform.TryTransform(startPoint, out startPoint);
                    transform.TryTransform(endPoint, out endPoint);

                    if (isChinesePinyin && hasVirtualSelection)
                    {
                        Rect rect = Rect.Union(compositionLine.StartRect, compositionLine.EndRect);
                        rect = transform.TransformBounds(rect);

                        drawingContext.PushOpacity(selectionOpacity);

                        drawingContext.DrawRectangle(selectionBrush, selectionPen, rect);

                        drawingContext.Pop();
                    }

                    if (squiggle)
                    {
                        // Draw the squiggle line with using of the PathFigure and DrawGemetry.
                        // We may revisit this logic to render the smooth squiggle line.
                        Point pathPoint = new Point(startPoint.X, startPoint.Y - halfLineHeight);

                        double squiggleGap = halfLineHeight;

                        PathFigure pathFigure = new PathFigure();
                        pathFigure.StartPoint = pathPoint;

                        int indexPoint = 0;

                        while (indexPoint < ((endPoint.X - startPoint.X) / (squiggleGap)))
                        {
                            if (indexPoint % 4 == 0 || indexPoint % 4 == 3)
                            {
                                pathPoint = new Point(pathPoint.X + squiggleGap, pathPoint.Y + halfLineHeight);
                                pathFigure.Segments.Add(new LineSegment(pathPoint, true));
                            }
                            else if (indexPoint % 4 == 1 || indexPoint % 4 == 2)
                            {
                                pathPoint = new Point(pathPoint.X + squiggleGap, pathPoint.Y - halfLineHeight);
                                pathFigure.Segments.Add(new LineSegment(pathPoint, true));
                            }

                            indexPoint++;
                        }

                        PathGeometry pathGeometry = new PathGeometry();
                        pathGeometry.Figures.Add(pathFigure);

                        // Draw the composition line with the squiggle
                        drawingContext.DrawGeometry(null, pen, pathGeometry);
                    }
                    else
                    {
                        drawingContext.DrawLine(pen, startPoint, endPoint);
                    }
                }
            }
        }