summaryrefslogtreecommitdiffstats
path: root/chrome/common/gfx/chrome_canvas_win.cc
blob: f28b0cb3d42aa88a85e1b69d3ee8b51e6ef833ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright (c) 2006-2008 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 "chrome/common/gfx/chrome_canvas.h"

#include <limits>

#include "base/gfx/rect.h"
#include "base/logging.h"
#include "skia/include/SkShader.h"
#include "chrome/common/gfx/chrome_font.h"
#include "chrome/common/l10n_util.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());
  if (l10n_util::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
// ChromeCanvas flags.
int ComputeFormatFlags(int flags) {
  int f = 0;

  // 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 & (ChromeCanvas::TEXT_ALIGN_CENTER |
                 ChromeCanvas::TEXT_ALIGN_RIGHT |
                 ChromeCanvas::TEXT_ALIGN_LEFT))) {
    flags |= l10n_util::DefaultCanvasTextAlignment();
  }

  if (flags & ChromeCanvas::HIDE_PREFIX)
    f |= DT_HIDEPREFIX;
  else if ((flags & ChromeCanvas::SHOW_PREFIX) == 0)
    f |= DT_NOPREFIX;

  if (flags & ChromeCanvas::MULTI_LINE) {
    f |= DT_WORDBREAK;
  } else {
    f |= DT_SINGLELINE | DT_VCENTER;
    if (!(flags & ChromeCanvas::NO_ELLIPSIS))
      f |= DT_END_ELLIPSIS;
  }

  // vertical alignment
  if (flags & ChromeCanvas::TEXT_VALIGN_TOP)
    f |= DT_TOP;
  else if (flags & ChromeCanvas::TEXT_VALIGN_BOTTOM)
    f |= DT_BOTTOM;
  else
    f |= DT_VCENTER;

  // horizontal alignment
  if (flags & ChromeCanvas::TEXT_ALIGN_CENTER)
    f |= DT_CENTER;
  else if (flags & ChromeCanvas::TEXT_ALIGN_RIGHT)
    f |= DT_RIGHT;
  else
    f |= DT_LEFT;

  // 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.
  if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
    f |= DT_RTLREADING;

  return f;
}

}  // anonymous namespace

ChromeCanvas::ChromeCanvas(int width, int height, bool is_opaque)
    : skia::PlatformCanvasWin(width, height, is_opaque) {
}

ChromeCanvas::ChromeCanvas() : skia::PlatformCanvasWin() {
}

ChromeCanvas::~ChromeCanvas() {
}

// static
void ChromeCanvas::SizeStringInt(const std::wstring& text,
                                 const ChromeFont& font,
                                 int *width, int *height, int flags) {
  HDC dc = GetDC(NULL);
  HFONT old_font = static_cast<HFONT>(SelectObject(dc, font.hfont()));
  RECT b;
  b.left = 0;
  b.top = 0;
  b.right = *width;
  if (b.right == 0 && !text.empty()) {
    // Width needs to be at least 1 or else DoDrawText will not resize it.
    b.right = 1;
  }
  b.bottom = *height;
  DoDrawText(dc, text, &b, ComputeFormatFlags(flags) | DT_CALCRECT);

  // 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);
  *width = b.right;
  *height = b.bottom;

  ReleaseDC(NULL, dc);
}

void ChromeCanvas::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;

  getTopPlatformDevice().prepareForGDI(x, y, w, h);
  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);
  DoDrawText(dc, text, &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);
  getTopPlatformDevice().postProcessGDI(x, y, w, h);
}

void ChromeCanvas::DrawStringInt(const std::wstring& text,
                                 const ChromeFont& font,
                                 const SkColor& color,
                                 int x, int y,
                                 int w, int h) {
  DrawStringInt(text, font, color, x, y, w, h,
                l10n_util::DefaultCanvasTextAlignment());
}

void ChromeCanvas::DrawStringInt(const std::wstring& text,
                                 const ChromeFont& font,
                                 const SkColor& color,
                                 int x, int y, int w, int h, int flags) {
  DrawStringInt(text, font.hfont(), color, x, y, w, h, flags);
}