OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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_skia.h" | 5 #include "ui/gfx/canvas_skia.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "base/i18n/rtl.h" | 9 #include "base/i18n/rtl.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 (f & DT_RIGHT) && base::i18n::StringContainsStrongRTLChars(text))) { | 131 (f & DT_RIGHT) && base::i18n::StringContainsStrongRTLChars(text))) { |
132 f |= DT_RTLREADING; | 132 f |= DT_RTLREADING; |
133 } | 133 } |
134 | 134 |
135 return f; | 135 return f; |
136 } | 136 } |
137 | 137 |
138 // Changes the alpha of the given bitmap. | 138 // Changes the alpha of the given bitmap. |
139 // If |fade_to_right| is true then the rect fades from opaque to clear, | 139 // If |fade_to_right| is true then the rect fades from opaque to clear, |
140 // otherwise the rect fades from clear to opaque. | 140 // otherwise the rect fades from clear to opaque. |
141 void FadeBitmapRect(skia::BitmapPlatformDevice& bmp_device, | 141 void FadeBitmapRect(SkDevice& bmp_device, |
142 const gfx::Rect& rect, | 142 const gfx::Rect& rect, |
143 bool fade_to_right) { | 143 bool fade_to_right) { |
144 SkBitmap bmp = bmp_device.accessBitmap(true); | 144 SkBitmap bmp = bmp_device.accessBitmap(true); |
145 DCHECK_EQ(SkBitmap::kARGB_8888_Config, bmp.config()); | 145 DCHECK_EQ(SkBitmap::kARGB_8888_Config, bmp.config()); |
146 SkAutoLockPixels lock(bmp); | 146 SkAutoLockPixels lock(bmp); |
147 float total_width = static_cast<float>(rect.width()); | 147 float total_width = static_cast<float>(rect.width()); |
148 | 148 |
149 for (int x = rect.x(); x < rect.right(); x++) { | 149 for (int x = rect.x(); x < rect.right(); x++) { |
150 float cur_width = static_cast<float>(fade_to_right ? | 150 float cur_width = static_cast<float>(fade_to_right ? |
151 rect.right() - x : x - rect.x()); | 151 rect.right() - x : x - rect.x()); |
152 // We want the fade effect to go from 0.2 to 1.0. | 152 // We want the fade effect to go from 0.2 to 1.0. |
153 float alpha_percent = ((cur_width / total_width) * 0.8f) + 0.2f; | 153 float alpha_percent = ((cur_width / total_width) * 0.8f) + 0.2f; |
154 | 154 |
155 for (int y = rect.y(); y < rect.bottom(); y++) { | 155 for (int y = rect.y(); y < rect.bottom(); y++) { |
156 SkColor color = bmp.getColor(x, y); | 156 SkColor color = bmp.getColor(x, y); |
157 SkAlpha alpha = static_cast<SkAlpha>(SkColorGetA(color) * alpha_percent); | 157 SkAlpha alpha = static_cast<SkAlpha>(SkColorGetA(color) * alpha_percent); |
158 *bmp.getAddr32(x, y) = SkPreMultiplyColor(SkColorSetA(color, alpha)); | 158 *bmp.getAddr32(x, y) = SkPreMultiplyColor(SkColorSetA(color, alpha)); |
159 } | 159 } |
160 } | 160 } |
161 } | 161 } |
162 | 162 |
163 // DrawText() doesn't support alpha channels. To create a transparent background | 163 // DrawText() doesn't support alpha channels. To create a transparent background |
164 // this function draws black on white. It then uses the intensity of black | 164 // this function draws black on white. It then uses the intensity of black |
165 // to determine how much alpha to use. The text is drawn in |gfx_text_rect| and | 165 // to determine how much alpha to use. The text is drawn in |gfx_text_rect| and |
166 // clipped to |gfx_draw_rect|. | 166 // clipped to |gfx_draw_rect|. |
167 void DrawTextAndClearBackground(skia::BitmapPlatformDevice& bmp_device, | 167 void DrawTextAndClearBackground(SkDevice& bmp_device, |
168 HFONT font, | 168 HFONT font, |
169 COLORREF text_color, | 169 COLORREF text_color, |
170 const string16& text, | 170 const string16& text, |
171 int flags, | 171 int flags, |
172 const gfx::Rect& gfx_text_rect, | 172 const gfx::Rect& gfx_text_rect, |
173 const gfx::Rect& gfx_draw_rect) { | 173 const gfx::Rect& gfx_draw_rect) { |
174 HDC hdc = bmp_device.BeginPlatformPaint(); | 174 HDC hdc = skia::BeginPlatformPaint(&bmp_device); |
175 | 175 |
176 // Clear the background by filling with white. | 176 // Clear the background by filling with white. |
177 HBRUSH fill_brush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); | 177 HBRUSH fill_brush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); |
178 HANDLE old_brush = SelectObject(hdc, fill_brush); | 178 HANDLE old_brush = SelectObject(hdc, fill_brush); |
179 RECT draw_rect = gfx_draw_rect.ToRECT(); | 179 RECT draw_rect = gfx_draw_rect.ToRECT(); |
180 FillRect(hdc, &draw_rect, fill_brush); | 180 FillRect(hdc, &draw_rect, fill_brush); |
181 SelectObject(hdc, old_brush); | 181 SelectObject(hdc, old_brush); |
182 | 182 |
183 // Set black text with trasparent background. | 183 // Set black text with trasparent background. |
184 SetBkMode(hdc, TRANSPARENT); | 184 SetBkMode(hdc, TRANSPARENT); |
(...skipping 26 matching lines...) Expand all Loading... |
211 // using SkBitmap::getColor() won't work here. | 211 // using SkBitmap::getColor() won't work here. |
212 SkColor color = *bmp.getAddr32(x, y); | 212 SkColor color = *bmp.getAddr32(x, y); |
213 // Calculate the alpha using the luminance. Since this is black text | 213 // Calculate the alpha using the luminance. Since this is black text |
214 // on a white background the luminosity must be inverted. | 214 // on a white background the luminosity must be inverted. |
215 BYTE alpha = 0xFF - color_utils::GetLuminanceForColor(color); | 215 BYTE alpha = 0xFF - color_utils::GetLuminanceForColor(color); |
216 *bmp.getAddr32(x, y) = SkPreMultiplyColor( | 216 *bmp.getAddr32(x, y) = SkPreMultiplyColor( |
217 SkColorSetARGB(alpha, text_color_r, text_color_g, text_color_b)); | 217 SkColorSetARGB(alpha, text_color_r, text_color_g, text_color_b)); |
218 } | 218 } |
219 } | 219 } |
220 | 220 |
221 bmp_device.EndPlatformPaint(); | 221 skia::EndPlatformPaint(&bmp_device); |
222 } | 222 } |
223 | 223 |
224 // Draws the given text with a fade out gradient. |bmp_device| is a bitmap | 224 // Draws the given text with a fade out gradient. |bmp_device| is a bitmap |
225 // that is used to temporary drawing. The text is drawn in |text_rect| and | 225 // that is used to temporary drawing. The text is drawn in |text_rect| and |
226 // clipped to |draw_rect|. | 226 // clipped to |draw_rect|. |
227 void DrawTextGradientPart(HDC hdc, | 227 void DrawTextGradientPart(HDC hdc, |
228 skia::BitmapPlatformDevice& bmp_device, | 228 SkDevice& bmp_device, |
229 const string16& text, | 229 const string16& text, |
230 const SkColor& color, | 230 const SkColor& color, |
231 HFONT font, | 231 HFONT font, |
232 const gfx::Rect& text_rect, | 232 const gfx::Rect& text_rect, |
233 const gfx::Rect& draw_rect, | 233 const gfx::Rect& draw_rect, |
234 bool fade_to_right, | 234 bool fade_to_right, |
235 int flags) { | 235 int flags) { |
236 DrawTextAndClearBackground(bmp_device, font, skia::SkColorToCOLORREF(color), | 236 DrawTextAndClearBackground(bmp_device, font, skia::SkColorToCOLORREF(color), |
237 text, flags, text_rect, draw_rect); | 237 text, flags, text_rect, draw_rect); |
238 FadeBitmapRect(bmp_device, draw_rect, fade_to_right); | 238 FadeBitmapRect(bmp_device, draw_rect, fade_to_right); |
239 BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; | 239 BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; |
240 | 240 |
241 HDC bmp_hdc = bmp_device.BeginPlatformPaint(); | 241 HDC bmp_hdc = skia::BeginPlatformPaint(&bmp_device); |
242 AlphaBlend(hdc, draw_rect.x(), draw_rect.y(), draw_rect.width(), | 242 AlphaBlend(hdc, draw_rect.x(), draw_rect.y(), draw_rect.width(), |
243 draw_rect.height(), bmp_hdc, draw_rect.x(), draw_rect.y(), | 243 draw_rect.height(), bmp_hdc, draw_rect.x(), draw_rect.y(), |
244 draw_rect.width(), draw_rect.height(), blend); | 244 draw_rect.width(), draw_rect.height(), blend); |
245 bmp_device.EndPlatformPaint(); | 245 skia::EndPlatformPaint(&bmp_device); |
246 } | 246 } |
247 | 247 |
248 enum PrimarySide { | 248 enum PrimarySide { |
249 PrimaryOnLeft, | 249 PrimaryOnLeft, |
250 PrimaryOnRight, | 250 PrimaryOnRight, |
251 }; | 251 }; |
252 | 252 |
253 // Divides |rect| horizontally into a |primary| of width |primary_width| and a | 253 // Divides |rect| horizontally into a |primary| of width |primary_width| and a |
254 // |secondary| taking up the remainder. | 254 // |secondary| taking up the remainder. |
255 void DivideRect(const gfx::Rect& rect, | 255 void DivideRect(const gfx::Rect& rect, |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 if (!clip.intersect(skia::RECTToSkIRect(text_bounds))) | 340 if (!clip.intersect(skia::RECTToSkIRect(text_bounds))) |
341 return; | 341 return; |
342 | 342 |
343 // Clamp the max amount of text we'll draw to 32K. There seem to be bugs in | 343 // Clamp the max amount of text we'll draw to 32K. There seem to be bugs in |
344 // DrawText() if you e.g. ask it to character-break a no-whitespace string of | 344 // DrawText() if you e.g. ask it to character-break a no-whitespace string of |
345 // length > 43680 (for which it draws nothing), and since we clamped to 2K in | 345 // length > 43680 (for which it draws nothing), and since we clamped to 2K in |
346 // SizeStringInt() we're unlikely to be able to display this much anyway. | 346 // SizeStringInt() we're unlikely to be able to display this much anyway. |
347 const int kMaxStringLength = 32768 - 1; // So the trailing \0 fits in 32K. | 347 const int kMaxStringLength = 32768 - 1; // So the trailing \0 fits in 32K. |
348 string16 clamped_string(text.substr(0, kMaxStringLength)); | 348 string16 clamped_string(text.substr(0, kMaxStringLength)); |
349 | 349 |
350 HDC dc = beginPlatformPaint(); | 350 HDC dc; |
351 SetBkMode(dc, TRANSPARENT); | 351 HFONT old_font; |
352 HFONT old_font = (HFONT)SelectObject(dc, font); | 352 { |
353 COLORREF brush_color = RGB(SkColorGetR(color), SkColorGetG(color), | 353 skia::ScopedPlatformPaint scoped_platform_paint(this); |
354 SkColorGetB(color)); | 354 dc = scoped_platform_paint.GetPlatformSurface(); |
355 SetTextColor(dc, brush_color); | 355 SetBkMode(dc, TRANSPARENT); |
| 356 old_font = (HFONT)SelectObject(dc, font); |
| 357 COLORREF brush_color = RGB(SkColorGetR(color), SkColorGetG(color), |
| 358 SkColorGetB(color)); |
| 359 SetTextColor(dc, brush_color); |
356 | 360 |
357 int f = ComputeFormatFlags(flags, clamped_string); | 361 int f = ComputeFormatFlags(flags, clamped_string); |
358 DoDrawText(dc, clamped_string, &text_bounds, f); | 362 DoDrawText(dc, clamped_string, &text_bounds, f); |
359 endPlatformPaint(); | 363 } |
360 | 364 |
361 // Restore the old font. This way we don't have to worry if the caller | 365 // Restore the old font. This way we don't have to worry if the caller |
362 // deletes the font and the DC lives longer. | 366 // deletes the font and the DC lives longer. |
363 SelectObject(dc, old_font); | 367 SelectObject(dc, old_font); |
364 | 368 |
365 // Windows will have cleared the alpha channel of the text we drew. Assume | 369 // Windows will have cleared the alpha channel of the text we drew. Assume |
366 // we're drawing to an opaque surface, or at least the text rect area is | 370 // we're drawing to an opaque surface, or at least the text rect area is |
367 // opaque. | 371 // opaque. |
368 getTopPlatformDevice().makeOpaque(clip.fLeft, clip.fTop, | 372 skia::MakeOpaque(this, clip.fLeft, clip.fTop, clip.width(), |
369 clip.width(), clip.height()); | 373 clip.height()); |
370 } | 374 } |
371 | 375 |
372 void CanvasSkia::DrawStringInt(const string16& text, | 376 void CanvasSkia::DrawStringInt(const string16& text, |
373 const gfx::Font& font, | 377 const gfx::Font& font, |
374 const SkColor& color, | 378 const SkColor& color, |
375 int x, int y, int w, int h, | 379 int x, int y, int w, int h, |
376 int flags) { | 380 int flags) { |
377 DrawStringInt(text, font.GetNativeFont(), color, x, y, w, h, flags); | 381 DrawStringInt(text, font.GetNativeFont(), color, x, y, w, h, flags); |
378 } | 382 } |
379 | 383 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 text_canvas.DrawRectInt(0, 0, w + 2, h + 2, bkgnd_paint); | 427 text_canvas.DrawRectInt(0, 0, w + 2, h + 2, bkgnd_paint); |
424 | 428 |
425 // Draw the text into the temporary buffer. This will have correct | 429 // Draw the text into the temporary buffer. This will have correct |
426 // ClearType since the background color is the same as the halo color. | 430 // ClearType since the background color is the same as the halo color. |
427 text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags); | 431 text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags); |
428 | 432 |
429 // Windows will have cleared the alpha channel for the pixels it drew. Make it | 433 // Windows will have cleared the alpha channel for the pixels it drew. Make it |
430 // opaque. We have to do this first since pixelShouldGetHalo will check for | 434 // opaque. We have to do this first since pixelShouldGetHalo will check for |
431 // 0 to see if a pixel has been modified to transparent, and black text that | 435 // 0 to see if a pixel has been modified to transparent, and black text that |
432 // Windows draw will look transparent to it! | 436 // Windows draw will look transparent to it! |
433 text_canvas.getTopPlatformDevice().makeOpaque(0, 0, w + 2, h + 2); | 437 skia::MakeOpaque(&text_canvas, 0, 0, w + 2, h + 2); |
434 | 438 |
435 uint32_t halo_premul = SkPreMultiplyColor(halo_color); | 439 uint32_t halo_premul = SkPreMultiplyColor(halo_color); |
436 SkBitmap& text_bitmap = const_cast<SkBitmap&>( | 440 SkBitmap& text_bitmap = const_cast<SkBitmap&>( |
437 text_canvas.getTopPlatformDevice().accessBitmap(true)); | 441 skia::GetTopDevice(text_canvas)->accessBitmap(true)); |
438 for (int cur_y = 0; cur_y < h + 2; cur_y++) { | 442 for (int cur_y = 0; cur_y < h + 2; cur_y++) { |
439 uint32_t* text_row = text_bitmap.getAddr32(0, cur_y); | 443 uint32_t* text_row = text_bitmap.getAddr32(0, cur_y); |
440 for (int cur_x = 0; cur_x < w + 2; cur_x++) { | 444 for (int cur_x = 0; cur_x < w + 2; cur_x++) { |
441 if (text_row[cur_x] == halo_premul) { | 445 if (text_row[cur_x] == halo_premul) { |
442 // This pixel was not touched by the text routines. See if it borders | 446 // This pixel was not touched by the text routines. See if it borders |
443 // a touched pixel in any of the 4 directions (not diagonally). | 447 // a touched pixel in any of the 4 directions (not diagonally). |
444 if (!pixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul)) | 448 if (!pixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul)) |
445 text_row[cur_x] = 0; // Make transparent. | 449 text_row[cur_x] = 0; // Make transparent. |
446 } else { | 450 } else { |
447 text_row[cur_x] |= 0xff << SK_A32_SHIFT; // Make opaque. | 451 text_row[cur_x] |= 0xff << SK_A32_SHIFT; // Make opaque. |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 DivideRect(solid_part, is_rtl ? PrimaryOnLeft : PrimaryOnRight, | 550 DivideRect(solid_part, is_rtl ? PrimaryOnLeft : PrimaryOnRight, |
547 gradient_width, &tail_part, &solid_part); | 551 gradient_width, &tail_part, &solid_part); |
548 | 552 |
549 // Grow |display_rect| by |offset_x|. | 553 // Grow |display_rect| by |offset_x|. |
550 gfx::Rect text_rect(gfx::Point(), display_rect.size()); | 554 gfx::Rect text_rect(gfx::Point(), display_rect.size()); |
551 if (!is_rtl) | 555 if (!is_rtl) |
552 text_rect.set_x(text_rect.x() - offset_x); | 556 text_rect.set_x(text_rect.x() - offset_x); |
553 text_rect.set_width(text_rect.width() + offset_x); | 557 text_rect.set_width(text_rect.width() + offset_x); |
554 | 558 |
555 // Create a temporary bitmap to draw the gradient to. | 559 // Create a temporary bitmap to draw the gradient to. |
556 scoped_ptr<skia::BitmapPlatformDevice> gradient_bitmap( | 560 scoped_ptr<SkDevice> gradient_bitmap( |
557 skia::BitmapPlatformDevice::create( | 561 skia::BitmapPlatformDevice::create( |
558 display_rect.width(), display_rect.height(), false, NULL)); | 562 display_rect.width(), display_rect.height(), false, NULL)); |
559 DCHECK(gradient_bitmap.get()); | 563 DCHECK(gradient_bitmap.get()); |
560 | 564 |
561 HDC hdc = beginPlatformPaint(); | 565 { |
562 if (is_truncating_head) | 566 skia::ScopedPlatformPaint scoped_platform_paint(this); |
563 DrawTextGradientPart(hdc, *gradient_bitmap, text, color, | 567 HDC hdc = scoped_platform_paint.GetPlatformSurface(); |
564 font.GetNativeFont(), text_rect, head_part, is_rtl, | 568 if (is_truncating_head) |
565 flags); | 569 DrawTextGradientPart(hdc, *gradient_bitmap, text, color, |
566 if (is_truncating_tail) | 570 font.GetNativeFont(), text_rect, head_part, is_rtl, |
567 DrawTextGradientPart(hdc, *gradient_bitmap, text, color, | 571 flags); |
568 font.GetNativeFont(), text_rect, tail_part, !is_rtl, | 572 if (is_truncating_tail) |
569 flags); | 573 DrawTextGradientPart(hdc, *gradient_bitmap, text, color, |
570 endPlatformPaint(); | 574 font.GetNativeFont(), text_rect, tail_part, !is_rtl, |
| 575 flags); |
| 576 } |
571 | 577 |
572 // Draw the solid part. | 578 // Draw the solid part. |
573 save(kClip_SaveFlag); | 579 save(kClip_SaveFlag); |
574 ClipRectInt(solid_part.x(), solid_part.y(), | 580 ClipRectInt(solid_part.x(), solid_part.y(), |
575 solid_part.width(), solid_part.height()); | 581 solid_part.width(), solid_part.height()); |
576 DrawStringInt(text, font, color, | 582 DrawStringInt(text, font, color, |
577 text_rect.x(), text_rect.y(), | 583 text_rect.x(), text_rect.y(), |
578 text_rect.width(), text_rect.height(), | 584 text_rect.width(), text_rect.height(), |
579 flags); | 585 flags); |
580 restore(); | 586 restore(); |
581 restore(); | 587 restore(); |
582 } | 588 } |
583 | 589 |
584 } // namespace gfx | 590 } // namespace gfx |
OLD | NEW |