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

Unified Diff: ui/gfx/render_text_win.cc

Issue 7265011: RenderText API Outline. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add some placeholder functionality on Windows. Created 9 years, 6 months 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 side-by-side diff with in-line comments
Download patch
Index: ui/gfx/render_text_win.cc
diff --git a/ui/gfx/render_text_win.cc b/ui/gfx/render_text_win.cc
new file mode 100755
index 0000000000000000000000000000000000000000..be5fd5cc758fb74215504cf82d86bd595e97273f
--- /dev/null
+++ b/ui/gfx/render_text_win.cc
@@ -0,0 +1,275 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/render_text_win.h"
+
+// TODO(msw): Remove headers we're not using after Uniscribe impl...
+#include "base/i18n/break_iterator.h"
+#include "base/i18n/rtl.h"
+#include "base/logging.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/canvas_skia.h"
+
+namespace {
+
+// TODO(msw): Remove this and use Uniscribe rendering.
+// Compute the windows flags necessary to implement the provided text Canvas
+// flags.
+int ComputeFormatFlags(int flags, const string16& text) {
+ // Setting the text alignment explicitly in case it hasn't already been set.
+ // This will make sure that we don't align text to the left on RTL locales
+ // just because no alignment flag was passed to DrawStringInt().
+ if (!(flags & (gfx::Canvas::TEXT_ALIGN_CENTER |
+ gfx::Canvas::TEXT_ALIGN_RIGHT |
+ gfx::Canvas::TEXT_ALIGN_LEFT))) {
+ flags |= gfx::CanvasSkia::DefaultCanvasTextAlignment();
+ }
+
+ // horizontal alignment
+ int f = 0;
+ if (flags & gfx::Canvas::TEXT_ALIGN_CENTER)
+ f |= DT_CENTER;
+ else if (flags & gfx::Canvas::TEXT_ALIGN_RIGHT)
+ f |= DT_RIGHT;
+ else
+ f |= DT_LEFT;
+
+ // vertical alignment
+ if (flags & gfx::Canvas::TEXT_VALIGN_TOP)
+ f |= DT_TOP;
+ else if (flags & gfx::Canvas::TEXT_VALIGN_BOTTOM)
+ f |= DT_BOTTOM;
+ else
+ f |= DT_VCENTER;
+
+ if (flags & gfx::Canvas::MULTI_LINE) {
+ f |= DT_WORDBREAK;
+ if (flags & gfx::Canvas::CHARACTER_BREAK)
+ f |= DT_EDITCONTROL; // Turns on character breaking (not documented)
+ else if (!(flags & gfx::Canvas::NO_ELLIPSIS))
+ f |= DT_WORD_ELLIPSIS;
+ } else {
+ f |= DT_SINGLELINE;
+ }
+
+ if (flags & gfx::Canvas::HIDE_PREFIX)
+ f |= DT_HIDEPREFIX;
+ else if ((flags & gfx::Canvas::SHOW_PREFIX) == 0)
+ f |= DT_NOPREFIX;
+
+ if (!(flags & gfx::Canvas::NO_ELLIPSIS))
+ f |= DT_END_ELLIPSIS;
+
+ // In order to make sure RTL/BiDi strings are rendered correctly, we must
+ // pass the flag DT_RTLREADING to DrawText (when the locale's language is
+ // a right-to-left language) so that Windows does the right thing.
+ //
+ // In addition to correctly displaying text containing both RTL and LTR
+ // elements (for example, a string containing a telephone number within a
+ // sentence in Hebrew, or a sentence in Hebrew that contains a word in
+ // English) this flag also makes sure that if there is not enough space to
+ // display the entire string, the ellipsis is displayed on the left hand side
+ // of the truncated string and not on the right hand side.
+ //
+ // We make a distinction between Chrome UI strings and text coming from a web
+ // page.
+ //
+ // For text coming from a web page we determine the alignment based on the
+ // first character with strong directionality. If the directionality of the
+ // first character with strong directionality in the text is LTR, the
+ // alignment is set to DT_LEFT, and the directionality should not be set as
+ // DT_RTLREADING.
+ //
+ // This heuristic doesn't work for Chrome UI strings since even in RTL
+ // locales, some of those might start with English text but we know they're
+ // localized so we always want them to be right aligned, and their
+ // directionality should be set as DT_RTLREADING.
+ //
+ // Caveat: If the string is purely LTR, don't set DTL_RTLREADING since when
+ // the flag is set, LRE-PDF don't have the desired effect of rendering
+ // multiline English-only text as LTR.
+ //
+ // Note that if the caller is explicitly requesting displaying the text
+ // using RTL directionality then we respect that and pass DT_RTLREADING to
+ // ::DrawText even if the locale is LTR.
+ if ((flags & gfx::Canvas::FORCE_RTL_DIRECTIONALITY) ||
+ (base::i18n::IsRTL() &&
+ (f & DT_RIGHT) && base::i18n::StringContainsStrongRTLChars(text))) {
+ f |= DT_RTLREADING;
+ }
+
+ return f;
+}
+
+// TODO(msw): Use Uniscribe.
+// We make sure that LTR text we draw in an RTL context is modified
+// appropriately to make sure it maintains it LTR orientation.
+void DoDrawText(HDC hdc,
+ const string16& text,
+ RECT* text_bounds,
+ int flags) {
+ // Only adjust string directionality if both of the following are true:
+ // 1. The current locale is RTL.
+ // 2. The string itself has RTL directionality.
+ const wchar_t* string_ptr = text.c_str();
+ int string_size = static_cast<int>(text.length());
+
+ string16 localized_text;
+ if (flags & DT_RTLREADING) {
+ localized_text = text;
+ base::i18n::AdjustStringForLocaleDirection(&localized_text);
+ string_ptr = localized_text.c_str();
+ string_size = static_cast<int>(localized_text.length());
+ }
+
+ DrawText(hdc, string_ptr, string_size, text_bounds, flags);
+}
+
+} // namespace
+
+namespace gfx {
+
+RenderTextWin::RenderTextWin()
+ : RenderText() {
+}
+
+RenderTextWin::RenderTextWin(const string16& text,
+ const gfx::Font& font,
+ const SkColor& color,
+ const gfx::Rect display_rect,
+ int flags)
+ : RenderText(text, font, color, display_rect, flags) {
+}
+
+RenderTextWin::~RenderTextWin() {
+}
+
+void RenderTextWin::Draw(HDC drawing_context) const {
+ // TODO(msw): Use Uniscribe.
+ gfx::Rect r = get_display_rect();
+ RECT text_bounds = { r.x(), r.y(), r.x() + r.width(), r.y() + r.height() };
+ int flags = ComputeFormatFlags(get_flags(), text());
+ DoDrawText(drawing_context, text(), &text_bounds, flags);
+}
+
+size_t RenderTextWin::FindCursorPosition(const gfx::Point& point) const {
+ // TODO(msw): Use Uniscribe.
+ const gfx::Font& font = GetStyleRanges()[0]->font;
+ // TODO(msw): gfx::Insets insets = GetInsets();
+ int left = 0;
+ int left_pos = 0;
+ int right = font.GetStringWidth(text());
+ int right_pos = text().length();
+
+ int x = point.x(); // TODO(msw): - insets.left() - text_offset_;
+ if (x <= left) return left_pos;
+ if (x >= right) return right_pos;
+ // binary searching the cursor position.
+ // TODO(oshima): use the center of character instead of edge.
+ // Binary search may not work for language like arabic.
+ while (std::abs(static_cast<long>(right_pos - left_pos) > 1)) {
+ int pivot_pos = left_pos + (right_pos - left_pos) / 2;
+ int pivot = font.GetStringWidth(text().substr(0, pivot_pos));
+ if (pivot < x) {
+ left = pivot;
+ left_pos = pivot_pos;
+ } else if (pivot == x) {
+ return pivot_pos;
+ } else {
+ right = pivot;
+ right_pos = pivot_pos;
+ }
+ }
+ return left_pos;
+}
+
+std::vector<gfx::Rect> RenderTextWin::GetSubstringBounds(
+ const ui::Range& range) const {
+ // TODO(msw): Use Uniscribe.
+ size_t start = range.GetMin();
+ size_t end = range.GetMax();
+ const gfx::Font& font = GetStyleRanges()[0]->font;
+ int start_x = font.GetStringWidth(text().substr(0, start));
+ int end_x = font.GetStringWidth(text().substr(0, end));
+ std::vector<gfx::Rect> bounds;
+ bounds.push_back(gfx::Rect(start_x, 0, end_x - start_x, font.GetHeight()));
+ return bounds;
+}
+
+size_t RenderTextWin::GetLeftCursorPosition(size_t position,
+ bool move_by_word) const {
+ // TODO(msw): Use Uniscribe.
+ if (!move_by_word)
+ return position == 0? position : position - 1;
+ // Notes: We always iterate words from the begining.
+ // This is probably fast enough for our usage, but we may
+ // want to modify WordIterator so that it can start from the
+ // middle of string and advance backwards.
+ base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
+ bool success = iter.Init();
+ DCHECK(success);
+ if (!success)
+ return position;
+ int last = 0;
+ while (iter.Advance()) {
+ if (iter.IsWord()) {
+ size_t begin = iter.pos() - iter.GetString().length();
+ if (begin == position) {
+ // The cursor is at the beginning of a word.
+ // Move to previous word.
+ break;
+ } else if(iter.pos() >= position) {
+ // The cursor is in the middle or at the end of a word.
+ // Move to the top of current word.
+ last = begin;
+ break;
+ } else {
+ last = iter.pos() - iter.GetString().length();
+ }
+ }
+ }
+
+ return last;
+}
+
+size_t RenderTextWin::GetRightCursorPosition(size_t position,
+ bool move_by_word) const {
+ // TODO(msw): Use Uniscribe.
+ if (!move_by_word)
+ return std::min(position + 1, text().length());
+ base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
+ bool success = iter.Init();
+ DCHECK(success);
+ if (!success)
+ return position;
+ size_t pos = 0;
+ while (iter.Advance()) {
+ pos = iter.pos();
+ if (iter.IsWord() && pos > position) {
+ break;
+ }
+ }
+ return pos;
+}
+
+gfx::Rect RenderTextWin::GetCursorBounds(size_t position,
+ bool insert_mode) const {
+ // TODO(msw): Use Uniscribe.
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
+RenderText* RenderText::CreateRenderText() {
+ return new RenderTextWin;
+}
+
+RenderText* RenderText::CreateRenderText(const string16& text,
+ const gfx::Font& font,
+ const SkColor& color,
+ const gfx::Rect& display_rect,
+ int flags) {
+ return new RenderTextWin(text, font, color, display_rect, flags);
+}
+
+} // namespace gfx

Powered by Google App Engine
This is Rietveld 408576698