protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); Rect rect = new Rect(0.0, 0.0, base.ActualWidth, base.ActualHeight); JapaneseTextSource source = new JapaneseTextSource(); source.Text = this.Text; JapaneseTextParagraphProperties textParagraphProperties = this.MakeTextProperties(); source.JapaneseTextRunProperties = (JapaneseTextRunProperties)textParagraphProperties.DefaultTextRunProperties; source.IsVarticalWriting = textParagraphProperties.IsVerticalWriting; if (textParagraphProperties.DefaultTextRunProperties.BackgroundBrush != null) { drawingContext.DrawRectangle(textParagraphProperties.DefaultTextRunProperties.BackgroundBrush, null, rect); } Rect paddingRect = new Rect(this.Padding.Left, this.Padding.Top, Math.Max(0.0, base.ActualWidth - this.Padding.Left - this.Padding.Right), Math.Max(0.0, base.ActualHeight - this.Padding.Top - this.Padding.Bottom)); Point center = new Point((paddingRect.Left + paddingRect.Right) / 2.0, (paddingRect.Top + paddingRect.Bottom) / 2.0); Point startPosition; double paragraphWidth; if (textParagraphProperties.IsVerticalWriting) { Point origin = paddingRect.TopRight; Transform transOrigin = new RotateTransform(-90.0, center.X, center.Y); startPosition = transOrigin.Transform(origin); paragraphWidth = Math.Abs(paddingRect.Height); Transform trans = new RotateTransform(90.0, center.X, center.Y); drawingContext.PushTransform(trans); } else { startPosition = paddingRect.TopLeft; paragraphWidth = Math.Abs(paddingRect.Width); } startPosition.Y += textParagraphProperties.JapaneseTextRunProperties.FontRenderingEmSize; int textStorePosition = 0; Point linePosition = startPosition; TextFormatter formatter = TextFormatter.Create(); while (textStorePosition < source.Text.Length) { using (TextLine textLine = formatter.FormatLine(source, textStorePosition, paragraphWidth, textParagraphProperties, null)) { foreach (IndexedGlyphRun indexedrun in textLine.GetIndexedGlyphRuns()) { if (textParagraphProperties.IsVerticalWriting) { source.UniscribeIndexedGlyphRun(indexedrun); Rect runRect; if (source.GlyphCount != 0 && source.Glyphs[0] != 0) { Point ansiLinePosition = linePosition; ansiLinePosition.Y -= textParagraphProperties.JapaneseTextRunProperties.FontRenderingEmSize / 2.0; runRect = this.DrawIndexedGlyphRun(drawingContext, indexedrun, ansiLinePosition, source, true); } else { Point ansiLinePosition = linePosition; ansiLinePosition.Y -= textParagraphProperties.JapaneseTextRunProperties.FontRenderingEmSize / 10.0; runRect = this.DrawIndexedGlyphRun(drawingContext, indexedrun, ansiLinePosition, source, false); } linePosition.X += runRect.Width; } else { Rect runRect = this.DrawIndexedGlyphRun(drawingContext, indexedrun, linePosition, source, false); linePosition.X += runRect.Width; } } textStorePosition += textLine.Length; linePosition.X = startPosition.X; linePosition.Y += textLine.Height; } } if (textParagraphProperties.IsVerticalWriting) { drawingContext.Pop(); } }
private void Render(Point location, string colour) { int textStorePosition = 0; bool flipped; Position = location; if (ParentAtom == null) { flipped = false; } else { flipped = Flipped; } var textStore = new FunctionalGroupTextSource(ParentGroup, colour, flipped); //main textformatter - this does the writing of the visual using (TextFormatter textFormatter = TextFormatter.Create()) { //set up the default paragraph properties var paraprops = new FunctionalGroupTextSource.GenericTextParagraphProperties( FlowDirection.LeftToRight, TextAlignment.Left, true, false, new LabelTextRunProperties(colour), TextWrapping.NoWrap, GlyphText.SymbolSize, 0d); var anchorRuns = textStore.Runs.Where(f => f.IsAnchor); string anchorString = string.Empty; foreach (var run in anchorRuns) { anchorString += run.Text; } using (TextLine myTextLine = textFormatter.FormatLine(textStore, textStorePosition, 999, paraprops, null)) { IList <TextBounds> textBounds; Rect firstRect = Rect.Empty; if (!Flipped) //isolate them at the beginning { textBounds = myTextLine.GetTextBounds(0, anchorString.Length); } else { //isolate them at the end var start = myTextLine.Length - 1 - anchorString.Length; textBounds = myTextLine.GetTextBounds(start, anchorString.Length); } //add all the bounds together foreach (TextBounds anchorBound in textBounds) { firstRect.Union(anchorBound.Rectangle); } //center will be position close to the origin 0,0 Point center = new Point((firstRect.Left + firstRect.Right) / 2, (firstRect.Top + firstRect.Bottom) / 2); //the displacement vector will be added to each relative coordinate for the glyph run var displacementVector = location - center; //locus is where the text line is drawn var locus = new Point(0, 0) + displacementVector; textBounds = myTextLine.GetTextBounds(0, 999); var obb = textBounds[0].Rectangle; //draw the line of text using (DrawingContext dc = RenderOpen()) { myTextLine.Draw(dc, locus, InvertAxes.None); #if DEBUG #if SHOWBOUNDS obb.Offset(new Vector(locus.X, locus.Y)); dc.DrawRectangle(null, new Pen(new SolidColorBrush(Colors.BlueViolet), 1.0), obb); #endif #endif var glyphRuns = myTextLine.GetIndexedGlyphRuns(); List <Point> outline = new List <Point>(); double advanceWidths = 0d; //build up the convex hull from each glyph //you need to add in the advance widths for each //glyph run as they are traversed, //to the outline foreach (IndexedGlyphRun igr in glyphRuns) { var originalRun = textStore.GetTextRun(igr.TextSourceCharacterIndex); var currentRun = igr.GlyphRun; //need to work out how much the current run has been offset from the baseline var runBounds = myTextLine.GetTextBounds(igr.TextSourceCharacterIndex, igr.TextSourceLength); //get the bounding rect var rect = runBounds[0].TextRunBounds[0].Rectangle; //it's relative to the baseline //adjust it rect.Offset(new Vector(locus.X, locus.Y)); var rectCopy = rect; #if DEBUG #if SHOWBOUNDS dc.DrawRectangle(null, new Pen(new SolidColorBrush(Colors.DarkOrange), 1.0), rect); #endif #endif var runOutline = GlyphUtils.GetOutline(currentRun); //need to see if the run has been super or sub-scripted var variants = originalRun.Properties.TypographyProperties.Variants; if (variants == FontVariants.Subscript || variants == FontVariants.Superscript) { //simply union in the rect -it's easier! outline.AddRange(new[] { rectCopy.BottomLeft, rectCopy.BottomRight, rectCopy.TopLeft, rectCopy.TopRight }); } else { //add in the points from the convex hull for (int i = 0; i < runOutline.Count; i++) { var point = runOutline[i] + displacementVector + new Vector(0.0, myTextLine.Baseline); point.X += advanceWidths; runOutline[i] = point; } outline.AddRange(runOutline); } advanceWidths += currentRun.AdvanceWidths.Sum(); } _sortedOutline = (from Point p in outline orderby p.X ascending, p.Y descending select p).ToList(); Hull = Geometry <Point> .GetHull(_sortedOutline, p => p); // Diag: Show Hulls or Atom centres #if DEBUG #if SHOWHULLS dc.DrawGeometry(null, new Pen(Brushes.GreenYellow, thickness: 1), HullGeometry); #endif #if SHOWATOMCENTRES dc.DrawEllipse(Brushes.Red, null, ParentAtom.Position, 5, 5); #endif #endif // End Diag dc.Close(); } } } }
public static void HandleLine2(TextLine?myTextLine, Point linePosition, int lineNo, int textStorePosition, object?change, ILineInfo2Base?curLineInfo = null, BTree <TextRunInfo>?btRuns = null, Action <CharInfo, ILineInfo2Base>?takeChar = null) { var curPos = linePosition; var indexedGlyphRuns = myTextLine?.GetIndexedGlyphRuns(); // var z = new List<TextRunInfo>(); // btRuns?.DescendGreaterThan(new TextRunInfo(null, textStorePosition - 1), // info => // { // z.Add(info); // return info.Value < textStorePosition + length; // }); // using (var enum2 = z.GetEnumerator()) { // var moveNext2 = enum2.MoveNext(); var lineCharIndex = 0; var xOrigin = linePosition.X + myTextLine !.Start; if (indexedGlyphRuns == null) { return; } var lineRun = 0; foreach (var glyphRunC in indexedGlyphRuns) { var gl = glyphRunC.GlyphRun; var advanceSum = gl.AdvanceWidths.Sum(); for (var i = 0; i < gl.Characters.Count; i++) { var i0 = gl.ClusterMap?[i] ?? i; var glAdvanceWidth = gl.AdvanceWidths[i0]; var glCharacter = gl.Characters[i]; var glCaretStop = gl.CaretStops?[i0]; var glyphIndex = gl.GlyphIndices[i0]; var storePosition = textStorePosition + lineCharIndex; // Trace.WriteLine("char line " + lineNo + "[" + storePosition + "]: " + glCharacter); var ci = new CharInfo(lineNo, storePosition, lineCharIndex, i, glCharacter, glAdvanceWidth, glCaretStop, xOrigin, linePosition.Y, gl.GlyphTypeface.Height * gl.FontRenderingEmSize, gl.ComputeAlignmentBox(), gl.BaselineOrigin, glyphIndex, gl.GlyphTypeface, gl.FontRenderingEmSize, lineRun); takeChar !(ci, curLineInfo !); lineCharIndex++; xOrigin += glAdvanceWidth; } lineRun++; // var item = new Rect(curPos, new Size(advanceSum, myTextLine.Height)); // if (!moveNext2) // {w // var sb = new StringBuilder(); // for (var c = curCharInfoNode; c != null; c = c.Next) sb.Append(c.Value.Character); // // throw new CodeControlException("enumerator empty " + sb); // } // if (prevTri?.TextRun != null && prevTri != null && offset < prevTri.Value + prevTri.TextRun.Length) // { // prevTri.Rect.Union(item); // } // else // { // var textRunInfo = new TextRunInfo(offset); // var tri = btRuns?.Get(textRunInfo); // if (tri == null) // { // var sb = new StringBuilder(); // for (var c = curCharInfoNode; c != null; c = c.Next) sb.Append(c.Value.Character); // throw new CodeControlException("Unable to find entry for " + offset); // } // // tri.Rect = item; // // rectBtree?.ReplaceOrInsert(new RectInfo(tri.Rect, offset, tri.TextRun)); // // prevTri = tri; // } curPos.X += advanceSum; } } #pragma warning disable 8601 #pragma warning restore 8601 }