| 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" | 12 #include "ui/gfx/font.h" |
| 13 #include "ui/gfx/font_list.h" | 13 #include "ui/gfx/font_list.h" |
| 14 #include "ui/gfx/insets.h" | 14 #include "ui/gfx/insets.h" |
| 15 #include "ui/gfx/rect.h" | 15 #include "ui/gfx/rect.h" |
| 16 #include "ui/gfx/render_text.h" | 16 #include "ui/gfx/render_text.h" |
| 17 #include "ui/gfx/shadow_value.h" | 17 #include "ui/gfx/shadow_value.h" |
| 18 #include "ui/gfx/text_utils.h" | 18 #include "ui/gfx/text_utils.h" |
| 19 | 19 |
| 20 namespace gfx { |
| 21 |
| 20 namespace { | 22 namespace { |
| 21 | 23 |
| 22 // If necessary, wraps |text| with RTL/LTR directionality characters based on | 24 // If necessary, wraps |text| with RTL/LTR directionality characters based on |
| 23 // |flags| and |text| content. | 25 // |flags| and |text| content. |
| 24 // Returns true if the text will be rendered right-to-left. | 26 // Returns true if the text will be rendered right-to-left. |
| 25 // TODO(msw): Nix this, now that RenderTextWin supports directionality directly. | 27 // TODO(msw): Nix this, now that RenderTextWin supports directionality directly. |
| 26 bool AdjustStringDirection(int flags, string16* text) { | 28 bool AdjustStringDirection(int flags, string16* text) { |
| 27 // TODO(msw): FORCE_LTR_DIRECTIONALITY does not work for RTL text now. | 29 // TODO(msw): FORCE_LTR_DIRECTIONALITY does not work for RTL text now. |
| 28 | 30 |
| 29 // If the string is empty or LTR was forced, simply return false since the | 31 // If the string is empty or LTR was forced, simply return false since the |
| 30 // default RenderText directionality is already LTR. | 32 // default RenderText directionality is already LTR. |
| 31 if (text->empty() || (flags & gfx::Canvas::FORCE_LTR_DIRECTIONALITY)) | 33 if (text->empty() || (flags & Canvas::FORCE_LTR_DIRECTIONALITY)) |
| 32 return false; | 34 return false; |
| 33 | 35 |
| 34 // If RTL is forced, apply it to the string. | 36 // If RTL is forced, apply it to the string. |
| 35 if (flags & gfx::Canvas::FORCE_RTL_DIRECTIONALITY) { | 37 if (flags & Canvas::FORCE_RTL_DIRECTIONALITY) { |
| 36 base::i18n::WrapStringWithRTLFormatting(text); | 38 base::i18n::WrapStringWithRTLFormatting(text); |
| 37 return true; | 39 return true; |
| 38 } | 40 } |
| 39 | 41 |
| 40 // If a direction wasn't forced but the UI language is RTL and there were | 42 // If a direction wasn't forced but the UI language is RTL and there were |
| 41 // strong RTL characters, ensure RTL is applied. | 43 // strong RTL characters, ensure RTL is applied. |
| 42 if (base::i18n::IsRTL() && base::i18n::StringContainsStrongRTLChars(*text)) { | 44 if (base::i18n::IsRTL() && base::i18n::StringContainsStrongRTLChars(*text)) { |
| 43 base::i18n::WrapStringWithRTLFormatting(text); | 45 base::i18n::WrapStringWithRTLFormatting(text); |
| 44 return true; | 46 return true; |
| 45 } | 47 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 *bitmap.getAddr32(x, y + 1) != halo_color && | 79 *bitmap.getAddr32(x, y + 1) != halo_color && |
| 78 *bitmap.getAddr32(x, y + 1) != 0) | 80 *bitmap.getAddr32(x, y + 1) != 0) |
| 79 return true; // Touched pixel below. | 81 return true; // Touched pixel below. |
| 80 return false; | 82 return false; |
| 81 } | 83 } |
| 82 | 84 |
| 83 // Strips accelerator character prefixes in |text| if needed, based on |flags|. | 85 // Strips accelerator character prefixes in |text| if needed, based on |flags|. |
| 84 // Returns a range in |text| to underline or ui::Range::InvalidRange() if | 86 // Returns a range in |text| to underline or ui::Range::InvalidRange() if |
| 85 // underlining is not needed. | 87 // underlining is not needed. |
| 86 ui::Range StripAcceleratorChars(int flags, string16* text) { | 88 ui::Range StripAcceleratorChars(int flags, string16* text) { |
| 87 if (flags & (gfx::Canvas::SHOW_PREFIX | gfx::Canvas::HIDE_PREFIX)) { | 89 if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) { |
| 88 int char_pos = -1; | 90 int char_pos = -1; |
| 89 int char_span = 0; | 91 int char_span = 0; |
| 90 *text = gfx::RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); | 92 *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span); |
| 91 if ((flags & gfx::Canvas::SHOW_PREFIX) && char_pos != -1) | 93 if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1) |
| 92 return ui::Range(char_pos, char_pos + char_span); | 94 return ui::Range(char_pos, char_pos + char_span); |
| 93 } | 95 } |
| 94 return ui::Range::InvalidRange(); | 96 return ui::Range::InvalidRange(); |
| 95 } | 97 } |
| 96 | 98 |
| 97 // Elides |text| and adjusts |range| appropriately. If eliding causes |range| | 99 // Elides |text| and adjusts |range| appropriately. If eliding causes |range| |
| 98 // to no longer point to the same character in |text|, |range| is made invalid. | 100 // to no longer point to the same character in |text|, |range| is made invalid. |
| 99 void ElideTextAndAdjustRange(const gfx::Font& font, | 101 void ElideTextAndAdjustRange(const Font& font, |
| 100 int width, | 102 int width, |
| 101 string16* text, | 103 string16* text, |
| 102 ui::Range* range) { | 104 ui::Range* range) { |
| 103 const char16 start_char = (range->IsValid() ? text->at(range->start()) : 0); | 105 const char16 start_char = (range->IsValid() ? text->at(range->start()) : 0); |
| 104 *text = ui::ElideText(*text, font, width, ui::ELIDE_AT_END); | 106 *text = ui::ElideText(*text, font, width, ui::ELIDE_AT_END); |
| 105 if (!range->IsValid()) | 107 if (!range->IsValid()) |
| 106 return; | 108 return; |
| 107 if (range->start() >= text->length() || | 109 if (range->start() >= text->length() || |
| 108 text->at(range->start()) != start_char) { | 110 text->at(range->start()) != start_char) { |
| 109 *range = ui::Range::InvalidRange(); | 111 *range = ui::Range::InvalidRange(); |
| 110 } | 112 } |
| 111 } | 113 } |
| 112 | 114 |
| 113 // Updates |render_text| from the specified parameters. | 115 // Updates |render_text| from the specified parameters. |
| 114 void UpdateRenderText(const gfx::Rect& rect, | 116 void UpdateRenderText(const Rect& rect, |
| 115 const string16& text, | 117 const string16& text, |
| 116 const gfx::Font& font, | 118 const Font& font, |
| 117 int flags, | 119 int flags, |
| 118 SkColor color, | 120 SkColor color, |
| 119 gfx::RenderText* render_text) { | 121 RenderText* render_text) { |
| 120 render_text->SetFont(font); | 122 render_text->SetFont(font); |
| 121 render_text->SetText(text); | 123 render_text->SetText(text); |
| 122 render_text->SetCursorEnabled(false); | 124 render_text->SetCursorEnabled(false); |
| 123 | 125 |
| 124 gfx::Rect display_rect = rect; | 126 Rect display_rect = rect; |
| 125 display_rect.set_height(font.GetHeight()); | 127 display_rect.set_height(font.GetHeight()); |
| 126 render_text->SetDisplayRect(display_rect); | 128 render_text->SetDisplayRect(display_rect); |
| 127 | 129 |
| 128 // 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, |
| 129 // if not specified. | 131 // if not specified. |
| 130 if (!(flags & (gfx::Canvas::TEXT_ALIGN_CENTER | | 132 if (!(flags & (Canvas::TEXT_ALIGN_CENTER | |
| 131 gfx::Canvas::TEXT_ALIGN_RIGHT | | 133 Canvas::TEXT_ALIGN_RIGHT | |
| 132 gfx::Canvas::TEXT_ALIGN_LEFT))) { | 134 Canvas::TEXT_ALIGN_LEFT))) { |
| 133 flags |= gfx::Canvas::DefaultCanvasTextAlignment(); | 135 flags |= Canvas::DefaultCanvasTextAlignment(); |
| 134 } | 136 } |
| 135 | 137 |
| 136 if (flags & gfx::Canvas::TEXT_ALIGN_RIGHT) | 138 if (flags & Canvas::TEXT_ALIGN_RIGHT) |
| 137 render_text->SetHorizontalAlignment(gfx::ALIGN_RIGHT); | 139 render_text->SetHorizontalAlignment(ALIGN_RIGHT); |
| 138 else if (flags & gfx::Canvas::TEXT_ALIGN_CENTER) | 140 else if (flags & Canvas::TEXT_ALIGN_CENTER) |
| 139 render_text->SetHorizontalAlignment(gfx::ALIGN_CENTER); | 141 render_text->SetHorizontalAlignment(ALIGN_CENTER); |
| 140 else | 142 else |
| 141 render_text->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 143 render_text->SetHorizontalAlignment(ALIGN_LEFT); |
| 142 | 144 |
| 143 if (flags & gfx::Canvas::NO_SUBPIXEL_RENDERING) | 145 if (flags & Canvas::NO_SUBPIXEL_RENDERING) |
| 144 render_text->set_background_is_transparent(true); | 146 render_text->set_background_is_transparent(true); |
| 145 | 147 |
| 146 gfx::StyleRange style; | 148 render_text->SetColor(color); |
| 147 style.foreground = color; | 149 render_text->SetStyle(BOLD, (font.GetStyle() & Font::BOLD) != 0); |
| 148 style.font_style = font.GetStyle(); | 150 render_text->SetStyle(ITALIC, (font.GetStyle() & Font::ITALIC) != 0); |
| 149 if (font.GetStyle() & gfx::Font::UNDERLINED) | 151 render_text->SetStyle(UNDERLINE, (font.GetStyle() & Font::UNDERLINE) != 0); |
| 150 style.underline = true; | |
| 151 render_text->set_default_style(style); | |
| 152 render_text->ApplyDefaultStyle(); | |
| 153 } | |
| 154 | |
| 155 // Adds an underline style to |render_text| over |range|. | |
| 156 void ApplyUnderlineStyle(const ui::Range& range, gfx::RenderText* render_text) { | |
| 157 gfx::StyleRange style = render_text->default_style(); | |
| 158 if (range.IsValid() && !style.underline) { | |
| 159 style.range = range; | |
| 160 style.underline = true; | |
| 161 render_text->ApplyStyleRange(style); | |
| 162 } | |
| 163 } | 152 } |
| 164 | 153 |
| 165 // Returns updated |flags| to match platform-specific expected behavior. | 154 // Returns updated |flags| to match platform-specific expected behavior. |
| 166 int AdjustPlatformSpecificFlags(const string16& text, int flags) { | 155 int AdjustPlatformSpecificFlags(const string16& text, int flags) { |
| 167 #if defined(OS_LINUX) | 156 #if defined(OS_LINUX) |
| 168 // TODO(asvitkine): ash/tooltips/tooltip_controller.cc adds \n's to the string | 157 // TODO(asvitkine): ash/tooltips/tooltip_controller.cc adds \n's to the string |
| 169 // without passing MULTI_LINE. | 158 // without passing MULTI_LINE. |
| 170 if (text.find('\n') != string16::npos) | 159 if (text.find('\n') != string16::npos) |
| 171 flags |= gfx::Canvas::MULTI_LINE; | 160 flags |= Canvas::MULTI_LINE; |
| 172 #endif | 161 #endif |
| 173 | 162 |
| 174 return flags; | 163 return flags; |
| 175 } | 164 } |
| 176 | 165 |
| 177 } // namespace | 166 } // namespace |
| 178 | 167 |
| 179 namespace gfx { | |
| 180 | |
| 181 // static | 168 // static |
| 182 void Canvas::SizeStringInt(const string16& text, | 169 void Canvas::SizeStringInt(const string16& text, |
| 183 const gfx::Font& font, | 170 const Font& font, |
| 184 int* width, int* height, | 171 int* width, int* height, |
| 185 int flags) { | 172 int flags) { |
| 186 DCHECK_GE(*width, 0); | 173 DCHECK_GE(*width, 0); |
| 187 DCHECK_GE(*height, 0); | 174 DCHECK_GE(*height, 0); |
| 188 | 175 |
| 189 flags = AdjustPlatformSpecificFlags(text, flags); | 176 flags = AdjustPlatformSpecificFlags(text, flags); |
| 190 | 177 |
| 191 string16 adjusted_text = text; | 178 string16 adjusted_text = text; |
| 192 #if defined(OS_WIN) | 179 #if defined(OS_WIN) |
| 193 AdjustStringDirection(flags, &adjusted_text); | 180 AdjustStringDirection(flags, &adjusted_text); |
| 194 #endif | 181 #endif |
| 195 | 182 |
| 196 if ((flags & MULTI_LINE) && *width != 0) { | 183 if ((flags & MULTI_LINE) && *width != 0) { |
| 197 ui::WordWrapBehavior wrap_behavior = ui::TRUNCATE_LONG_WORDS; | 184 ui::WordWrapBehavior wrap_behavior = ui::TRUNCATE_LONG_WORDS; |
| 198 if (flags & CHARACTER_BREAK) | 185 if (flags & CHARACTER_BREAK) |
| 199 wrap_behavior = ui::WRAP_LONG_WORDS; | 186 wrap_behavior = ui::WRAP_LONG_WORDS; |
| 200 else if (!(flags & NO_ELLIPSIS)) | 187 else if (!(flags & NO_ELLIPSIS)) |
| 201 wrap_behavior = ui::ELIDE_LONG_WORDS; | 188 wrap_behavior = ui::ELIDE_LONG_WORDS; |
| 202 | 189 |
| 203 gfx::Rect rect(*width, INT_MAX); | 190 Rect rect(*width, INT_MAX); |
| 204 std::vector<string16> strings; | 191 std::vector<string16> strings; |
| 205 ui::ElideRectangleText(adjusted_text, font, rect.width(), rect.height(), | 192 ui::ElideRectangleText(adjusted_text, font, rect.width(), rect.height(), |
| 206 wrap_behavior, &strings); | 193 wrap_behavior, &strings); |
| 207 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 194 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
| 208 UpdateRenderText(rect, string16(), font, flags, 0, render_text.get()); | 195 UpdateRenderText(rect, string16(), font, flags, 0, render_text.get()); |
| 209 | 196 |
| 210 int h = 0; | 197 int h = 0; |
| 211 int w = 0; | 198 int w = 0; |
| 212 for (size_t i = 0; i < strings.size(); ++i) { | 199 for (size_t i = 0; i < strings.size(); ++i) { |
| 213 StripAcceleratorChars(flags, &strings[i]); | 200 StripAcceleratorChars(flags, &strings[i]); |
| 214 render_text->SetText(strings[i]); | 201 render_text->SetText(strings[i]); |
| 215 const Size string_size = render_text->GetStringSize(); | 202 const Size string_size = render_text->GetStringSize(); |
| 216 w = std::max(w, string_size.width()); | 203 w = std::max(w, string_size.width()); |
| 217 h += string_size.height(); | 204 h += string_size.height(); |
| 218 } | 205 } |
| 219 *width = w; | 206 *width = w; |
| 220 *height = h; | 207 *height = h; |
| 221 } else { | 208 } else { |
| 222 // If the string is too long, the call by |RenderTextWin| to |ScriptShape()| | 209 // If the string is too long, the call by |RenderTextWin| to |ScriptShape()| |
| 223 // will inexplicably fail with result E_INVALIDARG. Guard against this. | 210 // will inexplicably fail with result E_INVALIDARG. Guard against this. |
| 224 const size_t kMaxRenderTextLength = 5000; | 211 const size_t kMaxRenderTextLength = 5000; |
| 225 if (adjusted_text.length() >= kMaxRenderTextLength) { | 212 if (adjusted_text.length() >= kMaxRenderTextLength) { |
| 226 *width = adjusted_text.length() * font.GetAverageCharacterWidth(); | 213 *width = adjusted_text.length() * font.GetAverageCharacterWidth(); |
| 227 *height = font.GetHeight(); | 214 *height = font.GetHeight(); |
| 228 } else { | 215 } else { |
| 229 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 216 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
| 230 gfx::Rect rect(*width, *height); | 217 Rect rect(*width, *height); |
| 231 StripAcceleratorChars(flags, &adjusted_text); | 218 StripAcceleratorChars(flags, &adjusted_text); |
| 232 UpdateRenderText(rect, adjusted_text, font, flags, 0, render_text.get()); | 219 UpdateRenderText(rect, adjusted_text, font, flags, 0, render_text.get()); |
| 233 const Size string_size = render_text->GetStringSize(); | 220 const Size string_size = render_text->GetStringSize(); |
| 234 *width = string_size.width(); | 221 *width = string_size.width(); |
| 235 *height = string_size.height(); | 222 *height = string_size.height(); |
| 236 } | 223 } |
| 237 } | 224 } |
| 238 } | 225 } |
| 239 | 226 |
| 240 void Canvas::DrawStringWithShadows(const string16& text, | 227 void Canvas::DrawStringWithShadows(const string16& text, |
| 241 const gfx::Font& font, | 228 const Font& font, |
| 242 SkColor color, | 229 SkColor color, |
| 243 const gfx::Rect& text_bounds, | 230 const Rect& text_bounds, |
| 244 int flags, | 231 int flags, |
| 245 const ShadowValues& shadows) { | 232 const ShadowValues& shadows) { |
| 246 if (!IntersectsClipRect(text_bounds)) | 233 if (!IntersectsClipRect(text_bounds)) |
| 247 return; | 234 return; |
| 248 | 235 |
| 249 flags = AdjustPlatformSpecificFlags(text, flags); | 236 flags = AdjustPlatformSpecificFlags(text, flags); |
| 250 | 237 |
| 251 gfx::Rect clip_rect(text_bounds); | 238 Rect clip_rect(text_bounds); |
| 252 clip_rect.Inset(ShadowValue::GetMargin(shadows)); | 239 clip_rect.Inset(ShadowValue::GetMargin(shadows)); |
| 253 | 240 |
| 254 canvas_->save(SkCanvas::kClip_SaveFlag); | 241 canvas_->save(SkCanvas::kClip_SaveFlag); |
| 255 ClipRect(clip_rect); | 242 ClipRect(clip_rect); |
| 256 | 243 |
| 257 gfx::Rect rect(text_bounds); | 244 Rect rect(text_bounds); |
| 258 string16 adjusted_text = text; | 245 string16 adjusted_text = text; |
| 259 | 246 |
| 260 #if defined(OS_WIN) | 247 #if defined(OS_WIN) |
| 261 AdjustStringDirection(flags, &adjusted_text); | 248 AdjustStringDirection(flags, &adjusted_text); |
| 262 #endif | 249 #endif |
| 263 | 250 |
| 264 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 251 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
| 265 render_text->SetTextShadows(shadows); | 252 render_text->SetTextShadows(shadows); |
| 266 | 253 |
| 267 if (flags & MULTI_LINE) { | 254 if (flags & MULTI_LINE) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 281 for (size_t i = 0; i < strings.size(); i++) { | 268 for (size_t i = 0; i < strings.size(); i++) { |
| 282 ui::Range range = StripAcceleratorChars(flags, &strings[i]); | 269 ui::Range range = StripAcceleratorChars(flags, &strings[i]); |
| 283 UpdateRenderText(rect, strings[i], font, flags, color, render_text.get()); | 270 UpdateRenderText(rect, strings[i], font, flags, color, render_text.get()); |
| 284 const int line_height = render_text->GetStringSize().height(); | 271 const int line_height = render_text->GetStringSize().height(); |
| 285 | 272 |
| 286 // TODO(msw|asvitkine): Center Windows multi-line text: crbug.com/107357 | 273 // TODO(msw|asvitkine): Center Windows multi-line text: crbug.com/107357 |
| 287 #if !defined(OS_WIN) | 274 #if !defined(OS_WIN) |
| 288 if (i == 0) { | 275 if (i == 0) { |
| 289 // TODO(msw|asvitkine): Support multi-line text with varied heights. | 276 // TODO(msw|asvitkine): Support multi-line text with varied heights. |
| 290 const int aggregate_height = strings.size() * line_height; | 277 const int aggregate_height = strings.size() * line_height; |
| 291 rect += gfx::Vector2d(0, (text_bounds.height() - aggregate_height) / 2); | 278 rect += Vector2d(0, (text_bounds.height() - aggregate_height) / 2); |
| 292 } | 279 } |
| 293 #endif | 280 #endif |
| 294 | 281 |
| 295 rect.set_height(line_height); | 282 rect.set_height(line_height); |
| 296 | 283 |
| 297 ApplyUnderlineStyle(range, render_text.get()); | 284 if (range.IsValid()) |
| 285 render_text->ApplyStyle(UNDERLINE, true, range); |
| 298 render_text->SetDisplayRect(rect); | 286 render_text->SetDisplayRect(rect); |
| 299 render_text->Draw(this); | 287 render_text->Draw(this); |
| 300 rect += gfx::Vector2d(0, line_height); | 288 rect += Vector2d(0, line_height); |
| 301 } | 289 } |
| 302 } else { | 290 } else { |
| 303 ui::Range range = StripAcceleratorChars(flags, &adjusted_text); | 291 ui::Range range = StripAcceleratorChars(flags, &adjusted_text); |
| 304 bool elide_text = ((flags & NO_ELLIPSIS) == 0); | 292 bool elide_text = ((flags & NO_ELLIPSIS) == 0); |
| 305 | 293 |
| 306 #if defined(OS_LINUX) | 294 #if defined(OS_LINUX) |
| 307 // On Linux, eliding really means fading the end of the string. But only | 295 // On Linux, eliding really means fading the end of the string. But only |
| 308 // for LTR text. RTL text is still elided (on the left) with "...". | 296 // for LTR text. RTL text is still elided (on the left) with "...". |
| 309 if (elide_text) { | 297 if (elide_text) { |
| 310 render_text->SetText(adjusted_text); | 298 render_text->SetText(adjusted_text); |
| 311 if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { | 299 if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { |
| 312 render_text->set_fade_tail(true); | 300 render_text->set_fade_tail(true); |
| 313 elide_text = false; | 301 elide_text = false; |
| 314 } | 302 } |
| 315 } | 303 } |
| 316 #endif | 304 #endif |
| 317 | 305 |
| 318 if (elide_text) { | 306 if (elide_text) { |
| 319 ElideTextAndAdjustRange(font, | 307 ElideTextAndAdjustRange(font, |
| 320 text_bounds.width(), | 308 text_bounds.width(), |
| 321 &adjusted_text, | 309 &adjusted_text, |
| 322 &range); | 310 &range); |
| 323 } | 311 } |
| 324 | 312 |
| 325 UpdateRenderText(rect, adjusted_text, font, flags, color, | 313 UpdateRenderText(rect, adjusted_text, font, flags, color, |
| 326 render_text.get()); | 314 render_text.get()); |
| 327 | 315 |
| 328 const int line_height = render_text->GetStringSize().height(); | 316 const int line_height = render_text->GetStringSize().height(); |
| 329 // Center the text vertically. | 317 // Center the text vertically. |
| 330 rect += gfx::Vector2d(0, (text_bounds.height() - line_height) / 2); | 318 rect += Vector2d(0, (text_bounds.height() - line_height) / 2); |
| 331 rect.set_height(line_height); | 319 rect.set_height(line_height); |
| 332 render_text->SetDisplayRect(rect); | 320 render_text->SetDisplayRect(rect); |
| 333 | 321 if (range.IsValid()) |
| 334 ApplyUnderlineStyle(range, render_text.get()); | 322 render_text->ApplyStyle(UNDERLINE, true, range); |
| 335 render_text->Draw(this); | 323 render_text->Draw(this); |
| 336 } | 324 } |
| 337 | 325 |
| 338 canvas_->restore(); | 326 canvas_->restore(); |
| 339 } | 327 } |
| 340 | 328 |
| 341 void Canvas::DrawStringWithHalo(const string16& text, | 329 void Canvas::DrawStringWithHalo(const string16& text, |
| 342 const gfx::Font& font, | 330 const Font& font, |
| 343 SkColor text_color, | 331 SkColor text_color, |
| 344 SkColor halo_color_in, | 332 SkColor halo_color_in, |
| 345 int x, int y, int w, int h, | 333 int x, int y, int w, int h, |
| 346 int flags) { | 334 int flags) { |
| 347 // Some callers will have semitransparent halo colors, which we don't handle | 335 // Some callers will have semitransparent halo colors, which we don't handle |
| 348 // (since the resulting image can have 1-bit transparency only). | 336 // (since the resulting image can have 1-bit transparency only). |
| 349 SkColor halo_color = SkColorSetA(halo_color_in, 0xFF); | 337 SkColor halo_color = SkColorSetA(halo_color_in, 0xFF); |
| 350 | 338 |
| 351 // Create a temporary buffer filled with the halo color. It must leave room | 339 // Create a temporary buffer filled with the halo color. It must leave room |
| 352 // for the 1-pixel border around the text. | 340 // for the 1-pixel border around the text. |
| 353 Size size(w + 2, h + 2); | 341 Size size(w + 2, h + 2); |
| 354 Canvas text_canvas(size, scale_factor(), true); | 342 Canvas text_canvas(size, scale_factor(), true); |
| 355 SkPaint bkgnd_paint; | 343 SkPaint bkgnd_paint; |
| 356 bkgnd_paint.setColor(halo_color); | 344 bkgnd_paint.setColor(halo_color); |
| 357 text_canvas.DrawRect(gfx::Rect(size), bkgnd_paint); | 345 text_canvas.DrawRect(Rect(size), bkgnd_paint); |
| 358 | 346 |
| 359 // Draw the text into the temporary buffer. This will have correct | 347 // Draw the text into the temporary buffer. This will have correct |
| 360 // ClearType since the background color is the same as the halo color. | 348 // ClearType since the background color is the same as the halo color. |
| 361 text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags); | 349 text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags); |
| 362 | 350 |
| 363 uint32_t halo_premul = SkPreMultiplyColor(halo_color); | 351 uint32_t halo_premul = SkPreMultiplyColor(halo_color); |
| 364 SkBitmap& text_bitmap = const_cast<SkBitmap&>( | 352 SkBitmap& text_bitmap = const_cast<SkBitmap&>( |
| 365 skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(true)); | 353 skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(true)); |
| 366 | 354 |
| 367 for (int cur_y = 0; cur_y < text_bitmap.height(); cur_y++) { | 355 for (int cur_y = 0; cur_y < text_bitmap.height(); cur_y++) { |
| 368 uint32_t* text_row = text_bitmap.getAddr32(0, cur_y); | 356 uint32_t* text_row = text_bitmap.getAddr32(0, cur_y); |
| 369 for (int cur_x = 0; cur_x < text_bitmap.width(); cur_x++) { | 357 for (int cur_x = 0; cur_x < text_bitmap.width(); cur_x++) { |
| 370 if (text_row[cur_x] == halo_premul) { | 358 if (text_row[cur_x] == halo_premul) { |
| 371 // This pixel was not touched by the text routines. See if it borders | 359 // This pixel was not touched by the text routines. See if it borders |
| 372 // a touched pixel in any of the 4 directions (not diagonally). | 360 // a touched pixel in any of the 4 directions (not diagonally). |
| 373 if (!PixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul)) | 361 if (!PixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul)) |
| 374 text_row[cur_x] = 0; // Make transparent. | 362 text_row[cur_x] = 0; // Make transparent. |
| 375 } else { | 363 } else { |
| 376 text_row[cur_x] |= 0xff << SK_A32_SHIFT; // Make opaque. | 364 text_row[cur_x] |= 0xff << SK_A32_SHIFT; // Make opaque. |
| 377 } | 365 } |
| 378 } | 366 } |
| 379 } | 367 } |
| 380 | 368 |
| 381 // Draw the halo bitmap with blur. | 369 // Draw the halo bitmap with blur. |
| 382 gfx::ImageSkia text_image = gfx::ImageSkia(gfx::ImageSkiaRep(text_bitmap, | 370 ImageSkia text_image = ImageSkia(ImageSkiaRep(text_bitmap, |
| 383 text_canvas.scale_factor())); | 371 text_canvas.scale_factor())); |
| 384 DrawImageInt(text_image, x - 1, y - 1); | 372 DrawImageInt(text_image, x - 1, y - 1); |
| 385 } | 373 } |
| 386 | 374 |
| 387 void Canvas::DrawFadeTruncatingString( | 375 void Canvas::DrawFadeTruncatingString( |
| 388 const string16& text, | 376 const string16& text, |
| 389 TruncateFadeMode truncate_mode, | 377 TruncateFadeMode truncate_mode, |
| 390 size_t desired_characters_to_truncate_from_head, | 378 size_t desired_characters_to_truncate_from_head, |
| 391 const gfx::Font& font, | 379 const Font& font, |
| 392 SkColor color, | 380 SkColor color, |
| 393 const gfx::Rect& display_rect) { | 381 const Rect& display_rect) { |
| 394 int flags = NO_ELLIPSIS; | 382 int flags = NO_ELLIPSIS; |
| 395 | 383 |
| 396 // If the whole string fits in the destination then just draw it directly. | 384 // If the whole string fits in the destination then just draw it directly. |
| 397 if (GetStringWidth(text, font) <= display_rect.width()) { | 385 if (GetStringWidth(text, font) <= display_rect.width()) { |
| 398 DrawStringInt(text, font, color, display_rect.x(), display_rect.y(), | 386 DrawStringInt(text, font, color, display_rect.x(), display_rect.y(), |
| 399 display_rect.width(), display_rect.height(), flags); | 387 display_rect.width(), display_rect.height(), flags); |
| 400 return; | 388 return; |
| 401 } | 389 } |
| 402 | 390 |
| 403 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 391 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 434 | 422 |
| 435 render_text->set_fade_tail(true); | 423 render_text->set_fade_tail(true); |
| 436 render_text->set_fade_head(true); | 424 render_text->set_fade_head(true); |
| 437 break; | 425 break; |
| 438 } | 426 } |
| 439 | 427 |
| 440 // Default to left alignment unless right alignment was chosen above. | 428 // Default to left alignment unless right alignment was chosen above. |
| 441 if (!(flags & TEXT_ALIGN_RIGHT)) | 429 if (!(flags & TEXT_ALIGN_RIGHT)) |
| 442 flags |= TEXT_ALIGN_LEFT; | 430 flags |= TEXT_ALIGN_LEFT; |
| 443 | 431 |
| 444 gfx::Rect rect = display_rect; | 432 Rect rect = display_rect; |
| 445 UpdateRenderText(rect, clipped_text, font, flags, color, render_text.get()); | 433 UpdateRenderText(rect, clipped_text, font, flags, color, render_text.get()); |
| 446 | 434 |
| 447 const int line_height = render_text->GetStringSize().height(); | 435 const int line_height = render_text->GetStringSize().height(); |
| 448 // Center the text vertically. | 436 // Center the text vertically. |
| 449 rect += gfx::Vector2d(0, (display_rect.height() - line_height) / 2); | 437 rect += Vector2d(0, (display_rect.height() - line_height) / 2); |
| 450 rect.set_height(line_height); | 438 rect.set_height(line_height); |
| 451 render_text->SetDisplayRect(rect); | 439 render_text->SetDisplayRect(rect); |
| 452 | 440 |
| 453 canvas_->save(SkCanvas::kClip_SaveFlag); | 441 canvas_->save(SkCanvas::kClip_SaveFlag); |
| 454 ClipRect(display_rect); | 442 ClipRect(display_rect); |
| 455 render_text->Draw(this); | 443 render_text->Draw(this); |
| 456 canvas_->restore(); | 444 canvas_->restore(); |
| 457 } | 445 } |
| 458 | 446 |
| 459 } // namespace gfx | 447 } // namespace gfx |
| OLD | NEW |