//-------------------------------------------------------------------- // // Public Properties // //--------------------------------------------------------------------- #region Static methods public static FixedSOMElement CreateFixedSOMElement(FixedPage page, UIElement uiElement, FixedNode fixedNode, int startIndex, int endIndex) { FixedSOMElement element = null; if (uiElement is Glyphs) { Glyphs glyphs = uiElement as Glyphs; if (glyphs.UnicodeString.Length > 0) { GlyphRun glyphRun = glyphs.ToGlyphRun(); Rect alignmentBox = glyphRun.ComputeAlignmentBox(); alignmentBox.Offset(glyphs.OriginX, glyphs.OriginY); GeneralTransform transform = glyphs.TransformToAncestor(page); if (startIndex < 0) { startIndex = 0; } if (endIndex < 0) { endIndex = glyphRun.Characters == null ? 0 : glyphRun.Characters.Count; } element = FixedSOMTextRun.Create(alignmentBox, transform, glyphs, fixedNode, startIndex, endIndex, false); } } else if (uiElement is Image) { element = FixedSOMImage.Create(page, uiElement as Image, fixedNode); } else if (uiElement is Path) { element = FixedSOMImage.Create(page, uiElement as Path, fixedNode); } return(element); }
// Token: 0x06002EE3 RID: 12003 RVA: 0x000D3B5C File Offset: 0x000D1D5C internal override ITextPointer GetNextCaretUnitPosition(ITextPointer position, LogicalDirection direction) { FixedTextPointer ftp = this.Container.VerifyPosition(position); FixedPosition fixedPosition; if (this._GetFixedPosition(ftp, out fixedPosition)) { DependencyObject element = this.FixedPage.GetElement(fixedPosition.Node); if (element is Glyphs) { Glyphs glyphs = (Glyphs)element; GlyphRun glyphRun = glyphs.ToGlyphRun(); int num = (glyphRun.Characters == null) ? 0 : glyphRun.Characters.Count; CharacterHit characterHit = (fixedPosition.Offset == num) ? new CharacterHit(fixedPosition.Offset - 1, 1) : new CharacterHit(fixedPosition.Offset, 0); CharacterHit obj = (direction == LogicalDirection.Forward) ? glyphRun.GetNextCaretCharacterHit(characterHit) : glyphRun.GetPreviousCaretCharacterHit(characterHit); if (!characterHit.Equals(obj)) { LogicalDirection edge = LogicalDirection.Forward; if (obj.TrailingLength > 0) { edge = LogicalDirection.Backward; } int offset = obj.FirstCharacterIndex + obj.TrailingLength; return(this._CreateTextPointer(new FixedPosition(fixedPosition.Node, offset), edge)); } } } ITextPointer textPointer = position.CreatePointer(); textPointer.MoveToNextInsertionPosition(direction); return(textPointer); }
// Token: 0x06002EF1 RID: 12017 RVA: 0x000D3FAC File Offset: 0x000D21AC private ITextPointer _SnapToText(Point point) { FixedNode[] line = this.Container.FixedTextBuilder.GetLine(this.PageIndex, point); ITextPointer textPointer; if (line != null && line.Length != 0) { double num = double.MaxValue; double xoffset = 0.0; Glyphs glyphs = null; FixedNode fixedNode = line[0]; foreach (FixedNode fixedNode2 in line) { Glyphs glyphsElement = this.FixedPage.GetGlyphsElement(fixedNode2); GeneralTransform generalTransform = this.FixedPage.TransformToDescendant(glyphsElement); Point inPoint = point; if (generalTransform != null) { generalTransform.TryTransform(inPoint, out inPoint); } GlyphRun glyphRun = glyphsElement.ToGlyphRun(); Rect rect = glyphRun.ComputeAlignmentBox(); rect.Offset(glyphsElement.OriginX, glyphsElement.OriginY); double num2 = Math.Max(0.0, (inPoint.X > rect.X) ? (inPoint.X - rect.Right) : (rect.X - inPoint.X)); double num3 = Math.Max(0.0, (inPoint.Y > rect.Y) ? (inPoint.Y - rect.Bottom) : (rect.Y - inPoint.Y)); double num4 = num2 + num3; if (glyphs == null || num4 < num) { num = num4; glyphs = glyphsElement; fixedNode = fixedNode2; xoffset = inPoint.X; } } int offset; LogicalDirection edge; this._GlyphRunHitTest(glyphs, xoffset, out offset, out edge); FixedPosition fixedPosition = new FixedPosition(fixedNode, offset); textPointer = this._CreateTextPointer(fixedPosition, edge); } else if (point.Y < this.FixedPage.Height / 2.0) { textPointer = ((ITextPointer)this.Start).CreatePointer(LogicalDirection.Forward); textPointer.MoveToInsertionPosition(LogicalDirection.Forward); } else { textPointer = ((ITextPointer)this.End).CreatePointer(LogicalDirection.Backward); textPointer.MoveToInsertionPosition(LogicalDirection.Backward); } return(textPointer); }
// Token: 0x06002EF4 RID: 12020 RVA: 0x000D4420 File Offset: 0x000D2620 internal static Rect _GetGlyphRunDesignRect(Glyphs g, int charStart, int charEnd) { GlyphRun glyphRun = g.ToGlyphRun(); if (glyphRun == null) { return(Rect.Empty); } Rect result = glyphRun.ComputeAlignmentBox(); result.Offset(glyphRun.BaselineOrigin.X, glyphRun.BaselineOrigin.Y); int num = 0; if (glyphRun.Characters != null) { num = glyphRun.Characters.Count; } else if (g.UnicodeString != null) { num = g.UnicodeString.Length; } if (charStart > num) { charStart = num; } else if (charStart < 0) { charStart = 0; } if (charEnd > num) { charEnd = num; } else if (charEnd < 0) { charEnd = 0; } double num2 = FixedTextView._GetDistanceToCharacter(glyphRun, charStart); double num3 = FixedTextView._GetDistanceToCharacter(glyphRun, charEnd); double width = num3 - num2; if ((glyphRun.BidiLevel & 1) != 0) { result.X = glyphRun.BaselineOrigin.X - num3; } else { result.X = glyphRun.BaselineOrigin.X + num2; } result.Width = width; return(result); }
// Token: 0x0600301A RID: 12314 RVA: 0x000D8690 File Offset: 0x000D6890 private void _UpdateHighlightForeground(DrawingContext dc, ArrayList highlights) { foreach (object obj in highlights) { FixedHighlight fixedHighlight = (FixedHighlight)obj; Brush brush = null; if (fixedHighlight.HighlightType != FixedHighlightType.None) { Glyphs glyphs = fixedHighlight.Glyphs; if (glyphs != null) { Rect rect = fixedHighlight.ComputeDesignRect(); if (!(rect == Rect.Empty)) { GeneralTransform generalTransform = fixedHighlight.Element.TransformToAncestor(this._page); Transform affineTransform = generalTransform.AffineTransform; if (affineTransform != null) { dc.PushTransform(affineTransform); } else { dc.PushTransform(Transform.Identity); } dc.PushClip(new RectangleGeometry(rect)); if (fixedHighlight.HighlightType == FixedHighlightType.TextSelection) { brush = SelectionHighlightInfo.ForegroundBrush; } else if (fixedHighlight.HighlightType == FixedHighlightType.AnnotationHighlight) { brush = fixedHighlight.ForegroundBrush; } GlyphRun glyphRun = glyphs.ToGlyphRun(); if (brush == null) { brush = glyphs.Fill; } dc.PushGuidelineY1(glyphRun.BaselineOrigin.Y); dc.PushClip(glyphs.Clip); dc.DrawGlyphRun(brush, glyphRun); dc.Pop(); dc.Pop(); dc.Pop(); dc.Pop(); } } } } }
/// <summary> /// Finds the next position at the edge of a caret unit in /// specified direction. /// </summary> /// <param name="position"> /// Initial text position of an object/character. /// </param> /// <param name="direction"> /// If Forward, this method returns the "caret unit" position following /// the initial position. /// If Backward, this method returns the caret unit" position preceding /// the initial position. /// </param> /// <returns> /// The next caret unit break position in specified direction. /// </returns> /// <exception cref="System.InvalidOperationException"> /// Throws InvalidOperationException if IsValid is false. /// If IsValid returns false, Validate method must be called before /// calling this method. /// </exception> /// <remarks> /// In the context of this method, "caret unit" refers to a group of one /// or more Unicode code points that map to a single rendered glyph. /// /// If position is located between two caret units, this method returns /// a new position located at the opposite edge of the caret unit in /// the indicated direction. /// If position is located within a group of Unicode code points that map /// to a single caret unit, this method returns a new position at /// the indicated edge of the containing caret unit. /// If position is located at the beginning of end of content -- there is /// no content in the indicated direction -- then this method returns /// a position located at the same location as initial position. /// </remarks> internal override ITextPointer GetNextCaretUnitPosition(ITextPointer position, LogicalDirection direction) { FixedTextPointer ftp = Container.VerifyPosition(position); FixedPosition fixedp; if (_GetFixedPosition(ftp, out fixedp)) { DependencyObject element = this.FixedPage.GetElement(fixedp.Node); if (element is Glyphs) { Glyphs g = (Glyphs)element; GlyphRun run = g.ToGlyphRun(); int characterCount = (run.Characters == null) ? 0 : run.Characters.Count; CharacterHit start = (fixedp.Offset == characterCount) ? new CharacterHit(fixedp.Offset - 1, 1) : new CharacterHit(fixedp.Offset, 0); CharacterHit next = (direction == LogicalDirection.Forward) ? run.GetNextCaretCharacterHit(start) : run.GetPreviousCaretCharacterHit(start); if (!start.Equals(next)) { LogicalDirection edge = LogicalDirection.Forward; if (next.TrailingLength > 0) { edge = LogicalDirection.Backward; } int index = next.FirstCharacterIndex + next.TrailingLength; return(_CreateTextPointer(new FixedPosition(fixedp.Node, index), edge)); } } } //default behavior is to simply move textpointer ITextPointer pointer = position.CreatePointer(); pointer.MoveToNextInsertionPosition(direction); return(pointer); }
// Token: 0x06002EF0 RID: 12016 RVA: 0x000D3F34 File Offset: 0x000D2134 private void _GlyphRunHitTest(Glyphs g, double xoffset, out int charIndex, out LogicalDirection edge) { charIndex = 0; edge = LogicalDirection.Forward; GlyphRun glyphRun = g.ToGlyphRun(); double distance; if ((glyphRun.BidiLevel & 1) != 0) { distance = glyphRun.BaselineOrigin.X - xoffset; } else { distance = xoffset - glyphRun.BaselineOrigin.X; } bool flag; CharacterHit caretCharacterHitFromDistance = glyphRun.GetCaretCharacterHitFromDistance(distance, out flag); charIndex = caretCharacterHitFromDistance.FirstCharacterIndex + caretCharacterHitFromDistance.TrailingLength; edge = ((caretCharacterHitFromDistance.TrailingLength > 0) ? LogicalDirection.Backward : LogicalDirection.Forward); }
private void _GlyphRunHitTest(Glyphs g, double xoffset, out int charIndex, out LogicalDirection edge) { charIndex = 0; edge = LogicalDirection.Forward; GlyphRun run = g.ToGlyphRun(); bool isInside; double distance; if ((run.BidiLevel & 1) != 0) { distance = run.BaselineOrigin.X - xoffset; } else { distance = xoffset - run.BaselineOrigin.X; } CharacterHit hit = run.GetCaretCharacterHitFromDistance(distance, out isInside); charIndex = hit.FirstCharacterIndex + hit.TrailingLength; edge = (hit.TrailingLength > 0) ? LogicalDirection.Backward : LogicalDirection.Forward; }
//determines whether and where a rectangle intersects a Glyphs private bool IntersectGlyphs(Glyphs g, double top, double left, double bottom, double right, out int begin, out int end, out bool includeEnd, out double baseline, out double height) { begin = 0; end = 0; includeEnd = false; GlyphRun run = g.ToGlyphRun(); Rect boundingRect = run.ComputeAlignmentBox(); boundingRect.Offset(run.BaselineOrigin.X, run.BaselineOrigin.Y); //useful for same line detection baseline = run.BaselineOrigin.Y; height = boundingRect.Height; double centerLine = boundingRect.Y + .5 * boundingRect.Height; GeneralTransform t = g.TransformToAncestor(_page); Point pt1; t.TryTransform(new Point(boundingRect.Left, centerLine), out pt1); Point pt2; t.TryTransform(new Point(boundingRect.Right, centerLine), out pt2); double dStart, dEnd; bool cross = false; if (pt1.X < left) { if (pt2.X < left) { return false; } cross = true; } else if (pt1.X > right) { if (pt2.X > right) { return false; } cross = true; } else if (pt2.X < left || pt2.X > right) { cross = true; } if (cross) { double d1 = (left - pt1.X) / (pt2.X - pt1.X); double d2 = (right - pt1.X) / (pt2.X - pt1.X); if (d2 > d1) { dStart = d1; dEnd = d2; } else { dStart = d2; dEnd = d1; } } else { dStart = 0; dEnd = 1; } cross = false; if (pt1.Y < top) { if (pt2.Y < top) { return false; } cross = true; } else if (pt1.Y > bottom) { if (pt2.Y > bottom) { return false; } cross = true; } else if (pt2.Y < top || pt2.Y > bottom) { cross = true; } if (cross) { double d1 = (top - pt1.Y) / (pt2.Y - pt1.Y); double d2 = (bottom - pt1.Y) / (pt2.Y - pt1.Y); if (d2 > d1) { if (d1 > dStart) { dStart = d1; } if (d2 < dEnd) { dEnd = d2; } } else { if (d2 > dStart) { dStart = d2; } if (d1 < dEnd) { dEnd = d1; } } } dStart = boundingRect.Left + boundingRect.Width * dStart; dEnd = boundingRect.Left + boundingRect.Width * dEnd; bool leftToRight = ((run.BidiLevel & 1) == 0); begin = GlyphRunHitTest(run, dStart, leftToRight); end = GlyphRunHitTest(run, dEnd, leftToRight); if (begin > end) { int temp = begin; begin = end; end = temp; } Debug.Assert(end >= begin); int characterCount = (run.Characters == null) ? 0 : run.Characters.Count; includeEnd = (end == characterCount); return true; }
// char index == -1 implies end of run. internal static Rect _GetGlyphRunDesignRect(Glyphs g, int charStart, int charEnd) { GlyphRun run = g.ToGlyphRun(); if (run == null) { return(Rect.Empty); } Rect designRect = run.ComputeAlignmentBox(); designRect.Offset(run.BaselineOrigin.X, run.BaselineOrigin.Y); int charCount = 0; if (run.Characters != null) { charCount = run.Characters.Count; } else if (g.UnicodeString != null) { charCount = g.UnicodeString.Length; } if (charStart > charCount) { //Extra space was added at the end of the run for contiguity Debug.Assert(charStart - charCount == 1); charStart = charCount; } else if (charStart < 0) { //This is a reversed run charStart = 0; } if (charEnd > charCount) { //Extra space was added at the end of the run for contiguity Debug.Assert(charEnd - charCount == 1); charEnd = charCount; } else if (charEnd < 0) { //This is a reversed run charEnd = 0; } double x1 = _GetDistanceToCharacter(run, charStart); double x2 = _GetDistanceToCharacter(run, charEnd); double width = x2 - x1; if ((run.BidiLevel & 1) != 0) { // right to left designRect.X = run.BaselineOrigin.X - x2; } else { designRect.X = run.BaselineOrigin.X + x1; } designRect.Width = width; return(designRect); }
// Token: 0x06002E37 RID: 11831 RVA: 0x000D0E28 File Offset: 0x000CF028 public static FixedSOMTextRun Create(Rect boundingRect, GeneralTransform transform, Glyphs glyphs, FixedNode fixedNode, int startIndex, int endIndex, bool allowReverseGlyphs) { if (string.IsNullOrEmpty(glyphs.UnicodeString) || glyphs.FontRenderingEmSize <= 0.0) { return(null); } FixedSOMTextRun fixedSOMTextRun = new FixedSOMTextRun(boundingRect, transform, fixedNode, startIndex, endIndex); fixedSOMTextRun._fontUri = glyphs.FontUri; fixedSOMTextRun._cultureInfo = glyphs.Language.GetCompatibleCulture(); fixedSOMTextRun._bidiLevel = glyphs.BidiLevel; fixedSOMTextRun._isSideways = glyphs.IsSideways; fixedSOMTextRun._fontSize = glyphs.FontRenderingEmSize; GlyphRun glyphRun = glyphs.ToGlyphRun(); GlyphTypeface glyphTypeface = glyphRun.GlyphTypeface; glyphTypeface.FamilyNames.TryGetValue(fixedSOMTextRun._cultureInfo, out fixedSOMTextRun._fontFamily); if (fixedSOMTextRun._fontFamily == null) { glyphTypeface.FamilyNames.TryGetValue(TypeConverterHelper.InvariantEnglishUS, out fixedSOMTextRun._fontFamily); } fixedSOMTextRun._fontStyle = glyphTypeface.Style; fixedSOMTextRun._fontWeight = glyphTypeface.Weight; fixedSOMTextRun._fontStretch = glyphTypeface.Stretch; fixedSOMTextRun._defaultCharWidth = ((glyphTypeface.XHeight > 0.0) ? (glyphTypeface.XHeight * glyphs.FontRenderingEmSize) : glyphRun.AdvanceWidths[startIndex]); Transform affineTransform = transform.AffineTransform; if (affineTransform != null && !affineTransform.Value.IsIdentity) { Matrix value = affineTransform.Value; double num = Math.Sqrt(value.M12 * value.M12 + value.M22 * value.M22); double num2 = Math.Sqrt(value.M11 * value.M11 + value.M21 * value.M21); fixedSOMTextRun._fontSize *= num; fixedSOMTextRun._defaultCharWidth *= num2; } fixedSOMTextRun._foreground = glyphs.Fill; string unicodeString = glyphs.UnicodeString; fixedSOMTextRun.Text = unicodeString.Substring(startIndex, endIndex - startIndex); if (allowReverseGlyphs && fixedSOMTextRun._bidiLevel == 0 && !fixedSOMTextRun._isSideways && startIndex == 0 && endIndex == unicodeString.Length && string.IsNullOrEmpty(glyphs.CaretStops) && FixedTextBuilder.MostlyRTL(unicodeString)) { char[] array = new char[fixedSOMTextRun.Text.Length]; for (int i = 0; i < fixedSOMTextRun.Text.Length; i++) { array[i] = fixedSOMTextRun.Text[fixedSOMTextRun.Text.Length - 1 - i]; } fixedSOMTextRun._isReversed = true; fixedSOMTextRun.Text = new string(array); } if (unicodeString == "" && glyphs.Indices != null && glyphs.Indices.Length > 0) { fixedSOMTextRun._isWhiteSpace = false; } else { fixedSOMTextRun._isWhiteSpace = true; for (int j = 0; j < unicodeString.Length; j++) { if (!char.IsWhiteSpace(unicodeString[j])) { fixedSOMTextRun._isWhiteSpace = false; break; } } } return(fixedSOMTextRun); }
//Processes the Glyphs element, create one or more text runs out of it, add to containing text line and text box private void _ProcessGlyphsElement(Glyphs glyphs, FixedNode node) { Debug.Assert(glyphs != null); string s = glyphs.UnicodeString; if (s.Length == 0 || glyphs.FontRenderingEmSize <= 0) { return; } //Multiple table cells separated by wide spaces should be identified GlyphRun glyphRun = glyphs.ToGlyphRun(); if (glyphRun == null) { //Could not create a GlyphRun out of this Glyphs element //Some key properties might be missing/invalid return; } Rect alignmentBox = glyphRun.ComputeAlignmentBox(); alignmentBox.Offset(glyphs.OriginX, glyphs.OriginY); GlyphTypeface typeFace = glyphRun.GlyphTypeface; GeneralTransform trans = glyphs.TransformToAncestor(_fixedPage); int charIndex= -1; double advWidth = 0; double cumulativeAdvWidth = 0; int lastAdvWidthIndex = 0; int textRunStartIndex = 0; double lastX = alignmentBox.Left; int glyphIndex = charIndex; do { charIndex = s.IndexOf(" ", charIndex+1, s.Length - charIndex -1, StringComparison.Ordinal); if (charIndex >=0 ) { if (glyphRun.ClusterMap != null && glyphRun.ClusterMap.Count > 0) { glyphIndex = glyphRun.ClusterMap[charIndex]; } else { glyphIndex = charIndex; } //Advance width of the space character in the font double advFont = typeFace.AdvanceWidths[glyphRun.GlyphIndices[glyphIndex]] * glyphRun.FontRenderingEmSize; double advSpecified = glyphRun.AdvanceWidths[glyphIndex]; if ((advSpecified / advFont) > 2) { //Are these seperated by a vertical line? advWidth = 0; for (int i=lastAdvWidthIndex; i<glyphIndex; i++) { advWidth += glyphRun.AdvanceWidths[i]; } cumulativeAdvWidth += advWidth; lastAdvWidthIndex = glyphIndex + 1; if (_lines.IsVerticallySeparated(glyphRun.BaselineOrigin.X + cumulativeAdvWidth, alignmentBox.Top, glyphRun.BaselineOrigin.X + cumulativeAdvWidth + advSpecified, alignmentBox.Bottom)) { //Create a new FixedTextRun Rect boundingRect = new Rect(lastX, alignmentBox.Top, advWidth + advFont, alignmentBox.Height); int endIndex = charIndex; if ((charIndex == 0 || s[charIndex-1] == ' ') && (charIndex != s.Length - 1)) { endIndex = charIndex + 1; } _CreateTextRun(boundingRect, trans, glyphs, node, textRunStartIndex, endIndex); lastX = lastX + advWidth + advSpecified; textRunStartIndex = charIndex+1; } cumulativeAdvWidth += advSpecified; } } } while (charIndex >= 0 && charIndex < s.Length-1); if (textRunStartIndex < s.Length) { //Last text run //For non-partitioned elements this will be the whole Glyphs element Rect boundingRect = new Rect(lastX, alignmentBox.Top, alignmentBox.Right-lastX, alignmentBox.Height); _CreateTextRun( boundingRect, trans, glyphs, node, textRunStartIndex, s.Length); } }
//Processes the Glyphs element, create one or more text runs out of it, add to containing text line and text box private void _ProcessGlyphsElement(Glyphs glyphs, FixedNode node) { Debug.Assert(glyphs != null); string s = glyphs.UnicodeString; if (s.Length == 0 || glyphs.FontRenderingEmSize <= 0) { return; } //Multiple table cells separated by wide spaces should be identified GlyphRun glyphRun = glyphs.ToGlyphRun(); if (glyphRun == null) { //Could not create a GlyphRun out of this Glyphs element //Some key properties might be missing/invalid return; } Rect alignmentBox = glyphRun.ComputeAlignmentBox(); alignmentBox.Offset(glyphs.OriginX, glyphs.OriginY); GlyphTypeface typeFace = glyphRun.GlyphTypeface; GeneralTransform trans = glyphs.TransformToAncestor(_fixedPage); int charIndex = -1; double advWidth = 0; double cumulativeAdvWidth = 0; int lastAdvWidthIndex = 0; int textRunStartIndex = 0; double lastX = alignmentBox.Left; int glyphIndex = charIndex; do { charIndex = s.IndexOf(" ", charIndex + 1, s.Length - charIndex - 1, StringComparison.Ordinal); if (charIndex >= 0) { if (glyphRun.ClusterMap != null && glyphRun.ClusterMap.Count > 0) { glyphIndex = glyphRun.ClusterMap[charIndex]; } else { glyphIndex = charIndex; } //Advance width of the space character in the font double advFont = typeFace.AdvanceWidths[glyphRun.GlyphIndices[glyphIndex]] * glyphRun.FontRenderingEmSize; double advSpecified = glyphRun.AdvanceWidths[glyphIndex]; if ((advSpecified / advFont) > 2) { //Are these seperated by a vertical line? advWidth = 0; for (int i = lastAdvWidthIndex; i < glyphIndex; i++) { advWidth += glyphRun.AdvanceWidths[i]; } cumulativeAdvWidth += advWidth; lastAdvWidthIndex = glyphIndex + 1; if (_lines.IsVerticallySeparated(glyphRun.BaselineOrigin.X + cumulativeAdvWidth, alignmentBox.Top, glyphRun.BaselineOrigin.X + cumulativeAdvWidth + advSpecified, alignmentBox.Bottom)) { //Create a new FixedTextRun Rect boundingRect = new Rect(lastX, alignmentBox.Top, advWidth + advFont, alignmentBox.Height); int endIndex = charIndex; if ((charIndex == 0 || s[charIndex - 1] == ' ') && (charIndex != s.Length - 1)) { endIndex = charIndex + 1; } _CreateTextRun(boundingRect, trans, glyphs, node, textRunStartIndex, endIndex); lastX = lastX + advWidth + advSpecified; textRunStartIndex = charIndex + 1; } cumulativeAdvWidth += advSpecified; } } } while (charIndex >= 0 && charIndex < s.Length - 1); if (textRunStartIndex < s.Length) { //Last text run //For non-partitioned elements this will be the whole Glyphs element Rect boundingRect = new Rect(lastX, alignmentBox.Top, alignmentBox.Right - lastX, alignmentBox.Height); _CreateTextRun(boundingRect, trans, glyphs, node, textRunStartIndex, s.Length); } }
//-------------------------------------------------------------------- // // Public Methods // //--------------------------------------------------------------------- #region public Methods public static FixedSOMTextRun Create(Rect boundingRect, GeneralTransform transform, Glyphs glyphs, FixedNode fixedNode, int startIndex, int endIndex, bool allowReverseGlyphs) { if (String.IsNullOrEmpty(glyphs.UnicodeString) || glyphs.FontRenderingEmSize <= 0) { return null; } FixedSOMTextRun run = new FixedSOMTextRun(boundingRect, transform, fixedNode, startIndex, endIndex); run._fontUri = glyphs.FontUri; run._cultureInfo = glyphs.Language.GetCompatibleCulture(); run._bidiLevel = glyphs.BidiLevel; run._isSideways = glyphs.IsSideways; run._fontSize = glyphs.FontRenderingEmSize; GlyphRun glyphRun = glyphs.ToGlyphRun(); GlyphTypeface gtf = glyphRun.GlyphTypeface; // Find font family // glyphs.FontUri, glyphRun.glyphTypeface gtf.FamilyNames.TryGetValue(run._cultureInfo, out run._fontFamily); if (run._fontFamily == null) { //Try getting the English name gtf.FamilyNames.TryGetValue(System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS, out run._fontFamily); } // Find font style (normal, italics, Oblique) // need to open Font file. run._fontStyle = gtf.Style; // Find font weight (bold, semibold, ExtraLight) run._fontWeight = gtf.Weight; // Find font stretch (UltraCondensed, SemiExpanded, etc) run._fontStretch = gtf.Stretch; //Height and width should be the same for x character run._defaultCharWidth = gtf.XHeight > 0 ? gtf.XHeight * glyphs.FontRenderingEmSize : glyphRun.AdvanceWidths[startIndex]; Transform trans = transform.AffineTransform; if (trans != null && !(trans.Value.IsIdentity)) { Matrix mat = trans.Value; double yScale = Math.Sqrt(mat.M12*mat.M12 + mat.M22*mat.M22); double xScale = Math.Sqrt(mat.M11 * mat.M11 + mat.M21 * mat.M21); run._fontSize *= yScale; run._defaultCharWidth *= xScale; } run._foreground = glyphs.Fill; String s = glyphs.UnicodeString; run.Text = s.Substring(startIndex, endIndex-startIndex); if (allowReverseGlyphs && run._bidiLevel == 0 && !run._isSideways && startIndex == 0 && endIndex == s.Length && String.IsNullOrEmpty(glyphs.CaretStops) && FixedTextBuilder.MostlyRTL(s)) { char[] chars = new char[run.Text.Length]; for (int i=0; i<run.Text.Length; i++) { chars[i] = run.Text[run.Text.Length - 1 - i]; } run._isReversed = true; run.Text = new string(chars); } if (s == "" && glyphs.Indices != null && glyphs.Indices.Length > 0) { run._isWhiteSpace = false; } else { run._isWhiteSpace = true; for (int i = 0; i < s.Length; i++) { if (!Char.IsWhiteSpace(s[i])) { run._isWhiteSpace = false; break; } } } return run; }
//-------------------------------------------------------------------- // // Public Methods // //--------------------------------------------------------------------- #region public Methods public static FixedSOMTextRun Create(Rect boundingRect, GeneralTransform transform, Glyphs glyphs, FixedNode fixedNode, int startIndex, int endIndex, bool allowReverseGlyphs) { if (String.IsNullOrEmpty(glyphs.UnicodeString) || glyphs.FontRenderingEmSize <= 0) { return(null); } FixedSOMTextRun run = new FixedSOMTextRun(boundingRect, transform, fixedNode, startIndex, endIndex); run._fontUri = glyphs.FontUri; run._cultureInfo = glyphs.Language.GetCompatibleCulture(); run._bidiLevel = glyphs.BidiLevel; run._isSideways = glyphs.IsSideways; run._fontSize = glyphs.FontRenderingEmSize; GlyphRun glyphRun = glyphs.ToGlyphRun(); GlyphTypeface gtf = glyphRun.GlyphTypeface; // Find font family // glyphs.FontUri, glyphRun.glyphTypeface gtf.FamilyNames.TryGetValue(run._cultureInfo, out run._fontFamily); if (run._fontFamily == null) { //Try getting the English name gtf.FamilyNames.TryGetValue(System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS, out run._fontFamily); } // Find font style (normal, italics, Oblique) // need to open Font file. run._fontStyle = gtf.Style; // Find font weight (bold, semibold, ExtraLight) run._fontWeight = gtf.Weight; // Find font stretch (UltraCondensed, SemiExpanded, etc) run._fontStretch = gtf.Stretch; //Height and width should be the same for x character run._defaultCharWidth = gtf.XHeight > 0 ? gtf.XHeight * glyphs.FontRenderingEmSize : glyphRun.AdvanceWidths[startIndex]; Transform trans = transform.AffineTransform; if (trans != null && !(trans.Value.IsIdentity)) { Matrix mat = trans.Value; double yScale = Math.Sqrt(mat.M12 * mat.M12 + mat.M22 * mat.M22); double xScale = Math.Sqrt(mat.M11 * mat.M11 + mat.M21 * mat.M21); run._fontSize *= yScale; run._defaultCharWidth *= xScale; } run._foreground = glyphs.Fill; String s = glyphs.UnicodeString; run.Text = s.Substring(startIndex, endIndex - startIndex); if (allowReverseGlyphs && run._bidiLevel == 0 && !run._isSideways && startIndex == 0 && endIndex == s.Length && String.IsNullOrEmpty(glyphs.CaretStops) && FixedTextBuilder.MostlyRTL(s)) { run._isReversed = true; run.Text = string.Create(run.Text.Length, run.Text, (destination, runText) => { for (int i = 0; i < destination.Length; i++) { destination[i] = runText[runText.Length - 1 - i]; } }); } if (s == "" && glyphs.Indices != null && glyphs.Indices.Length > 0) { run._isWhiteSpace = false; } else { run._isWhiteSpace = true; for (int i = 0; i < s.Length; i++) { if (!Char.IsWhiteSpace(s[i])) { run._isWhiteSpace = false; break; } } } return(run); }
internal void RenderFixedNode(DrawingContext dc) { // //Iterate through fix node to draw red dotted line // CultureInfo EnglishCulture = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; int lineCount = _lineResults.Length; if (lineCount == 0) { return; } FixedNode fixedStartPage = _lineResults[0].Start; FixedNode fixedEndPage = _lineResults[lineCount - 1].End; FixedNode[] fixedNodes = _fixedTextBuilder.FixedFlowMap.FixedOrderGetRangeNodes(fixedStartPage, fixedEndPage); FixedPage fp = _fixedTextBuilder.FixedTextContainer.FixedDocument.GetFixedPage(PageIndex); FormattedText ft; Point prevTextPoint = new Point(0, 0); DpiScale dpi = fp.GetDpi(); foreach (FixedNode currentFixedNode in fixedNodes) { if (currentFixedNode.Page == FixedFlowMap.FixedOrderStartPage) { prevTextPoint.X = prevTextPoint.Y = 0; ft = new FormattedText("FixedOrderStartPage", EnglishCulture, FlowDirection.LeftToRight, new Typeface("Courier New"), 8, Brushes.DarkViolet, dpi.PixelsPerDip); dc.DrawText(ft, prevTextPoint); continue; } if (currentFixedNode.Page == FixedFlowMap.FixedOrderEndPage) { prevTextPoint.X = fp.Width - 100; prevTextPoint.Y = fp.Height - 10; ft = new FormattedText("FixedOrderEndPage", EnglishCulture, FlowDirection.LeftToRight, new Typeface("Courier New"), 8, Brushes.DarkViolet, dpi.PixelsPerDip); dc.DrawText(ft, prevTextPoint); continue; } if (currentFixedNode[1] == FixedFlowMap.FixedOrderStartVisual || currentFixedNode[1] == FixedFlowMap.FixedOrderEndVisual) { prevTextPoint.X = 2; prevTextPoint.Y = prevTextPoint.Y + 10; String outputString = currentFixedNode[1] == FixedFlowMap.FixedOrderStartVisual ? "FixedOrderStartVisual" : "FixedOrderEndVisual"; ft = new FormattedText(outputString, EnglishCulture, FlowDirection.LeftToRight, new Typeface("Courier New"), 8, Brushes.DarkViolet, dpi.PixelsPerDip); dc.DrawText(ft, prevTextPoint); continue; } DependencyObject dependencyObject = fp.GetElement(currentFixedNode); Image image = dependencyObject as Image; if (image != null) { GeneralTransform transform = image.TransformToAncestor(fp); // You can't use GetContentBounds inside OnRender Rect boundingRect = new Rect(0, 0, image.Width, image.Height); Rect imageRect = transform.TransformBounds(boundingRect); if (!imageRect.IsEmpty) { // Image might overlap, inflate the box. imageRect.Inflate(1, 1); Pen pen = new Pen(Brushes.DarkMagenta, 1.5); DrawRectOutline(dc, pen, imageRect); prevTextPoint.X = imageRect.Right; prevTextPoint.Y = imageRect.Bottom - 10; } else { prevTextPoint.X = 2; prevTextPoint.Y = prevTextPoint.Y + 10; } ft = new FormattedText(currentFixedNode.ToString(), EnglishCulture, FlowDirection.LeftToRight, new Typeface("Courier New"), 8, Brushes.DarkViolet, dpi.PixelsPerDip); dc.DrawText(ft, prevTextPoint); continue; } Path path = dependencyObject as Path; if (path != null) { GeneralTransform transform = path.TransformToAncestor(fp); // You can't use GetContentBounds inside OnRender Rect boundingRect = path.Data.Bounds; Rect imageRect = transform.TransformBounds(boundingRect); if (!imageRect.IsEmpty) { // Image might overlap, inflate the box. imageRect.Inflate(1, 1); Pen pen = new Pen(Brushes.DarkMagenta, 1.5); DrawRectOutline(dc, pen, imageRect); prevTextPoint.X = imageRect.Right; prevTextPoint.Y = imageRect.Bottom - 10; } else { prevTextPoint.X = 2; prevTextPoint.Y = prevTextPoint.Y + 10; } ft = new FormattedText(currentFixedNode.ToString(), EnglishCulture, FlowDirection.LeftToRight, new Typeface("Courier New"), 8, Brushes.DarkViolet, dpi.PixelsPerDip); dc.DrawText(ft, prevTextPoint); continue; } Glyphs glyphs = dependencyObject as Glyphs; if (glyphs != null) { GlyphRun run = glyphs.ToGlyphRun(); if (run != null) { Rect glyphBox = run.ComputeAlignmentBox(); glyphBox.Offset(glyphs.OriginX, glyphs.OriginY); GeneralTransform transform = glyphs.TransformToAncestor(fp); // // Draw it using the dotted red line // Pen pen = new Pen(Brushes.Red, 0.5); Transform t = transform.AffineTransform; if (t != null) { dc.PushTransform(t); } else { dc.PushTransform(Transform.Identity); } DrawRectOutline(dc, pen, glyphBox); prevTextPoint.X = glyphBox.Right; prevTextPoint.Y = glyphBox.Bottom; transform.TryTransform(prevTextPoint, out prevTextPoint); dc.Pop(); // transform } else { prevTextPoint.X = 2; prevTextPoint.Y = prevTextPoint.Y + 10; } ft = new FormattedText(currentFixedNode.ToString(), EnglishCulture, FlowDirection.LeftToRight, new Typeface("Courier New"), 8, Brushes.DarkViolet, dpi.PixelsPerDip); dc.DrawText(ft, prevTextPoint); continue; } // // For anything else, there is this code to draw ... // prevTextPoint.X = 2; prevTextPoint.Y = prevTextPoint.Y + 10; ft = new FormattedText(currentFixedNode.ToString(), EnglishCulture, FlowDirection.LeftToRight, new Typeface("Courier New"), 8, Brushes.DarkViolet, dpi.PixelsPerDip); dc.DrawText(ft, prevTextPoint); } }
// Token: 0x06002DF9 RID: 11769 RVA: 0x000CEA3C File Offset: 0x000CCC3C private void _ProcessGlyphsElement(Glyphs glyphs, FixedNode node) { string unicodeString = glyphs.UnicodeString; if (unicodeString.Length == 0 || glyphs.FontRenderingEmSize <= 0.0) { return; } GlyphRun glyphRun = glyphs.ToGlyphRun(); if (glyphRun == null) { return; } Rect rect = glyphRun.ComputeAlignmentBox(); rect.Offset(glyphs.OriginX, glyphs.OriginY); GlyphTypeface glyphTypeface = glyphRun.GlyphTypeface; GeneralTransform trans = glyphs.TransformToAncestor(this._fixedPage); int num = -1; double num2 = 0.0; int num3 = 0; int num4 = 0; double num5 = rect.Left; do { num = unicodeString.IndexOf(" ", num + 1, unicodeString.Length - num - 1, StringComparison.Ordinal); if (num >= 0) { int num6; if (glyphRun.ClusterMap != null && glyphRun.ClusterMap.Count > 0) { num6 = (int)glyphRun.ClusterMap[num]; } else { num6 = num; } double num7 = glyphTypeface.AdvanceWidths[glyphRun.GlyphIndices[num6]] * glyphRun.FontRenderingEmSize; double num8 = glyphRun.AdvanceWidths[num6]; if (num8 / num7 > 2.0) { double num9 = 0.0; for (int i = num3; i < num6; i++) { num9 += glyphRun.AdvanceWidths[i]; } num2 += num9; num3 = num6 + 1; if (this._lines.IsVerticallySeparated(glyphRun.BaselineOrigin.X + num2, rect.Top, glyphRun.BaselineOrigin.X + num2 + num8, rect.Bottom)) { Rect boundingRect = new Rect(num5, rect.Top, num9 + num7, rect.Height); int endIndex = num; if ((num == 0 || unicodeString[num - 1] == ' ') && num != unicodeString.Length - 1) { endIndex = num + 1; } this._CreateTextRun(boundingRect, trans, glyphs, node, num4, endIndex); num5 = num5 + num9 + num8; num4 = num + 1; } num2 += num8; } } }while (num >= 0 && num < unicodeString.Length - 1); if (num4 < unicodeString.Length) { Rect boundingRect2 = new Rect(num5, rect.Top, rect.Right - num5, rect.Height); this._CreateTextRun(boundingRect2, trans, glyphs, node, num4, unicodeString.Length); } }
// char index == -1 implies end of run. internal static Rect _GetGlyphRunDesignRect(Glyphs g, int charStart, int charEnd) { GlyphRun run = g.ToGlyphRun(); if (run == null) { return Rect.Empty; } Rect designRect = run.ComputeAlignmentBox(); designRect.Offset(run.BaselineOrigin.X, run.BaselineOrigin.Y); int charCount = 0; if (run.Characters != null) { charCount = run.Characters.Count; } else if (g.UnicodeString != null) { charCount = g.UnicodeString.Length; } if (charStart > charCount) { //Extra space was added at the end of the run for contiguity Debug.Assert(charStart - charCount == 1); charStart = charCount; } else if (charStart < 0) { //This is a reversed run charStart = 0; } if (charEnd > charCount) { //Extra space was added at the end of the run for contiguity Debug.Assert(charEnd - charCount == 1); charEnd = charCount; } else if (charEnd < 0) { //This is a reversed run charEnd = 0; } double x1 = _GetDistanceToCharacter(run, charStart); double x2 = _GetDistanceToCharacter(run, charEnd); double width = x2 - x1; if ((run.BidiLevel & 1) != 0) { // right to left designRect.X = run.BaselineOrigin.X - x2; } else { designRect.X = run.BaselineOrigin.X + x1; } designRect.Width = width; return designRect; }
private ITextPointer _SnapToText(Point point) { ITextPointer itp = null; FixedNode[] fixedNodes = Container.FixedTextBuilder.GetLine(this.PageIndex, point); if (fixedNodes != null && fixedNodes.Length > 0) { double closestDistance = Double.MaxValue; double xoffset = 0; Glyphs closestGlyphs = null; FixedNode closestNode = fixedNodes[0]; foreach (FixedNode node in fixedNodes) { Glyphs startGlyphs = this.FixedPage.GetGlyphsElement(node); GeneralTransform tranToGlyphs = this.FixedPage.TransformToDescendant(startGlyphs); Point transformedPt = point; if (tranToGlyphs != null) { tranToGlyphs.TryTransform(transformedPt, out transformedPt); } GlyphRun run = startGlyphs.ToGlyphRun(); Rect alignmentRect = run.ComputeAlignmentBox(); alignmentRect.Offset(startGlyphs.OriginX, startGlyphs.OriginY); double horizontalDistance = Math.Max(0, (transformedPt.X > alignmentRect.X) ? (transformedPt.X - alignmentRect.Right) : (alignmentRect.X - transformedPt.X)); double verticalDistance = Math.Max(0, (transformedPt.Y > alignmentRect.Y) ? (transformedPt.Y - alignmentRect.Bottom) : (alignmentRect.Y - transformedPt.Y)); double manhattanDistance = horizontalDistance + verticalDistance; if (closestGlyphs == null || manhattanDistance < closestDistance) { closestDistance = manhattanDistance; closestGlyphs = startGlyphs; closestNode = node; xoffset = transformedPt.X; } } int index; LogicalDirection dir; _GlyphRunHitTest(closestGlyphs, xoffset, out index, out dir); FixedPosition fixedp = new FixedPosition(closestNode, index); itp = _CreateTextPointer(fixedp, dir); Debug.Assert(itp != null); } else { // // That condition is only possible when there is no line in the page // if (point.Y < this.FixedPage.Height / 2) { itp = ((ITextPointer)this.Start).CreatePointer(LogicalDirection.Forward); itp.MoveToInsertionPosition(LogicalDirection.Forward); } else { itp = ((ITextPointer)this.End).CreatePointer(LogicalDirection.Backward); itp.MoveToInsertionPosition(LogicalDirection.Backward); } } return(itp); }
/// <summary> /// 在指定点画出文字 /// </summary> /// <param name="s">所画的文字内容</param> /// <param name="p">文字坐标</param> /// <param name="fontsize">文字大小</param> /// <returns>返回文字形状</returns> private GlyphRun DataGraphPrintText(string s, Point p, int fontsize) { Glyphs text = new Glyphs(); text.OriginX = p.X; text.OriginY = p.Y; text.UnicodeString = s; text.FontUri = new Uri(FONT_URI); text.FontRenderingEmSize = fontsize; return text.ToGlyphRun(); }
// Token: 0x06002EF2 RID: 12018 RVA: 0x000D4194 File Offset: 0x000D2394 private bool _GetNextLineGlyphs(ref FixedPosition fixedp, ref LogicalDirection edge, double suggestedX, LogicalDirection scanDir) { int num = 1; int page = fixedp.Page; bool result = false; FixedNode[] nextLine = this.Container.FixedTextBuilder.GetNextLine(fixedp.Node, scanDir == LogicalDirection.Forward, ref num); if (nextLine != null && nextLine.Length != 0) { FixedPage fixedPage = this.Container.FixedDocument.SyncGetPage(page, false); if (double.IsInfinity(suggestedX)) { suggestedX = 0.0; } Point point = new Point(suggestedX, 0.0); Point point2 = new Point(suggestedX, 1000.0); FixedNode fixedNode = nextLine[0]; Glyphs g = null; double num2 = double.MaxValue; double xoffset = 0.0; for (int i = nextLine.Length - 1; i >= 0; i--) { FixedNode fixedNode2 = nextLine[i]; Glyphs glyphsElement = fixedPage.GetGlyphsElement(fixedNode2); if (glyphsElement != null) { GeneralTransform generalTransform = fixedPage.TransformToDescendant(glyphsElement); Point inPoint = point; Point inPoint2 = point2; if (generalTransform != null) { generalTransform.TryTransform(inPoint, out inPoint); generalTransform.TryTransform(inPoint2, out inPoint2); } double num3 = (inPoint2.X - inPoint.X) / (inPoint2.Y - inPoint.Y); GlyphRun glyphRun = glyphsElement.ToGlyphRun(); Rect rect = glyphRun.ComputeAlignmentBox(); rect.Offset(glyphsElement.OriginX, glyphsElement.OriginY); double num4; double num5; if (num3 > 1000.0 || num3 < -1000.0) { num4 = 0.0; num5 = ((inPoint.Y > rect.Y) ? (inPoint.Y - rect.Bottom) : (rect.Y - inPoint.Y)); } else { double num6 = (rect.Top + rect.Bottom) / 2.0; num4 = inPoint.X + num3 * (num6 - inPoint.Y); num5 = ((num4 > rect.X) ? (num4 - rect.Right) : (rect.X - num4)); } if (num5 < num2) { num2 = num5; xoffset = num4; fixedNode = fixedNode2; g = glyphsElement; if (num5 <= 0.0) { break; } } } } int offset; this._GlyphRunHitTest(g, xoffset, out offset, out edge); fixedp = new FixedPosition(fixedNode, offset); result = true; } return(result); }
// Token: 0x0600350F RID: 13583 RVA: 0x000F0670 File Offset: 0x000EE870 private bool IntersectGlyphs(Glyphs g, double top, double left, double bottom, double right, out int begin, out int end, out bool includeEnd, out double baseline, out double height) { begin = 0; end = 0; includeEnd = false; GlyphRun glyphRun = g.ToGlyphRun(); Rect rect = glyphRun.ComputeAlignmentBox(); rect.Offset(glyphRun.BaselineOrigin.X, glyphRun.BaselineOrigin.Y); baseline = glyphRun.BaselineOrigin.Y; height = rect.Height; double y = rect.Y + 0.5 * rect.Height; GeneralTransform generalTransform = g.TransformToAncestor(this._page); Point point; generalTransform.TryTransform(new Point(rect.Left, y), out point); Point point2; generalTransform.TryTransform(new Point(rect.Right, y), out point2); bool flag = false; if (point.X < left) { if (point2.X < left) { return(false); } flag = true; } else if (point.X > right) { if (point2.X > right) { return(false); } flag = true; } else if (point2.X < left || point2.X > right) { flag = true; } double num3; double num4; if (flag) { double num = (left - point.X) / (point2.X - point.X); double num2 = (right - point.X) / (point2.X - point.X); if (num2 > num) { num3 = num; num4 = num2; } else { num3 = num2; num4 = num; } } else { num3 = 0.0; num4 = 1.0; } flag = false; if (point.Y < top) { if (point2.Y < top) { return(false); } flag = true; } else if (point.Y > bottom) { if (point2.Y > bottom) { return(false); } flag = true; } else if (point2.Y < top || point2.Y > bottom) { flag = true; } if (flag) { double num5 = (top - point.Y) / (point2.Y - point.Y); double num6 = (bottom - point.Y) / (point2.Y - point.Y); if (num6 > num5) { if (num5 > num3) { num3 = num5; } if (num6 < num4) { num4 = num6; } } else { if (num6 > num3) { num3 = num6; } if (num5 < num4) { num4 = num5; } } } num3 = rect.Left + rect.Width * num3; num4 = rect.Left + rect.Width * num4; bool ltr = (glyphRun.BidiLevel & 1) == 0; begin = this.GlyphRunHitTest(glyphRun, num3, ltr); end = this.GlyphRunHitTest(glyphRun, num4, ltr); if (begin > end) { int num7 = begin; begin = end; end = num7; } int num8 = (glyphRun.Characters == null) ? 0 : glyphRun.Characters.Count; includeEnd = (end == num8); return(true); }
private void _UpdateHighlightForeground(DrawingContext dc, ArrayList highlights) { foreach (FixedHighlight fh in highlights) { Brush fg = null; if (fh.HighlightType == FixedHighlightType.None) { #if NEVER // use this code if you want to see unrecognized highlights bg = Brushes.Yellow; #else continue; #endif } Glyphs g = fh.Glyphs; if (g == null) { continue; } Rect clipRect = fh.ComputeDesignRect(); if (clipRect == Rect.Empty) { continue; } GeneralTransform transform = fh.Element.TransformToAncestor(_page); Transform t = transform.AffineTransform; if (t != null) { dc.PushTransform(t); } else { dc.PushTransform(Transform.Identity); } dc.PushClip(new RectangleGeometry(clipRect)); if (fh.HighlightType == FixedHighlightType.TextSelection) { fg = SelectionHighlightInfo.ForegroundBrush; } else if (fh.HighlightType == FixedHighlightType.AnnotationHighlight) { fg = fh.ForegroundBrush; } // can add cases for new types of highlights GlyphRun gr = g.ToGlyphRun(); if (fg == null) { fg = g.Fill; } dc.PushGuidelineY1(gr.BaselineOrigin.Y); dc.PushClip(g.Clip); dc.DrawGlyphRun(fg, gr); dc.Pop(); // Glyphs clip dc.Pop(); // Guideline dc.Pop(); // clip dc.Pop(); // transform } }
// If return false, nothing has been modified, which implies out of page boundary // The input of suggestedX is in the VisualRoot's cooridnate system private bool _GetNextLineGlyphs(ref FixedPosition fixedp, ref LogicalDirection edge, double suggestedX, LogicalDirection scanDir) { int count = 1; int pageIndex = fixedp.Page; bool moved = false; FixedNode[] fixedNodes = Container.FixedTextBuilder.GetNextLine(fixedp.Node, (scanDir == LogicalDirection.Forward), ref count); if (fixedNodes != null && fixedNodes.Length > 0) { FixedPage page = Container.FixedDocument.SyncGetPage(pageIndex, false); // This line contains multiple Glyhs. Scan backward // util we hit the first one whose OriginX is smaller // then suggestedX; if (Double.IsInfinity(suggestedX)) { suggestedX = 0; } Point topOfPage = new Point(suggestedX, 0); Point secondPoint = new Point(suggestedX, 1000); FixedNode hitNode = fixedNodes[0]; Glyphs hitGlyphs = null; double closestDistance = Double.MaxValue; double xoffset = 0; for (int i = fixedNodes.Length - 1; i >= 0; i--) { FixedNode node = fixedNodes[i]; Glyphs g = page.GetGlyphsElement(node); if (g != null) { GeneralTransform transform = page.TransformToDescendant(g); Point pt1 = topOfPage; Point pt2 = secondPoint; if (transform != null) { transform.TryTransform(pt1, out pt1); transform.TryTransform(pt2, out pt2); } double invSlope = (pt2.X - pt1.X) / (pt2.Y - pt1.Y); double xoff, distance; GlyphRun run = g.ToGlyphRun(); Rect box = run.ComputeAlignmentBox(); box.Offset(g.OriginX, g.OriginY); if (invSlope > 1000 || invSlope < -1000) { // special case for vertical text xoff = 0; distance = (pt1.Y > box.Y) ? (pt1.Y - box.Bottom) : (box.Y - pt1.Y); } else { double centerY = (box.Top + box.Bottom) / 2; xoff = pt1.X + invSlope * (centerY - pt1.Y); distance = (xoff > box.X) ? (xoff - box.Right) : (box.X - xoff); } if (distance < closestDistance) { closestDistance = distance; xoffset = xoff; hitNode = node; hitGlyphs = g; if (distance <= 0) { break; } } } } Debug.Assert(hitGlyphs != null); int charIdx; _GlyphRunHitTest(hitGlyphs, xoffset, out charIdx, out edge); fixedp = new FixedPosition(hitNode, charIdx); moved = true; } return(moved); }
//determines whether and where a rectangle intersects a Glyphs private bool IntersectGlyphs(Glyphs g, double top, double left, double bottom, double right, out int begin, out int end, out bool includeEnd, out double baseline, out double height) { begin = 0; end = 0; includeEnd = false; GlyphRun run = g.ToGlyphRun(); Rect boundingRect = run.ComputeAlignmentBox(); boundingRect.Offset(run.BaselineOrigin.X, run.BaselineOrigin.Y); //useful for same line detection baseline = run.BaselineOrigin.Y; height = boundingRect.Height; double centerLine = boundingRect.Y + .5 * boundingRect.Height; GeneralTransform t = g.TransformToAncestor(_page); Point pt1; t.TryTransform(new Point(boundingRect.Left, centerLine), out pt1); Point pt2; t.TryTransform(new Point(boundingRect.Right, centerLine), out pt2); double dStart, dEnd; bool cross = false; if (pt1.X < left) { if (pt2.X < left) { return(false); } cross = true; } else if (pt1.X > right) { if (pt2.X > right) { return(false); } cross = true; } else if (pt2.X < left || pt2.X > right) { cross = true; } if (cross) { double d1 = (left - pt1.X) / (pt2.X - pt1.X); double d2 = (right - pt1.X) / (pt2.X - pt1.X); if (d2 > d1) { dStart = d1; dEnd = d2; } else { dStart = d2; dEnd = d1; } } else { dStart = 0; dEnd = 1; } cross = false; if (pt1.Y < top) { if (pt2.Y < top) { return(false); } cross = true; } else if (pt1.Y > bottom) { if (pt2.Y > bottom) { return(false); } cross = true; } else if (pt2.Y < top || pt2.Y > bottom) { cross = true; } if (cross) { double d1 = (top - pt1.Y) / (pt2.Y - pt1.Y); double d2 = (bottom - pt1.Y) / (pt2.Y - pt1.Y); if (d2 > d1) { if (d1 > dStart) { dStart = d1; } if (d2 < dEnd) { dEnd = d2; } } else { if (d2 > dStart) { dStart = d2; } if (d1 < dEnd) { dEnd = d1; } } } dStart = boundingRect.Left + boundingRect.Width * dStart; dEnd = boundingRect.Left + boundingRect.Width * dEnd; bool leftToRight = ((run.BidiLevel & 1) == 0); begin = GlyphRunHitTest(run, dStart, leftToRight); end = GlyphRunHitTest(run, dEnd, leftToRight); if (begin > end) { int temp = begin; begin = end; end = temp; } Debug.Assert(end >= begin); int characterCount = (run.Characters == null) ? 0 : run.Characters.Count; includeEnd = (end == characterCount); return(true); }