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

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

Issue 8633019: Itemize and layout text lazily in RenderTextWin. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « ui/gfx/render_text_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/logging.h" 9 #include "base/logging.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 TextRun::~TextRun() { 138 TextRun::~TextRun() {
139 ScriptFreeCache(&script_cache); 139 ScriptFreeCache(&script_cache);
140 } 140 }
141 141
142 } // namespace internal 142 } // namespace internal
143 143
144 RenderTextWin::RenderTextWin() 144 RenderTextWin::RenderTextWin()
145 : RenderText(), 145 : RenderText(),
146 script_control_(), 146 script_control_(),
147 script_state_(), 147 script_state_(),
148 string_width_(0) { 148 string_width_(0) {
msw 2011/11/28 21:15:46 Init needs_layout_
Alexei Svitkine (slow) 2011/11/28 21:58:13 Embarrassing! Done.
149 // Omitting default constructors for script_* would leave POD uninitialized. 149 // Omitting default constructors for script_* would leave POD uninitialized.
150 HRESULT hr = 0; 150 HRESULT hr = 0;
151 151
152 // TODO(msw): Call ScriptRecordDigitSubstitution on WM_SETTINGCHANGE message. 152 // TODO(msw): Call ScriptRecordDigitSubstitution on WM_SETTINGCHANGE message.
153 // TODO(msw): Use Chrome/profile locale/language settings? 153 // TODO(msw): Use Chrome/profile locale/language settings?
154 hr = ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &digit_substitute_); 154 hr = ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &digit_substitute_);
155 DCHECK(SUCCEEDED(hr)); 155 DCHECK(SUCCEEDED(hr));
156 156
157 hr = ScriptApplyDigitSubstitution(&digit_substitute_, 157 hr = ScriptApplyDigitSubstitution(&digit_substitute_,
158 &script_control_, 158 &script_control_,
159 &script_state_); 159 &script_state_);
160 DCHECK(SUCCEEDED(hr)); 160 DCHECK(SUCCEEDED(hr));
161 script_control_.fMergeNeutralItems = true; 161 script_control_.fMergeNeutralItems = true;
162 162
163 MoveCursorTo(LeftEndSelectionModel()); 163 MoveCursorTo(LeftEndSelectionModel());
164 } 164 }
165 165
166 RenderTextWin::~RenderTextWin() { 166 RenderTextWin::~RenderTextWin() {
167 STLDeleteContainerPointers(runs_.begin(), runs_.end()); 167 STLDeleteContainerPointers(runs_.begin(), runs_.end());
168 } 168 }
169 169
170 int RenderTextWin::GetStringWidth() { 170 int RenderTextWin::GetStringWidth() {
171 EnsureLayout();
171 return string_width_; 172 return string_width_;
172 } 173 }
173 174
174 void RenderTextWin::Draw(Canvas* canvas) { 175 void RenderTextWin::Draw(Canvas* canvas) {
176 EnsureLayout();
175 DrawSelection(canvas); 177 DrawSelection(canvas);
176 DrawVisualText(canvas); 178 DrawVisualText(canvas);
177 DrawCursor(canvas); 179 DrawCursor(canvas);
178 } 180 }
179 181
180 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { 182 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
181 if (text().empty()) 183 if (text().empty())
182 return SelectionModel(); 184 return SelectionModel();
183 185
186 EnsureLayout();
184 // Find the run that contains the point and adjust the argument location. 187 // Find the run that contains the point and adjust the argument location.
185 Point p(ToTextPoint(point)); 188 Point p(ToTextPoint(point));
186 size_t run_index = GetRunContainingPoint(p); 189 size_t run_index = GetRunContainingPoint(p);
187 if (run_index == runs_.size()) 190 if (run_index == runs_.size())
188 return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel(); 191 return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel();
189 internal::TextRun* run = runs_[run_index]; 192 internal::TextRun* run = runs_[run_index];
190 193
191 int position = 0, trailing = 0; 194 int position = 0, trailing = 0;
192 HRESULT hr = ScriptXtoCP(p.x() - run->preceding_run_widths, 195 HRESULT hr = ScriptXtoCP(p.x() - run->preceding_run_widths,
193 run->range.length(), 196 run->range.length(),
194 run->glyph_count, 197 run->glyph_count,
195 run->logical_clusters.get(), 198 run->logical_clusters.get(),
196 run->visible_attributes.get(), 199 run->visible_attributes.get(),
197 run->advance_widths.get(), 200 run->advance_widths.get(),
198 &(run->script_analysis), 201 &(run->script_analysis),
199 &position, 202 &position,
200 &trailing); 203 &trailing);
201 DCHECK(SUCCEEDED(hr)); 204 DCHECK(SUCCEEDED(hr));
202 position += run->range.start(); 205 position += run->range.start();
203 206
204 size_t cursor = position + trailing; 207 size_t cursor = position + trailing;
205 DCHECK_GE(cursor, 0U); 208 DCHECK_GE(cursor, 0U);
206 DCHECK_LE(cursor, text().length()); 209 DCHECK_LE(cursor, text().length());
207 return SelectionModel(cursor, position, 210 return SelectionModel(cursor, position,
208 (trailing > 0) ? SelectionModel::TRAILING : SelectionModel::LEADING); 211 (trailing > 0) ? SelectionModel::TRAILING : SelectionModel::LEADING);
209 } 212 }
210 213
211 Rect RenderTextWin::GetCursorBounds(const SelectionModel& selection, 214 Rect RenderTextWin::GetCursorBounds(const SelectionModel& selection,
212 bool insert_mode) { 215 bool insert_mode) {
216 EnsureLayout();
217
213 // Highlight the logical cursor (selection end) when not in insert mode. 218 // Highlight the logical cursor (selection end) when not in insert mode.
214 size_t pos = insert_mode ? selection.caret_pos() : selection.selection_end(); 219 size_t pos = insert_mode ? selection.caret_pos() : selection.selection_end();
215 size_t run_index = GetRunContainingPosition(pos); 220 size_t run_index = GetRunContainingPosition(pos);
216 internal::TextRun* run = run_index == runs_.size() ? NULL : runs_[run_index]; 221 internal::TextRun* run = run_index == runs_.size() ? NULL : runs_[run_index];
217 222
218 int start_x = 0, end_x = 0; 223 int start_x = 0, end_x = 0;
219 if (run) { 224 if (run) {
220 HRESULT hr = 0; 225 HRESULT hr = 0;
221 hr = ScriptCPtoX(pos - run->range.start(), 226 hr = ScriptCPtoX(pos - run->range.start(),
222 false, 227 false,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 rect.set_x(rect.right()); 260 rect.set_x(rect.right());
256 rect.set_width(0); 261 rect.set_width(0);
257 } 262 }
258 rect.set_origin(ToViewPoint(rect.origin())); 263 rect.set_origin(ToViewPoint(rect.origin()));
259 return rect; 264 return rect;
260 } 265 }
261 266
262 SelectionModel RenderTextWin::GetLeftSelectionModel( 267 SelectionModel RenderTextWin::GetLeftSelectionModel(
263 const SelectionModel& selection, 268 const SelectionModel& selection,
264 BreakType break_type) { 269 BreakType break_type) {
270 EnsureLayout();
271
265 if (break_type == LINE_BREAK || text().empty()) 272 if (break_type == LINE_BREAK || text().empty())
266 return LeftEndSelectionModel(); 273 return LeftEndSelectionModel();
267 if (break_type == CHARACTER_BREAK) 274 if (break_type == CHARACTER_BREAK)
268 return LeftSelectionModel(selection); 275 return LeftSelectionModel(selection);
269 // TODO(msw): Implement word breaking. 276 // TODO(msw): Implement word breaking.
270 return RenderText::GetLeftSelectionModel(selection, break_type); 277 return RenderText::GetLeftSelectionModel(selection, break_type);
271 } 278 }
272 279
273 SelectionModel RenderTextWin::GetRightSelectionModel( 280 SelectionModel RenderTextWin::GetRightSelectionModel(
274 const SelectionModel& selection, 281 const SelectionModel& selection,
275 BreakType break_type) { 282 BreakType break_type) {
283 EnsureLayout();
284
276 if (break_type == LINE_BREAK || text().empty()) 285 if (break_type == LINE_BREAK || text().empty())
277 return RightEndSelectionModel(); 286 return RightEndSelectionModel();
278 if (break_type == CHARACTER_BREAK) 287 if (break_type == CHARACTER_BREAK)
279 return RightSelectionModel(selection); 288 return RightSelectionModel(selection);
280 // TODO(msw): Implement word breaking. 289 // TODO(msw): Implement word breaking.
281 return RenderText::GetRightSelectionModel(selection, break_type); 290 return RenderText::GetRightSelectionModel(selection, break_type);
282 } 291 }
283 292
284 SelectionModel RenderTextWin::LeftEndSelectionModel() { 293 SelectionModel RenderTextWin::LeftEndSelectionModel() {
msw 2011/11/28 21:15:46 Do we need EnsureLayout on these protected methods
Alexei Svitkine (slow) 2011/11/28 21:58:13 Done.
285 if (text().empty()) 294 if (text().empty())
286 return SelectionModel(0, 0, SelectionModel::LEADING); 295 return SelectionModel(0, 0, SelectionModel::LEADING);
287 size_t cursor = base::i18n::IsRTL() ? text().length() : 0; 296 size_t cursor = base::i18n::IsRTL() ? text().length() : 0;
288 internal::TextRun* run = runs_[visual_to_logical_[0]]; 297 internal::TextRun* run = runs_[visual_to_logical_[0]];
289 bool rtl = run->script_analysis.fRTL; 298 bool rtl = run->script_analysis.fRTL;
290 size_t caret = rtl ? run->range.end() - 1 : run->range.start(); 299 size_t caret = rtl ? run->range.end() - 1 : run->range.start();
291 SelectionModel::CaretPlacement placement = 300 SelectionModel::CaretPlacement placement =
292 rtl ? SelectionModel::TRAILING : SelectionModel::LEADING; 301 rtl ? SelectionModel::TRAILING : SelectionModel::LEADING;
293 return SelectionModel(cursor, caret, placement); 302 return SelectionModel(cursor, caret, placement);
294 } 303 }
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 bounds.push_back(rect); 365 bounds.push_back(rect);
357 } 366 }
358 } 367 }
359 return bounds; 368 return bounds;
360 } 369 }
361 370
362 bool RenderTextWin::IsCursorablePosition(size_t position) { 371 bool RenderTextWin::IsCursorablePosition(size_t position) {
363 if (position == 0 || position == text().length()) 372 if (position == 0 || position == text().length())
364 return true; 373 return true;
365 374
375 EnsureLayout();
366 size_t run_index = GetRunContainingPosition(position); 376 size_t run_index = GetRunContainingPosition(position);
367 if (run_index >= runs_.size()) 377 if (run_index >= runs_.size())
368 return false; 378 return false;
369 379
370 internal::TextRun* run = runs_[run_index]; 380 internal::TextRun* run = runs_[run_index];
371 size_t start = run->range.start(); 381 size_t start = run->range.start();
372 if (position == start) 382 if (position == start)
373 return true; 383 return true;
374 return run->logical_clusters[position - start] != 384 return run->logical_clusters[position - start] !=
375 run->logical_clusters[position - start - 1]; 385 run->logical_clusters[position - start - 1];
376 } 386 }
377 387
378 void RenderTextWin::UpdateLayout() { 388 void RenderTextWin::UpdateLayout() {
389 needs_layout_ = true;
msw 2011/11/28 21:15:46 Add a simple comment like "Layout is performed laz
Alexei Svitkine (slow) 2011/11/28 21:58:13 Done.
390 }
391
392 void RenderTextWin::EnsureLayout() {
msw 2011/11/28 21:15:46 This should be below IndexOfAdjacentGrapheme to ma
Alexei Svitkine (slow) 2011/11/28 21:58:13 Done.
393 if (!needs_layout_)
394 return;
379 // TODO(msw): Skip complex processing if ScriptIsComplex returns false. 395 // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
380 ItemizeLogicalText(); 396 ItemizeLogicalText();
381 if (!runs_.empty()) 397 if (!runs_.empty())
382 LayoutVisualText(); 398 LayoutVisualText();
msw 2011/11/28 21:15:46 I think we actually need to reset |string_width_|
Alexei Svitkine (slow) 2011/11/28 21:58:13 Good catch! Done.
399 needs_layout_ = false;
383 } 400 }
384 401
385 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { 402 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) {
403 EnsureLayout();
386 size_t run_index = GetRunContainingPosition(index); 404 size_t run_index = GetRunContainingPosition(index);
387 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL; 405 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL;
388 int start = run ? run->range.start() : 0; 406 int start = run ? run->range.start() : 0;
389 int length = run ? run->range.length() : text().length(); 407 int length = run ? run->range.length() : text().length();
390 int ch = index - start; 408 int ch = index - start;
391 WORD cluster = run ? run->logical_clusters[ch] : 0; 409 WORD cluster = run ? run->logical_clusters[ch] : 0;
392 410
393 if (!next) { 411 if (!next) {
394 do { 412 do {
395 ch--; 413 ch--;
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
549 internal::TextRun* run = runs_[visual_to_logical_[i]]; 567 internal::TextRun* run = runs_[visual_to_logical_[i]];
550 run->preceding_run_widths = preceding_run_widths; 568 run->preceding_run_widths = preceding_run_widths;
551 const ABC& abc = run->abc_widths; 569 const ABC& abc = run->abc_widths;
552 run->width = abc.abcA + abc.abcB + abc.abcC; 570 run->width = abc.abcA + abc.abcB + abc.abcC;
553 preceding_run_widths += run->width; 571 preceding_run_widths += run->width;
554 } 572 }
555 string_width_ = preceding_run_widths; 573 string_width_ = preceding_run_widths;
556 } 574 }
557 575
558 size_t RenderTextWin::GetRunContainingPosition(size_t position) const { 576 size_t RenderTextWin::GetRunContainingPosition(size_t position) const {
577 DCHECK(!needs_layout_);
559 // Find the text run containing the argument position. 578 // Find the text run containing the argument position.
560 size_t run = 0; 579 size_t run = 0;
561 for (; run < runs_.size(); ++run) 580 for (; run < runs_.size(); ++run)
562 if (runs_[run]->range.start() <= position && 581 if (runs_[run]->range.start() <= position &&
563 runs_[run]->range.end() > position) 582 runs_[run]->range.end() > position)
564 break; 583 break;
565 return run; 584 return run;
566 } 585 }
567 586
568 size_t RenderTextWin::GetRunContainingPoint(const Point& point) const { 587 size_t RenderTextWin::GetRunContainingPoint(const Point& point) const {
588 DCHECK(!needs_layout_);
569 // Find the text run containing the argument point (assumed already offset). 589 // Find the text run containing the argument point (assumed already offset).
570 size_t run = 0; 590 size_t run = 0;
571 for (; run < runs_.size(); ++run) 591 for (; run < runs_.size(); ++run)
572 if (runs_[run]->preceding_run_widths <= point.x() && 592 if (runs_[run]->preceding_run_widths <= point.x() &&
573 runs_[run]->preceding_run_widths + runs_[run]->width > point.x()) 593 runs_[run]->preceding_run_widths + runs_[run]->width > point.x())
574 break; 594 break;
575 return run; 595 return run;
576 } 596 }
577 597
578 SelectionModel RenderTextWin::FirstSelectionModelInsideRun( 598 SelectionModel RenderTextWin::FirstSelectionModelInsideRun(
msw 2011/11/28 21:15:46 Should these private methods |DCHECK(!needs_layout
Alexei Svitkine (slow) 2011/11/28 21:58:13 As they currently are, they don't need it. However
579 internal::TextRun* run) { 599 internal::TextRun* run) {
580 size_t caret = run->range.start(); 600 size_t caret = run->range.start();
581 size_t cursor = IndexOfAdjacentGrapheme(caret, true); 601 size_t cursor = IndexOfAdjacentGrapheme(caret, true);
582 return SelectionModel(cursor, caret, SelectionModel::TRAILING); 602 return SelectionModel(cursor, caret, SelectionModel::TRAILING);
583 } 603 }
584 604
585 SelectionModel RenderTextWin::LastSelectionModelInsideRun( 605 SelectionModel RenderTextWin::LastSelectionModelInsideRun(
586 internal::TextRun* run) { 606 internal::TextRun* run) {
587 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), false); 607 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), false);
588 return SelectionModel(caret, caret, SelectionModel::LEADING); 608 return SelectionModel(caret, caret, SelectionModel::LEADING);
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
734 Rect r(GetUpdatedCursorBounds()); 754 Rect r(GetUpdatedCursorBounds());
735 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height()); 755 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height());
736 } 756 }
737 } 757 }
738 758
739 RenderText* RenderText::CreateRenderText() { 759 RenderText* RenderText::CreateRenderText() {
740 return new RenderTextWin; 760 return new RenderTextWin;
741 } 761 }
742 762
743 } // namespace gfx 763 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698