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 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; }
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 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 unsafe LsErr GetGlyphExpansionInfoFullMixed( IntPtr pols, // Line Layout context LsDevice device, // kind of device LsTFlow textFlow, // text flow LsGlyphRunInfo *plsglyphrunInfo, // glyph-based run info LsNeighborInfo *plsneighborInfoLeft, // left neighbor info LsNeighborInfo *plsneighborInfoRight, // right neigbor info int maxPriorityLevel, // maximum priority level int **pplsexpansionLeft, // [in/out] fill in left expansion amount per priority level on the way out int **pplsexpansionRight, // [in/out] fill in right expansion amount per priority level on the way out LsExpType *plsexptype, // [in/out] fill in glyph expansion type for each glyph int *pduMinInk // [in/out] fill in glyph minimum expansion for exptAddInkContinuous ) { LsErr lserr = LsErr.None; Plsrun plsrun = Plsrun.Undefined; LSRun lsrun = null; try { Invariant.Assert(maxPriorityLevel == 3); plsrun = plsglyphrunInfo->plsrun; lsrun = FullText.StoreFrom(plsrun).GetRun(plsrun); int em = lsrun.EmSize; return ExpandGlyphs( plsglyphrunInfo, (int)(em * Constants.MaxInterWordExpansionPerEm), pplsexpansionLeft, pplsexpansionRight, plsexptype, LsExpType.AddWhiteSpace, // inter-word expansion type ((lsrun.BidiLevel & 1) == 0 ? LsExpType.AddWhiteSpace : LsExpType.None) ); } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("GetGlyphExpansionInfoFullMixed", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal unsafe LsErr GetRunCharWidths( IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun LsDevice device, // kind of device char* charString, // character string int stringLength, // string length int maxWidth, // max width allowance LsTFlow textFlow, // text flow int* charWidths, // [out] returning char widths up to given upperbound ref int totalWidth, // [out] total run width ref int stringLengthFitted // [out] number of char fitted ) { LsErr lserr = LsErr.None; LSRun lsrun = null; try { TextFormatterImp formatter; if (FullText != null) { lsrun = FullText.StoreFrom(plsrun).GetRun(plsrun); formatter = FullText.Formatter; } else { #if DEBUG Debug.Assert(Draw.CurrentLine.FullTextState != null); #endif lsrun = Draw.CurrentLine.GetRun(plsrun); formatter = Draw.CurrentLine.Formatter; } if (lsrun.Type == Plsrun.Text) { Debug.Assert(lsrun.Shapeable != null && stringLength > 0); lsrun.Shapeable.GetAdvanceWidthsUnshaped(charString, stringLength, TextFormatterImp.ToIdeal, charWidths); totalWidth = 0; stringLengthFitted = 0; do { totalWidth += charWidths[stringLengthFitted]; } while ( ++stringLengthFitted < stringLength && totalWidth <= maxWidth ); if (totalWidth <= maxWidth && FullText != null) { int cpLimit = lsrun.OffsetToFirstCp + stringLengthFitted; if (cpLimit > FullText.CpMeasured) { FullText.CpMeasured = cpLimit; } } } else { charWidths[0] = 0; totalWidth = 0; stringLengthFitted = stringLength; } } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("GetRunCharWidths", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal LsErr GetRunUnderlineInfo( IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun ref LsHeights lsHeights, // run height LsTFlow textFlow, // text flow direction ref LsULInfo ulInfo // [out] result underline info ) { LsErr lserr = LsErr.None; LSRun lsrun = null; try { lsrun = Draw.CurrentLine.GetRun(plsrun); Debug.Assert( !TextStore.IsContent(plsrun) || lsrun.Type == Plsrun.Text || lsrun.Type == Plsrun.InlineObject, "Invalid run" ); ulInfo = new LsULInfo(); double underlinePositionInEm; double underlineThicknessInEm; if (lsrun.Shapeable != null) { underlinePositionInEm = lsrun.Shapeable.UnderlinePosition; underlineThicknessInEm = lsrun.Shapeable.UnderlineThickness; } else { underlinePositionInEm = lsrun.RunProp.Typeface.UnderlinePosition; underlineThicknessInEm = lsrun.RunProp.Typeface.UnderlineThickness; } ulInfo.cNumberOfLines = 1; ulInfo.dvpFirstUnderlineOffset = (int)Math.Round(lsrun.EmSize * -underlinePositionInEm); ulInfo.dvpFirstUnderlineSize = (int)Math.Round(lsrun.EmSize * underlineThicknessInEm); Debug.Assert(ulInfo.dvpFirstUnderlineSize >= 0); if (ulInfo.dvpFirstUnderlineSize <= 0) ulInfo.dvpFirstUnderlineSize = 1; } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("GetAutoNumberInfo", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal LsErr FInterruptShaping( IntPtr pols, // Line Layout context LsTFlow textFlow, // text flow Plsrun plsrunFirst, // first run Plsrun plsrunSecond, // second run ref int fIsInterruptOk // [out] disconnect glyphs between runs? ) { LsErr lserr = LsErr.None; try { TextStore store = FullText.StoreFrom(plsrunFirst); if ( !TextStore.IsContent(plsrunFirst) || !TextStore.IsContent(plsrunSecond)) { fIsInterruptOk = 1; return LsErr.None; } LSRun lsrunFirst = store.GetRun(plsrunFirst); LSRun lsrunSecond = store.GetRun(plsrunSecond); fIsInterruptOk = !( lsrunFirst.BidiLevel == lsrunSecond.BidiLevel && lsrunFirst.Shapeable != null && lsrunSecond.Shapeable != null && lsrunFirst.Shapeable.CanShapeTogether(lsrunSecond.Shapeable) ) ? 1 : 0; } catch (Exception e) { SaveException(e, Plsrun.Undefined, null); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("FInterruptShaping", Plsrun.Undefined, null); lserr = LsErr.ClientAbort; } return lserr; }
internal unsafe LsErr GetGlyphsRedefined( IntPtr pols, // Line Layout context IntPtr* plsplsruns, // array of plsruns int* pcchPlsrun, // array of character count per run int plsrunCount, // number of runs char* pwchText, // character string int cchText, // character count LsTFlow textFlow, // text flow direction ushort* puGlyphsBuffer, // [in/out] fixed-size buffer for glyph indices uint* piGlyphPropsBuffer, // [in/out] fixed-size buffer for glyph properties list int cgiGlyphBuffers, // glyph buffers length in glyphs ref int fIsGlyphBuffersUsed, // [out] Boolean flag indicates glyph buffers being used ushort* puClusterMap, // [out] character-to-glyph cluster map ushort* puCharProperties, // [out] character properties int* pfCanGlyphAlone, // [out] parallel to character codes: glyphing does not depend on neighbor? ref int glyphCount // [out] glyph buffer length and returning actual glyph count ) { Invariant.Assert(puGlyphsBuffer != null && piGlyphPropsBuffer != null); LsErr lserr = LsErr.None; LSRun lsrunFirst = null; try { LSRun[] lsruns = RemapLSRuns(plsplsruns, plsrunCount); lsrunFirst = lsruns[0]; Debug.Assert(lsrunFirst.Shapeable != null); Debug.Assert(cchText > 0); // LineServices should not pass in zero character count; bool isRightToLeft = ((lsrunFirst.BidiLevel & 1) != 0); DWriteFontFeature[][] fontFeatures; uint[] fontFeatureRanges; uint actualGlyphCount; checked { uint uCchText = (uint)cchText; LSRun.CompileFeatureSet(lsruns, pcchPlsrun, uCchText, out fontFeatures, out fontFeatureRanges); GlyphTypeface glyphTypeface = lsrunFirst.Shapeable.GlyphTypeFace; FullText.Formatter.TextAnalyzer.GetGlyphs( (ushort*)pwchText, uCchText, glyphTypeface.FontDWrite, glyphTypeface.BlankGlyphIndex, false, isRightToLeft, lsrunFirst.RunProp.CultureInfo, fontFeatures, fontFeatureRanges, (uint)cgiGlyphBuffers, FullText.TextFormattingMode, lsrunFirst.Shapeable.ItemProps, puClusterMap, puCharProperties, puGlyphsBuffer, piGlyphPropsBuffer, pfCanGlyphAlone, out actualGlyphCount ); glyphCount = (int)actualGlyphCount; if (glyphCount <= cgiGlyphBuffers) { fIsGlyphBuffersUsed = 1; } else { fIsGlyphBuffersUsed = 0; } } } catch (Exception e) { SaveException(e, (Plsrun)(plsplsruns[0]), lsrunFirst); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("GetGlyphsRedefined", (Plsrun)(plsplsruns[0]), lsrunFirst); lserr = LsErr.ClientAbort; } return lserr; }
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; }
private void DrawTextDecorationCollection( LSRun lsrun, uint locationMask, TextDecorationCollection textDecorations, Brush foregroundBrush, int left, int underlineTop, int overlineTop, int strikethroughTop, int baselineTop, int length, int thickness, LsTFlow textFlow ) { Invariant.Assert(textDecorations != null); foreach (TextDecoration td in textDecorations) { if (((1U << (int)td.Location) & locationMask) != 0) { switch (td.Location) { case TextDecorationLocation.Underline: _boundingBox.Union( DrawTextDecoration( lsrun, foregroundBrush, new LSPOINT(left, underlineTop), length, thickness, textFlow, td ) ); break; case TextDecorationLocation.OverLine: _boundingBox.Union( DrawTextDecoration( lsrun, foregroundBrush, new LSPOINT(left, overlineTop), length, thickness, textFlow, td ) ); break; case TextDecorationLocation.Strikethrough: _boundingBox.Union( DrawTextDecoration( lsrun, foregroundBrush, new LSPOINT(left, strikethroughTop), length, thickness, textFlow, td ) ); break; case TextDecorationLocation.Baseline: _boundingBox.Union( DrawTextDecoration( lsrun, foregroundBrush, new LSPOINT(left, baselineTop), length, thickness, textFlow, td ) ); break; } } } }
private void DrawTextDecorations( LSRun lsrun, uint locationMask, int left, int underlineTop, int overlineTop, int strikethroughTop, int baselineTop, int length, int thickness, LsTFlow textFlow ) { TextMetrics.FullTextLine currentLine = Draw.CurrentLine; TextDecorationCollection textDecorations = currentLine.TextDecorations; if (textDecorations != null) { DrawTextDecorationCollection( lsrun, locationMask, textDecorations, currentLine.DefaultTextDecorationsBrush, left, underlineTop, overlineTop, strikethroughTop, baselineTop, length, thickness, textFlow ); } textDecorations = lsrun.RunProp.TextDecorations; if (textDecorations != null) { DrawTextDecorationCollection( lsrun, locationMask, textDecorations, lsrun.RunProp.ForegroundBrush, left, underlineTop, overlineTop, strikethroughTop, baselineTop, length, thickness, textFlow ); } }
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; }
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 GetGlyphPositions( IntPtr pols, // Line Layout context IntPtr* plsplsruns, // array of plsruns int* pcchPlsrun, // array of character count per run int plsrunCount, // number of runs LsDevice device, // on reference or presentation device char* pwchText, // character string ushort* puClusterMap, // character-to-glyph cluster map ushort* puCharProperties, // character properties int cchText, // character count ushort* puGlyphs, // glyph indices uint* piGlyphProperties, // glyph properties int glyphCount, // glyph count LsTFlow textFlow, // text flow direction int* piGlyphAdvances, // [out] glyph advances GlyphOffset* piiGlyphOffsets // [out] glyph offsets ) { LsErr lserr = LsErr.None; LSRun lsrunFirst = null; try { LSRun[] lsruns = RemapLSRuns(plsplsruns, plsrunCount); lsrunFirst = lsruns[0]; bool isRightToLeft = ((lsrunFirst.BidiLevel & 1) != 0); GlyphOffset[] glyphOffset; GlyphTypeface glyphTypeface = lsrunFirst.Shapeable.GlyphTypeFace; DWriteFontFeature[][] fontFeatures; uint[] fontFeatureRanges; LSRun.CompileFeatureSet(lsruns, pcchPlsrun, checked((uint)cchText), out fontFeatures, out fontFeatureRanges); FullText.Formatter.TextAnalyzer.GetGlyphPlacements( (ushort*)pwchText, puClusterMap, (ushort*)puCharProperties, (uint)cchText, puGlyphs, piGlyphProperties, (uint)glyphCount, glyphTypeface.FontDWrite, lsrunFirst.Shapeable.EmSize, TextFormatterImp.ToIdeal, false, isRightToLeft, lsrunFirst.RunProp.CultureInfo, fontFeatures, fontFeatureRanges, FullText.TextFormattingMode, lsrunFirst.Shapeable.ItemProps, Util.PixelsPerDip, piGlyphAdvances, out glyphOffset ); for (int i = 0; i < glyphCount; ++i) { piiGlyphOffsets[i].du = glyphOffset[i].du; piiGlyphOffsets[i].dv = glyphOffset[i].dv; } } catch (Exception e) { SaveException(e, (Plsrun)(plsplsruns[0]), lsrunFirst); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("GetGlyphPositions", (Plsrun)(plsplsruns[0]), lsrunFirst); lserr = LsErr.ClientAbort; } return lserr; }
internal LsErr GetRunTextMetrics( System.IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun LsDevice lsDevice, // kind of device LsTFlow lstFlow, // text flow ref LsTxM lstTextMetrics // [out] returning metrics ) { LsErr lserr = LsErr.None; LSRun lsrun = null; try { FullTextState fullText = FullText; TextStore store = fullText.StoreFrom(plsrun); lsrun = store.GetRun(plsrun); if (lsrun.Height > 0) { lstTextMetrics.dvAscent = lsrun.BaselineOffset; lstTextMetrics.dvMultiLineHeight = lsrun.Height; } else { Typeface typeface = store.Pap.DefaultTypeface; lstTextMetrics.dvAscent = (int)Math.Round(typeface.Baseline(store.Pap.EmSize, Constants.DefaultIdealToReal, Util.PixelsPerDip, fullText.TextFormattingMode)); lstTextMetrics.dvMultiLineHeight = (int)Math.Round(typeface.LineSpacing(store.Pap.EmSize, Constants.DefaultIdealToReal, Util.PixelsPerDip, fullText.TextFormattingMode)); } lstTextMetrics.dvDescent = lstTextMetrics.dvMultiLineHeight - lstTextMetrics.dvAscent; lstTextMetrics.fMonospaced = 0; } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("GetRunTextMetrics", 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 LsErr GetDurMaxExpandRagged( IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun LsTFlow lstFlow, // text flow ref int maxExpandRagged // [out] em width ) { LsErr lserr = LsErr.None; LSRun lsrun = null; try { lsrun = FullText.StoreFrom(plsrun).GetRun(plsrun); maxExpandRagged = lsrun.EmSize; } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("GetDurMaxExpandRagged", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal unsafe LsErr GetGlyphCompressionInfoFullMixed( IntPtr pols, // Line Layout context LsDevice device, // kind of device LsTFlow textFlow, // text flow LsGlyphRunInfo *plsglyphrunInfo, // glyph-based run info LsNeighborInfo *plsneighborInfoLeft, // left neighbor info LsNeighborInfo *plsneighborInfoRight, // right neigbor info int maxPriorityLevel, // maximum priority level int **pplscompressionLeft, // [in/out] fill in left compression amount per priority level on the way out int **pplscompressionRight // [in/out] fill in right compression amount per priority level on the way out ) { LsErr lserr = LsErr.None; Plsrun plsrun = Plsrun.Undefined; LSRun lsrun = null; try { Invariant.Assert(maxPriorityLevel == 3); plsrun = plsglyphrunInfo->plsrun; lsrun = FullText.StoreFrom(plsrun).GetRun(plsrun); int em = lsrun.EmSize; return CompressGlyphs( plsglyphrunInfo, (int)(em * Constants.MinInterWordCompressionPerEm), pplscompressionLeft, pplscompressionRight ); } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("GetGlyphCompressionInfoFullMixed", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
internal LsErr GetRunStrikethroughInfo( IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun ref LsHeights lsHeights, // run height LsTFlow textFlow, // text flow direction ref LsStInfo stInfo // [out] result strikethrough info ) { LsErr lserr = LsErr.None; LSRun lsrun = null; try { lsrun = Draw.CurrentLine.GetRun(plsrun); Debug.Assert( !TextStore.IsContent(plsrun) || lsrun.Type == Plsrun.Text || lsrun.Type == Plsrun.InlineObject, "Invalid run" ); stInfo = new LsStInfo(); double strikeThroughPositionInEm; double strikeThroughThicknessInEm; GetLSRunStrikethroughMetrics(lsrun, out strikeThroughPositionInEm, out strikeThroughThicknessInEm); stInfo.cNumberOfLines = 1; stInfo.dvpLowerStrikethroughOffset = (int)Math.Round(lsrun.EmSize * strikeThroughPositionInEm); stInfo.dvpLowerStrikethroughSize = (int)Math.Round(lsrun.EmSize * strikeThroughThicknessInEm); Debug.Assert(stInfo.dvpLowerStrikethroughSize >= 0); if (stInfo.dvpLowerStrikethroughSize <= 0) stInfo.dvpLowerStrikethroughSize = 1; } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("GetRunStrikethroughInfo", plsrun, lsrun); lserr = LsErr.ClientAbort; } return lserr; }
/// <summary> /// From LsTFlow to FlowDirection /// </summary> public static FlowDirection LsTFlowToFlowDirection(LsTFlow lstflow) { switch (lstflow) { //case LsTFlow.lstflowDefault: case LsTFlow.lstflowES: case LsTFlow.lstflowEN: return FlowDirection.LeftToRight; case LsTFlow.lstflowWS: case LsTFlow.lstflowWN: return FlowDirection.RightToLeft; // vertical flow is not supported case LsTFlow.lstflowSE: case LsTFlow.lstflowSW: case LsTFlow.lstflowNE: case LsTFlow.lstflowNW: break; } return FlowDirection.LeftToRight; }