 Chromium Code Reviews
 Chromium Code Reviews Issue 924543004:
  adding baseline options for super/sub scripting  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 924543004:
  adding baseline options for super/sub scripting  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| OLD | NEW | 
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 | 
| OLD | NEW |