protected bool RenderText(String text, DrawingContext dc, ViewUtil.ItemFont itemFont, Brush brush, double fontSize, double maxWidth, double maxHeight, double x, double baseline, ref double useHeight, bool nowrap = false) { if (x <= 0 || maxWidth <= 0) { useHeight = 0; return(false); } double totalHeight = 0; double fontHeight = fontSize * itemFont.GlyphType.Height; string[] lineText = text.Replace("\r", "").Split('\n'); foreach (string line in lineText) { //高さ確認 if (totalHeight + fontHeight > maxHeight) { //これ以上は無理 useHeight = totalHeight; return(false); } // ベースラインの位置の計算 // ビットマップフォントがかすれる問題 とりあえず整数にしておく Point origin = new Point(Math.Round(x), Math.Round(totalHeight + baseline)); //メイリオみたいに行間のあるフォントと MS P ゴシックみたいな行間のないフォントがあるので //なんとなく行間を作ってみる。 totalHeight += Math.Max(fontHeight, fontSize + 2); double totalWidth = 0; List <ushort> glyphIndexes = new List <ushort>(); List <double> advanceWidths = new List <double>(); for (int n = 0; n < line.Length; n++) { // XAML に合わせて、行頭の空白を無視する if (glyphIndexes.Count == 0 && (line[n] == ' ' || line[n] == '\x3000')) { continue; } //ushort glyphIndex = glyphType.CharacterToGlyphMap[line[n]]; //double width = glyphType.AdvanceWidths[glyphIndex] * fontSize; ushort glyphIndex = itemFont.GlyphIndexCache[line[n]]; if (glyphIndex == 0) { itemFont.GlyphType.CharacterToGlyphMap.TryGetValue(line[n], out glyphIndex); itemFont.GlyphIndexCache[line[n]] = glyphIndex; itemFont.GlyphWidthCache[glyphIndex] = (float)itemFont.GlyphType.AdvanceWidths[glyphIndex]; } double width = itemFont.GlyphWidthCache[glyphIndex] * fontSize; if (totalWidth + width > maxWidth) { if (nowrap == true) { break; //改行しない場合ここで終り } if (totalWidth == 0) { return(false); //一文字も置けなかった(glyphIndexesなどのCount=0のまま) } if (totalHeight + fontHeight > maxHeight) { //次の行無理 //glyphIndex = glyphType.CharacterToGlyphMap['…']; //double widthEllipsis = glyphType.AdvanceWidths[glyphIndex] * fontSize; glyphIndex = itemFont.GlyphType.CharacterToGlyphMap['…']; double widthEllipsis = itemFont.GlyphType.AdvanceWidths[glyphIndex] * fontSize; while (totalWidth - advanceWidths.Last() + widthEllipsis > maxWidth) { totalWidth -= advanceWidths.Last(); glyphIndexes.RemoveAt(glyphIndexes.Count - 1); advanceWidths.RemoveAt(advanceWidths.Count - 1); } glyphIndexes[glyphIndexes.Count - 1] = glyphIndex; advanceWidths[advanceWidths.Count - 1] = widthEllipsis; GlyphRun glyphRun = new GlyphRun(itemFont.GlyphType, 0, false, fontSize, glyphIndexes, origin, advanceWidths, null, null, null, null, null, null); dc.DrawGlyphRun(brush, glyphRun); useHeight = totalHeight; return(false); } else { //次の行いけるので今までの分出力 GlyphRun glyphRun = new GlyphRun(itemFont.GlyphType, 0, false, fontSize, glyphIndexes, origin, advanceWidths, null, null, null, null, null, null); dc.DrawGlyphRun(brush, glyphRun); origin = new Point(Math.Round(x), Math.Round(totalHeight + baseline)); totalHeight += Math.Max(fontHeight, fontSize + 2); totalWidth = 0; glyphIndexes = new List <ushort>(); advanceWidths = new List <double>(); // XAML に合わせて、行頭の空白を無視する if (line[n] == ' ' || line[n] == '\x3000') { continue; } } } glyphIndexes.Add(glyphIndex); advanceWidths.Add(width); totalWidth += width; } if (glyphIndexes.Count > 0) { GlyphRun glyphRun = new GlyphRun(itemFont.GlyphType, 0, false, fontSize, glyphIndexes, origin, advanceWidths, null, null, null, null, null, null); dc.DrawGlyphRun(brush, glyphRun); } } useHeight = totalHeight; return(true); }
protected bool RenderText(String text, ref List <TextDrawItem> textDrawList, ViewUtil.ItemFont itemFont, double fontSize, double maxWidth, double maxHeight, double x, double baseline, ref double useHeight, Brush fontColor, Matrix m) { double totalHeight = 0; double fontHeight = fontSize * itemFont.GlyphType.Height; string[] lineText = text.Replace("\r", "").Split('\n'); foreach (string line in lineText) { List <ushort> glyphIndexes = new List <ushort>(); List <double> advanceWidths = new List <double>(); //ベースラインの位置 double dpix = x * m.M11; double dpiy = (totalHeight + baseline) * m.M22; // ビットマップフォントがかすれる問題 とりあえず整数にしておく Point origin = new Point(Math.Round(dpix / m.M11), Math.Round(dpiy / m.M22)); //メイリオみたいに行間のあるフォントと MS P ゴシックみたいな行間のないフォントがあるので //なんとなく行間を作ってみる。 totalHeight += Math.Max(fontHeight, fontSize + 2); double totalWidth = 0; for (int n = 0; n < line.Length; n++) { // XAML に合わせて、行頭の空白を無視する if (glyphIndexes.Count == 0 && (line[n] == ' ' || line[n] == '\x3000')) { continue; } //この辞書検索が負荷の大部分を占めているのでテーブルルックアップする //(簡単なパフォーマンス計測をした結果、2~10倍くらい速くなったようだ) //ushort glyphIndex = itemFont.GlyphType.CharacterToGlyphMap[line[n]]; //double width = itemFont.GlyphType.AdvanceWidths[glyphIndex] * fontSize; ushort glyphIndex = itemFont.GlyphIndexCache[line[n]]; if (glyphIndex == 0) { itemFont.GlyphType.CharacterToGlyphMap.TryGetValue(line[n], out glyphIndex); itemFont.GlyphIndexCache[line[n]] = glyphIndex; itemFont.GlyphWidthCache[glyphIndex] = (float)itemFont.GlyphType.AdvanceWidths[glyphIndex]; } double width = itemFont.GlyphWidthCache[glyphIndex] * fontSize; if (totalWidth + width > maxWidth) { if (glyphIndexes.Count > 0) { TextDrawItem item = new TextDrawItem(); item.FontColor = fontColor; item.Text = new GlyphRun(itemFont.GlyphType, 0, false, fontSize, glyphIndexes, origin, advanceWidths, null, null, null, null, null, null); textDrawList.Add(item); } if (totalHeight > maxHeight) { //次の行無理 useHeight = totalHeight; return(false); } else { //次の行いける dpiy = (totalHeight + baseline) * m.M22; origin = new Point(Math.Round(dpix / m.M11), Math.Round(dpiy / m.M22)); totalHeight += Math.Max(fontHeight, fontSize + 2); totalWidth = 0; glyphIndexes = new List <ushort>(); advanceWidths = new List <double>(); // XAML に合わせて、行頭の空白を無視する if (line[n] == ' ' || line[n] == '\x3000') { continue; } } } glyphIndexes.Add(glyphIndex); advanceWidths.Add(width); totalWidth += width; } if (glyphIndexes.Count > 0) { TextDrawItem item = new TextDrawItem(); item.FontColor = fontColor; item.Text = new GlyphRun(itemFont.GlyphType, 0, false, fontSize, glyphIndexes, origin, advanceWidths, null, null, null, null, null, null); textDrawList.Add(item); } } useHeight = Math.Floor(totalHeight); return(true); }