| 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
|
|
|