| Index: ui/gfx/canvas_win.cc
|
| ===================================================================
|
| --- ui/gfx/canvas_win.cc (revision 145540)
|
| +++ ui/gfx/canvas_win.cc (working copy)
|
| @@ -1,583 +0,0 @@
|
| -// Copyright (c) 2012 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 "ui/gfx/canvas.h"
|
| -
|
| -#include <limits>
|
| -
|
| -#include "base/i18n/rtl.h"
|
| -#include "base/logging.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "base/win/scoped_gdi_object.h"
|
| -#include "skia/ext/bitmap_platform_device.h"
|
| -#include "skia/ext/skia_utils_win.h"
|
| -#include "third_party/skia/include/core/SkShader.h"
|
| -#include "ui/gfx/color_utils.h"
|
| -#include "ui/gfx/font.h"
|
| -#include "ui/gfx/rect.h"
|
| -#include "ui/gfx/shadow_value.h"
|
| -
|
| -namespace {
|
| -
|
| -static inline int Round(double x) {
|
| - // Why oh why is this not in a standard header?
|
| - return static_cast<int>(floor(x + 0.5));
|
| -}
|
| -
|
| -// 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 string16& text,
|
| - RECT* text_bounds,
|
| - int flags) {
|
| - // Only adjust string directionality if both of the following are true:
|
| - // 1. The current locale is RTL.
|
| - // 2. The string itself has RTL directionality.
|
| - const wchar_t* string_ptr = text.c_str();
|
| - int string_size = static_cast<int>(text.length());
|
| -
|
| - string16 localized_text;
|
| - if (flags & DT_RTLREADING) {
|
| - localized_text = text;
|
| - base::i18n::AdjustStringForLocaleDirection(&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 string16& 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. If the directionality of the first character with strong
|
| - // directionality in the text is RTL, its alignment is set to DT_RIGHT, and
|
| - // its directionality is set as DT_RTLREADING through
|
| - // FORCE_RTL_DIRECTIONALITY.
|
| - //
|
| - // 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 their directionality should be set as DT_RTLREADING if it
|
| - // contains strong RTL characters.
|
| - //
|
| - // 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.
|
| - int force_rtl = (flags & gfx::Canvas::FORCE_RTL_DIRECTIONALITY);
|
| - int force_ltr = (flags & gfx::Canvas::FORCE_LTR_DIRECTIONALITY);
|
| - bool is_rtl = base::i18n::IsRTL();
|
| - bool string_contains_strong_rtl_chars =
|
| - base::i18n::StringContainsStrongRTLChars(text);
|
| - if (force_rtl || (!force_ltr && is_rtl && string_contains_strong_rtl_chars))
|
| - f |= DT_RTLREADING;
|
| -
|
| - return f;
|
| -}
|
| -
|
| -// Changes the alpha of the given bitmap.
|
| -// If |fade_to_right| is true then the rect fades from opaque to clear,
|
| -// otherwise the rect fades from clear to opaque.
|
| -void FadeBitmapRect(SkDevice& bmp_device,
|
| - const gfx::Rect& rect,
|
| - bool fade_to_right) {
|
| - SkBitmap bmp = bmp_device.accessBitmap(true);
|
| - DCHECK_EQ(SkBitmap::kARGB_8888_Config, bmp.config());
|
| - SkAutoLockPixels lock(bmp);
|
| - float total_width = static_cast<float>(rect.width());
|
| -
|
| - for (int x = rect.x(); x < rect.right(); x++) {
|
| - float cur_width = static_cast<float>(fade_to_right ?
|
| - rect.right() - x : x - rect.x());
|
| - // We want the fade effect to go from 0.2 to 1.0.
|
| - float alpha_percent = ((cur_width / total_width) * 0.8f) + 0.2f;
|
| -
|
| - for (int y = rect.y(); y < rect.bottom(); y++) {
|
| - SkColor color = bmp.getColor(x, y);
|
| - SkAlpha alpha = static_cast<SkAlpha>(SkColorGetA(color) * alpha_percent);
|
| - *bmp.getAddr32(x, y) = SkPreMultiplyColor(SkColorSetA(color, alpha));
|
| - }
|
| - }
|
| -}
|
| -
|
| -// DrawText() doesn't support alpha channels. To create a transparent background
|
| -// this function draws black on white. It then uses the intensity of black
|
| -// to determine how much alpha to use. The text is drawn in |gfx_text_rect| and
|
| -// clipped to |gfx_draw_rect|.
|
| -void DrawTextAndClearBackground(SkCanvas* bmp_canvas,
|
| - HFONT font,
|
| - COLORREF text_color,
|
| - const string16& text,
|
| - int flags,
|
| - const gfx::Rect& gfx_text_rect,
|
| - const gfx::Rect& gfx_draw_rect) {
|
| - skia::ScopedPlatformPaint scoped_platform_paint(bmp_canvas);
|
| - HDC hdc = scoped_platform_paint.GetPlatformSurface();
|
| -
|
| - // Clear the background by filling with white.
|
| - HBRUSH fill_brush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
|
| - HANDLE old_brush = SelectObject(hdc, fill_brush);
|
| - RECT draw_rect = gfx_draw_rect.ToRECT();
|
| - FillRect(hdc, &draw_rect, fill_brush);
|
| - SelectObject(hdc, old_brush);
|
| -
|
| - // Set black text with transparent background.
|
| - SetBkMode(hdc, TRANSPARENT);
|
| - SetTextColor(hdc, 0);
|
| -
|
| - // Draw the text.
|
| - int save_dc_id = SaveDC(hdc);
|
| - // Clip the text to the draw destination.
|
| - IntersectClipRect(hdc, draw_rect.left, draw_rect.top,
|
| - draw_rect.right, draw_rect.bottom);
|
| - SelectObject(hdc, font);
|
| - RECT text_rect = gfx_text_rect.ToRECT();
|
| - DoDrawText(hdc, text, &text_rect,
|
| - ComputeFormatFlags(flags, text));
|
| - RestoreDC(hdc, save_dc_id);
|
| -
|
| - BYTE text_color_r = GetRValue(text_color);
|
| - BYTE text_color_g = GetGValue(text_color);
|
| - BYTE text_color_b = GetBValue(text_color);
|
| -
|
| - SkBitmap bmp = bmp_canvas->getTopDevice()->accessBitmap(true);
|
| - DCHECK_EQ(SkBitmap::kARGB_8888_Config, bmp.config());
|
| - SkAutoLockPixels lock(bmp);
|
| -
|
| - // At this point the bitmap has black text on white.
|
| - // The intensity of black tells us the alpha value of the text.
|
| - for (int y = draw_rect.top; y < draw_rect.bottom; y++) {
|
| - for (int x = draw_rect.left; x < draw_rect.right; x++) {
|
| - // Gets the color directly. DrawText doesn't premultiply alpha so
|
| - // using SkBitmap::getColor() won't work here.
|
| - SkColor color = *bmp.getAddr32(x, y);
|
| - // Calculate the alpha using the luminance. Since this is black text
|
| - // on a white background the luminosity must be inverted.
|
| - BYTE alpha = 0xFF - color_utils::GetLuminanceForColor(color);
|
| - *bmp.getAddr32(x, y) = SkPreMultiplyColor(
|
| - SkColorSetARGB(alpha, text_color_r, text_color_g, text_color_b));
|
| - }
|
| - }
|
| -}
|
| -
|
| -// Draws the given text with a fade out gradient. |bmp_device| is a bitmap
|
| -// that is used to temporary drawing. The text is drawn in |text_rect| and
|
| -// clipped to |draw_rect|.
|
| -void DrawTextGradientPart(HDC hdc,
|
| - SkCanvas* bmp_canvas,
|
| - const string16& text,
|
| - SkColor color,
|
| - HFONT font,
|
| - const gfx::Rect& text_rect,
|
| - const gfx::Rect& draw_rect,
|
| - bool fade_to_right,
|
| - int flags) {
|
| - DrawTextAndClearBackground(bmp_canvas, font, skia::SkColorToCOLORREF(color),
|
| - text, flags, text_rect, draw_rect);
|
| - FadeBitmapRect(*bmp_canvas->getTopDevice(), draw_rect, fade_to_right);
|
| - BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
|
| -
|
| - skia::ScopedPlatformPaint scoped_platform_paint(bmp_canvas);
|
| - HDC bmp_hdc = scoped_platform_paint.GetPlatformSurface();
|
| - AlphaBlend(hdc, draw_rect.x(), draw_rect.y(), draw_rect.width(),
|
| - draw_rect.height(), bmp_hdc, draw_rect.x(), draw_rect.y(),
|
| - draw_rect.width(), draw_rect.height(), blend);
|
| -}
|
| -
|
| -enum PrimarySide {
|
| - PrimaryOnLeft,
|
| - PrimaryOnRight,
|
| -};
|
| -
|
| -// Divides |rect| horizontally into a |primary| of width |primary_width| and a
|
| -// |secondary| taking up the remainder.
|
| -void DivideRect(const gfx::Rect& rect,
|
| - PrimarySide primary_side,
|
| - int primary_width,
|
| - gfx::Rect* primary,
|
| - gfx::Rect* secondary) {
|
| - *primary = rect;
|
| - *secondary = rect;
|
| - int remainder = rect.width() - primary_width;
|
| -
|
| - switch (primary_side) {
|
| - case PrimaryOnLeft:
|
| - primary->Inset(0, 0, remainder, 0);
|
| - secondary->Inset(primary_width, 0, 0, 0);
|
| - break;
|
| - case PrimaryOnRight:
|
| - primary->Inset(remainder, 0, 0, 0);
|
| - secondary->Inset(0, 0, primary_width, 0);
|
| - break;
|
| - }
|
| -}
|
| -
|
| -} // anonymous namespace
|
| -
|
| -namespace gfx {
|
| -
|
| -// static
|
| -void Canvas::SizeStringInt(const string16& 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.
|
| - string16 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.
|
| - int multiline_charbreak =
|
| - gfx::Canvas::MULTI_LINE | gfx::Canvas::CHARACTER_BREAK;
|
| - if ((flags & multiline_charbreak) == multiline_charbreak)
|
| - 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.GetNativeFont()));
|
| - 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 string16& text,
|
| - HFONT font,
|
| - SkColor color,
|
| - const gfx::Rect& text_bounds,
|
| - int flags) {
|
| - SkRect fclip;
|
| - if (!canvas_->getClipBounds(&fclip))
|
| - return;
|
| - RECT text_rect = text_bounds.ToRECT();
|
| - SkIRect clip;
|
| - fclip.round(&clip);
|
| - if (!clip.intersect(skia::RECTToSkIRect(text_rect)))
|
| - 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.
|
| - string16 clamped_string(text.substr(0, kMaxStringLength));
|
| -
|
| - HDC dc;
|
| - HFONT old_font;
|
| - {
|
| - skia::ScopedPlatformPaint scoped_platform_paint(canvas_);
|
| - dc = scoped_platform_paint.GetPlatformSurface();
|
| - SetBkMode(dc, TRANSPARENT);
|
| - 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_rect, f);
|
| - }
|
| -
|
| - // 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.
|
| - skia::MakeOpaque(canvas_, clip.fLeft, clip.fTop, clip.width(),
|
| - clip.height());
|
| -}
|
| -
|
| -void Canvas::DrawStringWithShadows(const string16& text,
|
| - const gfx::Font& font,
|
| - SkColor color,
|
| - const gfx::Rect& text_bounds,
|
| - int flags,
|
| - const ShadowValues& shadows) {
|
| - DLOG_IF(WARNING, !shadows.empty()) << "Text shadow not implemented.";
|
| -
|
| - DrawStringInt(text, font.GetNativeFont(), color, text_bounds, 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 string16& text,
|
| - const gfx::Font& font,
|
| - SkColor text_color,
|
| - 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 = SkColorSetA(halo_color_in, 0xFF);
|
| -
|
| - // Create a temporary buffer filled with the halo color. It must leave room
|
| - // for the 1-pixel border around the text.
|
| - Size size(w + 2, h + 2);
|
| - Canvas text_canvas(size, true);
|
| - SkPaint bkgnd_paint;
|
| - bkgnd_paint.setColor(halo_color);
|
| - text_canvas.DrawRect(gfx::Rect(size), 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!
|
| - skia::MakeOpaque(text_canvas.sk_canvas(), 0, 0, size.width(), size.height());
|
| -
|
| - uint32_t halo_premul = SkPreMultiplyColor(halo_color);
|
| - SkBitmap& text_bitmap = const_cast<SkBitmap&>(
|
| - skia::GetTopDevice(*text_canvas.sk_canvas())->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.
|
| - DrawImageInt(text_bitmap, x - 1, y - 1);
|
| -}
|
| -
|
| -void Canvas::DrawFadeTruncatingString(
|
| - const string16& text,
|
| - TruncateFadeMode truncate_mode,
|
| - size_t desired_characters_to_truncate_from_head,
|
| - const gfx::Font& font,
|
| - SkColor color,
|
| - const gfx::Rect& display_rect) {
|
| - int flags = NO_ELLIPSIS;
|
| -
|
| - // If the whole string fits in the destination then just draw it directly.
|
| - int total_string_width = 0;
|
| - int total_string_height = 0;
|
| - SizeStringInt(text, font, &total_string_width, &total_string_height,
|
| - flags | TEXT_VALIGN_TOP);
|
| -
|
| - if (total_string_width <= display_rect.width()) {
|
| - DrawStringInt(text, font, color, display_rect.x(), display_rect.y(),
|
| - display_rect.width(), display_rect.height(), 0);
|
| - return;
|
| - }
|
| -
|
| - int average_character_width = font.GetAverageCharacterWidth();
|
| - int clipped_string_width = total_string_width - display_rect.width();
|
| - // Clip the string by drawing it to the left by |offset_x|.
|
| - int offset_x = 0;
|
| - switch (truncate_mode) {
|
| - case TruncateFadeHead:
|
| - offset_x = clipped_string_width;
|
| - break;
|
| - case TruncateFadeHeadAndTail:
|
| - DCHECK_GT(desired_characters_to_truncate_from_head, 0u);
|
| - // Get the width of the beginning of the string we're clipping.
|
| - string16 clipped_head_string =
|
| - text.substr(0, desired_characters_to_truncate_from_head);
|
| - int clipped_width;
|
| - int clipped_height;
|
| - SizeStringInt(clipped_head_string, font,
|
| - &clipped_width, &clipped_height, flags);
|
| -
|
| - // This is the offset at which we start drawing. This causes the
|
| - // beginning of the string to get clipped.
|
| - offset_x = clipped_width;
|
| -
|
| - // Due to the fade effect the first character is hard to see.
|
| - // We want to make sure that the first character starting at
|
| - // |desired_characters_to_truncate_from_head| is readable so we reduce
|
| - // the offset by a little bit.
|
| - offset_x = std::max(0, Round(offset_x - average_character_width * 2));
|
| -
|
| - // If the offset is so large that there's empty space at the tail
|
| - // then reduce the offset so we can use up the empty space.
|
| - offset_x = std::min(offset_x, clipped_string_width);
|
| - break;
|
| - }
|
| - bool is_truncating_head = offset_x > 0;
|
| - bool is_truncating_tail = clipped_string_width > offset_x;
|
| -
|
| - bool is_rtl = (ComputeFormatFlags(flags, text) & DT_RTLREADING) != 0;
|
| - // |is_rtl| tells us if the given text is right to left or not. |is_rtl| can
|
| - // be false even if the UI is set to a right to left language.
|
| - // Now, normally, we right align all text if the UI is set to a right to
|
| - // left language. In this case though we don't want that because we render
|
| - // the ends of the string ourselves.
|
| - if (!is_rtl)
|
| - flags |= TEXT_ALIGN_LEFT;
|
| -
|
| - // Fade in/out about 2.5 characters of the beginning/end of the string.
|
| - // The .5 here is helpful if one of the characters is a space.
|
| - // Use a quarter of the display width if the string is very short.
|
| - int gradient_width = Round(std::min(average_character_width * 2.5,
|
| - display_rect.width() / 4.0));
|
| -
|
| - // Move the origin to |display_rect.origin()|. This simplifies all the
|
| - // drawing so that both the source and destination can be (0,0).
|
| - canvas_->save(SkCanvas::kMatrix_SaveFlag);
|
| - Translate(display_rect.origin());
|
| -
|
| - gfx::Rect solid_part(gfx::Point(), display_rect.size());
|
| - gfx::Rect head_part;
|
| - gfx::Rect tail_part;
|
| - if (is_truncating_head)
|
| - DivideRect(solid_part, is_rtl ? PrimaryOnRight : PrimaryOnLeft,
|
| - gradient_width, &head_part, &solid_part);
|
| - if (is_truncating_tail)
|
| - DivideRect(solid_part, is_rtl ? PrimaryOnLeft : PrimaryOnRight,
|
| - gradient_width, &tail_part, &solid_part);
|
| -
|
| - // Grow |display_rect| by |offset_x|.
|
| - gfx::Rect text_rect(gfx::Point(), display_rect.size());
|
| - if (!is_rtl)
|
| - text_rect.set_x(text_rect.x() - offset_x);
|
| - text_rect.set_width(text_rect.width() + offset_x);
|
| -
|
| - // Create a temporary bitmap to draw the gradient to.
|
| - scoped_ptr<SkCanvas> gradient_canvas(skia::CreateBitmapCanvas(
|
| - display_rect.width(), display_rect.height(), false));
|
| - gradient_canvas->clear(SkColorSetARGB(0, 0, 0, 0));
|
| -
|
| - {
|
| - skia::ScopedPlatformPaint scoped_platform_paint(canvas_);
|
| - HDC hdc = scoped_platform_paint.GetPlatformSurface();
|
| - if (is_truncating_head)
|
| - DrawTextGradientPart(hdc, gradient_canvas.get(), text, color,
|
| - font.GetNativeFont(), text_rect, head_part, is_rtl,
|
| - flags);
|
| - if (is_truncating_tail)
|
| - DrawTextGradientPart(hdc, gradient_canvas.get(), text, color,
|
| - font.GetNativeFont(), text_rect, tail_part, !is_rtl,
|
| - flags);
|
| - }
|
| -
|
| - // Draw the solid part.
|
| - canvas_->save(SkCanvas::kClip_SaveFlag);
|
| - ClipRect(solid_part);
|
| - DrawStringInt(text, font, color,
|
| - text_rect.x(), text_rect.y(),
|
| - text_rect.width(), text_rect.height(),
|
| - flags);
|
| - canvas_->restore();
|
| - canvas_->restore();
|
| -}
|
| -
|
| -} // namespace gfx
|
|
|