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 // Track the current color and style with iterators. |
542 StyleRanges::const_iterator style = styles.begin(); | 533 BreakList<SkColor>::const_iterator color = colors().list().begin(); |
534 BreakList<bool>::const_iterator style[NUM_TEXT_STYLES]; | |
535 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) | |
536 style[i] = styles(static_cast<TextStyle>(i)).list().begin(); | |
537 | |
538 // Build the list of runs from the script items and ranged colors/styles. | |
539 // TODO(msw): Only break for bold/italic, not color etc. See TextRun comment. | |
543 SCRIPT_ITEM* script_item = &script_items[0]; | 540 SCRIPT_ITEM* script_item = &script_items[0]; |
544 for (int run_break = 0; run_break < text_length;) { | 541 for (size_t run_break = 0; run_break < text_length;) { |
545 internal::TextRun* run = new internal::TextRun(); | 542 internal::TextRun* run = new internal::TextRun(); |
546 run->range.set_start(run_break); | 543 run->range.set_start(run_break); |
547 run->font = GetFont(); | 544 run->font = GetFont(); |
548 run->font_style = style->font_style; | 545 run->font_style = (style[BOLD]->second ? Font::BOLD : 0) | |
546 (style[ITALIC]->second ? Font::ITALIC : 0); | |
549 DeriveFontIfNecessary(run->font.GetFontSize(), run->font.GetHeight(), | 547 DeriveFontIfNecessary(run->font.GetFontSize(), run->font.GetHeight(), |
550 run->font_style, &run->font); | 548 run->font_style, &run->font); |
551 run->foreground = style->foreground; | 549 run->foreground = color->second; |
552 run->strike = style->strike; | 550 run->strike = style[STRIKE]->second; |
553 run->diagonal_strike = style->diagonal_strike; | 551 run->diagonal_strike = style[DIAGONAL_STRIKE]->second; |
554 run->underline = style->underline; | 552 run->underline = style[UNDERLINE]->second; |
555 run->script_analysis = script_item->a; | 553 run->script_analysis = script_item->a; |
556 | 554 |
557 // Find the range end and advance the structures as needed. | 555 // Find the next break and advance the iterators as needed. |
558 const int script_item_end = (script_item + 1)->iCharPos; | 556 const size_t script_item_break = (script_item + 1)->iCharPos; |
559 const int style_range_end = TextIndexToLayoutIndex(style->range.end()); | 557 run_break = std::min(script_item_break, GetNextBreak(color, style)); |
560 run_break = std::min(script_item_end, style_range_end); | 558 AdvanceIterators(run_break, &color, style); |
561 if (script_item_end <= style_range_end) | 559 script_item += script_item_break == run_break ? 1 : 0; |
Alexei Svitkine (slow)
2013/01/28 20:52:30
Nit: I'm not sure I like this style that you use t
msw
2013/01/29 17:17:25
Done here. I prefer my style, but I'll oblige for
| |
562 script_item++; | |
563 if (script_item_end >= style_range_end) | |
564 style++; | |
565 run->range.set_end(run_break); | 560 run->range.set_end(run_break); |
566 runs_.push_back(run); | 561 runs_.push_back(run); |
567 } | 562 } |
563 | |
564 // Undo the temporarily applied composition underlines and selection colors. | |
565 UndoCompositionAndSelectionStyles(); | |
568 } | 566 } |
569 | 567 |
570 void RenderTextWin::LayoutVisualText() { | 568 void RenderTextWin::LayoutVisualText() { |
571 DCHECK(!runs_.empty()); | 569 DCHECK(!runs_.empty()); |
572 | 570 |
573 if (!cached_hdc_) | 571 if (!cached_hdc_) |
574 cached_hdc_ = CreateCompatibleDC(NULL); | 572 cached_hdc_ = CreateCompatibleDC(NULL); |
575 | 573 |
576 HRESULT hr = E_FAIL; | 574 HRESULT hr = E_FAIL; |
577 string_size_.set_height(0); | 575 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()); | 842 size_t position = LayoutIndexToTextIndex(run->range.end()); |
845 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); | 843 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); |
846 return SelectionModel(position, CURSOR_FORWARD); | 844 return SelectionModel(position, CURSOR_FORWARD); |
847 } | 845 } |
848 | 846 |
849 RenderText* RenderText::CreateInstance() { | 847 RenderText* RenderText::CreateInstance() { |
850 return new RenderTextWin; | 848 return new RenderTextWin; |
851 } | 849 } |
852 | 850 |
853 } // namespace gfx | 851 } // namespace gfx |
OLD | NEW |