OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <limits.h> | 5 #include <limits.h> |
6 #include <stddef.h> | 6 #include <stddef.h> |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 | 10 |
11 #include "base/i18n/rtl.h" | |
12 #include "base/logging.h" | |
13 #include "base/numerics/safe_conversions.h" | |
14 #include "build/build_config.h" | |
15 #include "third_party/skia/include/core/SkBitmap.h" | |
16 #include "third_party/skia/include/core/SkPixmap.h" | |
17 #include "ui/gfx/canvas.h" | 11 #include "ui/gfx/canvas.h" |
18 #include "ui/gfx/font_list.h" | |
19 #include "ui/gfx/geometry/insets.h" | 12 #include "ui/gfx/geometry/insets.h" |
20 #include "ui/gfx/geometry/rect.h" | |
21 #include "ui/gfx/range/range.h" | |
22 #include "ui/gfx/render_text.h" | 13 #include "ui/gfx/render_text.h" |
23 #include "ui/gfx/shadow_value.h" | |
24 #include "ui/gfx/skia_util.h" | 14 #include "ui/gfx/skia_util.h" |
25 #include "ui/gfx/text_elider.h" | 15 #include "ui/gfx/text_elider.h" |
26 #include "ui/gfx/text_utils.h" | 16 #include "ui/gfx/text_utils.h" |
27 | 17 |
28 namespace gfx { | 18 namespace gfx { |
29 | 19 |
30 namespace { | 20 namespace { |
31 | 21 |
32 // Checks each pixel immediately adjacent to the given pixel in the bitmap. If | |
33 // any of them are not the halo color, returns true. This defines the halo of | |
34 // pixels that will appear around the text. Note that we have to check each | |
35 // pixel against both the halo color and transparent since | |
36 // |DrawStringRectWithHalo| will modify the bitmap as it goes, and cleared | |
37 // pixels shouldn't count as changed. | |
38 bool PixelShouldGetHalo(const SkPixmap& pixmap, | |
39 int x, int y, | |
40 SkColor halo_color) { | |
41 if (x > 0 && | |
42 *pixmap.addr32(x - 1, y) != halo_color && | |
43 *pixmap.addr32(x - 1, y) != 0) | |
44 return true; // Touched pixel to the left. | |
45 if (x < pixmap.width() - 1 && | |
46 *pixmap.addr32(x + 1, y) != halo_color && | |
47 *pixmap.addr32(x + 1, y) != 0) | |
48 return true; // Touched pixel to the right. | |
49 if (y > 0 && | |
50 *pixmap.addr32(x, y - 1) != halo_color && | |
51 *pixmap.addr32(x, y - 1) != 0) | |
52 return true; // Touched pixel above. | |
53 if (y < pixmap.height() - 1 && | |
54 *pixmap.addr32(x, y + 1) != halo_color && | |
55 *pixmap.addr32(x, y + 1) != 0) | |
56 return true; // Touched pixel below. | |
57 return false; | |
58 } | |
59 | |
60 // Strips accelerator character prefixes in |text| if needed, based on |flags|. | 22 // Strips accelerator character prefixes in |text| if needed, based on |flags|. |
61 // Returns a range in |text| to underline or Range::InvalidRange() if | 23 // Returns a range in |text| to underline or Range::InvalidRange() if |
62 // underlining is not needed. | 24 // underlining is not needed. |
63 Range StripAcceleratorChars(int flags, base::string16* text) { | 25 Range StripAcceleratorChars(int flags, base::string16* text) { |
64 if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) { | 26 if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) { |
65 int char_pos = -1; | 27 int char_pos = -1; |
66 int char_span = 0; | 28 int char_span = 0; |
67 *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); | 29 *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); |
68 if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1) | 30 if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1) |
69 return Range(char_pos, char_pos + char_span); | 31 return Range(char_pos, char_pos + char_span); |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 Rect clip_rect(text_bounds); | 156 Rect clip_rect(text_bounds); |
195 clip_rect.Inset(ShadowValue::GetMargin(shadows)); | 157 clip_rect.Inset(ShadowValue::GetMargin(shadows)); |
196 | 158 |
197 canvas_->save(); | 159 canvas_->save(); |
198 ClipRect(clip_rect); | 160 ClipRect(clip_rect); |
199 | 161 |
200 Rect rect(text_bounds); | 162 Rect rect(text_bounds); |
201 | 163 |
202 std::unique_ptr<RenderText> render_text(RenderText::CreateInstance()); | 164 std::unique_ptr<RenderText> render_text(RenderText::CreateInstance()); |
203 render_text->set_shadows(shadows); | 165 render_text->set_shadows(shadows); |
| 166 render_text->set_halo_effect(!!(flags & HALO_EFFECT)); |
204 | 167 |
205 if (flags & MULTI_LINE) { | 168 if (flags & MULTI_LINE) { |
206 WordWrapBehavior wrap_behavior = IGNORE_LONG_WORDS; | 169 WordWrapBehavior wrap_behavior = IGNORE_LONG_WORDS; |
207 if (flags & CHARACTER_BREAK) | 170 if (flags & CHARACTER_BREAK) |
208 wrap_behavior = WRAP_LONG_WORDS; | 171 wrap_behavior = WRAP_LONG_WORDS; |
209 else if (!(flags & NO_ELLIPSIS)) | 172 else if (!(flags & NO_ELLIPSIS)) |
210 wrap_behavior = ELIDE_LONG_WORDS; | 173 wrap_behavior = ELIDE_LONG_WORDS; |
211 | 174 |
212 std::vector<base::string16> strings; | 175 std::vector<base::string16> strings; |
213 ElideRectangleText(text, font_list, | 176 ElideRectangleText(text, font_list, |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 void Canvas::DrawStringRectWithHalo(const base::string16& text, | 240 void Canvas::DrawStringRectWithHalo(const base::string16& text, |
278 const FontList& font_list, | 241 const FontList& font_list, |
279 SkColor text_color, | 242 SkColor text_color, |
280 SkColor halo_color_in, | 243 SkColor halo_color_in, |
281 const Rect& display_rect, | 244 const Rect& display_rect, |
282 int flags) { | 245 int flags) { |
283 // Some callers will have semitransparent halo colors, which we don't handle | 246 // Some callers will have semitransparent halo colors, which we don't handle |
284 // (since the resulting image can have 1-bit transparency only). | 247 // (since the resulting image can have 1-bit transparency only). |
285 SkColor halo_color = SkColorSetA(halo_color_in, 0xFF); | 248 SkColor halo_color = SkColorSetA(halo_color_in, 0xFF); |
286 | 249 |
287 // Create a temporary buffer filled with the halo color. It must leave room | 250 // Draw the halo. |
288 // for the 1-pixel border around the text. | 251 DrawStringRectWithFlags(text, font_list, halo_color, display_rect, |
289 Size size(display_rect.width() + 2, display_rect.height() + 2); | 252 flags | HALO_EFFECT | NO_SUBPIXEL_RENDERING); |
290 Canvas text_canvas(size, image_scale(), false); | 253 // Draw the text. |
291 SkPaint bkgnd_paint; | 254 DrawStringRectWithFlags(text, font_list, text_color, display_rect, |
292 bkgnd_paint.setColor(halo_color); | 255 flags | NO_SUBPIXEL_RENDERING); |
293 text_canvas.DrawRect(Rect(size), bkgnd_paint); | |
294 | |
295 // Draw the text into the temporary buffer. This will have correct | |
296 // ClearType since the background color is the same as the halo color. | |
297 text_canvas.DrawStringRectWithFlags( | |
298 text, font_list, text_color, | |
299 Rect(1, 1, display_rect.width(), display_rect.height()), flags); | |
300 | |
301 uint32_t halo_premul = SkPreMultiplyColor(halo_color); | |
302 SkPixmap pixmap; | |
303 skia::GetWritablePixels(text_canvas.sk_canvas(), &pixmap); | |
304 | |
305 for (int cur_y = 0; cur_y < pixmap.height(); cur_y++) { | |
306 uint32_t* text_row = pixmap.writable_addr32(0, cur_y); | |
307 for (int cur_x = 0; cur_x < pixmap.width(); cur_x++) { | |
308 if (text_row[cur_x] == halo_premul) { | |
309 // This pixel was not touched by the text routines. See if it borders | |
310 // a touched pixel in any of the 4 directions (not diagonally). | |
311 if (!PixelShouldGetHalo(pixmap, cur_x, cur_y, halo_premul)) | |
312 text_row[cur_x] = 0; // Make transparent. | |
313 } else { | |
314 text_row[cur_x] |= 0xff << SK_A32_SHIFT; // Make opaque. | |
315 } | |
316 } | |
317 } | |
318 | |
319 // Draw the halo bitmap with blur. | |
320 SkBitmap bitmap; | |
321 bitmap.installPixels(pixmap.info(), pixmap.writable_addr(), | |
322 pixmap.rowBytes()); | |
323 ImageSkia text_image = ImageSkia(ImageSkiaRep(bitmap, | |
324 text_canvas.image_scale())); | |
325 DrawImageInt(text_image, display_rect.x() - 1, display_rect.y() - 1); | |
326 } | 256 } |
327 | 257 |
328 void Canvas::DrawFadedString(const base::string16& text, | 258 void Canvas::DrawFadedString(const base::string16& text, |
329 const FontList& font_list, | 259 const FontList& font_list, |
330 SkColor color, | 260 SkColor color, |
331 const Rect& display_rect, | 261 const Rect& display_rect, |
332 int flags) { | 262 int flags) { |
333 // If the whole string fits in the destination then just draw it directly. | 263 // If the whole string fits in the destination then just draw it directly. |
334 if (GetStringWidth(text, font_list) <= display_rect.width()) { | 264 if (GetStringWidth(text, font_list) <= display_rect.width()) { |
335 DrawStringRectWithFlags(text, font_list, color, display_rect, flags); | 265 DrawStringRectWithFlags(text, font_list, color, display_rect, flags); |
(...skipping 10 matching lines...) Expand all Loading... |
346 UpdateRenderText(rect, text, font_list, flags, color, render_text.get()); | 276 UpdateRenderText(rect, text, font_list, flags, color, render_text.get()); |
347 render_text->SetElideBehavior(FADE_TAIL); | 277 render_text->SetElideBehavior(FADE_TAIL); |
348 | 278 |
349 canvas_->save(); | 279 canvas_->save(); |
350 ClipRect(display_rect); | 280 ClipRect(display_rect); |
351 render_text->Draw(this); | 281 render_text->Draw(this); |
352 canvas_->restore(); | 282 canvas_->restore(); |
353 } | 283 } |
354 | 284 |
355 } // namespace gfx | 285 } // namespace gfx |
OLD | NEW |