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 ) {}
private int GetShapeableSymbolsWidth(TextShapeableSymbols textRun) { int result = 0; int text_length = textRun.Length; int[] advance_widths = new int[text_length]; GCHandle pin_handle; CharacterBuffer char_buf = textRun.CharacterBufferReference.CharacterBuffer; unsafe { IntPtr run_characters = char_buf.PinAndGetCharacterPointer(textRun.CharacterBufferReference.OffsetToFirstChar, out pin_handle); try { fixed(int *widths_ptr = advance_widths) { textRun.GetAdvanceWidthsUnshaped((char *)run_characters.ToPointer(), text_length, TextFormatterImp.ToIdeal, widths_ptr); } } finally { char_buf.UnpinCharacterPointer(pin_handle); } } for (int i = 0; i < text_length; i++) { result += advance_widths[i]; } return(result); }
/// <summary> /// Construct a full description of glyph data /// </summary> internal Glyphs( TextShapeableSymbols shapeable, char[] charArray, int[] glyphAdvances, ushort[] clusterMap, ushort[] glyphIndices, GlyphOffset[] glyphOffsets, double scalingFactor ) { _shapeable = shapeable; _charArray = charArray; _glyphAdvances = new double[glyphAdvances.Length]; double ToReal = 1.0 / scalingFactor; for (int i = 0; i < glyphAdvances.Length; i++) { _unscaledWidth += glyphAdvances[i]; _glyphAdvances[i] = glyphAdvances[i] * ToReal; _width += _glyphAdvances[i]; } if (glyphIndices != null) { _clusterMap = clusterMap; if (glyphOffsets != null) { _glyphOffsets = new PartialArray <Point>(new Point[glyphOffsets.Length]); for (int i = 0; i < glyphOffsets.Length; i++) { _glyphOffsets[i] = new Point( glyphOffsets[i].du * ToReal, glyphOffsets[i].dv * ToReal ); } } Debug.Assert(glyphAdvances.Length <= glyphIndices.Length); if (glyphAdvances.Length != glyphIndices.Length) { _glyphIndices = new ushort[glyphAdvances.Length]; for (int i = 0; i < glyphAdvances.Length; i++) { _glyphIndices[i] = glyphIndices[i]; } } else { _glyphIndices = glyphIndices; } } }
/// <summary> /// Construct a nominal description of glyph data /// </summary> internal Glyphs( TextShapeableSymbols shapeable, char[] charArray, int[] nominalAdvances, double scalingFactor ) : this( shapeable, charArray, nominalAdvances, null, // clusterMap null, // glyphIndices null, // glyphOffsets scalingFactor ) { }
/// <summary> /// Return value indicates whether two runs can shape together /// </summary> internal sealed override bool CanShapeTogether( TextShapeableSymbols shapeable ) { TextShapeableCharacters charShape = shapeable as TextShapeableCharacters; if (charShape == null) { return(false); } return (_shapeTypeface.Equals(charShape._shapeTypeface) // Extended characters need to be shaped by surrogate shaper. They cannot be shaped together with non-exteneded characters. && (_textItem.HasExtendedCharacter) == (charShape._textItem.HasExtendedCharacter) && _emSize == charShape._emSize && ( _properties.CultureInfo == null ? charShape._properties.CultureInfo == null : _properties.CultureInfo.Equals(charShape._properties.CultureInfo) ) && _nullShape == charShape._nullShape && (_textItem.CanShapeTogether(charShape._textItem))); }
/// <summary> /// Return value indicates whether two runs can shape together /// </summary> internal sealed override bool CanShapeTogether( TextShapeableSymbols shapeable ) { TextShapeableCharacters charShape = shapeable as TextShapeableCharacters; if (charShape == null) return false; return _shapeTypeface.Equals(charShape._shapeTypeface) // Extended characters need to be shaped by surrogate shaper. They cannot be shaped together with non-exteneded characters. && (_textItem.HasExtendedCharacter) == (charShape._textItem.HasExtendedCharacter) && _emSize == charShape._emSize && ( _properties.CultureInfo == null ? charShape._properties.CultureInfo == null : _properties.CultureInfo.Equals(charShape._properties.CultureInfo) ) && _nullShape == charShape._nullShape && (_textItem.CanShapeTogether(charShape._textItem)); }
/// <summary> /// Construct a full description of glyph data /// </summary> internal Glyphs( TextShapeableSymbols shapeable, char[] charArray, int[] glyphAdvances, ushort[] clusterMap, ushort[] glyphIndices, GlyphOffset[] glyphOffsets, double scalingFactor ) { _shapeable = shapeable; _charArray = charArray; // create double array for glyph run creation, because Shaping is all done in // ideal units. FormattedTextSymbol is used to draw text collapsing symbols // which usually contains very few glyphs. Using double[] and Point[] directly // is more efficient. _glyphAdvances = new double[glyphAdvances.Length]; double ToReal = 1.0 / scalingFactor; for (int i = 0; i < glyphAdvances.Length; i++) { _glyphAdvances[i] = glyphAdvances[i] * ToReal; _width += _glyphAdvances[i]; } if (glyphIndices != null) { _clusterMap = clusterMap; if (glyphOffsets != null) { _glyphOffsets = new PartialArray<Point>(new Point[glyphOffsets.Length]); for (int i = 0; i < glyphOffsets.Length; i++) { _glyphOffsets[i] = new Point( glyphOffsets[i].du * ToReal, glyphOffsets[i].dv * ToReal ); } } Debug.Assert(glyphAdvances.Length <= glyphIndices.Length); if (glyphAdvances.Length != glyphIndices.Length) { _glyphIndices = new ushort[glyphAdvances.Length]; for (int i = 0; i < glyphAdvances.Length; i++) { _glyphIndices[i] = glyphIndices[i]; } } else { _glyphIndices = glyphIndices; } } }
/// <summary> /// Construct a nominal description of glyph data /// </summary> internal Glyphs( TextShapeableSymbols shapeable, char[] charArray, int[] nominalAdvances, double scalingFactor ) : this( shapeable, charArray, nominalAdvances, null, // clusterMap null, // glyphIndices null, // glyphOffsets scalingFactor ) {}
/// <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; }
/// <summary> /// Construct a formatted run /// </summary> public FormattedTextSymbols( GlyphingCache glyphingCache, TextRun textSymbols, CharacterBufferRange chars, bool rightToLeft, double scalingFactor, float pixelsPerDip, TextFormattingMode textFormattingMode, bool isSideways ) { _textFormattingMode = textFormattingMode; _isSideways = isSideways; ITextSymbols symbols = textSymbols as ITextSymbols; Debug.Assert(symbols != null); // break down a single text run into pieces IList <TextShapeableSymbols> shapeables = symbols.GetTextShapeableSymbols( glyphingCache, chars.CharacterBufferReference, chars.Length, rightToLeft, // This is a bool indicating the RTL // based on the bidi level of text (if applicable). // For FormattedTextSymbols it is equal to paragraph flow direction. rightToLeft, // This is the flow direction of the paragraph as // specified by the user. DWrite needs the paragraph // flow direction of the paragraph // while WPF algorithms need the RTL of the text based on // Bidi if possible. null, // cultureInfo null, // textModifierScope _textFormattingMode, _isSideways ); Debug.Assert(shapeables != null && shapeables.Count > 0); _rightToLeft = rightToLeft; _glyphs = new Glyphs[shapeables.Count]; CharacterBuffer charBuffer = chars.CharacterBuffer; int offsetToFirstChar = chars.OffsetToFirstChar; int i = 0; int ich = 0; while (i < shapeables.Count) { TextShapeableSymbols current = shapeables[i] as TextShapeableSymbols; Debug.Assert(current != null); int cch = current.Length; int j; // make a separate character buffer for glyphrun persistence char[] charArray = new char[cch]; for (j = 0; j < cch; j++) { charArray[j] = charBuffer[offsetToFirstChar + ich + j]; } if (current.IsShapingRequired) { ushort[] clusterMap; ushort[] glyphIndices; int[] glyphAdvances; GlyphOffset[] glyphOffsets; // Note that we dont check for the chance of having multiple // shapeables shaped together here since we're dealing with // single-style text. There is virtually no chance to require // for adjacent runs to shape together. We rely on TextSymbols // to reduce duplication of the itemized shapeables for performance. unsafe { fixed(char *fixedCharArray = &charArray[0]) { MS.Internal.Text.TextInterface.TextAnalyzer textAnalyzer = MS.Internal.FontCache.DWriteFactory.Instance.CreateTextAnalyzer(); GlyphTypeface glyphTypeface = current.GlyphTypeFace; DWriteFontFeature[][] fontFeatures; uint[] fontFeatureRanges; uint unsignedCch = checked ((uint)cch); //LSRun.CompileFeatureSet(current.Properties.TypographyProperties, unsignedCch, out fontFeatures, out fontFeatureRanges); fontFeatures = new DWriteFontFeature[0][]; fontFeatureRanges = new uint[0]; textAnalyzer.GetGlyphsAndTheirPlacements( new IntPtr(fixedCharArray), unsignedCch, glyphTypeface.FontDWrite, glyphTypeface.BlankGlyphIndex, false, // no sideway support yet /************************************************************************************************/ // Should we break down the runs to know whats the Bidi for every range of characters? rightToLeft, current.Properties.CultureInfo, /************************************************************************************************/ fontFeatures, fontFeatureRanges, current.Properties.FontRenderingEmSize, scalingFactor, pixelsPerDip, _textFormattingMode, current.ItemProps, out clusterMap, out glyphIndices, out glyphAdvances, out glyphOffsets ); } _glyphs[i] = new Glyphs( current, charArray, glyphAdvances, clusterMap, glyphIndices, glyphOffsets, scalingFactor ); } } else { // shaping not required, // bypass glyphing process altogether int[] nominalAdvances = new int[charArray.Length]; unsafe { fixed(char *fixedCharArray = &charArray[0]) fixed(int *fixedNominalAdvances = &nominalAdvances[0]) { current.GetAdvanceWidthsUnshaped( fixedCharArray, cch, scalingFactor, // format resolution specified per em, fixedNominalAdvances ); } } _glyphs[i] = new Glyphs( current, charArray, nominalAdvances, scalingFactor ); } i++; ich += cch; } }