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

Side by Side 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, 5 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "ui/gfx/render_text_win.h"
6
7 // TODO(msw): Remove headers we're not using after Uniscribe impl...
8 #include "base/i18n/break_iterator.h"
9 #include "base/i18n/rtl.h"
10 #include "base/logging.h"
11 #include "ui/gfx/canvas.h"
12 #include "ui/gfx/canvas_skia.h"
13
14 namespace {
15
16 // TODO(msw): Remove this and use Uniscribe rendering.
17 // Compute the windows flags necessary to implement the provided text Canvas
18 // flags.
19 int ComputeFormatFlags(int flags, const string16& text) {
20 // Setting the text alignment explicitly in case it hasn't already been set.
21 // This will make sure that we don't align text to the left on RTL locales
22 // just because no alignment flag was passed to DrawStringInt().
23 if (!(flags & (gfx::Canvas::TEXT_ALIGN_CENTER |
24 gfx::Canvas::TEXT_ALIGN_RIGHT |
25 gfx::Canvas::TEXT_ALIGN_LEFT))) {
26 flags |= gfx::CanvasSkia::DefaultCanvasTextAlignment();
27 }
28
29 // horizontal alignment
30 int f = 0;
31 if (flags & gfx::Canvas::TEXT_ALIGN_CENTER)
32 f |= DT_CENTER;
33 else if (flags & gfx::Canvas::TEXT_ALIGN_RIGHT)
34 f |= DT_RIGHT;
35 else
36 f |= DT_LEFT;
37
38 // vertical alignment
39 if (flags & gfx::Canvas::TEXT_VALIGN_TOP)
40 f |= DT_TOP;
41 else if (flags & gfx::Canvas::TEXT_VALIGN_BOTTOM)
42 f |= DT_BOTTOM;
43 else
44 f |= DT_VCENTER;
45
46 if (flags & gfx::Canvas::MULTI_LINE) {
47 f |= DT_WORDBREAK;
48 if (flags & gfx::Canvas::CHARACTER_BREAK)
49 f |= DT_EDITCONTROL; // Turns on character breaking (not documented)
50 else if (!(flags & gfx::Canvas::NO_ELLIPSIS))
51 f |= DT_WORD_ELLIPSIS;
52 } else {
53 f |= DT_SINGLELINE;
54 }
55
56 if (flags & gfx::Canvas::HIDE_PREFIX)
57 f |= DT_HIDEPREFIX;
58 else if ((flags & gfx::Canvas::SHOW_PREFIX) == 0)
59 f |= DT_NOPREFIX;
60
61 if (!(flags & gfx::Canvas::NO_ELLIPSIS))
62 f |= DT_END_ELLIPSIS;
63
64 // In order to make sure RTL/BiDi strings are rendered correctly, we must
65 // pass the flag DT_RTLREADING to DrawText (when the locale's language is
66 // a right-to-left language) so that Windows does the right thing.
67 //
68 // In addition to correctly displaying text containing both RTL and LTR
69 // elements (for example, a string containing a telephone number within a
70 // sentence in Hebrew, or a sentence in Hebrew that contains a word in
71 // English) this flag also makes sure that if there is not enough space to
72 // display the entire string, the ellipsis is displayed on the left hand side
73 // of the truncated string and not on the right hand side.
74 //
75 // We make a distinction between Chrome UI strings and text coming from a web
76 // page.
77 //
78 // For text coming from a web page we determine the alignment based on the
79 // first character with strong directionality. If the directionality of the
80 // first character with strong directionality in the text is LTR, the
81 // alignment is set to DT_LEFT, and the directionality should not be set as
82 // DT_RTLREADING.
83 //
84 // This heuristic doesn't work for Chrome UI strings since even in RTL
85 // locales, some of those might start with English text but we know they're
86 // localized so we always want them to be right aligned, and their
87 // directionality should be set as DT_RTLREADING.
88 //
89 // Caveat: If the string is purely LTR, don't set DTL_RTLREADING since when
90 // the flag is set, LRE-PDF don't have the desired effect of rendering
91 // multiline English-only text as LTR.
92 //
93 // Note that if the caller is explicitly requesting displaying the text
94 // using RTL directionality then we respect that and pass DT_RTLREADING to
95 // ::DrawText even if the locale is LTR.
96 if ((flags & gfx::Canvas::FORCE_RTL_DIRECTIONALITY) ||
97 (base::i18n::IsRTL() &&
98 (f & DT_RIGHT) && base::i18n::StringContainsStrongRTLChars(text))) {
99 f |= DT_RTLREADING;
100 }
101
102 return f;
103 }
104
105 // TODO(msw): Use Uniscribe.
106 // We make sure that LTR text we draw in an RTL context is modified
107 // appropriately to make sure it maintains it LTR orientation.
108 void DoDrawText(HDC hdc,
109 const string16& text,
110 RECT* text_bounds,
111 int flags) {
112 // Only adjust string directionality if both of the following are true:
113 // 1. The current locale is RTL.
114 // 2. The string itself has RTL directionality.
115 const wchar_t* string_ptr = text.c_str();
116 int string_size = static_cast<int>(text.length());
117
118 string16 localized_text;
119 if (flags & DT_RTLREADING) {
120 localized_text = text;
121 base::i18n::AdjustStringForLocaleDirection(&localized_text);
122 string_ptr = localized_text.c_str();
123 string_size = static_cast<int>(localized_text.length());
124 }
125
126 DrawText(hdc, string_ptr, string_size, text_bounds, flags);
127 }
128
129 } // namespace
130
131 namespace gfx {
132
133 RenderTextWin::RenderTextWin()
134 : RenderText() {
135 }
136
137 RenderTextWin::RenderTextWin(const string16& text,
138 const gfx::Font& font,
139 const SkColor& color,
140 const gfx::Rect display_rect,
141 int flags)
142 : RenderText(text, font, color, display_rect, flags) {
143 }
144
145 RenderTextWin::~RenderTextWin() {
146 }
147
148 void RenderTextWin::Draw(HDC drawing_context) const {
149 // TODO(msw): Use Uniscribe.
150 gfx::Rect r = get_display_rect();
151 RECT text_bounds = { r.x(), r.y(), r.x() + r.width(), r.y() + r.height() };
152 int flags = ComputeFormatFlags(get_flags(), text());
153 DoDrawText(drawing_context, text(), &text_bounds, flags);
154 }
155
156 size_t RenderTextWin::FindCursorPosition(const gfx::Point& point) const {
157 // TODO(msw): Use Uniscribe.
158 const gfx::Font& font = GetStyleRanges()[0]->font;
159 // TODO(msw): gfx::Insets insets = GetInsets();
160 int left = 0;
161 int left_pos = 0;
162 int right = font.GetStringWidth(text());
163 int right_pos = text().length();
164
165 int x = point.x(); // TODO(msw): - insets.left() - text_offset_;
166 if (x <= left) return left_pos;
167 if (x >= right) return right_pos;
168 // binary searching the cursor position.
169 // TODO(oshima): use the center of character instead of edge.
170 // Binary search may not work for language like arabic.
171 while (std::abs(static_cast<long>(right_pos - left_pos) > 1)) {
172 int pivot_pos = left_pos + (right_pos - left_pos) / 2;
173 int pivot = font.GetStringWidth(text().substr(0, pivot_pos));
174 if (pivot < x) {
175 left = pivot;
176 left_pos = pivot_pos;
177 } else if (pivot == x) {
178 return pivot_pos;
179 } else {
180 right = pivot;
181 right_pos = pivot_pos;
182 }
183 }
184 return left_pos;
185 }
186
187 std::vector<gfx::Rect> RenderTextWin::GetSubstringBounds(
188 const ui::Range& range) const {
189 // TODO(msw): Use Uniscribe.
190 size_t start = range.GetMin();
191 size_t end = range.GetMax();
192 const gfx::Font& font = GetStyleRanges()[0]->font;
193 int start_x = font.GetStringWidth(text().substr(0, start));
194 int end_x = font.GetStringWidth(text().substr(0, end));
195 std::vector<gfx::Rect> bounds;
196 bounds.push_back(gfx::Rect(start_x, 0, end_x - start_x, font.GetHeight()));
197 return bounds;
198 }
199
200 size_t RenderTextWin::GetLeftCursorPosition(size_t position,
201 bool move_by_word) const {
202 // TODO(msw): Use Uniscribe.
203 if (!move_by_word)
204 return position == 0? position : position - 1;
205 // Notes: We always iterate words from the begining.
206 // This is probably fast enough for our usage, but we may
207 // want to modify WordIterator so that it can start from the
208 // middle of string and advance backwards.
209 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
210 bool success = iter.Init();
211 DCHECK(success);
212 if (!success)
213 return position;
214 int last = 0;
215 while (iter.Advance()) {
216 if (iter.IsWord()) {
217 size_t begin = iter.pos() - iter.GetString().length();
218 if (begin == position) {
219 // The cursor is at the beginning of a word.
220 // Move to previous word.
221 break;
222 } else if(iter.pos() >= position) {
223 // The cursor is in the middle or at the end of a word.
224 // Move to the top of current word.
225 last = begin;
226 break;
227 } else {
228 last = iter.pos() - iter.GetString().length();
229 }
230 }
231 }
232
233 return last;
234 }
235
236 size_t RenderTextWin::GetRightCursorPosition(size_t position,
237 bool move_by_word) const {
238 // TODO(msw): Use Uniscribe.
239 if (!move_by_word)
240 return std::min(position + 1, text().length());
241 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
242 bool success = iter.Init();
243 DCHECK(success);
244 if (!success)
245 return position;
246 size_t pos = 0;
247 while (iter.Advance()) {
248 pos = iter.pos();
249 if (iter.IsWord() && pos > position) {
250 break;
251 }
252 }
253 return pos;
254 }
255
256 gfx::Rect RenderTextWin::GetCursorBounds(size_t position,
257 bool insert_mode) const {
258 // TODO(msw): Use Uniscribe.
259 NOTIMPLEMENTED();
260 return gfx::Rect();
261 }
262
263 RenderText* RenderText::CreateRenderText() {
264 return new RenderTextWin;
265 }
266
267 RenderText* RenderText::CreateRenderText(const string16& text,
268 const gfx::Font& font,
269 const SkColor& color,
270 const gfx::Rect& display_rect,
271 int flags) {
272 return new RenderTextWin(text, font, color, display_rect, flags);
273 }
274
275 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698