| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/pango_util.h" | 5 #include "ui/gfx/pango_util.h" |
| 6 | 6 |
| 7 #include <cairo/cairo.h> | 7 #include <cairo/cairo.h> |
| 8 #include <pango/pango.h> | 8 #include <pango/pango.h> |
| 9 #include <pango/pangocairo.h> | 9 #include <pango/pangocairo.h> |
| 10 #include <string> | 10 #include <string> |
| 11 | 11 |
| 12 #include <algorithm> | 12 #include <algorithm> |
| 13 #include <map> | 13 #include <map> |
| 14 | 14 |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
| 17 #include "ui/gfx/canvas.h" | 17 #include "ui/gfx/canvas.h" |
| 18 #include "ui/gfx/font_list.h" | 18 #include "ui/gfx/font_list.h" |
| 19 #include "ui/gfx/font_render_params.h" | 19 #include "ui/gfx/font_render_params.h" |
| 20 #include "ui/gfx/linux_font_delegate.h" | 20 #include "ui/gfx/linux_font_delegate.h" |
| 21 #include "ui/gfx/platform_font_pango.h" | 21 #include "ui/gfx/platform_font_pango.h" |
| 22 #include "ui/gfx/text_utils.h" | 22 #include "ui/gfx/text_utils.h" |
| 23 | 23 |
| 24 namespace gfx { | 24 namespace gfx { |
| 25 | 25 |
| 26 namespace { | 26 namespace { |
| 27 | 27 |
| 28 // Marker for accelerators in the text. | |
| 29 const gunichar kAcceleratorChar = '&'; | |
| 30 | |
| 31 // Creates and returns a PangoContext. The caller owns the context. | 28 // Creates and returns a PangoContext. The caller owns the context. |
| 32 PangoContext* GetPangoContext() { | 29 PangoContext* GetPangoContext() { |
| 33 PangoFontMap* font_map = pango_cairo_font_map_get_default(); | 30 PangoFontMap* font_map = pango_cairo_font_map_get_default(); |
| 34 return pango_font_map_create_context(font_map); | 31 return pango_font_map_create_context(font_map); |
| 35 } | 32 } |
| 36 | 33 |
| 37 // Creates a new cairo_font_options_t based on |params|. | |
| 38 cairo_font_options_t* CreateCairoFontOptions(const FontRenderParams& params) { | |
| 39 cairo_font_options_t* cairo_font_options = cairo_font_options_create(); | |
| 40 | |
| 41 FontRenderParams::SubpixelRendering subpixel = params.subpixel_rendering; | |
| 42 if (!params.antialiasing) { | |
| 43 cairo_font_options_set_antialias(cairo_font_options, CAIRO_ANTIALIAS_NONE); | |
| 44 } else if (subpixel == FontRenderParams::SUBPIXEL_RENDERING_NONE) { | |
| 45 cairo_font_options_set_antialias(cairo_font_options, CAIRO_ANTIALIAS_GRAY); | |
| 46 } else { | |
| 47 cairo_font_options_set_antialias(cairo_font_options, | |
| 48 CAIRO_ANTIALIAS_SUBPIXEL); | |
| 49 cairo_subpixel_order_t cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; | |
| 50 if (subpixel == FontRenderParams::SUBPIXEL_RENDERING_RGB) | |
| 51 cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; | |
| 52 else if (subpixel == FontRenderParams::SUBPIXEL_RENDERING_BGR) | |
| 53 cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; | |
| 54 else if (subpixel == FontRenderParams::SUBPIXEL_RENDERING_VRGB) | |
| 55 cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; | |
| 56 else if (subpixel == FontRenderParams::SUBPIXEL_RENDERING_VBGR) | |
| 57 cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; | |
| 58 else | |
| 59 NOTREACHED() << "Unhandled subpixel rendering type " << subpixel; | |
| 60 cairo_font_options_set_subpixel_order(cairo_font_options, | |
| 61 cairo_subpixel_order); | |
| 62 } | |
| 63 | |
| 64 if (params.hinting == FontRenderParams::HINTING_NONE || | |
| 65 params.subpixel_positioning) { | |
| 66 cairo_font_options_set_hint_style(cairo_font_options, | |
| 67 CAIRO_HINT_STYLE_NONE); | |
| 68 cairo_font_options_set_hint_metrics(cairo_font_options, | |
| 69 CAIRO_HINT_METRICS_OFF); | |
| 70 } else { | |
| 71 cairo_hint_style_t cairo_hint_style = CAIRO_HINT_STYLE_DEFAULT; | |
| 72 if (params.hinting == FontRenderParams::HINTING_SLIGHT) | |
| 73 cairo_hint_style = CAIRO_HINT_STYLE_SLIGHT; | |
| 74 else if (params.hinting == FontRenderParams::HINTING_MEDIUM) | |
| 75 cairo_hint_style = CAIRO_HINT_STYLE_MEDIUM; | |
| 76 else if (params.hinting == FontRenderParams::HINTING_FULL) | |
| 77 cairo_hint_style = CAIRO_HINT_STYLE_FULL; | |
| 78 else | |
| 79 NOTREACHED() << "Unhandled hinting style " << params.hinting; | |
| 80 cairo_font_options_set_hint_style(cairo_font_options, cairo_hint_style); | |
| 81 cairo_font_options_set_hint_metrics(cairo_font_options, | |
| 82 CAIRO_HINT_METRICS_ON); | |
| 83 } | |
| 84 | |
| 85 return cairo_font_options; | |
| 86 } | |
| 87 | |
| 88 // Returns the DPI that should be used by Pango. | 34 // Returns the DPI that should be used by Pango. |
| 89 double GetPangoDPI() { | 35 double GetPangoDPI() { |
| 90 static double dpi = -1.0; | 36 static double dpi = -1.0; |
| 91 if (dpi < 0.0) { | 37 if (dpi < 0.0) { |
| 92 const gfx::LinuxFontDelegate* delegate = gfx::LinuxFontDelegate::instance(); | 38 const gfx::LinuxFontDelegate* delegate = gfx::LinuxFontDelegate::instance(); |
| 93 if (delegate) | 39 if (delegate) |
| 94 dpi = delegate->GetFontDPI(); | 40 dpi = delegate->GetFontDPI(); |
| 95 if (dpi <= 0.0) | 41 if (dpi <= 0.0) |
| 96 dpi = 96.0; | 42 dpi = 96.0; |
| 97 } | 43 } |
| 98 return dpi; | 44 return dpi; |
| 99 } | 45 } |
| 100 | 46 |
| 101 // Returns the number of pixels in a point. | 47 // Returns the number of pixels in a point. |
| 102 // - multiply a point size by this to get pixels ("device units") | 48 // - multiply a point size by this to get pixels ("device units") |
| 103 // - divide a pixel size by this to get points | 49 // - divide a pixel size by this to get points |
| 104 double GetPixelsInPoint() { | 50 double GetPixelsInPoint() { |
| 105 static double pixels_in_point = GetPangoDPI() / 72.0; // 72 points in an inch | 51 static double pixels_in_point = GetPangoDPI() / 72.0; // 72 points in an inch |
| 106 return pixels_in_point; | 52 return pixels_in_point; |
| 107 } | 53 } |
| 108 | 54 |
| 109 } // namespace | 55 } // namespace |
| 110 | 56 |
| 111 void SetUpPangoLayout( | |
| 112 PangoLayout* layout, | |
| 113 const base::string16& text, | |
| 114 const FontList& font_list, | |
| 115 base::i18n::TextDirection text_direction, | |
| 116 int flags) { | |
| 117 cairo_font_options_t* cairo_font_options = CreateCairoFontOptions( | |
| 118 font_list.GetPrimaryFont().GetFontRenderParams()); | |
| 119 | |
| 120 // If we got an explicit request to turn off subpixel rendering, disable it. | |
| 121 if ((flags & Canvas::NO_SUBPIXEL_RENDERING) && | |
| 122 (cairo_font_options_get_antialias(cairo_font_options) == | |
| 123 CAIRO_ANTIALIAS_SUBPIXEL)) | |
| 124 cairo_font_options_set_antialias(cairo_font_options, CAIRO_ANTIALIAS_GRAY); | |
| 125 | |
| 126 // This needs to be done early on; it has no effect when called just before | |
| 127 // pango_cairo_show_layout(). | |
| 128 pango_cairo_context_set_font_options( | |
| 129 pango_layout_get_context(layout), cairo_font_options); | |
| 130 cairo_font_options_destroy(cairo_font_options); | |
| 131 cairo_font_options = NULL; | |
| 132 | |
| 133 // Set Pango's base text direction explicitly from |text_direction|. | |
| 134 pango_layout_set_auto_dir(layout, FALSE); | |
| 135 pango_context_set_base_dir(pango_layout_get_context(layout), | |
| 136 (text_direction == base::i18n::RIGHT_TO_LEFT ? | |
| 137 PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR)); | |
| 138 | |
| 139 if (flags & Canvas::TEXT_ALIGN_CENTER) { | |
| 140 // We don't support center aligned w/ eliding. | |
| 141 DCHECK(gfx::Canvas::NO_ELLIPSIS); | |
| 142 pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); | |
| 143 } else if (flags & Canvas::TEXT_ALIGN_RIGHT) { | |
| 144 pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT); | |
| 145 } | |
| 146 | |
| 147 if (flags & Canvas::NO_ELLIPSIS) { | |
| 148 pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); | |
| 149 if (flags & Canvas::MULTI_LINE) { | |
| 150 pango_layout_set_wrap(layout, | |
| 151 (flags & Canvas::CHARACTER_BREAK) ? | |
| 152 PANGO_WRAP_WORD_CHAR : PANGO_WRAP_WORD); | |
| 153 } | |
| 154 } else if (text_direction == base::i18n::RIGHT_TO_LEFT) { | |
| 155 pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); | |
| 156 } else { | |
| 157 // Fading the text will be handled in the draw operation. | |
| 158 // Ensure that the text is only on one line. | |
| 159 pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); | |
| 160 pango_layout_set_width(layout, -1); | |
| 161 } | |
| 162 | |
| 163 // Set the layout's resolution to match the resolution used to convert from | |
| 164 // points to pixels. | |
| 165 pango_cairo_context_set_resolution(pango_layout_get_context(layout), | |
| 166 GetPangoDPI()); | |
| 167 | |
| 168 // Set text and accelerator character if needed. | |
| 169 if (flags & Canvas::SHOW_PREFIX) { | |
| 170 // Escape the text string to be used as markup. | |
| 171 std::string utf8 = base::UTF16ToUTF8(text); | |
| 172 gchar* escaped_text = g_markup_escape_text(utf8.c_str(), utf8.size()); | |
| 173 pango_layout_set_markup_with_accel(layout, | |
| 174 escaped_text, | |
| 175 strlen(escaped_text), | |
| 176 kAcceleratorChar, NULL); | |
| 177 g_free(escaped_text); | |
| 178 } else { | |
| 179 std::string utf8; | |
| 180 | |
| 181 // Remove the ampersand character. A double ampersand is output as | |
| 182 // a single ampersand. | |
| 183 if (flags & Canvas::HIDE_PREFIX) { | |
| 184 DCHECK_EQ(1, g_unichar_to_utf8(kAcceleratorChar, NULL)); | |
| 185 base::string16 accelerator_removed = | |
| 186 RemoveAcceleratorChar(text, | |
| 187 static_cast<base::char16>(kAcceleratorChar), | |
| 188 NULL, NULL); | |
| 189 utf8 = base::UTF16ToUTF8(accelerator_removed); | |
| 190 } else { | |
| 191 utf8 = base::UTF16ToUTF8(text); | |
| 192 } | |
| 193 | |
| 194 pango_layout_set_text(layout, utf8.data(), utf8.size()); | |
| 195 } | |
| 196 | |
| 197 ScopedPangoFontDescription desc(pango_font_description_from_string( | |
| 198 font_list.GetFontDescriptionString().c_str())); | |
| 199 pango_layout_set_font_description(layout, desc.get()); | |
| 200 } | |
| 201 | |
| 202 int GetPangoFontSizeInPixels(PangoFontDescription* pango_font) { | 57 int GetPangoFontSizeInPixels(PangoFontDescription* pango_font) { |
| 203 // If the size is absolute, then it's in Pango units rather than points. There | 58 // If the size is absolute, then it's in Pango units rather than points. There |
| 204 // are PANGO_SCALE Pango units in a device unit (pixel). | 59 // are PANGO_SCALE Pango units in a device unit (pixel). |
| 205 if (pango_font_description_get_size_is_absolute(pango_font)) | 60 if (pango_font_description_get_size_is_absolute(pango_font)) |
| 206 return pango_font_description_get_size(pango_font) / PANGO_SCALE; | 61 return pango_font_description_get_size(pango_font) / PANGO_SCALE; |
| 207 | 62 |
| 208 // Otherwise, we need to convert from points. | 63 // Otherwise, we need to convert from points. |
| 209 return static_cast<int>(GetPixelsInPoint() * | 64 return static_cast<int>(GetPixelsInPoint() * |
| 210 pango_font_description_get_size(pango_font) / PANGO_SCALE + 0.5); | 65 pango_font_description_get_size(pango_font) / PANGO_SCALE + 0.5); |
| 211 } | 66 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 228 | 83 |
| 229 if (i == desc_to_metrics->end()) { | 84 if (i == desc_to_metrics->end()) { |
| 230 PangoFontMetrics* metrics = pango_context_get_metrics(context, desc, NULL); | 85 PangoFontMetrics* metrics = pango_context_get_metrics(context, desc, NULL); |
| 231 desc_to_metrics->insert(std::make_pair(desc_hash, metrics)); | 86 desc_to_metrics->insert(std::make_pair(desc_hash, metrics)); |
| 232 return metrics; | 87 return metrics; |
| 233 } | 88 } |
| 234 return i->second; | 89 return i->second; |
| 235 } | 90 } |
| 236 | 91 |
| 237 } // namespace gfx | 92 } // namespace gfx |
| OLD | NEW |