15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/font_list.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/insets.h"
1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/range/range.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/render_text.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/shadow_value.h"
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/text_elider.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/text_utils.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace gfx {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_WIN)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If necessary, wraps |text| with RTL/LTR directionality characters based on
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |flags| and |text| content.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if the text will be rendered right-to-left.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(msw): Nix this, now that RenderTextWin supports directionality directly.
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool AdjustStringDirection(int flags, base::string16* text) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(msw): FORCE_LTR_DIRECTIONALITY does not work for RTL text now.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the string is empty or LTR was forced, simply return false since the
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // default RenderText directionality is already LTR.
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (text->empty() || (flags & Canvas::FORCE_LTR_DIRECTIONALITY))
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If RTL is forced, apply it to the string.
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (flags & Canvas::FORCE_RTL_DIRECTIONALITY) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::i18n::WrapStringWithRTLFormatting(text);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a direction wasn't forced but the UI language is RTL and there were
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // strong RTL characters, ensure RTL is applied.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::i18n::IsRTL() && base::i18n::StringContainsStrongRTLChars(*text)) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::i18n::WrapStringWithRTLFormatting(text);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the default case, the string should be rendered as LTR. RenderText's
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // default directionality is LTR, so the text doesn't need to be wrapped.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that individual runs within the string may still be rendered RTL
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (which will be the case for RTL text under non-RTL locales, since under RTL
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // locales it will be handled by the if statement above).
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif  // defined(OS_WIN)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks each pixel immediately adjacent to the given pixel in the bitmap. If
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// any of them are not the halo color, returns true. This defines the halo of
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// pixels that will appear around the text. Note that we have to check each
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// pixel against both the halo color and transparent since
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// |DrawStringRectWithHalo| will modify the bitmap as it goes, and cleared
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// pixels shouldn't count as changed.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PixelShouldGetHalo(const SkBitmap& bitmap,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int x, int y,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        SkColor halo_color) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (x > 0 &&
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *bitmap.getAddr32(x - 1, y) != halo_color &&
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *bitmap.getAddr32(x - 1, y) != 0)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;  // Touched pixel to the left.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (x < bitmap.width() - 1 &&
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *bitmap.getAddr32(x + 1, y) != halo_color &&
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *bitmap.getAddr32(x + 1, y) != 0)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;  // Touched pixel to the right.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (y > 0 &&
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *bitmap.getAddr32(x, y - 1) != halo_color &&
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *bitmap.getAddr32(x, y - 1) != 0)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;  // Touched pixel above.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (y < bitmap.height() - 1 &&
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *bitmap.getAddr32(x, y + 1) != halo_color &&
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *bitmap.getAddr32(x, y + 1) != 0)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;  // Touched pixel below.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Strips accelerator character prefixes in |text| if needed, based on |flags|.
8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Returns a range in |text| to underline or Range::InvalidRange() if
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// underlining is not needed.
89d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)Range StripAcceleratorChars(int flags, base::string16* text) {
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int char_pos = -1;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int char_span = 0;
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *text = RemoveAcceleratorChar(*text, '&', &char_pos, &char_span);
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if ((flags & Canvas::SHOW_PREFIX) && char_pos != -1)
95d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return Range(char_pos, char_pos + char_span);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
97d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return Range::InvalidRange();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Elides |text| and adjusts |range| appropriately. If eliding causes |range|
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to no longer point to the same character in |text|, |range| is made invalid.
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ElideTextAndAdjustRange(const FontList& font_list,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int width,
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                             base::string16* text,
105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                             Range* range) {
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const base::char16 start_char =
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      (range->IsValid() ? text->at(range->start()) : 0);
10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  *text = ElideText(*text, font_list, width, ELIDE_TAIL);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!range->IsValid())
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (range->start() >= text->length() ||
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      text->at(range->start()) != start_char) {
113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    *range = Range::InvalidRange();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Updates |render_text| from the specified parameters.
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void UpdateRenderText(const Rect& rect,
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      const base::string16& text,
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                      const FontList& font_list,
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      int flags,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      SkColor color,
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      RenderText* render_text) {
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  render_text->SetFontList(font_list);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(text);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetCursorEnabled(false);
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_text->SetDisplayRect(rect);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the text alignment explicitly based on the directionality of the UI,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if not specified.
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!(flags & (Canvas::TEXT_ALIGN_CENTER |
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 Canvas::TEXT_ALIGN_RIGHT |
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 Canvas::TEXT_ALIGN_LEFT))) {
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    flags |= Canvas::DefaultCanvasTextAlignment();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (flags & Canvas::TEXT_ALIGN_RIGHT)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    render_text->SetHorizontalAlignment(ALIGN_RIGHT);
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (flags & Canvas::TEXT_ALIGN_CENTER)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    render_text->SetHorizontalAlignment(ALIGN_CENTER);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    render_text->SetHorizontalAlignment(ALIGN_LEFT);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (flags & Canvas::NO_SUBPIXEL_RENDERING)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    render_text->set_background_is_transparent(true);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  render_text->SetColor(color);
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const int font_style = font_list.GetFontStyle();
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  render_text->SetStyle(BOLD, (font_style & Font::BOLD) != 0);
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  render_text->SetStyle(ITALIC, (font_style & Font::ITALIC) != 0);
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  render_text->SetStyle(UNDERLINE, (font_style & Font::UNDERLINE) != 0);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void Canvas::SizeStringFloat(const base::string16& text,
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             const FontList& font_list,
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             float* width, float* height,
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             int line_height,
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             int flags) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(*width, 0);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(*height, 0);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::string16 adjusted_text = text;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdjustStringDirection(flags, &adjusted_text);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((flags & MULTI_LINE) && *width != 0) {
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    WordWrapBehavior wrap_behavior = TRUNCATE_LONG_WORDS;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (flags & CHARACTER_BREAK)
17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      wrap_behavior = WRAP_LONG_WORDS;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (!(flags & NO_ELLIPSIS))
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      wrap_behavior = ELIDE_LONG_WORDS;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Rect rect(*width, INT_MAX);
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::vector<base::string16> strings;
17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ElideRectangleText(adjusted_text, font_list, rect.width(), rect.height(),
18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                       wrap_behavior, &strings);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    UpdateRenderText(rect, base::string16(), font_list, flags, 0,
1833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                     render_text.get());
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    float h = 0;
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    float w = 0;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < strings.size(); ++i) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StripAcceleratorChars(flags, &strings[i]);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_text->SetText(strings[i]);
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const SizeF& string_size = render_text->GetStringSizeF();
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      w = std::max(w, string_size.width());
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      h += (i > 0 && line_height > 0) ? line_height : string_size.height();
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *width = w;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *height = h;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the string is too long, the call by |RenderTextWin| to |ScriptShape()|
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // will inexplicably fail with result E_INVALIDARG. Guard against this.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const size_t kMaxRenderTextLength = 5000;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (adjusted_text.length() >= kMaxRenderTextLength) {
2013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      *width = font_list.GetExpectedTextWidth(adjusted_text.length());
2023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      *height = font_list.GetHeight();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Rect rect(*width, *height);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StripAcceleratorChars(flags, &adjusted_text);
2073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      UpdateRenderText(rect, adjusted_text, font_list, flags, 0,
2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                       render_text.get());
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const SizeF& string_size = render_text->GetStringSizeF();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *width = string_size.width();
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *height = string_size.height();
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void Canvas::DrawStringRectWithShadows(const base::string16& text,
2173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                       const FontList& font_list,
2183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                       SkColor color,
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                       const Rect& text_bounds,
2203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                       int line_height,
2213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                       int flags,
2223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                       const ShadowValues& shadows) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IntersectsClipRect(text_bounds))
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Rect clip_rect(text_bounds);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  clip_rect.Inset(ShadowValue::GetMargin(shadows));
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
229effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  canvas_->save();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClipRect(clip_rect);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Rect rect(text_bounds);
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::string16 adjusted_text = text;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdjustStringDirection(flags, &adjusted_text);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  render_text->set_shadows(shadows);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (flags & MULTI_LINE) {
24346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    WordWrapBehavior wrap_behavior = IGNORE_LONG_WORDS;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (flags & CHARACTER_BREAK)
24546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      wrap_behavior = WRAP_LONG_WORDS;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (!(flags & NO_ELLIPSIS))
24746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      wrap_behavior = ELIDE_LONG_WORDS;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::vector<base::string16> strings;
25046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ElideRectangleText(adjusted_text, font_list, text_bounds.width(),
25146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                       text_bounds.height(), wrap_behavior, &strings);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < strings.size(); i++) {
254d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      Range range = StripAcceleratorChars(flags, &strings[i]);
2553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      UpdateRenderText(rect, strings[i], font_list, flags, color,
2563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                       render_text.get());
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      int line_padding = 0;
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (line_height > 0)
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        line_padding = line_height - render_text->GetStringSize().height();
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      else
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        line_height = render_text->GetStringSize().height();
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(msw|asvitkine): Center Windows multi-line text: crbug.com/107357
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_WIN)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (i == 0) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(msw|asvitkine): Support multi-line text with varied heights.
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        const int text_height = strings.size() * line_height - line_padding;
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        rect += Vector2d(0, (text_bounds.height() - text_height) / 2);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      rect.set_height(line_height - line_padding);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (range.IsValid())
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        render_text->ApplyStyle(UNDERLINE, true, range);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_text->SetDisplayRect(rect);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_text->Draw(this);
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      rect += Vector2d(0, line_height);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
281d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    Range range = StripAcceleratorChars(flags, &adjusted_text);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool elide_text = ((flags & NO_ELLIPSIS) == 0);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // On Linux, eliding really means fading the end of the string. But only
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // for LTR text. RTL text is still elided (on the left) with "...".
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (elide_text) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_text->SetText(adjusted_text);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) {
29046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        render_text->SetElideBehavior(FADE_TAIL);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elide_text = false;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (elide_text) {
29746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ElideTextAndAdjustRange(font_list, text_bounds.width(), &adjusted_text,
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &range);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    UpdateRenderText(rect, adjusted_text, font_list, flags, color,
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     render_text.get());
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (range.IsValid())
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      render_text->ApplyStyle(UNDERLINE, true, range);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    render_text->Draw(this);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas_->restore();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void Canvas::DrawStringRectWithHalo(const base::string16& text,
3123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                    const FontList& font_list,
3133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                    SkColor text_color,
3143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                    SkColor halo_color_in,
3153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                    const Rect& display_rect,
3163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                    int flags) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some callers will have semitransparent halo colors, which we don't handle
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (since the resulting image can have 1-bit transparency only).
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkColor halo_color = SkColorSetA(halo_color_in, 0xFF);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a temporary buffer filled with the halo color. It must leave room
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for the 1-pixel border around the text.
3233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Size size(display_rect.width() + 2, display_rect.height() + 2);
3241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Canvas text_canvas(size, image_scale(), false);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkPaint bkgnd_paint;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bkgnd_paint.setColor(halo_color);
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  text_canvas.DrawRect(Rect(size), bkgnd_paint);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw the text into the temporary buffer. This will have correct
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ClearType since the background color is the same as the halo color.
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  text_canvas.DrawStringRectWithFlags(
3323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      text, font_list, text_color,
3333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      Rect(1, 1, display_rect.width(), display_rect.height()), flags);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32_t halo_premul = SkPreMultiplyColor(halo_color);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkBitmap& text_bitmap = const_cast<SkBitmap&>(
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(true));
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int cur_y = 0; cur_y < text_bitmap.height(); cur_y++) {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t* text_row = text_bitmap.getAddr32(0, cur_y);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int cur_x = 0; cur_x < text_bitmap.width(); cur_x++) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (text_row[cur_x] == halo_premul) {
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // This pixel was not touched by the text routines. See if it borders
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // a touched pixel in any of the 4 directions (not diagonally).
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!PixelShouldGetHalo(text_bitmap, cur_x, cur_y, halo_premul))
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          text_row[cur_x] = 0;  // Make transparent.
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        text_row[cur_x] |= 0xff << SK_A32_SHIFT;  // Make opaque.
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw the halo bitmap with blur.
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ImageSkia text_image = ImageSkia(ImageSkiaRep(text_bitmap,
35568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      text_canvas.image_scale()));
3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DrawImageInt(text_image, display_rect.x() - 1, display_rect.y() - 1);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void Canvas::DrawFadedString(const base::string16& text,
36046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                             const FontList& font_list,
36146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                             SkColor color,
36246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                             const Rect& display_rect,
36346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                             int flags) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the whole string fits in the destination then just draw it directly.
3653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (GetStringWidth(text, font_list) <= display_rect.width()) {
3663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DrawStringRectWithFlags(text, font_list, color, display_rect, flags);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
370116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Align with forced content directionality, overriding alignment flags.
371116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (flags & FORCE_RTL_DIRECTIONALITY) {
372116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    flags &= ~(TEXT_ALIGN_CENTER | TEXT_ALIGN_LEFT);
373116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    flags |= TEXT_ALIGN_RIGHT;
374116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else if (flags & FORCE_LTR_DIRECTIONALITY) {
375116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    flags &= ~(TEXT_ALIGN_CENTER | TEXT_ALIGN_RIGHT);
376116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    flags |= TEXT_ALIGN_LEFT;
377116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else if (!(flags & TEXT_ALIGN_LEFT) && !(flags & TEXT_ALIGN_RIGHT)) {
378116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Also align with content directionality instead of fading both ends.
37946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    flags &= ~TEXT_ALIGN_CENTER;
38046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const bool is_rtl = base::i18n::GetFirstStrongCharacterDirection(text) ==
38146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        base::i18n::RIGHT_TO_LEFT;
38246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    flags |= is_rtl ? TEXT_ALIGN_RIGHT : TEXT_ALIGN_LEFT;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
38446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  flags |= NO_ELLIPSIS;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Rect rect = display_rect;
3881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  UpdateRenderText(rect, text, font_list, flags, color, render_text.get());
38946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  render_text->SetElideBehavior(FADE_TAIL);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
391effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  canvas_->save();
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClipRect(display_rect);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->Draw(this);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas_->restore();
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gfx
398