| 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 "ui/gfx/canvas.h" | 5 #include "ui/gfx/canvas.h" |
| 6 | 6 |
| 7 #include "base/i18n/rtl.h" | 7 #include "base/i18n/rtl.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
| 10 #include "ui/base/range/range.h" | 10 #include "ui/base/range/range.h" |
| 11 #include "ui/base/text/text_elider.h" | 11 #include "ui/base/text/text_elider.h" |
| 12 #include "ui/gfx/font.h" | |
| 13 #include "ui/gfx/font_list.h" | 12 #include "ui/gfx/font_list.h" |
| 14 #include "ui/gfx/insets.h" | 13 #include "ui/gfx/insets.h" |
| 15 #include "ui/gfx/rect.h" | 14 #include "ui/gfx/rect.h" |
| 16 #include "ui/gfx/render_text.h" | 15 #include "ui/gfx/render_text.h" |
| 17 #include "ui/gfx/shadow_value.h" | 16 #include "ui/gfx/shadow_value.h" |
| 18 #include "ui/gfx/text_utils.h" | 17 #include "ui/gfx/text_utils.h" |
| 19 | 18 |
| 20 namespace gfx { | 19 namespace gfx { |
| 21 | 20 |
| 22 namespace { | 21 namespace { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 50 // default directionality is LTR, so the text doesn't need to be wrapped. | 49 // default directionality is LTR, so the text doesn't need to be wrapped. |
| 51 // Note that individual runs within the string may still be rendered RTL | 50 // Note that individual runs within the string may still be rendered RTL |
| 52 // (which will be the case for RTL text under non-RTL locales, since under RTL | 51 // (which will be the case for RTL text under non-RTL locales, since under RTL |
| 53 // locales it will be handled by the if statement above). | 52 // locales it will be handled by the if statement above). |
| 54 return false; | 53 return false; |
| 55 } | 54 } |
| 56 | 55 |
| 57 // Checks each pixel immediately adjacent to the given pixel in the bitmap. If | 56 // Checks each pixel immediately adjacent to the given pixel in the bitmap. If |
| 58 // any of them are not the halo color, returns true. This defines the halo of | 57 // any of them are not the halo color, returns true. This defines the halo of |
| 59 // pixels that will appear around the text. Note that we have to check each | 58 // pixels that will appear around the text. Note that we have to check each |
| 60 // pixel against both the halo color and transparent since |DrawStringWithHalo| | 59 // pixel against both the halo color and transparent since |
| 61 // will modify the bitmap as it goes, and cleared pixels shouldn't count as | 60 // |DrawStringWithHaloRect| will modify the bitmap as it goes, and cleared |
| 62 // changed. | 61 // pixels shouldn't count as changed. |
| 63 bool PixelShouldGetHalo(const SkBitmap& bitmap, | 62 bool PixelShouldGetHalo(const SkBitmap& bitmap, |
| 64 int x, int y, | 63 int x, int y, |
| 65 SkColor halo_color) { | 64 SkColor halo_color) { |
| 66 if (x > 0 && | 65 if (x > 0 && |
| 67 *bitmap.getAddr32(x - 1, y) != halo_color && | 66 *bitmap.getAddr32(x - 1, y) != halo_color && |
| 68 *bitmap.getAddr32(x - 1, y) != 0) | 67 *bitmap.getAddr32(x - 1, y) != 0) |
| 69 return true; // Touched pixel to the left. | 68 return true; // Touched pixel to the left. |
| 70 if (x < bitmap.width() - 1 && | 69 if (x < bitmap.width() - 1 && |
| 71 *bitmap.getAddr32(x + 1, y) != halo_color && | 70 *bitmap.getAddr32(x + 1, y) != halo_color && |
| 72 *bitmap.getAddr32(x + 1, y) != 0) | 71 *bitmap.getAddr32(x + 1, y) != 0) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 91 int char_span = 0; | 90 int char_span = 0; |
| 92 *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); | 91 *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); |
| 93 if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1) | 92 if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1) |
| 94 return ui::Range(char_pos, char_pos + char_span); | 93 return ui::Range(char_pos, char_pos + char_span); |
| 95 } | 94 } |
| 96 return ui::Range::InvalidRange(); | 95 return ui::Range::InvalidRange(); |
| 97 } | 96 } |
| 98 | 97 |
| 99 // Elides |text| and adjusts |range| appropriately. If eliding causes |range| | 98 // Elides |text| and adjusts |range| appropriately. If eliding causes |range| |
| 100 // to no longer point to the same character in |text|, |range| is made invalid. | 99 // to no longer point to the same character in |text|, |range| is made invalid. |
| 101 void ElideTextAndAdjustRange(const Font& font, | 100 void ElideTextAndAdjustRange(const FontList& font_list, |
| 102 int width, | 101 int width, |
| 103 base::string16* text, | 102 base::string16* text, |
| 104 ui::Range* range) { | 103 ui::Range* range) { |
| 105 const base::char16 start_char = | 104 const base::char16 start_char = |
| 106 (range->IsValid() ? text->at(range->start()) : 0); | 105 (range->IsValid() ? text->at(range->start()) : 0); |
| 107 *text = ui::ElideText(*text, font, width, ui::ELIDE_AT_END); | 106 *text = ui::ElideText(*text, font_list, width, ui::ELIDE_AT_END); |
| 108 if (!range->IsValid()) | 107 if (!range->IsValid()) |
| 109 return; | 108 return; |
| 110 if (range->start() >= text->length() || | 109 if (range->start() >= text->length() || |
| 111 text->at(range->start()) != start_char) { | 110 text->at(range->start()) != start_char) { |
| 112 *range = ui::Range::InvalidRange(); | 111 *range = ui::Range::InvalidRange(); |
| 113 } | 112 } |
| 114 } | 113 } |
| 115 | 114 |
| 116 // Updates |render_text| from the specified parameters. | 115 // Updates |render_text| from the specified parameters. |
| 117 void UpdateRenderText(const Rect& rect, | 116 void UpdateRenderText(const Rect& rect, |
| 118 const base::string16& text, | 117 const base::string16& text, |
| 119 const Font& font, | 118 const FontList& font_list, |
| 120 int flags, | 119 int flags, |
| 121 SkColor color, | 120 SkColor color, |
| 122 RenderText* render_text) { | 121 RenderText* render_text) { |
| 123 render_text->SetFont(font); | 122 render_text->SetFontList(font_list); |
| 124 render_text->SetText(text); | 123 render_text->SetText(text); |
| 125 render_text->SetCursorEnabled(false); | 124 render_text->SetCursorEnabled(false); |
| 126 | 125 |
| 127 Rect display_rect = rect; | 126 Rect display_rect = rect; |
| 128 display_rect.set_height(font.GetHeight()); | 127 display_rect.set_height(font_list.GetHeight()); |
| 129 render_text->SetDisplayRect(display_rect); | 128 render_text->SetDisplayRect(display_rect); |
| 130 | 129 |
| 131 // Set the text alignment explicitly based on the directionality of the UI, | 130 // Set the text alignment explicitly based on the directionality of the UI, |
| 132 // if not specified. | 131 // if not specified. |
| 133 if (!(flags & (Canvas::TEXT_ALIGN_CENTER | | 132 if (!(flags & (Canvas::TEXT_ALIGN_CENTER | |
| 134 Canvas::TEXT_ALIGN_RIGHT | | 133 Canvas::TEXT_ALIGN_RIGHT | |
| 135 Canvas::TEXT_ALIGN_LEFT))) { | 134 Canvas::TEXT_ALIGN_LEFT))) { |
| 136 flags |= Canvas::DefaultCanvasTextAlignment(); | 135 flags |= Canvas::DefaultCanvasTextAlignment(); |
| 137 } | 136 } |
| 138 | 137 |
| 139 if (flags & Canvas::TEXT_ALIGN_RIGHT) | 138 if (flags & Canvas::TEXT_ALIGN_RIGHT) |
| 140 render_text->SetHorizontalAlignment(ALIGN_RIGHT); | 139 render_text->SetHorizontalAlignment(ALIGN_RIGHT); |
| 141 else if (flags & Canvas::TEXT_ALIGN_CENTER) | 140 else if (flags & Canvas::TEXT_ALIGN_CENTER) |
| 142 render_text->SetHorizontalAlignment(ALIGN_CENTER); | 141 render_text->SetHorizontalAlignment(ALIGN_CENTER); |
| 143 else | 142 else |
| 144 render_text->SetHorizontalAlignment(ALIGN_LEFT); | 143 render_text->SetHorizontalAlignment(ALIGN_LEFT); |
| 145 | 144 |
| 146 if (flags & Canvas::NO_SUBPIXEL_RENDERING) | 145 if (flags & Canvas::NO_SUBPIXEL_RENDERING) |
| 147 render_text->set_background_is_transparent(true); | 146 render_text->set_background_is_transparent(true); |
| 148 | 147 |
| 149 render_text->SetColor(color); | 148 render_text->SetColor(color); |
| 150 render_text->SetStyle(BOLD, (font.GetStyle() & Font::BOLD) != 0); | 149 const int font_style = font_list.GetFontStyle(); |
| 151 render_text->SetStyle(ITALIC, (font.GetStyle() & Font::ITALIC) != 0); | 150 render_text->SetStyle(BOLD, (font_style & Font::BOLD) != 0); |
| 152 render_text->SetStyle(UNDERLINE, (font.GetStyle() & Font::UNDERLINE) != 0); | 151 render_text->SetStyle(ITALIC, (font_style & Font::ITALIC) != 0); |
| 152 render_text->SetStyle(UNDERLINE, (font_style & Font::UNDERLINE) != 0); |
| 153 } | 153 } |
| 154 | 154 |
| 155 // Returns updated |flags| to match platform-specific expected behavior. | 155 // Returns updated |flags| to match platform-specific expected behavior. |
| 156 int AdjustPlatformSpecificFlags(const base::string16& text, int flags) { | 156 int AdjustPlatformSpecificFlags(const base::string16& text, int flags) { |
| 157 #if defined(OS_LINUX) | 157 #if defined(OS_LINUX) |
| 158 // TODO(asvitkine): ash/tooltips/tooltip_controller.cc adds \n's to the string | 158 // TODO(asvitkine): ash/tooltips/tooltip_controller.cc adds \n's to the string |
| 159 // without passing MULTI_LINE. | 159 // without passing MULTI_LINE. |
| 160 if (text.find('\n') != base::string16::npos) | 160 if (text.find('\n') != base::string16::npos) |
| 161 flags |= Canvas::MULTI_LINE; | 161 flags |= Canvas::MULTI_LINE; |
| 162 #endif | 162 #endif |
| 163 | 163 |
| 164 return flags; | 164 return flags; |
| 165 } | 165 } |
| 166 | 166 |
| 167 } // namespace | 167 } // namespace |
| 168 | 168 |
| 169 // static | 169 // static |
| 170 void Canvas::SizeStringInt(const base::string16& text, | 170 void Canvas::SizeStringInt(const base::string16& text, |
| 171 const Font& font, | 171 const FontList& font_list, |
| 172 int* width, int* height, | 172 int* width, int* height, |
| 173 int line_height, | 173 int line_height, |
| 174 int flags) { | 174 int flags) { |
| 175 DCHECK_GE(*width, 0); | 175 DCHECK_GE(*width, 0); |
| 176 DCHECK_GE(*height, 0); | 176 DCHECK_GE(*height, 0); |
| 177 | 177 |
| 178 flags = AdjustPlatformSpecificFlags(text, flags); | 178 flags = AdjustPlatformSpecificFlags(text, flags); |
| 179 | 179 |
| 180 base::string16 adjusted_text = text; | 180 base::string16 adjusted_text = text; |
| 181 #if defined(OS_WIN) | 181 #if defined(OS_WIN) |
| 182 AdjustStringDirection(flags, &adjusted_text); | 182 AdjustStringDirection(flags, &adjusted_text); |
| 183 #endif | 183 #endif |
| 184 | 184 |
| 185 if ((flags & MULTI_LINE) && *width != 0) { | 185 if ((flags & MULTI_LINE) && *width != 0) { |
| 186 ui::WordWrapBehavior wrap_behavior = ui::TRUNCATE_LONG_WORDS; | 186 ui::WordWrapBehavior wrap_behavior = ui::TRUNCATE_LONG_WORDS; |
| 187 if (flags & CHARACTER_BREAK) | 187 if (flags & CHARACTER_BREAK) |
| 188 wrap_behavior = ui::WRAP_LONG_WORDS; | 188 wrap_behavior = ui::WRAP_LONG_WORDS; |
| 189 else if (!(flags & NO_ELLIPSIS)) | 189 else if (!(flags & NO_ELLIPSIS)) |
| 190 wrap_behavior = ui::ELIDE_LONG_WORDS; | 190 wrap_behavior = ui::ELIDE_LONG_WORDS; |
| 191 | 191 |
| 192 Rect rect(*width, INT_MAX); | 192 Rect rect(*width, INT_MAX); |
| 193 std::vector<base::string16> strings; | 193 std::vector<base::string16> strings; |
| 194 ui::ElideRectangleText(adjusted_text, font, rect.width(), rect.height(), | 194 ui::ElideRectangleText(adjusted_text, font_list, |
| 195 rect.width(), rect.height(), |
| 195 wrap_behavior, &strings); | 196 wrap_behavior, &strings); |
| 196 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 197 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
| 197 UpdateRenderText(rect, base::string16(), font, flags, 0, render_text.get()); | 198 UpdateRenderText(rect, base::string16(), font_list, flags, 0, |
| 199 render_text.get()); |
| 198 | 200 |
| 199 int h = 0; | 201 int h = 0; |
| 200 int w = 0; | 202 int w = 0; |
| 201 for (size_t i = 0; i < strings.size(); ++i) { | 203 for (size_t i = 0; i < strings.size(); ++i) { |
| 202 StripAcceleratorChars(flags, &strings[i]); | 204 StripAcceleratorChars(flags, &strings[i]); |
| 203 render_text->SetText(strings[i]); | 205 render_text->SetText(strings[i]); |
| 204 const Size string_size = render_text->GetStringSize(); | 206 const Size& string_size = render_text->GetStringSize(); |
| 205 w = std::max(w, string_size.width()); | 207 w = std::max(w, string_size.width()); |
| 206 h += (i > 0 && line_height > 0) ? line_height : string_size.height(); | 208 h += (i > 0 && line_height > 0) ? line_height : string_size.height(); |
| 207 } | 209 } |
| 208 *width = w; | 210 *width = w; |
| 209 *height = h; | 211 *height = h; |
| 210 } else { | 212 } else { |
| 211 // If the string is too long, the call by |RenderTextWin| to |ScriptShape()| | 213 // If the string is too long, the call by |RenderTextWin| to |ScriptShape()| |
| 212 // will inexplicably fail with result E_INVALIDARG. Guard against this. | 214 // will inexplicably fail with result E_INVALIDARG. Guard against this. |
| 213 const size_t kMaxRenderTextLength = 5000; | 215 const size_t kMaxRenderTextLength = 5000; |
| 214 if (adjusted_text.length() >= kMaxRenderTextLength) { | 216 if (adjusted_text.length() >= kMaxRenderTextLength) { |
| 215 *width = adjusted_text.length() * font.GetAverageCharacterWidth(); | 217 *width = font_list.GetExpectedTextWidth(adjusted_text.length()); |
| 216 *height = font.GetHeight(); | 218 *height = font_list.GetHeight(); |
| 217 } else { | 219 } else { |
| 218 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 220 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
| 219 Rect rect(*width, *height); | 221 Rect rect(*width, *height); |
| 220 StripAcceleratorChars(flags, &adjusted_text); | 222 StripAcceleratorChars(flags, &adjusted_text); |
| 221 UpdateRenderText(rect, adjusted_text, font, flags, 0, render_text.get()); | 223 UpdateRenderText(rect, adjusted_text, font_list, flags, 0, |
| 222 const Size string_size = render_text->GetStringSize(); | 224 render_text.get()); |
| 225 const Size& string_size = render_text->GetStringSize(); |
| 223 *width = string_size.width(); | 226 *width = string_size.width(); |
| 224 *height = string_size.height(); | 227 *height = string_size.height(); |
| 225 } | 228 } |
| 226 } | 229 } |
| 227 } | 230 } |
| 228 | 231 |
| 229 void Canvas::DrawStringWithShadows(const base::string16& text, | 232 void Canvas::DrawStringWithShadowsRect(const base::string16& text, |
| 230 const Font& font, | 233 const FontList& font_list, |
| 231 SkColor color, | 234 SkColor color, |
| 232 const Rect& text_bounds, | 235 const Rect& text_bounds, |
| 233 int line_height, | 236 int line_height, |
| 234 int flags, | 237 int flags, |
| 235 const ShadowValues& shadows) { | 238 const ShadowValues& shadows) { |
| 236 if (!IntersectsClipRect(text_bounds)) | 239 if (!IntersectsClipRect(text_bounds)) |
| 237 return; | 240 return; |
| 238 | 241 |
| 239 flags = AdjustPlatformSpecificFlags(text, flags); | 242 flags = AdjustPlatformSpecificFlags(text, flags); |
| 240 | 243 |
| 241 Rect clip_rect(text_bounds); | 244 Rect clip_rect(text_bounds); |
| 242 clip_rect.Inset(ShadowValue::GetMargin(shadows)); | 245 clip_rect.Inset(ShadowValue::GetMargin(shadows)); |
| 243 | 246 |
| 244 canvas_->save(SkCanvas::kClip_SaveFlag); | 247 canvas_->save(SkCanvas::kClip_SaveFlag); |
| 245 ClipRect(clip_rect); | 248 ClipRect(clip_rect); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 256 | 259 |
| 257 if (flags & MULTI_LINE) { | 260 if (flags & MULTI_LINE) { |
| 258 ui::WordWrapBehavior wrap_behavior = ui::IGNORE_LONG_WORDS; | 261 ui::WordWrapBehavior wrap_behavior = ui::IGNORE_LONG_WORDS; |
| 259 if (flags & CHARACTER_BREAK) | 262 if (flags & CHARACTER_BREAK) |
| 260 wrap_behavior = ui::WRAP_LONG_WORDS; | 263 wrap_behavior = ui::WRAP_LONG_WORDS; |
| 261 else if (!(flags & NO_ELLIPSIS)) | 264 else if (!(flags & NO_ELLIPSIS)) |
| 262 wrap_behavior = ui::ELIDE_LONG_WORDS; | 265 wrap_behavior = ui::ELIDE_LONG_WORDS; |
| 263 | 266 |
| 264 std::vector<base::string16> strings; | 267 std::vector<base::string16> strings; |
| 265 ui::ElideRectangleText(adjusted_text, | 268 ui::ElideRectangleText(adjusted_text, |
| 266 font, | 269 font_list, |
| 267 text_bounds.width(), text_bounds.height(), | 270 text_bounds.width(), text_bounds.height(), |
| 268 wrap_behavior, | 271 wrap_behavior, |
| 269 &strings); | 272 &strings); |
| 270 | 273 |
| 271 for (size_t i = 0; i < strings.size(); i++) { | 274 for (size_t i = 0; i < strings.size(); i++) { |
| 272 ui::Range range = StripAcceleratorChars(flags, &strings[i]); | 275 ui::Range range = StripAcceleratorChars(flags, &strings[i]); |
| 273 UpdateRenderText(rect, strings[i], font, flags, color, render_text.get()); | 276 UpdateRenderText(rect, strings[i], font_list, flags, color, |
| 277 render_text.get()); |
| 274 int line_padding = 0; | 278 int line_padding = 0; |
| 275 if (line_height > 0) | 279 if (line_height > 0) |
| 276 line_padding = line_height - render_text->GetStringSize().height(); | 280 line_padding = line_height - render_text->GetStringSize().height(); |
| 277 else | 281 else |
| 278 line_height = render_text->GetStringSize().height(); | 282 line_height = render_text->GetStringSize().height(); |
| 279 | 283 |
| 280 // TODO(msw|asvitkine): Center Windows multi-line text: crbug.com/107357 | 284 // TODO(msw|asvitkine): Center Windows multi-line text: crbug.com/107357 |
| 281 #if !defined(OS_WIN) | 285 #if !defined(OS_WIN) |
| 282 if (i == 0) { | 286 if (i == 0) { |
| 283 // TODO(msw|asvitkine): Support multi-line text with varied heights. | 287 // TODO(msw|asvitkine): Support multi-line text with varied heights. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 304 if (elide_text) { | 308 if (elide_text) { |
| 305 render_text->SetText(adjusted_text); | 309 render_text->SetText(adjusted_text); |
| 306 if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { | 310 if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { |
| 307 render_text->set_fade_tail(true); | 311 render_text->set_fade_tail(true); |
| 308 elide_text = false; | 312 elide_text = false; |
| 309 } | 313 } |
| 310 } | 314 } |
| 311 #endif | 315 #endif |
| 312 | 316 |
| 313 if (elide_text) { | 317 if (elide_text) { |
| 314 ElideTextAndAdjustRange(font, | 318 ElideTextAndAdjustRange(font_list, |
| 315 text_bounds.width(), | 319 text_bounds.width(), |
| 316 &adjusted_text, | 320 &adjusted_text, |
| 317 &range); | 321 &range); |
| 318 } | 322 } |
| 319 | 323 |
| 320 UpdateRenderText(rect, adjusted_text, font, flags, color, | 324 UpdateRenderText(rect, adjusted_text, font_list, flags, color, |
| 321 render_text.get()); | 325 render_text.get()); |
| 322 | 326 |
| 323 const int text_height = render_text->GetStringSize().height(); | 327 const int text_height = render_text->GetStringSize().height(); |
| 324 // Center the text vertically. | 328 // Center the text vertically. |
| 325 rect += Vector2d(0, (text_bounds.height() - text_height) / 2); | 329 rect += Vector2d(0, (text_bounds.height() - text_height) / 2); |
| 326 rect.set_height(text_height); | 330 rect.set_height(text_height); |
| 327 render_text->SetDisplayRect(rect); | 331 render_text->SetDisplayRect(rect); |
| 328 if (range.IsValid()) | 332 if (range.IsValid()) |
| 329 render_text->ApplyStyle(UNDERLINE, true, range); | 333 render_text->ApplyStyle(UNDERLINE, true, range); |
| 330 render_text->Draw(this); | 334 render_text->Draw(this); |
| 331 } | 335 } |
| 332 | 336 |
| 333 canvas_->restore(); | 337 canvas_->restore(); |
| 334 } | 338 } |
| 335 | 339 |
| 336 void Canvas::DrawStringWithHalo(const base::string16& text, | 340 void Canvas::DrawStringWithHaloRect(const base::string16& text, |
| 337 const Font& font, | 341 const FontList& font_list, |
| 338 SkColor text_color, | 342 SkColor text_color, |
| 339 SkColor halo_color_in, | 343 SkColor halo_color_in, |
| 340 int x, int y, int w, int h, | 344 const Rect& display_rect, |
| 341 int flags) { | 345 int flags) { |
| 342 // Some callers will have semitransparent halo colors, which we don't handle | 346 // Some callers will have semitransparent halo colors, which we don't handle |
| 343 // (since the resulting image can have 1-bit transparency only). | 347 // (since the resulting image can have 1-bit transparency only). |
| 344 SkColor halo_color = SkColorSetA(halo_color_in, 0xFF); | 348 SkColor halo_color = SkColorSetA(halo_color_in, 0xFF); |
| 345 | 349 |
| 346 // Create a temporary buffer filled with the halo color. It must leave room | 350 // Create a temporary buffer filled with the halo color. It must leave room |
| 347 // for the 1-pixel border around the text. | 351 // for the 1-pixel border around the text. |
| 348 Size size(w + 2, h + 2); | 352 Size size(display_rect.width() + 2, display_rect.height() + 2); |
| 349 Canvas text_canvas(size, scale_factor(), true); | 353 Canvas text_canvas(size, scale_factor(), true); |
| 350 SkPaint bkgnd_paint; | 354 SkPaint bkgnd_paint; |
| 351 bkgnd_paint.setColor(halo_color); | 355 bkgnd_paint.setColor(halo_color); |
| 352 text_canvas.DrawRect(Rect(size), bkgnd_paint); | 356 text_canvas.DrawRect(Rect(size), bkgnd_paint); |
| 353 | 357 |
| 354 // Draw the text into the temporary buffer. This will have correct | 358 // Draw the text into the temporary buffer. This will have correct |
| 355 // ClearType since the background color is the same as the halo color. | 359 // ClearType since the background color is the same as the halo color. |
| 356 text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags); | 360 text_canvas.DrawStringWithFlagsRect( |
| 361 text, font_list, text_color, |
| 362 Rect(1, 1, display_rect.width(), display_rect.height()), flags); |
| 357 | 363 |
| 358 uint32_t halo_premul = SkPreMultiplyColor(halo_color); | 364 uint32_t halo_premul = SkPreMultiplyColor(halo_color); |
| 359 SkBitmap& text_bitmap = const_cast<SkBitmap&>( | 365 SkBitmap& text_bitmap = const_cast<SkBitmap&>( |
| 360 skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(true)); | 366 skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(true)); |
| 361 | 367 |
| 362 for (int cur_y = 0; cur_y < text_bitmap.height(); cur_y++) { | 368 for (int cur_y = 0; cur_y < text_bitmap.height(); cur_y++) { |
| 363 uint32_t* text_row = text_bitmap.getAddr32(0, cur_y); | 369 uint32_t* text_row = text_bitmap.getAddr32(0, cur_y); |
| 364 for (int cur_x = 0; cur_x < text_bitmap.width(); cur_x++) { | 370 for (int cur_x = 0; cur_x < text_bitmap.width(); cur_x++) { |
| 365 if (text_row[cur_x] == halo_premul) { | 371 if (text_row[cur_x] == halo_premul) { |
| 366 // This pixel was not touched by the text routines. See if it borders | 372 // This pixel was not touched by the text routines. See if it borders |
| 367 // a touched pixel in any of the 4 directions (not diagonally). | 373 // a touched pixel in any of the 4 directions (not diagonally). |
| 368 if (!PixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul)) | 374 if (!PixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul)) |
| 369 text_row[cur_x] = 0; // Make transparent. | 375 text_row[cur_x] = 0; // Make transparent. |
| 370 } else { | 376 } else { |
| 371 text_row[cur_x] |= 0xff << SK_A32_SHIFT; // Make opaque. | 377 text_row[cur_x] |= 0xff << SK_A32_SHIFT; // Make opaque. |
| 372 } | 378 } |
| 373 } | 379 } |
| 374 } | 380 } |
| 375 | 381 |
| 376 // Draw the halo bitmap with blur. | 382 // Draw the halo bitmap with blur. |
| 377 ImageSkia text_image = ImageSkia(ImageSkiaRep(text_bitmap, | 383 ImageSkia text_image = ImageSkia(ImageSkiaRep(text_bitmap, |
| 378 text_canvas.scale_factor())); | 384 text_canvas.scale_factor())); |
| 379 DrawImageInt(text_image, x - 1, y - 1); | 385 DrawImageInt(text_image, display_rect.x() - 1, display_rect.y() - 1); |
| 380 } | 386 } |
| 381 | 387 |
| 382 void Canvas::DrawFadeTruncatingString( | 388 void Canvas::DrawFadeTruncatingStringRect( |
| 383 const base::string16& text, | 389 const base::string16& text, |
| 384 TruncateFadeMode truncate_mode, | 390 TruncateFadeMode truncate_mode, |
| 385 size_t desired_characters_to_truncate_from_head, | 391 size_t desired_characters_to_truncate_from_head, |
| 386 const Font& font, | 392 const FontList& font_list, |
| 387 SkColor color, | 393 SkColor color, |
| 388 const Rect& display_rect) { | 394 const Rect& display_rect) { |
| 389 int flags = NO_ELLIPSIS; | 395 int flags = NO_ELLIPSIS; |
| 390 | 396 |
| 391 // If the whole string fits in the destination then just draw it directly. | 397 // If the whole string fits in the destination then just draw it directly. |
| 392 if (GetStringWidth(text, font) <= display_rect.width()) { | 398 if (GetStringWidth(text, font_list) <= display_rect.width()) { |
| 393 DrawStringInt(text, font, color, display_rect.x(), display_rect.y(), | 399 DrawStringWithFlagsRect(text, font_list, color, display_rect, flags); |
| 394 display_rect.width(), display_rect.height(), flags); | |
| 395 return; | 400 return; |
| 396 } | 401 } |
| 397 | 402 |
| 398 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 403 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
| 399 base::string16 clipped_text = text; | 404 base::string16 clipped_text = text; |
| 400 const bool is_rtl = AdjustStringDirection(flags, &clipped_text); | 405 const bool is_rtl = AdjustStringDirection(flags, &clipped_text); |
| 401 | 406 |
| 402 switch (truncate_mode) { | 407 switch (truncate_mode) { |
| 403 case TruncateFadeTail: | 408 case TruncateFadeTail: |
| 404 render_text->set_fade_tail(true); | 409 render_text->set_fade_tail(true); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 430 render_text->set_fade_tail(true); | 435 render_text->set_fade_tail(true); |
| 431 render_text->set_fade_head(true); | 436 render_text->set_fade_head(true); |
| 432 break; | 437 break; |
| 433 } | 438 } |
| 434 | 439 |
| 435 // Default to left alignment unless right alignment was chosen above. | 440 // Default to left alignment unless right alignment was chosen above. |
| 436 if (!(flags & TEXT_ALIGN_RIGHT)) | 441 if (!(flags & TEXT_ALIGN_RIGHT)) |
| 437 flags |= TEXT_ALIGN_LEFT; | 442 flags |= TEXT_ALIGN_LEFT; |
| 438 | 443 |
| 439 Rect rect = display_rect; | 444 Rect rect = display_rect; |
| 440 UpdateRenderText(rect, clipped_text, font, flags, color, render_text.get()); | 445 UpdateRenderText(rect, clipped_text, font_list, flags, color, |
| 446 render_text.get()); |
| 441 | 447 |
| 442 const int line_height = render_text->GetStringSize().height(); | 448 const int line_height = render_text->GetStringSize().height(); |
| 443 // Center the text vertically. | 449 // Center the text vertically. |
| 444 rect += Vector2d(0, (display_rect.height() - line_height) / 2); | 450 rect += Vector2d(0, (display_rect.height() - line_height) / 2); |
| 445 rect.set_height(line_height); | 451 rect.set_height(line_height); |
| 446 render_text->SetDisplayRect(rect); | 452 render_text->SetDisplayRect(rect); |
| 447 | 453 |
| 448 canvas_->save(SkCanvas::kClip_SaveFlag); | 454 canvas_->save(SkCanvas::kClip_SaveFlag); |
| 449 ClipRect(display_rect); | 455 ClipRect(display_rect); |
| 450 render_text->Draw(this); | 456 render_text->Draw(this); |
| 451 canvas_->restore(); | 457 canvas_->restore(); |
| 452 } | 458 } |
| 453 | 459 |
| 454 } // namespace gfx | 460 } // namespace gfx |
| OLD | NEW |