/// <summary> /// Construct an lsrun /// </summary> private LSRun( TextRunInfo runInfo, IList <TextEffect> textEffects, Plsrun type, int offsetToFirstCp, int textRunLength, int emSize, ushort charFlags, CharacterBufferRange charBufferRange, int baselineOffset, int height, TextShapeableSymbols shapeable, byte bidiLevel ) { _runInfo = runInfo; _type = type; _offsetToFirstCp = offsetToFirstCp; _textRunLength = textRunLength; _emSize = emSize; _charFlags = charFlags; _charBufferRange = charBufferRange; _baselineOffset = baselineOffset; _height = height; _bidiLevel = bidiLevel; _shapeable = shapeable; _textEffects = textEffects; }
private IList <TextEffect> _textEffects; // TextEffects that should be applied for this run /// <summary> /// Construct an lsrun /// </summary> internal LSRun( TextRunInfo runInfo, IList <TextEffect> textEffects, Plsrun type, int offsetToFirstCp, int textRunLength, int emSize, ushort charFlags, CharacterBufferRange charBufferRange, TextShapeableSymbols shapeable, double realToIdeal, byte bidiLevel ) : this( runInfo, textEffects, type, offsetToFirstCp, textRunLength, emSize, charFlags, charBufferRange, (shapeable != null ? (int)Math.Round(shapeable.Baseline * realToIdeal) : 0), (shapeable != null ? (int)Math.Round(shapeable.Height * realToIdeal) : 0), shapeable, bidiLevel ) { }
/// <summary> /// Constructing a textrun info /// </summary> /// <param name="charBufferRange">characte buffer range for the run</param> /// <param name="textRunLength">textrun length</param> /// <param name="offsetToFirstCp">character offset to run first cp</param> /// <param name="textRun">text run</param> /// <param name="lsRunType">the internal LS run type </param> /// <param name="charFlags">character attribute flags</param> /// <param name="digitCulture">digit culture for the run</param> /// <param name="contextualSubstitution">contextual number substitution for the run</param> /// <param name="symbolTypeface">if true, indicates a text run in a symbol (i.e., non-Unicode) font</param> /// <param name="modifierScope">The current TextModifier scope for this TextRunInfo</param> internal TextRunInfo( CharacterBufferRange charBufferRange, int textRunLength, int offsetToFirstCp, TextRun textRun, Plsrun lsRunType, ushort charFlags, CultureInfo digitCulture, bool contextualSubstitution, bool symbolTypeface, TextModifierScope modifierScope ) { _charBufferRange = charBufferRange; _textRunLength = textRunLength; _offsetToFirstCp = offsetToFirstCp; _textRun = textRun; _plsrun = lsRunType; _charFlags = charFlags; _digitCulture = digitCulture; _runFlags = 0; _modifierScope = modifierScope; if (contextualSubstitution) { _runFlags |= (ushort)RunFlags.ContextualSubstitution; } if (symbolTypeface) { _runFlags |= (ushort)RunFlags.IsSymbol; } }
private IList<TextEffect> _textEffects; // TextEffects that should be applied for this run /// <summary> /// Construct an lsrun /// </summary> internal LSRun( TextRunInfo runInfo, IList<TextEffect> textEffects, Plsrun type, int offsetToFirstCp, int textRunLength, int emSize, ushort charFlags, CharacterBufferRange charBufferRange, TextShapeableSymbols shapeable, double realToIdeal, byte bidiLevel ) : this( runInfo, textEffects, type, offsetToFirstCp, textRunLength, emSize, charFlags, charBufferRange, (shapeable != null ? (int)Math.Round(shapeable.Baseline * realToIdeal) : 0), (shapeable != null ? (int)Math.Round(shapeable.Height * realToIdeal) : 0), shapeable, bidiLevel ) {}
/// <summary> /// Map LSCP to host CP, and return the last LSRun /// before the specified limit. /// </summary> internal LSRun CountText( int lscpLim, int cpFirst, out int count ) { LSRun lastRun = null; count = 0; int lsccp = lscpLim - _store.CpFirst; Debug.Assert(lsccp > 0, "Zero-length text line!"); foreach (Span span in _store.PlsrunVector) { if (lsccp <= 0) { break; } Plsrun plsrun = (Plsrun)span.element; // There should be no marker runs in _plsrunVector. Debug.Assert(!TextStore.IsMarker(plsrun)); // Is it a normal, non-static, LSRun? if (plsrun >= Plsrun.FormatAnchor) { // Get the run and remember the last run. lastRun = _store.GetRun(plsrun); // Accumulate the length. int cpRun = lastRun.Length; if (cpRun > 0) { if (lsccp < span.length && cpRun == span.length) { count += lsccp; break; } count += cpRun; } } lsccp -= span.length; } // make char count relative to cpFirst as the cpFirst of this metrics may not // be the same as the cpFirst of the store in optimal paragraph formatting. count = count - cpFirst + _store.CpFirst; return(lastRun); }
/// <summary> /// Construct an lsrun for a constant control char /// </summary> internal LSRun( Plsrun type, IntPtr controlChar ) : this( null, // text run info type, controlChar, 0, // textRunLength -1, // offsetToFirstChar 0 ) { }
/// <summary> /// Convert the specified external CP to LSCP corresponding to a possible break position for optimal break. /// </summary> /// <remarks> /// There is a generic issue that one CP could map to multiple LSCPs when it comes to /// lsrun that occupies no actual CP. Such lsrun is generated by line layout during /// formatting to accomplsih specific purpose i.e. run representing open and close /// reverse object or a fake-linebreak lsrun. /// /// According to SergeyGe and Antons, LS will never breaks immediately after open reverse /// or immediately before close reverse. It also never break before a linebreak character. /// /// Therefore, it is safe to make an assumption here that one CP will indeed map to one /// LSCP given being the LSCP before the open reverse and the LSCP after the close reverse. /// Never the vice-versa. /// /// This is the reason why the loop inside this method may overread the PLSRUN span by /// one span at the end. The loop is designed to skip over all the lsruns with zero CP /// which is not the open reverse. /// /// This logic is exactly the same as the one used by FullTextLine.PrefetchLSRuns. Any /// attempt to change it needs to be thoroughly reviewed. The same logic is to be applied /// accordingly on PrefetchLSRuns. /// /// [Wchao, 5-24-2005] /// /// </remarks> internal int GetBreakpointInternalCp(int cp) { int ccp = cp - _store.CpFirst; int lscp = _store.CpFirst; int ccpCurrent = 0; SpanVector plsrunVector = _store.PlsrunVector; LSRun lsrun; int i = 0; int lastSpanLength = 0; int lastRunLength = 0; do { Span span = plsrunVector[i]; Plsrun plsrun = (Plsrun)span.element; lsrun = _store.GetRun(plsrun); if (ccp == ccpCurrent && lsrun.Type == Plsrun.Reverse) { break; } lastSpanLength = span.length; lastRunLength = (plsrun >= Plsrun.FormatAnchor ? lsrun.Length : 0); lscp += lastSpanLength; ccpCurrent += lastRunLength; } while (++i < plsrunVector.Count && lsrun.Type != Plsrun.ParaBreak && ccp >= ccpCurrent ); // Since we may overread the span vector by one span, // we need to subtract the accumulated lscp by the number of cp we may have overread. if (ccpCurrent == ccp || lastSpanLength == lastRunLength) { return(lscp - ccpCurrent + ccp); } Invariant.Assert(ccpCurrent - ccp == lastRunLength); return(lscp - lastSpanLength); }
internal LSRun( TextRunInfo runInfo, Plsrun type, IntPtr controlChar, int textRunLength, int offsetToFirstCp, byte bidiLevel ) { unsafe { _runInfo = runInfo; _type = type; _charBufferRange = new CharacterBufferRange((char *)controlChar, 1); _textRunLength = textRunLength; _offsetToFirstCp = offsetToFirstCp; _bidiLevel = bidiLevel; } }
/// <summary> /// Construct an lsrun for a constant control char /// </summary> internal LSRun( Plsrun type, IntPtr controlChar ) : this( null, // text run info type, controlChar, 0, // textRunLength -1, // offsetToFirstChar 0 ) {}
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; }
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 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 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 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 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; }
/// <summary> /// Get a text store containing the specified plsrun /// </summary> internal TextStore StoreFrom(Plsrun plsrun) { return(TextStore.IsMarker(plsrun) ? _markerStore : _store); }
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 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; }
/// <summary> /// Construct an lsrun /// </summary> private LSRun( TextRunInfo runInfo, IList<TextEffect> textEffects, Plsrun type, int offsetToFirstCp, int textRunLength, int emSize, ushort charFlags, CharacterBufferRange charBufferRange, int baselineOffset, int height, TextShapeableSymbols shapeable, byte bidiLevel ) { _runInfo = runInfo; _type = type; _offsetToFirstCp = offsetToFirstCp; _textRunLength = textRunLength; _emSize = emSize; _charFlags = charFlags; _charBufferRange = charBufferRange; _baselineOffset = baselineOffset; _height = height; _bidiLevel = bidiLevel; _shapeable = shapeable; _textEffects = textEffects; }
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 LsErr InlineFormat( System.IntPtr pols, // Line Layout context Plsrun plsrun, // plsrun int lscpInline, // first cp of the run int currentPosition, // inline's current pen location in text direction int rightMargin, // right margin ref ObjDim pobjDim, // [out] object dimension out int fFirstRealOnLine, // [out] is this run the first in line out int fPenPositionUsed, // [out] is pen position used to format object out LsBrkCond breakBefore, // [out] break condition before this object out LsBrkCond breakAfter // [out] break condition after this object ) { LsErr lserr = LsErr.None; LSRun lsrun = null; fFirstRealOnLine = 0; fPenPositionUsed = 0; breakBefore = LsBrkCond.Please; breakAfter = LsBrkCond.Please; try { TextFormatterImp formatter = FullText.Formatter; TextStore store = FullText.StoreFrom(plsrun); lsrun = store.GetRun(plsrun); TextEmbeddedObject textObject = lsrun.TextRun as TextEmbeddedObject; Debug.Assert(textObject != null); int cpInline = store.GetExternalCp(lscpInline); fFirstRealOnLine = (cpInline == store.CpFirst) ? 1 : 0; TextEmbeddedObjectMetrics metrics = store.FormatTextObject( textObject, cpInline, currentPosition, rightMargin ); pobjDim = new ObjDim(); pobjDim.dur = TextFormatterImp.RealToIdeal(metrics.Width); pobjDim.heightsRef.dvMultiLineHeight = TextFormatterImp.RealToIdeal(metrics.Height); pobjDim.heightsRef.dvAscent = TextFormatterImp.RealToIdeal(metrics.Baseline); pobjDim.heightsRef.dvDescent = pobjDim.heightsRef.dvMultiLineHeight - pobjDim.heightsRef.dvAscent; pobjDim.heightsPres = pobjDim.heightsRef; breakBefore = BreakConditionToLsBrkCond(textObject.BreakBefore); breakAfter = BreakConditionToLsBrkCond(textObject.BreakAfter); fPenPositionUsed = (!textObject.HasFixedSize) ? 1 : 0; lsrun.BaselineOffset = pobjDim.heightsRef.dvAscent; lsrun.Height = pobjDim.heightsRef.dvMultiLineHeight; } catch (Exception e) { SaveException(e, plsrun, lsrun); lserr = LsErr.ClientAbort; } catch { SaveNonCLSException("InlineFormat", 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 LSRun( TextRunInfo runInfo, Plsrun type, IntPtr controlChar, int textRunLength, int offsetToFirstCp, byte bidiLevel ) { unsafe { _runInfo = runInfo; _type = type; _charBufferRange = new CharacterBufferRange((char*)controlChar, 1); _textRunLength = textRunLength; _offsetToFirstCp = offsetToFirstCp; _bidiLevel = bidiLevel; } }
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 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; }
/// <summary> /// Get LSRun from plsrun /// </summary> internal LSRun GetRun(Plsrun plsrun) { ArrayList lsruns = _lsrunsMainText; if (TextStore.IsMarker(plsrun)) { lsruns = _lsrunsMarkerText; } plsrun = TextStore.ToIndex(plsrun); return (LSRun)( TextStore.IsContent(plsrun) ? lsruns[(int)(plsrun - Plsrun.FormatAnchor)] : TextStore.ControlRuns[(int)plsrun] ); }
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; }
/// <summary> /// Get a text store containing the specified plsrun /// </summary> internal TextStore StoreFrom(Plsrun plsrun) { return TextStore.IsMarker(plsrun) ? _markerStore : _store; }
private void SaveException(Exception e, Plsrun plsrun, LSRun lsrun) { e.Data[ExceptionContext.Key] = new ExceptionContext(e.Data[ExceptionContext.Key], e.StackTrace, plsrun, lsrun); _exception = e; }
private void SaveNonCLSException(string methodName, Plsrun plsrun, LSRun lsrun) { Exception e = new System.Exception(SR.Get(SRID.NonCLSException)); e.Data[ExceptionContext.Key] = new ExceptionContext(null, methodName, plsrun, lsrun); _exception = e; }
public ExceptionContext(object innerContext, string stackTraceOrMethodName, Plsrun plsrun, LSRun lsrun) { _stackTraceOrMethodName = stackTraceOrMethodName; _plsrun = (uint)plsrun; _lsrun = lsrun; _innerContext = innerContext; }
/// <summary> /// Fetch cached textrun /// </summary> internal TextRun FetchTextRun( FormatSettings settings, int cpFetch, int cpFirst, out int offsetToFirstCp, out int runLength ) { SpanRider textRunSpanRider = new SpanRider(_textRunVector, _latestPosition, cpFetch); _latestPosition = textRunSpanRider.SpanPosition; TextRun textRun = (TextRun)textRunSpanRider.CurrentElement; if (textRun == null) { // run not already cached, fetch new run and cache it textRun = settings.TextSource.GetTextRun(cpFetch); if (textRun.Length < 1) { throw new ArgumentOutOfRangeException("textRun.Length", SR.Get(SRID.ParameterMustBeGreaterThanZero)); } Plsrun plsrun = TextRunInfo.GetRunType(textRun); if (plsrun == Plsrun.Text || plsrun == Plsrun.InlineObject) { TextRunProperties properties = textRun.Properties; if (properties == null) { throw new ArgumentException(SR.Get(SRID.TextRunPropertiesCannotBeNull)); } if (properties.FontRenderingEmSize <= 0) { throw new ArgumentException(SR.Get(SRID.PropertyOfClassMustBeGreaterThanZero, "FontRenderingEmSize", "TextRunProperties")); } double realMaxFontRenderingEmSize = Constants.RealInfiniteWidth / Constants.GreatestMutiplierOfEm; if (properties.FontRenderingEmSize > realMaxFontRenderingEmSize) { throw new ArgumentException(SR.Get(SRID.PropertyOfClassCannotBeGreaterThan, "FontRenderingEmSize", "TextRunProperties", realMaxFontRenderingEmSize)); } CultureInfo culture = CultureMapper.GetSpecificCulture(properties.CultureInfo); if (culture == null) { throw new ArgumentException(SR.Get(SRID.PropertyOfClassCannotBeNull, "CultureInfo", "TextRunProperties")); } if (properties.Typeface == null) { throw new ArgumentException(SR.Get(SRID.PropertyOfClassCannotBeNull, "Typeface", "TextRunProperties")); } } // // TextRun is specifial to SpanVector because TextRun also encodes position which needs to be // consistent with the positions encoded by SpanVector. In run cache, the begining of a span // should always correspond to the begining of a cached text run. If the end of the currently fetched // run overlaps with the begining of an already cached run, the begining of the cached run needs to be // adjusted as well as its span. Because we can't gurantee the correctness of the overlapped range // so we'll simply remove the overlapped runs here. // // Move the rider to the end of the current run textRunSpanRider.At(cpFetch + textRun.Length - 1); _latestPosition = textRunSpanRider.SpanPosition; if (textRunSpanRider.CurrentElement != _textRunVector.Default) { // The end overlaps with one or more cached runs, clear the range from the // begining of the current fetched run to the end of the last overlapped cached run. _latestPosition = _textRunVector.SetReference( cpFetch, textRunSpanRider.CurrentPosition + textRunSpanRider.Length - cpFetch, _textRunVector.Default, _latestPosition ); } _latestPosition = _textRunVector.SetReference(cpFetch, textRun.Length, textRun, _latestPosition); // Refresh the rider's SpanPosition following previous SpanVector.SetReference calls textRunSpanRider.At(_latestPosition, cpFetch); } // If the TextRun was obtained from the cache, make sure it has the right PixelsPerDip set on its properties. if (textRun.Properties != null) { textRun.Properties.PixelsPerDip = settings.TextSource.PixelsPerDip; } offsetToFirstCp = textRunSpanRider.CurrentPosition - textRunSpanRider.CurrentSpanStart; runLength = textRunSpanRider.Length; Debug.Assert(textRun != null && runLength > 0, "Invalid run!"); bool isText = textRun is ITextSymbols; if (isText) { // Chop text run to optimal length so we dont spend forever analysing // them all at once. int looseCharLength = TextStore.TypicalCharactersPerLine - cpFetch + cpFirst; if (looseCharLength <= 0) { // this line already exceeds typical line length, incremental fetch goes // about a quarter of the typical length. looseCharLength = (int)Math.Round(TextStore.TypicalCharactersPerLine * 0.25); } if (runLength > looseCharLength) { if (TextRunInfo.GetRunType(textRun) == Plsrun.Text) { // // When chopping the run at the typical line length, // - don't chop in between of higher & lower surrogate // - don't chop combining mark away from its base character // - don't chop joiner from surrounding characters // // Starting from the initial chopping point, we look ahead to find a safe position. We stop at // a limit in case the run consists of many combining mark & joiner. That is rare and doesn't make // much sense in shaping already. // CharacterBufferReference charBufferRef = textRun.CharacterBufferReference; // We look ahead by one more line at most. It is not normal to have // so many combining mark or joiner characters in a row. It doesn't make sense to // look further if so. int lookAheadLimit = Math.Min(runLength, looseCharLength + TextStore.TypicalCharactersPerLine); int sizeOfChar = 0; int endOffset = 0; bool canBreakAfterPrecedingChar = false; for (endOffset = looseCharLength - 1; endOffset < lookAheadLimit; endOffset += sizeOfChar) { CharacterBufferRange charString = new CharacterBufferRange( charBufferRef.CharacterBuffer, charBufferRef.OffsetToFirstChar + offsetToFirstCp + endOffset, runLength - endOffset ); int ch = Classification.UnicodeScalar(charString, out sizeOfChar); // We can only safely break if the preceding char is not a joiner character (i.e. can-break-after), // and the current char is not combining or joiner (i.e. can-break-before). if (canBreakAfterPrecedingChar && !Classification.IsCombining(ch) && !Classification.IsJoiner(ch)) { break; } canBreakAfterPrecedingChar = !Classification.IsJoiner(ch); } looseCharLength = Math.Min(runLength, endOffset); } runLength = looseCharLength; } } Debug.Assert( // valid run found runLength > 0 // non-text run always fetched at run start && (isText || textRunSpanRider.CurrentSpanStart - textRunSpanRider.CurrentPosition == 0) // span rider of both text and format point to valid position && (textRunSpanRider.Length > 0 && textRunSpanRider.CurrentElement != null), "Text run fetching error!" ); return(textRun); }