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_win.h" | 5 #include "ui/gfx/render_text_win.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/i18n/break_iterator.h" | 9 #include "base/i18n/break_iterator.h" |
10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 if (base::win::GetVersion() < base::win::VERSION_VISTA) { | 104 if (base::win::GetVersion() < base::win::VERSION_VISTA) { |
105 PlatformFontWin* platform_font = | 105 PlatformFontWin* platform_font = |
106 static_cast<PlatformFontWin*>(font->platform_font()); | 106 static_cast<PlatformFontWin*>(font->platform_font()); |
107 *font = platform_font->DeriveFontWithHeight(font_height, target_style); | 107 *font = platform_font->DeriveFontWithHeight(font_height, target_style); |
108 return; | 108 return; |
109 } | 109 } |
110 | 110 |
111 const int current_style = (font->GetStyle() & kStyleMask); | 111 const int current_style = (font->GetStyle() & kStyleMask); |
112 const int current_size = font->GetFontSize(); | 112 const int current_size = font->GetFontSize(); |
113 if (current_style != target_style || current_size != font_size) | 113 if (current_style != target_style || current_size != font_size) |
114 *font = font->DeriveFont(font_size - current_size, font_style); | 114 *font = font->DeriveFont(font_size - current_size, target_style); |
115 } | 115 } |
116 | 116 |
117 // Returns true if |c| is a Unicode BiDi control character. | 117 // Returns true if |c| is a Unicode BiDi control character. |
118 bool IsUnicodeBidiControlCharacter(char16 c) { | 118 bool IsUnicodeBidiControlCharacter(char16 c) { |
119 return c == base::i18n::kRightToLeftMark || | 119 return c == base::i18n::kRightToLeftMark || |
120 c == base::i18n::kLeftToRightMark || | 120 c == base::i18n::kLeftToRightMark || |
121 c == base::i18n::kLeftToRightEmbeddingMark || | 121 c == base::i18n::kLeftToRightEmbeddingMark || |
122 c == base::i18n::kRightToLeftEmbeddingMark || | 122 c == base::i18n::kRightToLeftEmbeddingMark || |
123 c == base::i18n::kPopDirectionalFormatting || | 123 c == base::i18n::kPopDirectionalFormatting || |
124 c == base::i18n::kLeftToRightOverride || | 124 c == base::i18n::kLeftToRightOverride || |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 pos = iter.pos() - iter.GetString().length(); | 327 pos = iter.pos() - iter.GetString().length(); |
328 } | 328 } |
329 } | 329 } |
330 } | 330 } |
331 } | 331 } |
332 return SelectionModel(pos, CURSOR_FORWARD); | 332 return SelectionModel(pos, CURSOR_FORWARD); |
333 } | 333 } |
334 | 334 |
335 void RenderTextWin::SetSelectionModel(const SelectionModel& model) { | 335 void RenderTextWin::SetSelectionModel(const SelectionModel& model) { |
336 RenderText::SetSelectionModel(model); | 336 RenderText::SetSelectionModel(model); |
337 // TODO(xji): The styles are applied to text inside ItemizeLogicalText(). So, | 337 // TODO(xji|msw): The text selection color is applied in ItemizeLogicalText(). |
338 // we need to update layout here in order for the styles, such as selection | 338 // So, the layout must be updated in order to draw the proper selection range. |
339 // foreground, to be picked up. Eventually, we should separate styles from | 339 // Colors should be applied in DrawVisualText(), as done by RenderTextLinux. |
340 // layout by applying foreground, strike, and underline styles during | |
341 // DrawVisualText as what RenderTextLinux does. | |
342 ResetLayout(); | 340 ResetLayout(); |
343 } | 341 } |
344 | 342 |
345 void RenderTextWin::GetGlyphBounds(size_t index, | 343 void RenderTextWin::GetGlyphBounds(size_t index, |
346 ui::Range* xspan, | 344 ui::Range* xspan, |
347 int* height) { | 345 int* height) { |
348 const size_t run_index = | 346 const size_t run_index = |
349 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); | 347 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); |
350 DCHECK_LT(run_index, runs_.size()); | 348 DCHECK_LT(run_index, runs_.size()); |
351 internal::TextRun* run = runs_[run_index]; | 349 internal::TextRun* run = runs_[run_index]; |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 for (int glyph = 0; glyph < run->glyph_count; glyph++) { | 478 for (int glyph = 0; glyph < run->glyph_count; glyph++) { |
481 pos[glyph].set(glyph_x + run->offsets[glyph].du, | 479 pos[glyph].set(glyph_x + run->offsets[glyph].du, |
482 y + run->offsets[glyph].dv); | 480 y + run->offsets[glyph].dv); |
483 glyph_x += SkIntToScalar(run->advance_widths[glyph]); | 481 glyph_x += SkIntToScalar(run->advance_widths[glyph]); |
484 } | 482 } |
485 | 483 |
486 renderer.SetTextSize(run->font.GetFontSize()); | 484 renderer.SetTextSize(run->font.GetFontSize()); |
487 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style); | 485 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style); |
488 renderer.SetForegroundColor(run->foreground); | 486 renderer.SetForegroundColor(run->foreground); |
489 renderer.DrawPosText(&pos[0], run->glyphs.get(), run->glyph_count); | 487 renderer.DrawPosText(&pos[0], run->glyphs.get(), run->glyph_count); |
490 // TODO(oshima|msw): Consider refactoring StyleRange into Style | 488 renderer.DrawDecorations(x, y, run->width, run->underline, run->strike, |
491 // class and StyleRange containing Style, and use Style class in | 489 run->diagonal_strike); |
492 // TextRun class. This may conflict with msw's comment in | |
493 // TextRun, so please consult with msw when refactoring. | |
494 StyleRange style; | |
495 style.strike = run->strike; | |
496 style.diagonal_strike = run->diagonal_strike; | |
497 style.underline = run->underline; | |
498 renderer.DrawDecorations(x, y, run->width, style); | |
499 | 490 |
500 x = glyph_x; | 491 x = glyph_x; |
501 } | 492 } |
502 } | 493 } |
503 | 494 |
504 void RenderTextWin::ItemizeLogicalText() { | 495 void RenderTextWin::ItemizeLogicalText() { |
505 runs_.clear(); | 496 runs_.clear(); |
506 string_size_ = Size(0, GetFont().GetHeight()); | 497 string_size_ = Size(0, GetFont().GetHeight()); |
507 common_baseline_ = 0; | 498 common_baseline_ = 0; |
508 | 499 |
509 // Set Uniscribe's base text direction. | 500 // Set Uniscribe's base text direction. |
510 script_state_.uBidiLevel = | 501 script_state_.uBidiLevel = |
511 (GetTextDirection() == base::i18n::RIGHT_TO_LEFT) ? 1 : 0; | 502 (GetTextDirection() == base::i18n::RIGHT_TO_LEFT) ? 1 : 0; |
512 | 503 |
513 if (text().empty()) | 504 if (text().empty()) |
514 return; | 505 return; |
515 | 506 |
516 HRESULT hr = E_OUTOFMEMORY; | 507 HRESULT hr = E_OUTOFMEMORY; |
517 int script_items_count = 0; | 508 int script_items_count = 0; |
518 std::vector<SCRIPT_ITEM> script_items; | 509 std::vector<SCRIPT_ITEM> script_items; |
519 const int text_length = GetLayoutText().length(); | 510 const size_t text_length = GetLayoutText().length(); |
520 for (size_t n = kGuessItems; hr == E_OUTOFMEMORY && n < kMaxItems; n *= 2) { | 511 for (size_t n = kGuessItems; hr == E_OUTOFMEMORY && n < kMaxItems; n *= 2) { |
521 // Derive the array of Uniscribe script items from the logical text. | 512 // Derive the array of Uniscribe script items from the logical text. |
522 // ScriptItemize always adds a terminal array item so that the length of the | 513 // ScriptItemize always adds a terminal array item so that the length of the |
523 // last item can be derived from the terminal SCRIPT_ITEM::iCharPos. | 514 // last item can be derived from the terminal SCRIPT_ITEM::iCharPos. |
524 script_items.resize(n); | 515 script_items.resize(n); |
525 hr = ScriptItemize(GetLayoutText().c_str(), | 516 hr = ScriptItemize(GetLayoutText().c_str(), |
526 text_length, | 517 text_length, |
527 n - 1, | 518 n - 1, |
528 &script_control_, | 519 &script_control_, |
529 &script_state_, | 520 &script_state_, |
530 &script_items[0], | 521 &script_items[0], |
531 &script_items_count); | 522 &script_items_count); |
532 } | 523 } |
533 DCHECK(SUCCEEDED(hr)); | 524 DCHECK(SUCCEEDED(hr)); |
534 | 525 |
535 if (script_items_count <= 0) | 526 if (script_items_count <= 0) |
536 return; | 527 return; |
537 | 528 |
538 // Build the list of runs, merge font/underline styles. | 529 // Temporarily apply composition underlines and selection colors. |
539 // TODO(msw): Only break for font changes, not color etc. See TextRun comment. | 530 ApplyCompositionAndSelectionStyles(); |
540 StyleRanges styles(style_ranges()); | 531 |
541 ApplyCompositionAndSelectionStyles(&styles); | 532 // Build the list of runs from the script items and ranged colors/styles. |
542 StyleRanges::const_iterator style = styles.begin(); | 533 // TODO(msw): Only break for bold/italic, not color etc. See TextRun comment. |
| 534 internal::StyleIterator style(colors(), styles()); |
543 SCRIPT_ITEM* script_item = &script_items[0]; | 535 SCRIPT_ITEM* script_item = &script_items[0]; |
544 for (int run_break = 0; run_break < text_length;) { | 536 const size_t layout_text_length = GetLayoutText().length(); |
| 537 for (size_t run_break = 0; run_break < layout_text_length;) { |
545 internal::TextRun* run = new internal::TextRun(); | 538 internal::TextRun* run = new internal::TextRun(); |
546 run->range.set_start(run_break); | 539 run->range.set_start(run_break); |
547 run->font = GetFont(); | 540 run->font = GetFont(); |
548 run->font_style = style->font_style; | 541 run->font_style = (style.style(BOLD) ? Font::BOLD : 0) | |
| 542 (style.style(ITALIC) ? Font::ITALIC : 0); |
549 DeriveFontIfNecessary(run->font.GetFontSize(), run->font.GetHeight(), | 543 DeriveFontIfNecessary(run->font.GetFontSize(), run->font.GetHeight(), |
550 run->font_style, &run->font); | 544 run->font_style, &run->font); |
551 run->foreground = style->foreground; | 545 run->foreground = style.color(); |
552 run->strike = style->strike; | 546 run->strike = style.style(STRIKE); |
553 run->diagonal_strike = style->diagonal_strike; | 547 run->diagonal_strike = style.style(DIAGONAL_STRIKE); |
554 run->underline = style->underline; | 548 run->underline = style.style(UNDERLINE); |
555 run->script_analysis = script_item->a; | 549 run->script_analysis = script_item->a; |
556 | 550 |
557 // Find the range end and advance the structures as needed. | 551 // Find the next break and advance the iterators as needed. |
558 const int script_item_end = (script_item + 1)->iCharPos; | 552 const size_t script_item_break = (script_item + 1)->iCharPos; |
559 const int style_range_end = TextIndexToLayoutIndex(style->range.end()); | 553 run_break = std::min(script_item_break, |
560 run_break = std::min(script_item_end, style_range_end); | 554 TextIndexToLayoutIndex(style.GetRange().end())); |
561 if (script_item_end <= style_range_end) | 555 style.UpdatePosition(LayoutIndexToTextIndex(run_break)); |
| 556 if (script_item_break == run_break) |
562 script_item++; | 557 script_item++; |
563 if (script_item_end >= style_range_end) | |
564 style++; | |
565 run->range.set_end(run_break); | 558 run->range.set_end(run_break); |
566 runs_.push_back(run); | 559 runs_.push_back(run); |
567 } | 560 } |
| 561 |
| 562 // Undo the temporarily applied composition underlines and selection colors. |
| 563 UndoCompositionAndSelectionStyles(); |
568 } | 564 } |
569 | 565 |
570 void RenderTextWin::LayoutVisualText() { | 566 void RenderTextWin::LayoutVisualText() { |
571 DCHECK(!runs_.empty()); | 567 DCHECK(!runs_.empty()); |
572 | 568 |
573 if (!cached_hdc_) | 569 if (!cached_hdc_) |
574 cached_hdc_ = CreateCompatibleDC(NULL); | 570 cached_hdc_ = CreateCompatibleDC(NULL); |
575 | 571 |
576 HRESULT hr = E_FAIL; | 572 HRESULT hr = E_FAIL; |
577 string_size_.set_height(0); | 573 string_size_.set_height(0); |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
844 size_t position = LayoutIndexToTextIndex(run->range.end()); | 840 size_t position = LayoutIndexToTextIndex(run->range.end()); |
845 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); | 841 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); |
846 return SelectionModel(position, CURSOR_FORWARD); | 842 return SelectionModel(position, CURSOR_FORWARD); |
847 } | 843 } |
848 | 844 |
849 RenderText* RenderText::CreateInstance() { | 845 RenderText* RenderText::CreateInstance() { |
850 return new RenderTextWin; | 846 return new RenderTextWin; |
851 } | 847 } |
852 | 848 |
853 } // namespace gfx | 849 } // namespace gfx |
OLD | NEW |