diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-23 23:04:23 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-23 23:04:23 +0000 |
commit | 3024338797b31cd0e0357878bcd5b084e4a8af69 (patch) | |
tree | cf20d1d15f3907bb625a7cd1e465bbc47118821e /gfx/canvas_win.cc | |
parent | 218f45da1c19e775cf72f46cc72f1c624927fd93 (diff) | |
download | chromium_src-3024338797b31cd0e0357878bcd5b084e4a8af69.zip chromium_src-3024338797b31cd0e0357878bcd5b084e4a8af69.tar.gz chromium_src-3024338797b31cd0e0357878bcd5b084e4a8af69.tar.bz2 |
Canvas refactoring part 2.
- Rename Canvas to CanvasSkia.
- Create a subclass Canvas that inherits from CanvasSkia for compatibility.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/2862025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50664 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gfx/canvas_win.cc')
-rw-r--r-- | gfx/canvas_win.cc | 293 |
1 files changed, 0 insertions, 293 deletions
diff --git a/gfx/canvas_win.cc b/gfx/canvas_win.cc deleted file mode 100644 index 98c5f74..0000000 --- a/gfx/canvas_win.cc +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gfx/canvas.h" - -#include <limits> - -#include "base/i18n/rtl.h" -#include "gfx/font.h" -#include "gfx/rect.h" -#include "third_party/skia/include/core/SkShader.h" - -namespace { - -// We make sure that LTR text we draw in an RTL context is modified -// appropriately to make sure it maintains it LTR orientation. -void DoDrawText(HDC hdc, const std::wstring& text, - RECT* text_bounds, int flags) { - std::wstring localized_text; - const wchar_t* string_ptr = text.c_str(); - int string_size = static_cast<int>(text.length()); - // Only adjust string directionality if both of the following are true: - // 1. The current locale is RTL. - // 2. The string itself has RTL directionality. - if (flags & DT_RTLREADING) { - if (base::i18n::AdjustStringForLocaleDirection(text, &localized_text)) { - string_ptr = localized_text.c_str(); - string_size = static_cast<int>(localized_text.length()); - } - } - - DrawText(hdc, string_ptr, string_size, text_bounds, flags); -} - -// Compute the windows flags necessary to implement the provided text Canvas -// flags. -int ComputeFormatFlags(int flags, const std::wstring& text) { - // Setting the text alignment explicitly in case it hasn't already been set. - // This will make sure that we don't align text to the left on RTL locales - // just because no alignment flag was passed to DrawStringInt(). - if (!(flags & (gfx::Canvas::TEXT_ALIGN_CENTER | - gfx::Canvas::TEXT_ALIGN_RIGHT | - gfx::Canvas::TEXT_ALIGN_LEFT))) { - flags |= gfx::Canvas::DefaultCanvasTextAlignment(); - } - - // horizontal alignment - int f = 0; - if (flags & gfx::Canvas::TEXT_ALIGN_CENTER) - f |= DT_CENTER; - else if (flags & gfx::Canvas::TEXT_ALIGN_RIGHT) - f |= DT_RIGHT; - else - f |= DT_LEFT; - - // vertical alignment - if (flags & gfx::Canvas::TEXT_VALIGN_TOP) - f |= DT_TOP; - else if (flags & gfx::Canvas::TEXT_VALIGN_BOTTOM) - f |= DT_BOTTOM; - else - f |= DT_VCENTER; - - if (flags & gfx::Canvas::MULTI_LINE) { - f |= DT_WORDBREAK; - if (flags & gfx::Canvas::CHARACTER_BREAK) - f |= DT_EDITCONTROL; // Turns on character breaking (not documented) - else if (!(flags & gfx::Canvas::NO_ELLIPSIS)) - f |= DT_WORD_ELLIPSIS; - } else { - f |= DT_SINGLELINE; - } - - if (flags & gfx::Canvas::HIDE_PREFIX) - f |= DT_HIDEPREFIX; - else if ((flags & gfx::Canvas::SHOW_PREFIX) == 0) - f |= DT_NOPREFIX; - - if (!(flags & gfx::Canvas::NO_ELLIPSIS)) - f |= DT_END_ELLIPSIS; - - // In order to make sure RTL/BiDi strings are rendered correctly, we must - // pass the flag DT_RTLREADING to DrawText (when the locale's language is - // a right-to-left language) so that Windows does the right thing. - // - // In addition to correctly displaying text containing both RTL and LTR - // elements (for example, a string containing a telephone number within a - // sentence in Hebrew, or a sentence in Hebrew that contains a word in - // English) this flag also makes sure that if there is not enough space to - // display the entire string, the ellipsis is displayed on the left hand side - // of the truncated string and not on the right hand side. - // - // We make a distinction between Chrome UI strings and text coming from a web - // page. - // - // For text coming from a web page we determine the alignment based on the - // first character with strong directionality. If the directionality of the - // first character with strong directionality in the text is LTR, the - // alignment is set to DT_LEFT, and the directionality should not be set as - // DT_RTLREADING. - // - // This heuristic doesn't work for Chrome UI strings since even in RTL - // locales, some of those might start with English text but we know they're - // localized so we always want them to be right aligned, and their - // directionality should be set as DT_RTLREADING. - // - // Caveat: If the string is purely LTR, don't set DTL_RTLREADING since when - // the flag is set, LRE-PDF don't have the desired effect of rendering - // multiline English-only text as LTR. - // - // Note that if the caller is explicitly requesting displaying the text - // using RTL directionality then we respect that and pass DT_RTLREADING to - // ::DrawText even if the locale is LTR. - if ((flags & gfx::Canvas::FORCE_RTL_DIRECTIONALITY) || - (base::i18n::IsRTL() && - (f & DT_RIGHT) && base::i18n::StringContainsStrongRTLChars(text))) { - f |= DT_RTLREADING; - } - - return f; -} - -} // anonymous namespace - -namespace gfx { - -Canvas::Canvas(int width, int height, bool is_opaque) - : skia::PlatformCanvas(width, height, is_opaque) { -} - -Canvas::Canvas() : skia::PlatformCanvas() { -} - -Canvas::~Canvas() { -} - -// static -void Canvas::SizeStringInt(const std::wstring& text, - const gfx::Font& font, - int* width, int* height, int flags) { - // Clamp the max amount of text we'll measure to 2K. When the string is - // actually drawn, it will be clipped to whatever size box is provided, and - // the time to do that doesn't depend on the length being clipped off. - const int kMaxStringLength = 2048 - 1; // So the trailing \0 fits in 2K. - std::wstring clamped_string(text.substr(0, kMaxStringLength)); - - if (*width == 0) { - // If multi-line + character break are on, the computed width will be one - // character wide (useless). Furthermore, if in this case the provided text - // contains very long "words" (substrings without a word-breaking point), - // DrawText() can run extremely slowly (e.g. several seconds). So in this - // case, we turn character breaking off to get a more accurate "desired" - // width and avoid the slowdown. - if (flags & (gfx::Canvas::MULTI_LINE | gfx::Canvas::CHARACTER_BREAK)) - flags &= ~gfx::Canvas::CHARACTER_BREAK; - - // Weird undocumented behavior: if the width is 0, DoDrawText() won't - // calculate a size at all. So set it to 1, which it will then change. - if (!text.empty()) - *width = 1; - } - RECT r = { 0, 0, *width, *height }; - - HDC dc = GetDC(NULL); - HFONT old_font = static_cast<HFONT>(SelectObject(dc, font.hfont())); - DoDrawText(dc, clamped_string, &r, - ComputeFormatFlags(flags, clamped_string) | DT_CALCRECT); - SelectObject(dc, old_font); - ReleaseDC(NULL, dc); - - *width = r.right; - *height = r.bottom; -} - -void Canvas::DrawStringInt(const std::wstring& text, HFONT font, - const SkColor& color, int x, int y, int w, int h, - int flags) { - if (!IntersectsClipRectInt(x, y, w, h)) - return; - - // Clamp the max amount of text we'll draw to 32K. There seem to be bugs in - // DrawText() if you e.g. ask it to character-break a no-whitespace string of - // length > 43680 (for which it draws nothing), and since we clamped to 2K in - // SizeStringInt() we're unlikely to be able to display this much anyway. - const int kMaxStringLength = 32768 - 1; // So the trailing \0 fits in 32K. - std::wstring clamped_string(text.substr(0, kMaxStringLength)); - - RECT text_bounds = { x, y, x + w, y + h }; - HDC dc = beginPlatformPaint(); - SetBkMode(dc, TRANSPARENT); - HFONT old_font = (HFONT)SelectObject(dc, font); - COLORREF brush_color = RGB(SkColorGetR(color), SkColorGetG(color), - SkColorGetB(color)); - SetTextColor(dc, brush_color); - - int f = ComputeFormatFlags(flags, clamped_string); - DoDrawText(dc, clamped_string, &text_bounds, f); - endPlatformPaint(); - - // Restore the old font. This way we don't have to worry if the caller - // deletes the font and the DC lives longer. - SelectObject(dc, old_font); - - // Windows will have cleared the alpha channel of the text we drew. Assume - // we're drawing to an opaque surface, or at least the text rect area is - // opaque. - getTopPlatformDevice().makeOpaque(x, y, w, h); -} - -void Canvas::DrawStringInt(const std::wstring& text, - const gfx::Font& font, - const SkColor& color, - int x, int y, int w, int h, int flags) { - DrawStringInt(text, font.hfont(), color, x, y, w, h, flags); -} - -// Checks each pixel immediately adjacent to the given pixel in the bitmap. If -// any of them are not the halo color, returns true. This defines the halo of -// pixels that will appear around the text. Note that we have to check each -// pixel against both the halo color and transparent since DrawStringWithHalo -// will modify the bitmap as it goes, and clears pixels shouldn't count as -// changed. -static bool pixelShouldGetHalo(const SkBitmap& bitmap, int x, int y, - SkColor halo_color) { - if (x > 0 && - *bitmap.getAddr32(x - 1, y) != halo_color && - *bitmap.getAddr32(x - 1, y) != 0) - return true; // Touched pixel to the left. - if (x < bitmap.width() - 1 && - *bitmap.getAddr32(x + 1, y) != halo_color && - *bitmap.getAddr32(x + 1, y) != 0) - return true; // Touched pixel to the right. - if (y > 0 && - *bitmap.getAddr32(x, y - 1) != halo_color && - *bitmap.getAddr32(x, y - 1) != 0) - return true; // Touched pixel above. - if (y < bitmap.height() - 1 && - *bitmap.getAddr32(x, y + 1) != halo_color && - *bitmap.getAddr32(x, y + 1) != 0) - return true; // Touched pixel below. - return false; -} - -void Canvas::DrawStringWithHalo(const std::wstring& text, - const gfx::Font& font, - const SkColor& text_color, - const SkColor& halo_color_in, - int x, int y, int w, int h, - int flags) { - // Some callers will have semitransparent halo colors, which we don't handle - // (since the resulting image can have 1-bit transparency only). - SkColor halo_color = halo_color_in | 0xFF000000; - - // Create a temporary buffer filled with the halo color. It must leave room - // for the 1-pixel border around the text. - Canvas text_canvas(w + 2, h + 2, true); - SkPaint bkgnd_paint; - bkgnd_paint.setColor(halo_color); - text_canvas.FillRectInt(0, 0, w + 2, h + 2, bkgnd_paint); - - // Draw the text into the temporary buffer. This will have correct - // ClearType since the background color is the same as the halo color. - text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags); - - // Windows will have cleared the alpha channel for the pixels it drew. Make it - // opaque. We have to do this first since pixelShouldGetHalo will check for - // 0 to see if a pixel has been modified to transparent, and black text that - // Windows draw will look transparent to it! - text_canvas.getTopPlatformDevice().makeOpaque(0, 0, w + 2, h + 2); - - uint32_t halo_premul = SkPreMultiplyColor(halo_color); - SkBitmap& text_bitmap = const_cast<SkBitmap&>( - text_canvas.getTopPlatformDevice().accessBitmap(true)); - for (int cur_y = 0; cur_y < h + 2; cur_y++) { - uint32_t* text_row = text_bitmap.getAddr32(0, cur_y); - for (int cur_x = 0; cur_x < w + 2; cur_x++) { - if (text_row[cur_x] == halo_premul) { - // This pixel was not touched by the text routines. See if it borders - // a touched pixel in any of the 4 directions (not diagonally). - if (!pixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul)) - text_row[cur_x] = 0; // Make transparent. - } else { - text_row[cur_x] |= 0xff << SK_A32_SHIFT; // Make opaque. - } - } - } - - // Draw the halo bitmap with blur. - drawBitmap(text_bitmap, SkIntToScalar(x - 1), SkIntToScalar(y - 1)); -} - -} // namespace gfx |