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

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: address comments 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_linux.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 #include <map> 8 #include <map>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 102
103 RenderTextWin::~RenderTextWin() { 103 RenderTextWin::~RenderTextWin() {
104 ScriptFreeCache(&script_cache_); 104 ScriptFreeCache(&script_cache_);
105 STLDeleteContainerPointers(runs_.begin(), runs_.end()); 105 STLDeleteContainerPointers(runs_.begin(), runs_.end());
106 } 106 }
107 107
108 int RenderTextWin::GetStringWidth() { 108 int RenderTextWin::GetStringWidth() {
109 return string_width_; 109 return string_width_;
110 } 110 }
111 111
112 void RenderTextWin::Draw(Canvas* canvas) {
113 DrawSelection(canvas);
114 DrawVisualText(canvas);
115 DrawCursor(canvas);
116 }
117
118 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { 112 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
119 if (text().empty()) 113 if (text().empty())
120 return SelectionModel(); 114 return SelectionModel();
121 115
122 // Find the run that contains the point and adjust the argument location. 116 // Find the run that contains the point and adjust the argument location.
123 Point p(ToTextPoint(point)); 117 Point p(ToTextPoint(point));
124 size_t run_index = GetRunContainingPoint(p); 118 size_t run_index = GetRunContainingPoint(p);
125 if (run_index == runs_.size()) 119 if (run_index == runs_.size())
126 return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel(); 120 return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel();
127 internal::TextRun* run = runs_[run_index]; 121 internal::TextRun* run = runs_[run_index];
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 return SelectionModel(0, 0, SelectionModel::LEADING); 230 return SelectionModel(0, 0, SelectionModel::LEADING);
237 size_t cursor = base::i18n::IsRTL() ? 0 : text().length(); 231 size_t cursor = base::i18n::IsRTL() ? 0 : text().length();
238 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]]; 232 internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]];
239 bool rtl = run->script_analysis.fRTL; 233 bool rtl = run->script_analysis.fRTL;
240 size_t caret = rtl ? run->range.start() : run->range.end() - 1; 234 size_t caret = rtl ? run->range.start() : run->range.end() - 1;
241 SelectionModel::CaretPlacement placement = 235 SelectionModel::CaretPlacement placement =
242 rtl ? SelectionModel::LEADING : SelectionModel::TRAILING; 236 rtl ? SelectionModel::LEADING : SelectionModel::TRAILING;
243 return SelectionModel(cursor, caret, placement); 237 return SelectionModel(cursor, caret, placement);
244 } 238 }
245 239
246 std::vector<Rect> RenderTextWin::GetSubstringBounds(size_t from, size_t to) { 240 void RenderTextWin::GetSubstringBounds(size_t from,
241 size_t to,
242 std::vector<Rect>* bounds) {
247 ui::Range range(from, to); 243 ui::Range range(from, to);
248 DCHECK(ui::Range(0, text().length()).Contains(range)); 244 DCHECK(ui::Range(0, text().length()).Contains(range));
249 Point display_offset(GetUpdatedDisplayOffset()); 245 Point display_offset(GetUpdatedDisplayOffset());
250 std::vector<Rect> bounds;
251 HRESULT hr = 0; 246 HRESULT hr = 0;
247 bounds->clear();
252 248
253 // Add a Rect for each run/selection intersection. 249 // Add a Rect for each run/selection intersection.
254 // TODO(msw): The bounds should probably not always be leading the range ends. 250 // TODO(msw): The bounds should probably not always be leading the range ends.
255 for (size_t i = 0; i < runs_.size(); ++i) { 251 for (size_t i = 0; i < runs_.size(); ++i) {
256 internal::TextRun* run = runs_[visual_to_logical_[i]]; 252 internal::TextRun* run = runs_[visual_to_logical_[i]];
257 ui::Range intersection = run->range.Intersect(range); 253 ui::Range intersection = run->range.Intersect(range);
258 if (intersection.IsValid()) { 254 if (intersection.IsValid()) {
259 DCHECK(!intersection.is_reversed()); 255 DCHECK(!intersection.is_reversed());
260 int start_offset = 0; 256 int start_offset = 0;
261 hr = ScriptCPtoX(intersection.start() - run->range.start(), 257 hr = ScriptCPtoX(intersection.start() - run->range.start(),
(...skipping 18 matching lines...) Expand all
280 &end_offset); 276 &end_offset);
281 DCHECK(SUCCEEDED(hr)); 277 DCHECK(SUCCEEDED(hr));
282 if (start_offset > end_offset) 278 if (start_offset > end_offset)
283 std::swap(start_offset, end_offset); 279 std::swap(start_offset, end_offset);
284 Rect rect(run->preceding_run_widths + start_offset, 0, 280 Rect rect(run->preceding_run_widths + start_offset, 0,
285 end_offset - start_offset, run->font.GetHeight()); 281 end_offset - start_offset, run->font.GetHeight());
286 // Center the rect vertically in the display area. 282 // Center the rect vertically in the display area.
287 rect.Offset(0, (display_rect().height() - rect.height()) / 2); 283 rect.Offset(0, (display_rect().height() - rect.height()) / 2);
288 rect.set_origin(ToViewPoint(rect.origin())); 284 rect.set_origin(ToViewPoint(rect.origin()));
289 // Union this with the last rect if they're adjacent. 285 // Union this with the last rect if they're adjacent.
290 if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) { 286 if (!bounds->empty() && rect.SharesEdgeWith(bounds->back())) {
291 rect = rect.Union(bounds.back()); 287 rect = rect.Union(bounds->back());
292 bounds.pop_back(); 288 bounds->pop_back();
293 } 289 }
294 bounds.push_back(rect); 290 bounds->push_back(rect);
295 } 291 }
296 } 292 }
297 return bounds; 293 return;
298 } 294 }
299 295
300 bool RenderTextWin::IsCursorablePosition(size_t position) { 296 bool RenderTextWin::IsCursorablePosition(size_t position) {
301 if (position == 0 || position == text().length()) 297 if (position == 0 || position == text().length())
302 return true; 298 return true;
303 299
304 size_t run_index = GetRunContainingPosition(position); 300 size_t run_index = GetRunContainingPosition(position);
305 if (run_index >= runs_.size()) 301 if (run_index >= runs_.size())
306 return false; 302 return false;
307 303
308 internal::TextRun* run = runs_[run_index]; 304 internal::TextRun* run = runs_[run_index];
309 size_t start = run->range.start(); 305 size_t start = run->range.start();
310 if (position == start) 306 if (position == start)
311 return true; 307 return true;
312 return run->logical_clusters[position - start] != 308 return run->logical_clusters[position - start] !=
313 run->logical_clusters[position - start - 1]; 309 run->logical_clusters[position - start - 1];
314 } 310 }
315 311
316 void RenderTextWin::UpdateLayout() { 312 void RenderTextWin::UpdateLayout() {
317 // TODO(msw): Skip complex processing if ScriptIsComplex returns false. 313 // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
318 ItemizeLogicalText(); 314 ItemizeLogicalText();
319 HDC hdc = CreateCompatibleDC(NULL); 315 HDC hdc = CreateCompatibleDC(NULL);
320 LayoutVisualText(hdc); 316 LayoutVisualText(hdc);
321 DeleteDC(hdc); 317 DeleteDC(hdc);
322 } 318 }
323 319
320 void RenderTextWin::DrawVisualText(Canvas* canvas) {
321 if (text().empty())
322 return;
323
324 SkCanvas* canvas_skia = canvas->GetSkCanvas();
325
326 Point offset(ToViewPoint(Point()));
327 // TODO(msw): Establish a vertical baseline for strings of mixed font heights.
328 size_t height = default_style().font.GetHeight();
329
330 SkScalar x = SkIntToScalar(offset.x());
331 SkScalar y = SkIntToScalar(offset.y());
332 // Center the text vertically in the display area.
333 y += (display_rect().height() - height) / 2;
334 // Offset by the font size to account for Skia expecting y to be the bottom.
335 y += default_style().font.GetFontSize();
336
337 SkPaint paint;
338 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
339 paint.setStyle(SkPaint::kFill_Style);
340 paint.setAntiAlias(true);
341 paint.setSubpixelText(true);
342 paint.setLCDRenderText(true);
343
344 std::vector<SkPoint> pos;
345 for (size_t i = 0; i < runs_.size(); ++i) {
346 // Get the run specified by the visual-to-logical map.
347 internal::TextRun* run = runs_[visual_to_logical_[i]];
348
349 // TODO(msw): Font default/fallback and style integration.
350 SkTypeface::Style style = SkTypeface::kNormal;
351 SkTypeface* typeface =
352 SkTypeface::CreateFromName(run->font.GetFontName().c_str(), style);
353 if (typeface) {
354 paint.setTypeface(typeface);
355 // |paint| adds its own ref. Release the ref from CreateFromName.
356 typeface->unref();
357 }
358 paint.setTextSize(run->font.GetFontSize());
359 paint.setColor(run->foreground);
360
361 SkScalar run_x = x;
362
363 // Based on WebCore::skiaDrawText.
364 pos.resize(run->glyph_count);
365 for (int glyph = 0; glyph < run->glyph_count; glyph++) {
366 pos[glyph].set(x + run->offsets[glyph].du,
367 y + run->offsets[glyph].dv);
368 x += SkIntToScalar(run->advance_widths[glyph]);
369 }
370
371 size_t byte_length = run->glyph_count * sizeof(WORD);
372 canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint);
373
374 if (run->strike || run->underline)
375 DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y);
376 }
377 }
378
324 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { 379 size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) {
325 size_t run_index = GetRunContainingPosition(index); 380 size_t run_index = GetRunContainingPosition(index);
326 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL; 381 internal::TextRun* run = run_index < runs_.size() ? runs_[run_index] : NULL;
327 int start = run ? run->range.start() : 0; 382 int start = run ? run->range.start() : 0;
328 int length = run ? run->range.length() : text().length(); 383 int length = run ? run->range.length() : text().length();
329 int ch = index - start; 384 int ch = index - start;
330 WORD cluster = run ? run->logical_clusters[ch] : 0; 385 WORD cluster = run ? run->logical_clusters[ch] : 0;
331 386
332 if (!next) { 387 if (!next) {
333 do { 388 do {
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 640
586 // The character is at the end of its run; go to the next visual run. 641 // The character is at the end of its run; go to the next visual run.
587 size_t visual_index = logical_to_visual_[run_index]; 642 size_t visual_index = logical_to_visual_[run_index];
588 if (visual_index == runs_.size() - 1) 643 if (visual_index == runs_.size() - 1)
589 return RightEndSelectionModel(); 644 return RightEndSelectionModel();
590 internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]]; 645 internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]];
591 return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) : 646 return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) :
592 FirstSelectionModelInsideRun(next); 647 FirstSelectionModelInsideRun(next);
593 } 648 }
594 649
595 void RenderTextWin::DrawSelection(Canvas* canvas) {
596 std::vector<Rect> sel(
597 GetSubstringBounds(GetSelectionStart(), GetCursorPosition()));
598 SkColor color = focused() ? kFocusedSelectionColor : kUnfocusedSelectionColor;
599 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i)
600 canvas->FillRect(color, *i);
601 }
602
603 void RenderTextWin::DrawVisualText(Canvas* canvas) {
604 if (text().empty())
605 return;
606
607 SkCanvas* canvas_skia = canvas->GetSkCanvas();
608
609 Point offset(ToViewPoint(Point()));
610 // TODO(msw): Establish a vertical baseline for strings of mixed font heights.
611 size_t height = default_style().font.GetHeight();
612
613 SkScalar x = SkIntToScalar(offset.x());
614 SkScalar y = SkIntToScalar(offset.y());
615 // Center the text vertically in the display area.
616 y += (display_rect().height() - height) / 2;
617 // Offset by the font size to account for Skia expecting y to be the bottom.
618 y += default_style().font.GetFontSize();
619
620 SkPaint paint;
621 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
622 paint.setStyle(SkPaint::kFill_Style);
623 paint.setAntiAlias(true);
624 paint.setSubpixelText(true);
625 paint.setLCDRenderText(true);
626
627 std::vector<SkPoint> pos;
628 for (size_t i = 0; i < runs_.size(); ++i) {
629 // Get the run specified by the visual-to-logical map.
630 internal::TextRun* run = runs_[visual_to_logical_[i]];
631
632 // TODO(msw): Font default/fallback and style integration.
633 SkTypeface::Style style = SkTypeface::kNormal;
634 SkTypeface* typeface =
635 SkTypeface::CreateFromName(run->font.GetFontName().c_str(), style);
636 if (typeface) {
637 paint.setTypeface(typeface);
638 // |paint| adds its own ref. Release the ref from CreateFromName.
639 typeface->unref();
640 }
641 paint.setTextSize(run->font.GetFontSize());
642 paint.setColor(run->foreground);
643
644 SkScalar run_x = x;
645
646 // Based on WebCore::skiaDrawText.
647 pos.resize(run->glyph_count);
648 for (int glyph = 0; glyph < run->glyph_count; glyph++) {
649 pos[glyph].set(x + run->offsets[glyph].du,
650 y + run->offsets[glyph].dv);
651 x += SkIntToScalar(run->advance_widths[glyph]);
652 }
653
654 size_t byte_length = run->glyph_count * sizeof(WORD);
655 canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint);
656
657 if (run->strike || run->underline)
658 DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y);
659 }
660 }
661
662 void RenderTextWin::DrawCursor(Canvas* canvas) {
663 // Paint cursor. Replace cursor is drawn as rectangle for now.
664 // TODO(msw): Draw a better cursor with a better indication of association.
665 if (cursor_visible() && focused()) {
666 Rect r(GetUpdatedCursorBounds());
667 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height());
668 }
669 }
670
671 RenderText* RenderText::CreateRenderText() { 650 RenderText* RenderText::CreateRenderText() {
672 return new RenderTextWin; 651 return new RenderTextWin;
673 } 652 }
674 653
675 } // namespace gfx 654 } // namespace gfx
OLDNEW
« ui/gfx/render_text_linux.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