Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(819)

Side by Side Diff: ui/gfx/render_text.cc

Issue 924543004: adding baseline options for super/sub scripting (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: changed to ToRoundedInt Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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.h" 5 #include "ui/gfx/render_text.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <climits> 8 #include <climits>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 FontRenderParams::Hinting params_hinting) { 167 FontRenderParams::Hinting params_hinting) {
168 switch (params_hinting) { 168 switch (params_hinting) {
169 case FontRenderParams::HINTING_NONE: return SkPaint::kNo_Hinting; 169 case FontRenderParams::HINTING_NONE: return SkPaint::kNo_Hinting;
170 case FontRenderParams::HINTING_SLIGHT: return SkPaint::kSlight_Hinting; 170 case FontRenderParams::HINTING_SLIGHT: return SkPaint::kSlight_Hinting;
171 case FontRenderParams::HINTING_MEDIUM: return SkPaint::kNormal_Hinting; 171 case FontRenderParams::HINTING_MEDIUM: return SkPaint::kNormal_Hinting;
172 case FontRenderParams::HINTING_FULL: return SkPaint::kFull_Hinting; 172 case FontRenderParams::HINTING_FULL: return SkPaint::kFull_Hinting;
173 } 173 }
174 return SkPaint::kNo_Hinting; 174 return SkPaint::kNo_Hinting;
175 } 175 }
176 176
177 // Make sure ranges don't break text graphemes. If a range in |break_list|
178 // does break a grapheme in |render_text|, the range will be slightly
179 // extended to encompass the grapheme.
180 template <typename T>
181 void RestoreBreakList(RenderText* render_text, BreakList<T>& break_list) {
182 break_list.SetMax(render_text->text().length());
183 Range range;
184 while (range.end() < break_list.max()) {
185 const auto& current_break = break_list.GetBreak(range.end());
186 range = break_list.GetRange(current_break);
187 if (range.end() < break_list.max() &&
188 !render_text->IsValidCursorIndex(range.end())) {
189 range.set_end(
190 render_text->IndexOfAdjacentGrapheme(range.end(), CURSOR_FORWARD));
191 break_list.ApplyValue(current_break->second, range);
192 }
193 }
194 }
195
177 } // namespace 196 } // namespace
178 197
179 namespace internal { 198 namespace internal {
180 199
181 // Value of |underline_thickness_| that indicates that underline metrics have 200 // Value of |underline_thickness_| that indicates that underline metrics have
182 // not been set explicitly. 201 // not been set explicitly.
183 const SkScalar kUnderlineMetricsNotSet = -1.0f; 202 const SkScalar kUnderlineMetricsNotSet = -1.0f;
184 203
185 SkiaTextRenderer::SkiaTextRenderer(Canvas* canvas) 204 SkiaTextRenderer::SkiaTextRenderer(Canvas* canvas)
186 : canvas_(canvas), 205 : canvas_(canvas),
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 canvas_->DrawLine(start_, end, paint_); 361 canvas_->DrawLine(start_, end, paint_);
343 362
344 if (clipped) 363 if (clipped)
345 canvas_->Restore(); 364 canvas_->Restore();
346 365
347 x += pieces_[i].first; 366 x += pieces_[i].first;
348 } 367 }
349 } 368 }
350 369
351 StyleIterator::StyleIterator(const BreakList<SkColor>& colors, 370 StyleIterator::StyleIterator(const BreakList<SkColor>& colors,
352 const std::vector<BreakList<bool> >& styles) 371 const BreakList<BaselineStyle>& baselines,
353 : colors_(colors), 372 const std::vector<BreakList<bool>>& styles)
354 styles_(styles) { 373 : colors_(colors), baselines_(baselines), styles_(styles) {
355 color_ = colors_.breaks().begin(); 374 color_ = colors_.breaks().begin();
375 baseline_ = baselines_.breaks().begin();
356 for (size_t i = 0; i < styles_.size(); ++i) 376 for (size_t i = 0; i < styles_.size(); ++i)
357 style_.push_back(styles_[i].breaks().begin()); 377 style_.push_back(styles_[i].breaks().begin());
358 } 378 }
359 379
360 StyleIterator::~StyleIterator() {} 380 StyleIterator::~StyleIterator() {}
361 381
362 Range StyleIterator::GetRange() const { 382 Range StyleIterator::GetRange() const {
363 Range range(colors_.GetRange(color_)); 383 Range range(colors_.GetRange(color_));
384 range = range.Intersect(baselines_.GetRange(baseline_));
364 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) 385 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i)
365 range = range.Intersect(styles_[i].GetRange(style_[i])); 386 range = range.Intersect(styles_[i].GetRange(style_[i]));
366 return range; 387 return range;
367 } 388 }
368 389
369 void StyleIterator::UpdatePosition(size_t position) { 390 void StyleIterator::UpdatePosition(size_t position) {
370 color_ = colors_.GetBreak(position); 391 color_ = colors_.GetBreak(position);
392 baseline_ = baselines_.GetBreak(position);
371 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) 393 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i)
372 style_[i] = styles_[i].GetBreak(position); 394 style_[i] = styles_[i].GetBreak(position);
373 } 395 }
374 396
375 LineSegment::LineSegment() : width(0), run(0) {} 397 LineSegment::LineSegment() : width(0), run(0) {}
376 398
377 LineSegment::~LineSegment() {} 399 LineSegment::~LineSegment() {}
378 400
379 Line::Line() : preceding_heights(0), baseline(0) {} 401 Line::Line() : preceding_heights(0), baseline(0) {}
380 402
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 RenderText* RenderText::CreateInstanceForEditing() { 438 RenderText* RenderText::CreateInstanceForEditing() {
417 return new RenderTextHarfBuzz; 439 return new RenderTextHarfBuzz;
418 } 440 }
419 441
420 void RenderText::SetText(const base::string16& text) { 442 void RenderText::SetText(const base::string16& text) {
421 DCHECK(!composition_range_.IsValid()); 443 DCHECK(!composition_range_.IsValid());
422 if (text_ == text) 444 if (text_ == text)
423 return; 445 return;
424 text_ = text; 446 text_ = text;
425 447
426 // Adjust ranged styles and colors to accommodate a new text length. 448 // Adjust ranged styles, baselines, and colors to accommodate a new text
427 // Clear style ranges as they might break new text graphemes and apply 449 // length. Clear style ranges as they might break new text graphemes and apply
428 // the first style to the whole text instead. 450 // the first style to the whole text instead.
429 const size_t text_length = text_.length(); 451 const size_t text_length = text_.length();
430 colors_.SetMax(text_length); 452 colors_.SetMax(text_length);
453 baselines_.SetValue(baselines_.breaks().begin()->second);
454 baselines_.SetMax(text_length);
431 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) { 455 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) {
432 BreakList<bool>& break_list = styles_[style]; 456 BreakList<bool>& break_list = styles_[style];
433 break_list.SetValue(break_list.breaks().begin()->second); 457 break_list.SetValue(break_list.breaks().begin()->second);
434 break_list.SetMax(text_length); 458 break_list.SetMax(text_length);
435 } 459 }
436 cached_bounds_and_offset_valid_ = false; 460 cached_bounds_and_offset_valid_ = false;
437 461
438 // Reset selection model. SetText should always followed by SetSelectionModel 462 // Reset selection model. SetText should always followed by SetSelectionModel
439 // or SetCursorPosition in upper layer. 463 // or SetCursorPosition in upper layer.
440 SetSelectionModel(SelectionModel()); 464 SetSelectionModel(SelectionModel());
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
663 } 687 }
664 688
665 void RenderText::SetColor(SkColor value) { 689 void RenderText::SetColor(SkColor value) {
666 colors_.SetValue(value); 690 colors_.SetValue(value);
667 } 691 }
668 692
669 void RenderText::ApplyColor(SkColor value, const Range& range) { 693 void RenderText::ApplyColor(SkColor value, const Range& range) {
670 colors_.ApplyValue(value, range); 694 colors_.ApplyValue(value, range);
671 } 695 }
672 696
697 void RenderText::SetBaselineStyle(BaselineStyle value) {
698 baselines_.SetValue(value);
699 }
700
701 void RenderText::ApplyBaselineStyle(BaselineStyle value, const Range& range) {
702 baselines_.ApplyValue(value, range);
703 }
704
673 void RenderText::SetStyle(TextStyle style, bool value) { 705 void RenderText::SetStyle(TextStyle style, bool value) {
674 styles_[style].SetValue(value); 706 styles_[style].SetValue(value);
675 707
676 cached_bounds_and_offset_valid_ = false; 708 cached_bounds_and_offset_valid_ = false;
677 // TODO(oshima|msw): Not all style change requires layout changes. 709 // TODO(oshima|msw): Not all style change requires layout changes.
678 // Consider optimizing based on the type of change. 710 // Consider optimizing based on the type of change.
679 OnLayoutTextAttributeChanged(false); 711 OnLayoutTextAttributeChanged(false);
680 } 712 }
681 713
682 void RenderText::ApplyStyle(TextStyle style, bool value, const Range& range) { 714 void RenderText::ApplyStyle(TextStyle style, bool value, const Range& range) {
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
903 text_direction_(base::i18n::UNKNOWN_DIRECTION), 935 text_direction_(base::i18n::UNKNOWN_DIRECTION),
904 cursor_enabled_(true), 936 cursor_enabled_(true),
905 cursor_visible_(false), 937 cursor_visible_(false),
906 insert_mode_(true), 938 insert_mode_(true),
907 cursor_color_(kDefaultColor), 939 cursor_color_(kDefaultColor),
908 selection_color_(kDefaultColor), 940 selection_color_(kDefaultColor),
909 selection_background_focused_color_(kDefaultSelectionBackgroundColor), 941 selection_background_focused_color_(kDefaultSelectionBackgroundColor),
910 focused_(false), 942 focused_(false),
911 composition_range_(Range::InvalidRange()), 943 composition_range_(Range::InvalidRange()),
912 colors_(kDefaultColor), 944 colors_(kDefaultColor),
945 baselines_(NORMAL_BASELINE),
913 styles_(NUM_TEXT_STYLES), 946 styles_(NUM_TEXT_STYLES),
914 composition_and_selection_styles_applied_(false), 947 composition_and_selection_styles_applied_(false),
915 obscured_(false), 948 obscured_(false),
916 obscured_reveal_index_(-1), 949 obscured_reveal_index_(-1),
917 truncate_length_(0), 950 truncate_length_(0),
918 elide_behavior_(NO_ELIDE), 951 elide_behavior_(NO_ELIDE),
919 text_elided_(false), 952 text_elided_(false),
920 min_line_height_(0), 953 min_line_height_(0),
921 multiline_(false), 954 multiline_(false),
922 subpixel_rendering_suppressed_(false), 955 subpixel_rendering_suppressed_(false),
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after
1279 1312
1280 TRACE_EVENT0("ui", "RenderText::Elide"); 1313 TRACE_EVENT0("ui", "RenderText::Elide");
1281 1314
1282 // Create a RenderText copy with attributes that affect the rendering width. 1315 // Create a RenderText copy with attributes that affect the rendering width.
1283 scoped_ptr<RenderText> render_text = CreateInstanceOfSameType(); 1316 scoped_ptr<RenderText> render_text = CreateInstanceOfSameType();
1284 render_text->SetFontList(font_list_); 1317 render_text->SetFontList(font_list_);
1285 render_text->SetDirectionalityMode(directionality_mode_); 1318 render_text->SetDirectionalityMode(directionality_mode_);
1286 render_text->SetCursorEnabled(cursor_enabled_); 1319 render_text->SetCursorEnabled(cursor_enabled_);
1287 render_text->set_truncate_length(truncate_length_); 1320 render_text->set_truncate_length(truncate_length_);
1288 render_text->styles_ = styles_; 1321 render_text->styles_ = styles_;
1322 render_text->baselines_ = baselines_;
1289 render_text->colors_ = colors_; 1323 render_text->colors_ = colors_;
1290 if (text_width == 0) { 1324 if (text_width == 0) {
1291 render_text->SetText(text); 1325 render_text->SetText(text);
1292 text_width = render_text->GetContentWidthF(); 1326 text_width = render_text->GetContentWidthF();
1293 } 1327 }
1294 if (text_width <= available_width) 1328 if (text_width <= available_width)
1295 return text; 1329 return text;
1296 1330
1297 const base::string16 ellipsis = base::string16(kEllipsisUTF16); 1331 const base::string16 ellipsis = base::string16(kEllipsisUTF16);
1298 const bool insert_ellipsis = (behavior != TRUNCATE); 1332 const bool insert_ellipsis = (behavior != TRUNCATE);
1299 const bool elide_in_middle = (behavior == ELIDE_MIDDLE); 1333 const bool elide_in_middle = (behavior == ELIDE_MIDDLE);
1300 const bool elide_at_beginning = (behavior == ELIDE_HEAD); 1334 const bool elide_at_beginning = (behavior == ELIDE_HEAD);
1301 1335
1302 if (insert_ellipsis) { 1336 if (insert_ellipsis) {
1303 render_text->SetText(ellipsis); 1337 render_text->SetText(ellipsis);
1304 const float ellipsis_width = render_text->GetContentWidthF(); 1338 const float ellipsis_width = render_text->GetContentWidthF();
1305 if (ellipsis_width > available_width) 1339 if (ellipsis_width > available_width)
1306 return base::string16(); 1340 return base::string16();
1307 } 1341 }
1308 1342
1309 StringSlicer slicer(text, ellipsis, elide_in_middle, elide_at_beginning); 1343 StringSlicer slicer(text, ellipsis, elide_in_middle, elide_at_beginning);
1310 1344
1311 // Use binary search to compute the elided text. 1345 // Use binary search to compute the elided text.
1312 size_t lo = 0; 1346 size_t lo = 0;
1313 size_t hi = text.length() - 1; 1347 size_t hi = text.length() - 1;
1314 const base::i18n::TextDirection text_direction = GetTextDirection(text); 1348 const base::i18n::TextDirection text_direction = GetTextDirection(text);
1315 for (size_t guess = (lo + hi) / 2; lo <= hi; guess = (lo + hi) / 2) { 1349 for (size_t guess = (lo + hi) / 2; lo <= hi; guess = (lo + hi) / 2) {
1316 // Restore colors. They will be truncated to size by SetText. 1350 // Restore colors. They will be truncated to size by SetText.
1317 render_text->colors_ = colors_; 1351 render_text->colors_ = colors_;
1352 render_text->baselines_ = baselines_;
msw 2015/02/25 16:02:33 I think you can remove this with the call to Resto
dschuyler 2015/02/26 02:11:02 Done.
1318 base::string16 new_text = 1353 base::string16 new_text =
1319 slicer.CutString(guess, insert_ellipsis && behavior != ELIDE_TAIL); 1354 slicer.CutString(guess, insert_ellipsis && behavior != ELIDE_TAIL);
1320 render_text->SetText(new_text); 1355 render_text->SetText(new_text);
1321 1356
1322 // This has to be an additional step so that the ellipsis is rendered with 1357 // This has to be an additional step so that the ellipsis is rendered with
1323 // same style as trailing part of the text. 1358 // same style as trailing part of the text.
1324 if (insert_ellipsis && behavior == ELIDE_TAIL) { 1359 if (insert_ellipsis && behavior == ELIDE_TAIL) {
1325 // When ellipsis follows text whose directionality is not the same as that 1360 // When ellipsis follows text whose directionality is not the same as that
1326 // of the whole text, it will be rendered with the directionality of the 1361 // of the whole text, it will be rendered with the directionality of the
1327 // whole text. Since we want ellipsis to indicate continuation of the 1362 // whole text. Since we want ellipsis to indicate continuation of the
1328 // preceding text, we force the directionality of ellipsis to be same as 1363 // preceding text, we force the directionality of ellipsis to be same as
1329 // the preceding text using LTR or RTL markers. 1364 // the preceding text using LTR or RTL markers.
1330 base::i18n::TextDirection trailing_text_direction = 1365 base::i18n::TextDirection trailing_text_direction =
1331 base::i18n::GetLastStrongCharacterDirection(new_text); 1366 base::i18n::GetLastStrongCharacterDirection(new_text);
1332 new_text.append(ellipsis); 1367 new_text.append(ellipsis);
1333 if (trailing_text_direction != text_direction) { 1368 if (trailing_text_direction != text_direction) {
1334 if (trailing_text_direction == base::i18n::LEFT_TO_RIGHT) 1369 if (trailing_text_direction == base::i18n::LEFT_TO_RIGHT)
1335 new_text += base::i18n::kLeftToRightMark; 1370 new_text += base::i18n::kLeftToRightMark;
1336 else 1371 else
1337 new_text += base::i18n::kRightToLeftMark; 1372 new_text += base::i18n::kRightToLeftMark;
1338 } 1373 }
1339 render_text->SetText(new_text); 1374 render_text->SetText(new_text);
1340 } 1375 }
1341 1376
1342 // Restore styles. Make sure style ranges don't break new text graphemes. 1377 // Restore styles and baselines without breaking multi-character graphemes.
1343 render_text->styles_ = styles_; 1378 render_text->styles_ = styles_;
1344 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) { 1379 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
1345 BreakList<bool>& break_list = render_text->styles_[style]; 1380 RestoreBreakList(render_text.get(), render_text->styles_[style]);
1346 break_list.SetMax(render_text->text_.length()); 1381 RestoreBreakList(render_text.get(), baselines_);
1347 Range range;
1348 while (range.end() < break_list.max()) {
1349 BreakList<bool>::const_iterator current_break =
1350 break_list.GetBreak(range.end());
1351 range = break_list.GetRange(current_break);
1352 if (range.end() < break_list.max() &&
1353 !render_text->IsValidCursorIndex(range.end())) {
1354 range.set_end(render_text->IndexOfAdjacentGrapheme(range.end(),
1355 CURSOR_FORWARD));
1356 break_list.ApplyValue(current_break->second, range);
1357 }
1358 }
1359 }
1360 1382
1361 // We check the width of the whole desired string at once to ensure we 1383 // We check the width of the whole desired string at once to ensure we
1362 // handle kerning/ligatures/etc. correctly. 1384 // handle kerning/ligatures/etc. correctly.
1363 const float guess_width = render_text->GetContentWidthF(); 1385 const float guess_width = render_text->GetContentWidthF();
1364 if (guess_width == available_width) 1386 if (guess_width == available_width)
1365 break; 1387 break;
1366 if (guess_width > available_width) { 1388 if (guess_width > available_width) {
1367 hi = guess - 1; 1389 hi = guess - 1;
1368 // Move back on the loop terminating condition when the guess is too wide. 1390 // Move back on the loop terminating condition when the guess is too wide.
1369 if (hi < lo) 1391 if (hi < lo)
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
1456 1478
1457 SetDisplayOffset(display_offset_.x() + delta_x); 1479 SetDisplayOffset(display_offset_.x() + delta_x);
1458 } 1480 }
1459 1481
1460 void RenderText::DrawSelection(Canvas* canvas) { 1482 void RenderText::DrawSelection(Canvas* canvas) {
1461 for (const Rect& s : GetSubstringBounds(selection())) 1483 for (const Rect& s : GetSubstringBounds(selection()))
1462 canvas->FillRect(s, selection_background_focused_color_); 1484 canvas->FillRect(s, selection_background_focused_color_);
1463 } 1485 }
1464 1486
1465 } // namespace gfx 1487 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698