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

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

Issue 8536047: Separate selection highlight from pango layout (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: synchistory Created 9 years 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
« ui/gfx/render_text.cc ('K') | « 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 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 return string_width_; 171 return string_width_;
172 } 172 }
173 173
174 void RenderTextWin::Draw(Canvas* canvas) {
Alexei Svitkine (slow) 2011/11/29 15:41:37 I have a CL that adds an EnsureLayout() call here:
xji 2011/11/29 23:07:15 Done. And I made EnsureLayout() to base too.
175 DrawSelection(canvas);
176 DrawVisualText(canvas);
177 DrawCursor(canvas);
178 }
179
180 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { 174 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
181 if (text().empty()) 175 if (text().empty())
182 return SelectionModel(); 176 return SelectionModel();
183 177
184 // Find the run that contains the point and adjust the argument location. 178 // Find the run that contains the point and adjust the argument location.
185 Point p(ToTextPoint(point)); 179 Point p(ToTextPoint(point));
186 size_t run_index = GetRunContainingPoint(p); 180 size_t run_index = GetRunContainingPoint(p);
187 if (run_index == runs_.size()) 181 if (run_index == runs_.size())
188 return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel(); 182 return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel();
189 internal::TextRun* run = runs_[run_index]; 183 internal::TextRun* run = runs_[run_index];
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 return SelectionModel(0, 0, SelectionModel::LEADING); 292 return SelectionModel(0, 0, SelectionModel::LEADING);
299 size_t cursor = base::i18n::IsRTL() ? 0 : text().length(); 293 size_t cursor = base::i18n::IsRTL() ? 0 : text().length();
300 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]]; 294 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]];
301 bool rtl = run->script_analysis.fRTL; 295 bool rtl = run->script_analysis.fRTL;
302 size_t caret = rtl ? run->range.start() : run->range.end() - 1; 296 size_t caret = rtl ? run->range.start() : run->range.end() - 1;
303 SelectionModel::CaretPlacement placement = 297 SelectionModel::CaretPlacement placement =
304 rtl ? SelectionModel::LEADING : SelectionModel::TRAILING; 298 rtl ? SelectionModel::LEADING : SelectionModel::TRAILING;
305 return SelectionModel(cursor, caret, placement); 299 return SelectionModel(cursor, caret, placement);
306 } 300 }
307 301
308 std::vector<Rect> RenderTextWin::GetSubstringBounds(size_t from, size_t to) { 302 void RenderTextWin::GetSubstringBounds(size_t from,
303 size_t to,
304 std::vector<Rect>* bounds) {
309 ui::Range range(from, to); 305 ui::Range range(from, to);
310 DCHECK(ui::Range(0, text().length()).Contains(range)); 306 DCHECK(ui::Range(0, text().length()).Contains(range));
311 Point display_offset(GetUpdatedDisplayOffset()); 307 Point display_offset(GetUpdatedDisplayOffset());
312 std::vector<Rect> bounds;
313 HRESULT hr = 0; 308 HRESULT hr = 0;
309 bounds->clear();
314 310
315 // Add a Rect for each run/selection intersection. 311 // Add a Rect for each run/selection intersection.
316 // TODO(msw): The bounds should probably not always be leading the range ends. 312 // TODO(msw): The bounds should probably not always be leading the range ends.
317 for (size_t i = 0; i < runs_.size(); ++i) { 313 for (size_t i = 0; i < runs_.size(); ++i) {
318 internal::TextRun* run = runs_[visual_to_logical_[i]]; 314 internal::TextRun* run = runs_[visual_to_logical_[i]];
319 ui::Range intersection = run->range.Intersect(range); 315 ui::Range intersection = run->range.Intersect(range);
320 if (intersection.IsValid()) { 316 if (intersection.IsValid()) {
321 DCHECK(!intersection.is_reversed()); 317 DCHECK(!intersection.is_reversed());
322 int start_offset = 0; 318 int start_offset = 0;
323 hr = ScriptCPtoX(intersection.start() - run->range.start(), 319 hr = ScriptCPtoX(intersection.start() - run->range.start(),
(...skipping 18 matching lines...) Expand all
342 &end_offset); 338 &end_offset);
343 DCHECK(SUCCEEDED(hr)); 339 DCHECK(SUCCEEDED(hr));
344 if (start_offset > end_offset) 340 if (start_offset > end_offset)
345 std::swap(start_offset, end_offset); 341 std::swap(start_offset, end_offset);
346 Rect rect(run->preceding_run_widths + start_offset, 0, 342 Rect rect(run->preceding_run_widths + start_offset, 0,
347 end_offset - start_offset, run->font.GetHeight()); 343 end_offset - start_offset, run->font.GetHeight());
348 // Center the rect vertically in the display area. 344 // Center the rect vertically in the display area.
349 rect.Offset(0, (display_rect().height() - rect.height()) / 2); 345 rect.Offset(0, (display_rect().height() - rect.height()) / 2);
350 rect.set_origin(ToViewPoint(rect.origin())); 346 rect.set_origin(ToViewPoint(rect.origin()));
351 // Union this with the last rect if they're adjacent. 347 // Union this with the last rect if they're adjacent.
352 if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) { 348 if (!bounds->empty() && rect.SharesEdgeWith(bounds->back())) {
353 rect = rect.Union(bounds.back()); 349 rect = rect.Union(bounds->back());
354 bounds.pop_back(); 350 bounds->pop_back();
355 } 351 }
356 bounds.push_back(rect); 352 bounds->push_back(rect);
357 } 353 }
358 } 354 }
359 return bounds; 355 return;
360 } 356 }
361 357
362 bool RenderTextWin::IsCursorablePosition(size_t position) { 358 bool RenderTextWin::IsCursorablePosition(size_t position) {
363 if (position == 0 || position == text().length()) 359 if (position == 0 || position == text().length())
364 return true; 360 return true;
365 361
366 size_t run_index = GetRunContainingPosition(position); 362 size_t run_index = GetRunContainingPosition(position);
367 if (run_index >= runs_.size()) 363 if (run_index >= runs_.size())
368 return false; 364 return false;
369 365
370 internal::TextRun* run = runs_[run_index]; 366 internal::TextRun* run = runs_[run_index];
371 size_t start = run->range.start(); 367 size_t start = run->range.start();
372 if (position == start) 368 if (position == start)
373 return true; 369 return true;
374 return run->logical_clusters[position - start] != 370 return run->logical_clusters[position - start] !=
375 run->logical_clusters[position - start - 1]; 371 run->logical_clusters[position - start - 1];
376 } 372 }
377 373
378 void RenderTextWin::UpdateLayout() { 374 void RenderTextWin::UpdateLayout() {
379 // TODO(msw): Skip complex processing if ScriptIsComplex returns false. 375 // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
380 ItemizeLogicalText(); 376 ItemizeLogicalText();
381 if (!runs_.empty()) 377 if (!runs_.empty())
382 LayoutVisualText(); 378 LayoutVisualText();
383 } 379 }
384 380
381 void RenderTextWin::DrawVisualText(Canvas* canvas) {
382 if (text().empty())
383 return;
384
385 SkCanvas* canvas_skia = canvas->GetSkCanvas();
386
387 Point offset(ToViewPoint(Point()));
388 // TODO(msw): Establish a vertical baseline for strings of mixed font heights.
389 size_t height = default_style().font.GetHeight();
390
391 SkScalar x = SkIntToScalar(offset.x());
392 SkScalar y = SkIntToScalar(offset.y());
393 // Center the text vertically in the display area.
394 y += (display_rect().height() - height) / 2;
395 // Offset by the font size to account for Skia expecting y to be the bottom.
396 y += default_style().font.GetFontSize();
397
398 SkPaint paint;
399 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
400 paint.setStyle(SkPaint::kFill_Style);
401 paint.setAntiAlias(true);
402 paint.setSubpixelText(true);
403 paint.setLCDRenderText(true);
404
405 std::vector<SkPoint> pos;
406 for (size_t i = 0; i < runs_.size(); ++i) {
407 // Get the run specified by the visual-to-logical map.
408 internal::TextRun* run = runs_[visual_to_logical_[i]];
409
410 // TODO(msw): Font default/fallback and style integration.
411 SkTypeface::Style style = SkTypeface::kNormal;
412 SkTypeface* typeface =
413 SkTypeface::CreateFromName(run->font.GetFontName().c_str(), style);
414 if (typeface) {
415 paint.setTypeface(typeface);
416 // |paint| adds its own ref. Release the ref from CreateFromName.
417 typeface->unref();
418 }
419 paint.setTextSize(run->font.GetFontSize());
420 paint.setColor(run->foreground);
421
422 SkScalar run_x = x;
423
424 // Based on WebCore::skiaDrawText.
425 pos.resize(run->glyph_count);
426 for (int glyph = 0; glyph < run->glyph_count; glyph++) {
427 pos[glyph].set(x + run->offsets[glyph].du,
428 y + run->offsets[glyph].dv);
429 x += SkIntToScalar(run->advance_widths[glyph]);
430 }
431
432 size_t byte_length = run->glyph_count * sizeof(WORD);
433 canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint);
434
435 if (run->strike || run->underline)
436 DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y);
437 }
438 }
439
385 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { 440 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) {
386 size_t run_index = GetRunContainingPosition(index); 441 size_t run_index = GetRunContainingPosition(index);
387 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL; 442 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL;
388 int start = run ? run->range.start() : 0; 443 int start = run ? run->range.start() : 0;
389 int length = run ? run->range.length() : text().length(); 444 int length = run ? run->range.length() : text().length();
390 int ch = index - start; 445 int ch = index - start;
391 WORD cluster = run ? run->logical_clusters[ch] : 0; 446 WORD cluster = run ? run->logical_clusters[ch] : 0;
392 447
393 if (!next) { 448 if (!next) {
394 do { 449 do {
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 708
654 // The character is at the end of its run; go to the next visual run. 709 // The character is at the end of its run; go to the next visual run.
655 size_t visual_index = logical_to_visual_[run_index]; 710 size_t visual_index = logical_to_visual_[run_index];
656 if (visual_index == runs_.size() - 1) 711 if (visual_index == runs_.size() - 1)
657 return RightEndSelectionModel(); 712 return RightEndSelectionModel();
658 internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]]; 713 internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]];
659 return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) : 714 return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) :
660 FirstSelectionModelInsideRun(next); 715 FirstSelectionModelInsideRun(next);
661 } 716 }
662 717
663 void RenderTextWin::DrawSelection(Canvas* canvas) {
664 std::vector<Rect> sel(
665 GetSubstringBounds(GetSelectionStart(), GetCursorPosition()));
666 SkColor color = focused() ? kFocusedSelectionColor : kUnfocusedSelectionColor;
667 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i)
668 canvas->FillRect(color, *i);
669 }
670
671 void RenderTextWin::DrawVisualText(Canvas* canvas) {
672 if (text().empty())
673 return;
674
675 SkCanvas* canvas_skia = canvas->GetSkCanvas();
676
677 Point offset(ToViewPoint(Point()));
678 // TODO(msw): Establish a vertical baseline for strings of mixed font heights.
679 size_t height = default_style().font.GetHeight();
680
681 SkScalar x = SkIntToScalar(offset.x());
682 SkScalar y = SkIntToScalar(offset.y());
683 // Center the text vertically in the display area.
684 y += (display_rect().height() - height) / 2;
685 // Offset by the font size to account for Skia expecting y to be the bottom.
686 y += default_style().font.GetFontSize();
687
688 SkPaint paint;
689 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
690 paint.setStyle(SkPaint::kFill_Style);
691 paint.setAntiAlias(true);
692 paint.setSubpixelText(true);
693 paint.setLCDRenderText(true);
694
695 std::vector<SkPoint> pos;
696 for (size_t i = 0; i < runs_.size(); ++i) {
697 // Get the run specified by the visual-to-logical map.
698 internal::TextRun* run = runs_[visual_to_logical_[i]];
699
700 // TODO(msw): Font default/fallback and style integration.
701 SkTypeface::Style style = SkTypeface::kNormal;
702 SkTypeface* typeface =
703 SkTypeface::CreateFromName(run->font.GetFontName().c_str(), style);
704 if (typeface) {
705 paint.setTypeface(typeface);
706 // |paint| adds its own ref. Release the ref from CreateFromName.
707 typeface->unref();
708 }
709 paint.setTextSize(run->font.GetFontSize());
710 paint.setColor(run->foreground);
711
712 SkScalar run_x = x;
713
714 // Based on WebCore::skiaDrawText.
715 pos.resize(run->glyph_count);
716 for (int glyph = 0; glyph < run->glyph_count; glyph++) {
717 pos[glyph].set(x + run->offsets[glyph].du,
718 y + run->offsets[glyph].dv);
719 x += SkIntToScalar(run->advance_widths[glyph]);
720 }
721
722 size_t byte_length = run->glyph_count * sizeof(WORD);
723 canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint);
724
725 if (run->strike || run->underline)
726 DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y);
727 }
728 }
729
730 void RenderTextWin::DrawCursor(Canvas* canvas) {
731 // Paint cursor. Replace cursor is drawn as rectangle for now.
732 // TODO(msw): Draw a better cursor with a better indication of association.
733 if (cursor_visible() && focused()) {
734 Rect r(GetUpdatedCursorBounds());
735 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height());
736 }
737 }
738
739 RenderText* RenderText::CreateRenderText() { 718 RenderText* RenderText::CreateRenderText() {
740 return new RenderTextWin; 719 return new RenderTextWin;
741 } 720 }
742 721
743 } // namespace gfx 722 } // namespace gfx
OLDNEW
« ui/gfx/render_text.cc ('K') | « ui/gfx/render_text_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698