OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/render_text_harfbuzz.h" | 5 #include "ui/gfx/render_text_harfbuzz.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <map> | 8 #include <map> |
9 | 9 |
10 #include "base/i18n/bidi_line_iterator.h" | 10 #include "base/i18n/bidi_line_iterator.h" |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
69 // |paint|'s font. | 69 // |paint|'s font. |
70 void GetGlyphWidthAndExtents(SkPaint* paint, | 70 void GetGlyphWidthAndExtents(SkPaint* paint, |
71 hb_codepoint_t codepoint, | 71 hb_codepoint_t codepoint, |
72 hb_position_t* width, | 72 hb_position_t* width, |
73 hb_glyph_extents_t* extents) { | 73 hb_glyph_extents_t* extents) { |
74 DCHECK_LE(codepoint, 0xFFFFU); | 74 DCHECK_LE(codepoint, 0xFFFFU); |
75 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 75 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
76 | 76 |
77 SkScalar sk_width; | 77 SkScalar sk_width; |
78 SkRect sk_bounds; | 78 SkRect sk_bounds; |
79 uint16_t glyph = codepoint; | 79 uint16_t glyph = static_cast<uint16_t>(codepoint); |
msw
2014/10/17 22:13:23
ditto nit q: DCHECK against uint32_t -> uint16_t o
Peter Kasting
2014/10/21 01:20:45
This was checked above (line 74).
| |
80 | 80 |
81 paint->getTextWidths(&glyph, sizeof(glyph), &sk_width, &sk_bounds); | 81 paint->getTextWidths(&glyph, sizeof(glyph), &sk_width, &sk_bounds); |
82 if (width) | 82 if (width) |
83 *width = SkiaScalarToHarfBuzzPosition(sk_width); | 83 *width = SkiaScalarToHarfBuzzPosition(sk_width); |
84 if (extents) { | 84 if (extents) { |
85 // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to be | 85 // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to be |
86 // y-grows-up. | 86 // y-grows-up. |
87 extents->x_bearing = SkiaScalarToHarfBuzzPosition(sk_bounds.fLeft); | 87 extents->x_bearing = SkiaScalarToHarfBuzzPosition(sk_bounds.fLeft); |
88 extents->y_bearing = SkiaScalarToHarfBuzzPosition(-sk_bounds.fTop); | 88 extents->y_bearing = SkiaScalarToHarfBuzzPosition(-sk_bounds.fTop); |
89 extents->width = SkiaScalarToHarfBuzzPosition(sk_bounds.width()); | 89 extents->width = SkiaScalarToHarfBuzzPosition(sk_bounds.width()); |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
266 hb_face_t* get() { | 266 hb_face_t* get() { |
267 return face_; | 267 return face_; |
268 } | 268 } |
269 | 269 |
270 private: | 270 private: |
271 hb_face_t* face_; | 271 hb_face_t* face_; |
272 }; | 272 }; |
273 | 273 |
274 // Creates a HarfBuzz font from the given Skia face and text size. | 274 // Creates a HarfBuzz font from the given Skia face and text size. |
275 hb_font_t* CreateHarfBuzzFont(SkTypeface* skia_face, | 275 hb_font_t* CreateHarfBuzzFont(SkTypeface* skia_face, |
276 int text_size, | 276 SkScalar text_size, |
277 const FontRenderParams& params, | 277 const FontRenderParams& params, |
278 bool background_is_transparent) { | 278 bool background_is_transparent) { |
279 typedef std::pair<HarfBuzzFace, GlyphCache> FaceCache; | 279 typedef std::pair<HarfBuzzFace, GlyphCache> FaceCache; |
280 | 280 |
281 // TODO(ckocagil): This shouldn't grow indefinitely. Maybe use base::MRUCache? | 281 // TODO(ckocagil): This shouldn't grow indefinitely. Maybe use base::MRUCache? |
282 static std::map<SkFontID, FaceCache> face_caches; | 282 static std::map<SkFontID, FaceCache> face_caches; |
283 | 283 |
284 FaceCache* face_cache = &face_caches[skia_face->uniqueID()]; | 284 FaceCache* face_cache = &face_caches[skia_face->uniqueID()]; |
285 if (face_cache->first.get() == NULL) | 285 if (face_cache->first.get() == NULL) |
286 face_cache->first.Init(skia_face); | 286 face_cache->first.Init(skia_face); |
(...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
875 | 875 |
876 for (size_t i = 0; i < runs_.size(); ++i) { | 876 for (size_t i = 0; i < runs_.size(); ++i) { |
877 const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]]; | 877 const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]]; |
878 internal::LineSegment segment; | 878 internal::LineSegment segment; |
879 segment.x_range = Range(current_x, current_x + run.width); | 879 segment.x_range = Range(current_x, current_x + run.width); |
880 segment.char_range = run.range; | 880 segment.char_range = run.range; |
881 segment.run = i; | 881 segment.run = i; |
882 lines[0].segments.push_back(segment); | 882 lines[0].segments.push_back(segment); |
883 | 883 |
884 paint.setTypeface(run.skia_face.get()); | 884 paint.setTypeface(run.skia_face.get()); |
885 paint.setTextSize(run.font_size); | 885 paint.setTextSize(SkIntToScalar(run.font_size)); |
886 SkPaint::FontMetrics metrics; | 886 SkPaint::FontMetrics metrics; |
887 paint.getFontMetrics(&metrics); | 887 paint.getFontMetrics(&metrics); |
888 | 888 |
889 lines[0].size.set_width(lines[0].size.width() + run.width); | 889 lines[0].size.set_width(lines[0].size.width() + run.width); |
890 lines[0].size.set_height(std::max(lines[0].size.height(), | 890 lines[0].size.set_height(std::max(lines[0].size.height(), |
891 metrics.fDescent - metrics.fAscent)); | 891 metrics.fDescent - metrics.fAscent)); |
892 lines[0].baseline = std::max(lines[0].baseline, | 892 lines[0].baseline = std::max(lines[0].baseline, |
893 SkScalarRoundToInt(-metrics.fAscent)); | 893 SkScalarRoundToInt(-metrics.fAscent)); |
894 } | 894 } |
895 | 895 |
896 set_lines(&lines); | 896 set_lines(&lines); |
897 } | 897 } |
898 } | 898 } |
899 | 899 |
900 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { | 900 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { |
901 DCHECK(!needs_layout_); | 901 DCHECK(!needs_layout_); |
902 internal::SkiaTextRenderer renderer(canvas); | 902 internal::SkiaTextRenderer renderer(canvas); |
903 ApplyFadeEffects(&renderer); | 903 ApplyFadeEffects(&renderer); |
904 ApplyTextShadows(&renderer); | 904 ApplyTextShadows(&renderer); |
905 ApplyCompositionAndSelectionStyles(); | 905 ApplyCompositionAndSelectionStyles(); |
906 | 906 |
907 int current_x = 0; | 907 int current_x = 0; |
908 const Vector2d line_offset = GetLineOffset(0); | 908 const Vector2d line_offset = GetLineOffset(0); |
909 for (size_t i = 0; i < runs_.size(); ++i) { | 909 for (size_t i = 0; i < runs_.size(); ++i) { |
910 const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]]; | 910 const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]]; |
911 renderer.SetTypeface(run.skia_face.get()); | 911 renderer.SetTypeface(run.skia_face.get()); |
912 renderer.SetTextSize(run.font_size); | 912 renderer.SetTextSize(SkIntToScalar(run.font_size)); |
913 renderer.SetFontRenderParams(run.render_params, | 913 renderer.SetFontRenderParams(run.render_params, |
914 background_is_transparent()); | 914 background_is_transparent()); |
915 | 915 |
916 Vector2d origin = line_offset + Vector2d(current_x, lines()[0].baseline); | 916 Vector2d origin = line_offset + Vector2d(current_x, lines()[0].baseline); |
917 scoped_ptr<SkPoint[]> positions(new SkPoint[run.glyph_count]); | 917 scoped_ptr<SkPoint[]> positions(new SkPoint[run.glyph_count]); |
918 for (size_t j = 0; j < run.glyph_count; ++j) { | 918 for (size_t j = 0; j < run.glyph_count; ++j) { |
919 positions[j] = run.positions[j]; | 919 positions[j] = run.positions[j]; |
920 positions[j].offset(SkIntToScalar(origin.x()), SkIntToScalar(origin.y())); | 920 positions[j].offset(SkIntToScalar(origin.x()), SkIntToScalar(origin.y())); |
921 } | 921 } |
922 | 922 |
923 for (BreakList<SkColor>::const_iterator it = | 923 for (BreakList<SkColor>::const_iterator it = |
924 colors().GetBreak(run.range.start()); | 924 colors().GetBreak(run.range.start()); |
925 it != colors().breaks().end() && it->first < run.range.end(); | 925 it != colors().breaks().end() && it->first < run.range.end(); |
926 ++it) { | 926 ++it) { |
927 const Range intersection = colors().GetRange(it).Intersect(run.range); | 927 const Range intersection = colors().GetRange(it).Intersect(run.range); |
928 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); | 928 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); |
929 // The range may be empty if a portion of a multi-character grapheme is | 929 // The range may be empty if a portion of a multi-character grapheme is |
930 // selected, yielding two colors for a single glyph. For now, this just | 930 // selected, yielding two colors for a single glyph. For now, this just |
931 // paints the glyph with a single style, but it should paint it twice, | 931 // paints the glyph with a single style, but it should paint it twice, |
932 // clipped according to selection bounds. See http://crbug.com/366786 | 932 // clipped according to selection bounds. See http://crbug.com/366786 |
933 if (colored_glyphs.is_empty()) | 933 if (colored_glyphs.is_empty()) |
934 continue; | 934 continue; |
935 | 935 |
936 renderer.SetForegroundColor(it->second); | 936 renderer.SetForegroundColor(it->second); |
937 renderer.DrawPosText(&positions[colored_glyphs.start()], | 937 renderer.DrawPosText(&positions[colored_glyphs.start()], |
938 &run.glyphs[colored_glyphs.start()], | 938 &run.glyphs[colored_glyphs.start()], |
939 colored_glyphs.length()); | 939 colored_glyphs.length()); |
940 int width = (colored_glyphs.end() == run.glyph_count ? run.width : | 940 // !!! Should this be SkScalarRoundToInt, or SkScalarCeilToInt? |
msw
2014/10/17 22:13:23
Again, Dan or Cem might have more informed advice,
Daniel Erat
2014/10/17 23:20:05
i'm not sure about this either, but rounding seems
Peter Kasting
2014/10/21 01:20:45
After in-person discussion, I fixed bugs in this c
| |
941 run.positions[colored_glyphs.end()].x()) - | 941 int width = SkScalarFloorToInt( |
942 run.positions[colored_glyphs.start()].x(); | 942 (colored_glyphs.end() == run.glyph_count ? |
943 run.width : run.positions[colored_glyphs.end()].x()) - | |
944 run.positions[colored_glyphs.start()].x()); | |
943 renderer.DrawDecorations(origin.x(), origin.y(), width, run.underline, | 945 renderer.DrawDecorations(origin.x(), origin.y(), width, run.underline, |
944 run.strike, run.diagonal_strike); | 946 run.strike, run.diagonal_strike); |
945 } | 947 } |
946 | 948 |
947 current_x += run.width; | 949 current_x += run.width; |
948 } | 950 } |
949 | 951 |
950 renderer.EndDiagonalStrike(); | 952 renderer.EndDiagonalStrike(); |
951 | 953 |
952 UndoCompositionAndSelectionStyles(); | 954 UndoCompositionAndSelectionStyles(); |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1138 skia::RefPtr<SkTypeface> skia_face = | 1140 skia::RefPtr<SkTypeface> skia_face = |
1139 internal::CreateSkiaTypeface(font_family, run->font_style); | 1141 internal::CreateSkiaTypeface(font_family, run->font_style); |
1140 if (skia_face == NULL) | 1142 if (skia_face == NULL) |
1141 return false; | 1143 return false; |
1142 run->skia_face = skia_face; | 1144 run->skia_face = skia_face; |
1143 FontRenderParamsQuery query(false); | 1145 FontRenderParamsQuery query(false); |
1144 query.families.push_back(font_family); | 1146 query.families.push_back(font_family); |
1145 query.pixel_size = run->font_size; | 1147 query.pixel_size = run->font_size; |
1146 query.style = run->font_style; | 1148 query.style = run->font_style; |
1147 run->render_params = GetFontRenderParams(query, NULL); | 1149 run->render_params = GetFontRenderParams(query, NULL); |
1148 hb_font_t* harfbuzz_font = CreateHarfBuzzFont(run->skia_face.get(), | 1150 hb_font_t* harfbuzz_font = CreateHarfBuzzFont( |
1149 run->font_size, run->render_params, background_is_transparent()); | 1151 run->skia_face.get(), SkIntToScalar(run->font_size), run->render_params, |
1152 background_is_transparent()); | |
1150 | 1153 |
1151 // Create a HarfBuzz buffer and add the string to be shaped. The HarfBuzz | 1154 // Create a HarfBuzz buffer and add the string to be shaped. The HarfBuzz |
1152 // buffer holds our text, run information to be used by the shaping engine, | 1155 // buffer holds our text, run information to be used by the shaping engine, |
1153 // and the resulting glyph data. | 1156 // and the resulting glyph data. |
1154 hb_buffer_t* buffer = hb_buffer_create(); | 1157 hb_buffer_t* buffer = hb_buffer_create(); |
1155 hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16*>(text.c_str()), | 1158 hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16*>(text.c_str()), |
1156 text.length(), run->range.start(), run->range.length()); | 1159 text.length(), run->range.start(), run->range.length()); |
1157 hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script)); | 1160 hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script)); |
1158 hb_buffer_set_direction(buffer, | 1161 hb_buffer_set_direction(buffer, |
1159 run->is_rtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); | 1162 run->is_rtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); |
1160 // TODO(ckocagil): Should we determine the actual language? | 1163 // TODO(ckocagil): Should we determine the actual language? |
1161 hb_buffer_set_language(buffer, hb_language_get_default()); | 1164 hb_buffer_set_language(buffer, hb_language_get_default()); |
1162 | 1165 |
1163 // Shape the text. | 1166 // Shape the text. |
1164 hb_shape(harfbuzz_font, buffer, NULL, 0); | 1167 hb_shape(harfbuzz_font, buffer, NULL, 0); |
1165 | 1168 |
1166 // Populate the run fields with the resulting glyph data in the buffer. | 1169 // Populate the run fields with the resulting glyph data in the buffer. |
1167 unsigned int glyph_count = 0; | 1170 unsigned int glyph_count = 0; |
1168 hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count); | 1171 hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count); |
1169 run->glyph_count = glyph_count; | 1172 run->glyph_count = glyph_count; |
1170 hb_glyph_position_t* hb_positions = | 1173 hb_glyph_position_t* hb_positions = |
1171 hb_buffer_get_glyph_positions(buffer, NULL); | 1174 hb_buffer_get_glyph_positions(buffer, NULL); |
1172 run->glyphs.reset(new uint16[run->glyph_count]); | 1175 run->glyphs.reset(new uint16[run->glyph_count]); |
1173 run->glyph_to_char.resize(run->glyph_count); | 1176 run->glyph_to_char.resize(run->glyph_count); |
1174 run->positions.reset(new SkPoint[run->glyph_count]); | 1177 run->positions.reset(new SkPoint[run->glyph_count]); |
1175 run->width = 0.0f; | 1178 run->width = 0.0f; |
1176 for (size_t i = 0; i < run->glyph_count; ++i) { | 1179 for (size_t i = 0; i < run->glyph_count; ++i) { |
1177 run->glyphs[i] = infos[i].codepoint; | 1180 run->glyphs[i] = static_cast<uint16>(infos[i].codepoint); |
msw
2014/10/17 22:13:23
ditto nit q: DCHECK against uint32_t -> uint16_t o
Peter Kasting
2014/10/21 01:20:45
Added a DCHECK. Used numeric_limits::max here for
| |
1178 run->glyph_to_char[i] = infos[i].cluster; | 1181 run->glyph_to_char[i] = infos[i].cluster; |
1179 const int x_offset = SkFixedToScalar(hb_positions[i].x_offset); | 1182 const int x_offset = |
1180 const int y_offset = SkFixedToScalar(hb_positions[i].y_offset); | 1183 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_offset)); |
msw
2014/10/17 22:13:23
Hmm, this looks like it undoes my <https://coderev
Peter Kasting
2014/10/21 01:20:46
Yeah, this is a remnant of how the code looked bef
| |
1181 run->positions[i].set(run->width + x_offset, -y_offset); | 1184 const int y_offset = |
1182 run->width += SkFixedToScalar(hb_positions[i].x_advance); | 1185 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].y_offset)); |
1186 run->positions[i].iset(run->width + x_offset, -y_offset); | |
1187 run->width += | |
1188 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance)); | |
1183 #if defined(OS_LINUX) | 1189 #if defined(OS_LINUX) |
1184 // Match Pango's glyph rounding logic on Linux. | 1190 // Match Pango's glyph rounding logic on Linux. |
1185 if (!run->render_params.subpixel_positioning) | 1191 if (!run->render_params.subpixel_positioning) |
1186 run->width = std::floor(run->width + 0.5f); | 1192 run->width = std::floor(run->width + 0.5f); |
1187 #endif | 1193 #endif |
1188 } | 1194 } |
1189 | 1195 |
1190 hb_buffer_destroy(buffer); | 1196 hb_buffer_destroy(buffer); |
1191 hb_font_destroy(harfbuzz_font); | 1197 hb_font_destroy(harfbuzz_font); |
1192 return true; | 1198 return true; |
1193 } | 1199 } |
1194 | 1200 |
1195 } // namespace gfx | 1201 } // namespace gfx |
OLD | NEW |