/// <summary> /// Create a rectangle of the two specified UV coordinates /// </summary> /// <param name="origin">line drawing origin</param> /// <param name="topLeft">logical top-left point</param> /// <param name="bottomRight">logical bottom-right point</param> /// <param name="line">container line</param> internal static Rect RectUV( Point origin, LSPOINT topLeft, LSPOINT bottomRight, TextMetrics.FullTextLine line ) { int dx = topLeft.x - bottomRight.x; if(dx == 1 || dx == -1) { // in certain situation LS can be off by 1 bottomRight.x = topLeft.x; } Rect rect = new Rect( new Point(line.Formatter.IdealToReal(topLeft.x), line.Formatter.IdealToReal(topLeft.y)), new Point(line.Formatter.IdealToReal(bottomRight.x), line.Formatter.IdealToReal(bottomRight.y)) ); if(DoubleUtil.AreClose(rect.TopLeft.X, rect.BottomRight.X)) { rect.Width = 0; } if(DoubleUtil.AreClose(rect.TopLeft.Y, rect.BottomRight.Y)) { rect.Height = 0; } return rect; }
public override IEnumerable<IndexedGlyphRun> GetIndexedGlyphRuns() { if ((_statusFlags & StatusFlags.IsDisposed) != 0) { throw new ObjectDisposedException(SR.Get(SRID.TextLineHasBeenDisposed)); } IEnumerable<IndexedGlyphRun> result = null; if (_ploline.Value != System.IntPtr.Zero) { TextFormatterContext context = _metrics._formatter.AcquireContext( new DrawingState(null, new Point(0, 0), null, this), _ploc.Value ); // // Kick off line enumeration // LsErr lserr = LsErr.None; LSPOINT point = new LSPOINT(0, 0); lserr = UnsafeNativeMethods.LoEnumLine( _ploline.Value, // line false, // reverse enumeration false, // geometry needed ref point // starting point ); // result result = context.IndexedGlyphRuns; // get the exception in context before it is released Exception callbackException = context.CallbackException; // clear the context context.ClearIndexedGlyphRuns(); context.Release(); if (lserr != LsErr.None) { if (callbackException != null) { // rethrow exception thrown in callbacks throw callbackException; } else { // throw with LS error codes TextFormatterContext.ThrowExceptionFromLsError(SR.Get(SRID.EnumLineFailure, lserr), lserr); } } } return result; }
private unsafe GlyphRun ComputeShapedGlyphRun( LSRun lsrun, // ls run TextFormatterImp textFormatterImp, // The TextFormatter Implementation bool originProvided, // flag indicate whether the origin of the run is provided LSPOINT lsrunOrigin, // physical start of the run int charCount, // characters count char *pwchText, // characters for the GlyphRun ushort *puClusterMap, // cluster map int glyphCount, // glyph count ushort *puGlyphs, // glyph indices int *piJustifiedGlyphAdvances, // glyph advances GlyphOffset *piiGlyphOffsets, // glyph offsets bool justify ) { TextMetrics.FullTextLine currentLine = Draw.CurrentLine; Point runOrigin = new Point(); int nominalX = 0; int nominalY = 0; if (originProvided) { if (currentLine.RightToLeft) { lsrunOrigin.x = -lsrunOrigin.x; } if (textFormatterImp.TextFormattingMode == TextFormattingMode.Display && justify) { LSRun.UVToNominalXY( Draw.LineOrigin, Draw.VectorToLineOrigin, currentLine.LSLineUToParagraphU(lsrunOrigin.x), lsrunOrigin.y + lsrun.BaselineMoveOffset, currentLine, out nominalX, out nominalY ); } else { runOrigin = LSRun.UVToXY( Draw.LineOrigin, Draw.VectorToLineOrigin, currentLine.LSLineUToParagraphU(lsrunOrigin.x), lsrunOrigin.y + lsrun.BaselineMoveOffset, currentLine ); } } char[] charString = new char[charCount]; ushort[] clusterMap = new ushort[charCount]; for (int i = 0; i < charCount; i++) { charString[i] = pwchText[i]; clusterMap[i] = puClusterMap[i]; } ushort[] glyphIndices = new ushort[glyphCount]; IList<double> glyphAdvances; IList<Point> glyphOffsets; bool isRightToLeft = (lsrun.BidiLevel & 1) != 0; if (textFormatterImp.TextFormattingMode == TextFormattingMode.Ideal) { glyphAdvances = new ThousandthOfEmRealDoubles(textFormatterImp.IdealToReal(lsrun.EmSize), glyphCount); glyphOffsets = new ThousandthOfEmRealPoints(textFormatterImp.IdealToReal(lsrun.EmSize), glyphCount); for (int i = 0; i < glyphCount; i++) { glyphIndices[i] = puGlyphs[i]; glyphAdvances[i] = textFormatterImp.IdealToReal(piJustifiedGlyphAdvances[i]); glyphOffsets[i] = new Point( textFormatterImp.IdealToReal(piiGlyphOffsets[i].du), textFormatterImp.IdealToReal(piiGlyphOffsets[i].dv) ); } } else { if (justify) { AdjustMetricsForDisplayModeJustifiedText( pwchText, piJustifiedGlyphAdvances, glyphCount, isRightToLeft, nominalX, nominalY, out runOrigin, out glyphAdvances ); } else { glyphAdvances = new List<double>(glyphCount); for (int i = 0; i < glyphCount; i++) { glyphAdvances.Add(textFormatterImp.IdealToReal(piJustifiedGlyphAdvances[i])); } } glyphOffsets = new List<Point>(glyphCount); for (int i = 0; i < glyphCount; i++) { glyphIndices[i] = puGlyphs[i]; glyphOffsets.Add(new Point( textFormatterImp.IdealToReal(piiGlyphOffsets[i].du), textFormatterImp.IdealToReal(piiGlyphOffsets[i].dv) )); } } #if CHECK_GLYPHS if ( lsrun._glyphs != null && glyphCount <= lsrun._glyphs.Length) { for (int i = 0; i < glyphCount; i++) { Debug.Assert(glyphIndices[i] == lsrun._glyphs[i], "Corrupted glyphs"); } } #endif GlyphRun glyphRun = lsrun.Shapeable.ComputeShapedGlyphRun( runOrigin, charString, clusterMap, glyphIndices, glyphAdvances, glyphOffsets, isRightToLeft, false // no sideway support yet ); return glyphRun; }
private unsafe GlyphRun ComputeUnshapedGlyphRun( LSRun lsrun, // LSrun used to shape the GlyphRun LsTFlow textFlow, // flow direction TextFormatterImp textFormatterImp, // The TextFormatter Implementation bool originProvided, // flag indicate whether the origin of the run is provided LSPOINT lsrunOrigin, // physical start of the run int dupRun, // width of the run int cchText, // character count char *pwchText, // characters for display int *piCharAdvances, // character advance widths, bool justify ) { GlyphRun glyphRun = null; if (lsrun.Type == Plsrun.Text) { Debug.Assert(lsrun.Shapeable != null); Point runOrigin = new Point(); int nominalX = 0; int nominalY = 0; if (originProvided) { TextMetrics.FullTextLine currentLine = Draw.CurrentLine; if (textFlow == LsTFlow.lstflowWS) { lsrunOrigin.x -= dupRun; } if (currentLine.RightToLeft) { lsrunOrigin.x = -lsrunOrigin.x; } if (textFormatterImp.TextFormattingMode == TextFormattingMode.Display && justify) { LSRun.UVToNominalXY( Draw.LineOrigin, Draw.VectorToLineOrigin, currentLine.LSLineUToParagraphU(lsrunOrigin.x), lsrunOrigin.y + lsrun.BaselineMoveOffset, currentLine, out nominalX, out nominalY ); } else { runOrigin = LSRun.UVToXY( Draw.LineOrigin, Draw.VectorToLineOrigin, currentLine.LSLineUToParagraphU(lsrunOrigin.x), lsrunOrigin.y + lsrun.BaselineMoveOffset, currentLine ); } } char[] charString = new char[cchText]; IList<double> charWidths; bool isRightToLeft = (lsrun.BidiLevel & 1) != 0; if (textFormatterImp.TextFormattingMode == TextFormattingMode.Ideal) { charWidths = new ThousandthOfEmRealDoubles(textFormatterImp.IdealToReal(lsrun.EmSize), cchText); for (int i = 0; i < cchText; i++) { charString[i] = pwchText[i]; charWidths[i] = textFormatterImp.IdealToReal(piCharAdvances[i]); } } else { if (justify) { AdjustMetricsForDisplayModeJustifiedText( pwchText, piCharAdvances, cchText, isRightToLeft, nominalX, nominalY, out runOrigin, out charWidths ); } else { charWidths = new List<double>(cchText); for (int i = 0; i < cchText; i++) { charWidths.Add(textFormatterImp.IdealToReal(piCharAdvances[i])); } } for (int i = 0; i < cchText; i++) { charString[i] = pwchText[i]; } } glyphRun = lsrun.Shapeable.ComputeUnshapedGlyphRun( runOrigin, charString, charWidths ); } return glyphRun; }
internal unsafe LsErr EnumText( IntPtr pols, // ls context Plsrun plsrun, // plsrun int cpFirst, // first cp of the ls dnode int dcp, // dcp of the dnode char *pwchText, // characters for glyph run int cchText, // length of characters LsTFlow lstFlow, // flow direction int fReverseOrder, // flag for reverse order enumeration int fGeometryProvided, // flag for providing geometry ref LSPOINT pptStart, // [in] logical start of the run ref LsHeights pheights, // [in] height (iff geometryProvided) int dupRun, // width of the run int glyphBaseRun, // flag for glyph based run int *piCharAdvances, // character advance widths (iff !glyphBaseRun) ushort *puClusterMap, // cluster map (iff glyphBaseRun) ushort *characterProperties, // character properties (iff glyphBaseRun) ushort *puGlyphs, // glyph indices (iff glyphBaseRun) int *piJustifiedGlyphAdvances, // glyph advances (iff glyphBaseRun) GlyphOffset *piiGlyphOffsets, // glyph offsets (iff glyphBaseRun) uint *piGlyphProperties, // glyph properties (iff glyphProperties) int glyphCount // glyph count ) { Debug.Assert(fGeometryProvided == 0, "Line enumeration doesn't need geometry information"); if (cpFirst < 0) { return LsErr.None; } LsErr lserr = LsErr.None; LSRun lsrun = null; try { TextMetrics.FullTextLine currentLine = Draw.CurrentLine; lsrun = currentLine.GetRun(plsrun); GlyphRun glyphRun = null; if (glyphBaseRun != 0) { if (glyphCount > 0) { glyphRun = ComputeShapedGlyphRun( lsrun, currentLine.Formatter, false, // glyph run origin not provided pptStart, cchText, pwchText, puClusterMap, glyphCount, puGlyphs, piJustifiedGlyphAdvances, piiGlyphOffsets, currentLine.IsJustified ); } } else if (cchText > 0) { dupRun = 0; for (int i = 0; i < cchText; i++) { dupRun += piCharAdvances[i]; } glyphRun = ComputeUnshapedGlyphRun( lsrun, lstFlow, currentLine.Formatter, false, // glyph run origin not provided at enumeration pptStart, dupRun, cchText, pwchText, piCharAdvances, currentLine.IsJustified ); } if (glyphRun != null) { IndexedGlyphRuns.Add( new IndexedGlyphRun( currentLine.GetExternalCp(cpFirst), dcp, glyphRun ) ); } } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("EnumText", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal unsafe LsErr EnumTab( IntPtr pols, // pointer to context Plsrun plsrun, // plsrun int cpFirst, // first cp of the dnode run char *pwchText, // a single tab character char tabLeader, // a single tab leader character LsTFlow lstFlow, // flow direction int fReverseOrder, // flag for reverse order enumeration int fGeometryProvided, // flag for providing geometry information ref LSPOINT pptStart, // [in] logical start of the run (iff geometryProvided) ref LsHeights heights, // [in] height (iff geometryProvided) int dupRun // width of the run ) { if (cpFirst < 0) { return LsErr.None; } LsErr lserr = LsErr.None; LSRun lsrun = null; try { TextMetrics.FullTextLine currentLine = Draw.CurrentLine; lsrun = currentLine.GetRun(plsrun); GlyphRun glyphRun = null; if (lsrun.Type == Plsrun.Text) { int charWidth = 0; lsrun.Shapeable.GetAdvanceWidthsUnshaped( &tabLeader, 1, TextFormatterImp.ToIdeal, &charWidth ); glyphRun = ComputeUnshapedGlyphRun( lsrun, lstFlow, currentLine.Formatter, false, // glyph run origin not provided at enumeration time pptStart, charWidth, 1, &tabLeader, &charWidth, currentLine.IsJustified ); } if (glyphRun != null) { IndexedGlyphRuns.Add( new IndexedGlyphRun( currentLine.GetExternalCp(cpFirst), 1, // dcp is 1 for a Tab character glyphRun ) ); } } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("EnumTab", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal unsafe LsErr DrawGlyphs( IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun char* pwchText, // character string ushort* puClusterMap, // character-to-cluster map ushort* puCharProperties, // character properties int charCount, // character count ushort* puGlyphs, // glyph indices int* piJustifiedGlyphAdvances, // justified glyph advances int* piGlyphAdvances, // original ideal glyph advances GlyphOffset* piiGlyphOffsets, // glyph offsets uint* piGlyphProperties, // glyph properties LsExpType* plsExpType, // glyph expansion types int glyphCount, // glyph count LsTFlow textFlow, // text flow uint displayMode, // draw transparent or opaque ref LSPOINT ptRun, // [in] display position (at baseline) ref LsHeights lsHeights, // [in] run height metrics int runWidth, // run overall advance width ref LSRECT clippingRect // [in] clipping rectangle if any applied ) { LsErr lserr = LsErr.None; LSRun lsrun = null; try { TextMetrics.FullTextLine currentLine = Draw.CurrentLine; lsrun = currentLine.GetRun(plsrun); Debug.Assert(TextStore.IsContent(plsrun) && lsrun.Shapeable != null); GlyphRun glyphRun = ComputeShapedGlyphRun( lsrun, currentLine.Formatter, true, // origin of the glyph run provided at drawing time ptRun, charCount, pwchText, puClusterMap, glyphCount, puGlyphs, piJustifiedGlyphAdvances, piiGlyphOffsets, currentLine.IsJustified ); if (glyphRun != null) { DrawingContext drawingContext = Draw.DrawingContext; Draw.SetGuidelineY(glyphRun.BaselineOrigin.Y); try { _boundingBox.Union( lsrun.DrawGlyphRun( drawingContext, null, // draw with the run's foreground glyphRun ) ); } finally { Draw.UnsetGuidelineY(); } } } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("DrawGlyphs", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal static extern LsErr LoEnumLine( IntPtr ploline, bool reverseOder, bool fGeometryneeded, ref LSPOINT pt );
private Rect DrawTextDecoration( LSRun lsrun, // lsrun Brush foregroundBrush, // default brush if text decoration has no pen LSPOINT ptOrigin, // drawing origin int ulLength, // underline length int ulThickness, // underline thickness LsTFlow textFlow, // text flow direction TextDecoration textDecoration //TextDecoration to be draw (add to sublinecollection ) { switch (textFlow) { case LsTFlow.lstflowWS: case LsTFlow.lstflowNE: case LsTFlow.lstflowNW: ptOrigin.x -= ulLength; break; } TextMetrics.FullTextLine currentLine = Draw.CurrentLine; if (currentLine.RightToLeft) { ptOrigin.x = -ptOrigin.x; } int u = currentLine.LSLineUToParagraphU(ptOrigin.x); Point baselineOrigin = LSRun.UVToXY( Draw.LineOrigin, Draw.VectorToLineOrigin, u, currentLine.BaselineOffset, currentLine ); Point lineOrigin = LSRun.UVToXY( Draw.LineOrigin, Draw.VectorToLineOrigin, u, ptOrigin.y + lsrun.BaselineMoveOffset, currentLine ); double penThickness = 1.0; if (textDecoration.Pen != null) { penThickness = textDecoration.Pen.Thickness; } switch (textDecoration.PenThicknessUnit) { case TextDecorationUnit.FontRecommended: penThickness = currentLine.Formatter.IdealToReal(ulThickness * penThickness); break; case TextDecorationUnit.FontRenderingEmSize: penThickness = currentLine.Formatter.IdealToReal(penThickness * lsrun.EmSize); break; case TextDecorationUnit.Pixel: break; default: Debug.Assert(false, "Not supported TextDecorationUnit"); break; } penThickness = Math.Abs(penThickness); double unitValue = 1.0; switch (textDecoration.PenOffsetUnit) { case TextDecorationUnit.FontRecommended: unitValue = (lineOrigin.Y - baselineOrigin.Y); break; case TextDecorationUnit.FontRenderingEmSize: unitValue = currentLine.Formatter.IdealToReal(lsrun.EmSize); break; case TextDecorationUnit.Pixel: unitValue = 1.0; break; default: Debug.Assert(false, "Not supported TextDecorationUnit"); break; } double lineLength = currentLine.Formatter.IdealToReal(ulLength); DrawingContext drawingContext = Draw.DrawingContext; if (drawingContext != null) { double drawingPenThickness = penThickness; Point drawingLineOrigin = lineOrigin; bool animated = !textDecoration.CanFreeze && (unitValue != 0); int pushCount = 0; // counter for the number of explicit DrawingContext.Push() Draw.SetGuidelineY(baselineOrigin.Y); try { if (animated) { ScaleTransform scaleTransform = new ScaleTransform( 1.0, // X scale unitValue, // y scale drawingLineOrigin.X, // reference point of scaling drawingLineOrigin.Y // reference point of scaling ); TranslateTransform yTranslate = new TranslateTransform( 0, // x translate textDecoration.PenOffset // y translate ); drawingPenThickness = drawingPenThickness / Math.Abs(unitValue); drawingContext.PushTransform(scaleTransform); pushCount++; drawingContext.PushTransform(yTranslate); pushCount++; } else { drawingLineOrigin.Y += unitValue * textDecoration.PenOffset; } drawingContext.PushGuidelineY2(baselineOrigin.Y, drawingLineOrigin.Y - drawingPenThickness * 0.5 - baselineOrigin.Y); pushCount++; if (textDecoration.Pen == null) { drawingContext.DrawRectangle( foregroundBrush, // fill using foreground null, // null pen for rectangle stroke new Rect( drawingLineOrigin.X, drawingLineOrigin.Y - drawingPenThickness * 0.5, lineLength, drawingPenThickness ) ); } else { Pen textDecorationPen = textDecoration.Pen.CloneCurrentValue(); if (Object.ReferenceEquals(textDecoration.Pen, textDecorationPen)) { textDecorationPen = textDecoration.Pen.Clone(); } textDecorationPen.Thickness = drawingPenThickness; drawingContext.DrawLine( textDecorationPen, drawingLineOrigin, new Point(drawingLineOrigin.X + lineLength, drawingLineOrigin.Y) ); } } finally { for (int i = 0; i < pushCount; i++) { drawingContext.Pop(); } Draw.UnsetGuidelineY(); } } return new Rect( lineOrigin.X, lineOrigin.Y + unitValue * textDecoration.PenOffset - penThickness * 0.5, lineLength, penThickness ); }
internal unsafe LsErr DrawTextRun( IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun ref LSPOINT ptText, // [in] text origin char* pwchText, // character string int* piCharAdvances, // char advance widths int cchText, // text length LsTFlow textFlow, // text flow uint displayMode, // draw in transparent or opaque ref LSPOINT ptRun, // [in] run origin ref LsHeights lsHeights, // [in] run height int dupRun, // run length ref LSRECT clipRect // [in] from DisplayLine's clip rectangle param ) { LsErr lserr = LsErr.None; LSRun lsrun = null; try { TextMetrics.FullTextLine currentLine = Draw.CurrentLine; lsrun = currentLine.GetRun(plsrun); GlyphRun glyphRun = ComputeUnshapedGlyphRun( lsrun, textFlow, currentLine.Formatter, true, // origin of the glyph run provided at drawing time ptText, dupRun, cchText, pwchText, piCharAdvances, currentLine.IsJustified ); if (glyphRun != null) { DrawingContext drawingContext = Draw.DrawingContext; Draw.SetGuidelineY(glyphRun.BaselineOrigin.Y); try { _boundingBox.Union( lsrun.DrawGlyphRun( drawingContext, null, // draw with the run's foreground brush glyphRun ) ); } finally { Draw.UnsetGuidelineY(); } } } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("DrawTextRun", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal LsErr DrawUnderline( IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun uint ulType, // kind of underline ref LSPOINT ptOrigin, // [in] drawing origin int ulLength, // underline length int ulThickness, // underline thickness LsTFlow textFlow, // text flow direction uint displayMode, // display mode ref LSRECT clipRect // [in] clipping rectangle ) { LsErr lserr = LsErr.None; LSRun lsrun = null; try { if (!TextStore.IsContent(plsrun)) { return LsErr.None; } lsrun = Draw.CurrentLine.GetRun(plsrun); const uint locationMask = (1U << (int)TextDecorationLocation.Underline); DrawTextDecorations( lsrun, locationMask, ptOrigin.x, // left ptOrigin.y, // underline top from LS 0, // overline top; not used 0, // strikethrough top; not used 0, // baseline top; not used ulLength, ulThickness, textFlow ); } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("DrawUnderline", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal LsErr DrawStrikethrough( IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun uint stType, // kind of strike ref LSPOINT ptOrigin, // [in] drawing origin int stLength, // strike length int stThickness, // strike thickness LsTFlow textFlow, // text flow direction uint displayMode, // display mode ref LSRECT clipRect // [in] clipping rectangle ) { LsErr lserr = LsErr.None; LSRun lsrun = null; try { if (!TextStore.IsContent(plsrun)) { return LsErr.None; } TextMetrics.FullTextLine currentLine = Draw.CurrentLine; lsrun = currentLine.GetRun(plsrun); double strikeThroughPositionInEm; double strikeThroughThicknessInEm; GetLSRunStrikethroughMetrics(lsrun, out strikeThroughPositionInEm, out strikeThroughThicknessInEm); int baselineTop = ptOrigin.y + (int)Math.Round(lsrun.EmSize * strikeThroughPositionInEm); int overlineTop = baselineTop - (lsrun.BaselineOffset - (int)Math.Round(lsrun.EmSize * strikeThroughThicknessInEm)); const uint locationMask = (1U << (int)TextDecorationLocation.OverLine) | (1U << (int)TextDecorationLocation.Strikethrough) | (1U << (int)TextDecorationLocation.Baseline); DrawTextDecorations( lsrun, locationMask, ptOrigin.x, // left 0, // underline top; not used overlineTop, ptOrigin.y, // strikethrough top from LS baselineTop, stLength, stThickness, textFlow ); } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("DrawStrikethrough", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal static extern LsErr LoQueryLinePointPcp( IntPtr ploline, ref LSPOINT ptQuery, // use POINT as POINTUV int depthQueryMax, IntPtr pSubLineInfo, // passing raw pinned pointer for out array out int actualDepthQuery, out LsTextCell lsTextCell );
private void QueryLinePointPcp( Point ptQuery, LsQSubInfo[] subLineInfo, out int actualDepthQuery, out LsTextCell lsTextCell ) { Debug.Assert(_ploline.Value != IntPtr.Zero); LsErr lserr = LsErr.None; lsTextCell = new LsTextCell(); unsafe { fixed(LsQSubInfo* plsqsubl = subLineInfo) { LSPOINT pt = new LSPOINT((int)ptQuery.X, (int)ptQuery.Y); lserr = UnsafeNativeMethods.LoQueryLinePointPcp( _ploline.Value, ref pt, subLineInfo.Length, (System.IntPtr)plsqsubl, out actualDepthQuery, out lsTextCell ); } } if(lserr != LsErr.None) { TextFormatterContext.ThrowExceptionFromLsError(SR.Get(SRID.QueryLineFailure, lserr), lserr); } if (lsTextCell.lscpEndCell < lsTextCell.lscpStartCell) { // When hit-testing is done on a generated hyphen of a hyphenated word, LS can only tell // the start LSCP and not the end LSCP. Argurably this is LS bug. In such situation they // should assume the end LSCP being the last LSCP of the line. // // However our code assumes that LS must tell both and the text cell must have size greater // than one codepoint. We count on that to reliably advance the caret position. // // The LSPTS bug#1005 has been filed and while we are still debating, we need to unblock // ourselves. What we can do is to assume that the next caret stop in this case is always // the next codepoint. lsTextCell.lscpEndCell = lsTextCell.lscpStartCell; } }
internal LsErr InlineDraw( System.IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun ref LSPOINT ptRun, // [in] pen position at which to render the object LsTFlow textFlow, // text flow direction int runWidth // object width ) { LsErr lserr = LsErr.None; LSRun lsrun = null; try { TextMetrics.FullTextLine currentLine = Draw.CurrentLine; lsrun = currentLine.GetRun(plsrun); LSPOINT lsrunOrigin = ptRun; Debug.Assert(lsrun.Type == Plsrun.InlineObject); int baseDirection = currentLine.RightToLeft ? 1 : 0; int runDirection = (int)(lsrun.BidiLevel & 1); if (baseDirection != 0) { lsrunOrigin.x = -lsrunOrigin.x; } TextEmbeddedObject textObject = lsrun.TextRun as TextEmbeddedObject; Debug.Assert(textObject != null); Debug.Assert(textFlow != LsTFlow.lstflowWS || runDirection != 0); if ((baseDirection ^ runDirection) != 0) { lsrunOrigin.x -= runWidth; } Point baselineOrigin = new Point( currentLine.Formatter.IdealToReal(currentLine.LSLineUToParagraphU(lsrunOrigin.x))+ Draw.VectorToLineOrigin.X, currentLine.Formatter.IdealToReal((lsrunOrigin.y + lsrun.BaselineMoveOffset)) + Draw.VectorToLineOrigin.Y ); Rect objectBounds = textObject.ComputeBoundingBox( baseDirection != 0, // rightToLeft false // no sideway support yet ); if (!objectBounds.IsEmpty) { objectBounds.X += baselineOrigin.X; objectBounds.Y += baselineOrigin.Y; } _boundingBox.Union( new Rect( LSRun.UVToXY( Draw.LineOrigin, new Point(), objectBounds.Location.X, objectBounds.Location.Y, currentLine ), LSRun.UVToXY( Draw.LineOrigin, new Point(), objectBounds.Location.X + objectBounds.Size.Width, objectBounds.Location.Y + objectBounds.Size.Height, currentLine ) ) ); DrawingContext drawingContext = Draw.DrawingContext; if (drawingContext != null) { Draw.SetGuidelineY(baselineOrigin.Y); try { if (Draw.AntiInversion == null) { textObject.Draw( drawingContext, LSRun.UVToXY( Draw.LineOrigin, new Point(), baselineOrigin.X, baselineOrigin.Y, currentLine ), baseDirection != 0, false ); } else { drawingContext.PushTransform(Draw.AntiInversion); try { textObject.Draw(drawingContext, baselineOrigin, baseDirection != 0, false); } finally { drawingContext.Pop(); } } } finally { Draw.UnsetGuidelineY(); } } } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("InlineDraw", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
private void DrawTextLine( DrawingContext drawingContext, Point origin, MatrixTransform antiInversion ) { Rect boundingBox = Rect.Empty; if (_ploline.Value != System.IntPtr.Zero) { TextFormatterContext context; LsErr lserr = LsErr.None; LSRECT rect = new LSRECT(0, 0, _metrics._textWidthAtTrailing, _metrics._height); // DrawingState needs to be properly disposed after performing actual drawing operations. using (DrawingState drawingState = new DrawingState(drawingContext, origin, antiInversion, this)) { context = _metrics._formatter.AcquireContext( drawingState, _ploc.Value ); // set the collector and send the line to LS to draw context.EmptyBoundingBox(); // LS line reference origin LSPOINT lsRefOrigin = new LSPOINT(0, _metrics._baselineOffset); lserr = UnsafeNativeMethods.LoDisplayLine( _ploline.Value, ref lsRefOrigin, 1, // 0 - opaque, 1 - transparent ref rect ); } boundingBox = context.BoundingBox; // get the exception in context before it is released Exception callbackException = context.CallbackException; context.Release(); if(lserr != LsErr.None) { if(callbackException != null) { // rethrow exception thrown in callbacks throw callbackException; } else { // throw with LS error codes TextFormatterContext.ThrowExceptionFromLsError(SR.Get(SRID.CreateLineFailure, lserr), lserr); } } // keep context alive at least til here GC.KeepAlive(context); } if (_collapsingSymbol != null) { // draw collapsing symbol if any Point vectorToOrigin = new Point(); if (antiInversion != null) { vectorToOrigin = origin; origin.X = origin.Y = 0; } boundingBox.Union(DrawCollapsingSymbol(drawingContext, origin, vectorToOrigin)); } BuildOverhang(origin, boundingBox); _statusFlags |= StatusFlags.BoundingBoxComputed; }
internal static extern LsErr LoDisplayLine( IntPtr ploline, ref LSPOINT pt, uint displayMode, ref LSRECT clipRect );