| File: | _build/../src/drawing-cairo.cc |
| Warning: | line 356, column 3 Value stored to 'n_cr_glyphs' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* |
| 2 | * Copyright (C) 2003,2008 Red Hat, Inc. |
| 3 | * Copyright © 2019, 2020 Christian Persch |
| 4 | * |
| 5 | * This library is free software; you can redistribute it and/or |
| 6 | * modify it under the terms of the GNU Lesser General Public |
| 7 | * License as published by the Free Software Foundation; either |
| 8 | * version 3 of the License, or (at your option) any later version. |
| 9 | * |
| 10 | * This library is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | * Lesser General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
| 17 | */ |
| 18 | |
| 19 | #include "config.h" |
| 20 | |
| 21 | #include <cmath> |
| 22 | |
| 23 | #include "bidi.hh" |
| 24 | #include "debug.h" |
| 25 | #include "drawing-cairo.hh" |
| 26 | #include "fonts-pangocairo.hh" |
| 27 | |
| 28 | /* cairo_show_glyphs accepts runs up to 102 glyphs before it allocates a |
| 29 | * temporary array. |
| 30 | * |
| 31 | * Setting this to a large value can cause dramatic slow-downs for some |
| 32 | * xservers (notably fglrx), see bug #410534. |
| 33 | */ |
| 34 | #define MAX_RUN_LENGTH100 100 |
| 35 | |
| 36 | #define BTE_DRAW_NORMAL0 0 |
| 37 | #define BTE_DRAW_BOLD1 1 |
| 38 | #define BTE_DRAW_ITALIC2 2 |
| 39 | #define BTE_DRAW_BOLD_ITALIC3 3 |
| 40 | |
| 41 | static unsigned |
| 42 | attr_to_style(uint32_t attr) |
| 43 | { |
| 44 | auto style = unsigned{0}; |
| 45 | if (attr & BTE_ATTR_BOLD(1U << (((0) + (4)) + (1)))) |
| 46 | style |= BTE_DRAW_BOLD1; |
| 47 | if (attr & BTE_ATTR_ITALIC(1U << ((((0) + (4)) + (1)) + (1)))) |
| 48 | style |= BTE_DRAW_ITALIC2; |
| 49 | return style; |
| 50 | } |
| 51 | |
| 52 | static inline constexpr double |
| 53 | _bte_draw_get_undercurl_rad(gint width) |
| 54 | { |
| 55 | return width / 2. / M_SQRT21.41421356237309504880; |
| 56 | } |
| 57 | |
| 58 | static inline constexpr double |
| 59 | _bte_draw_get_undercurl_arc_height(gint width) |
| 60 | { |
| 61 | return _bte_draw_get_undercurl_rad(width) * (1. - M_SQRT21.41421356237309504880 / 2.); |
| 62 | } |
| 63 | |
| 64 | double |
| 65 | _bte_draw_get_undercurl_height(gint width, double line_width) |
| 66 | { |
| 67 | return 2. * _bte_draw_get_undercurl_arc_height(width) + line_width; |
| 68 | } |
| 69 | |
| 70 | namespace bte { |
| 71 | namespace view { |
| 72 | |
| 73 | DrawingContext::~DrawingContext() |
| 74 | { |
| 75 | clear_font_cache(); |
| 76 | } |
| 77 | |
| 78 | void |
| 79 | DrawingContext::clear_font_cache() |
| 80 | { |
| 81 | // m_fonts = {}; |
| 82 | |
| 83 | for (auto style = int{0}; style < 4; ++style) { |
| 84 | if (m_fonts[style] != nullptr) |
| 85 | m_fonts[style]->unref(); |
| 86 | m_fonts[style] = nullptr; |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | void |
| 91 | DrawingContext::set_cairo(cairo_t* cr) noexcept |
| 92 | { |
| 93 | m_cr = cr; |
| 94 | } |
| 95 | |
| 96 | void |
| 97 | DrawingContext::clip(cairo_rectangle_int_t const* rect) |
| 98 | { |
| 99 | cairo_save(m_cr); |
| 100 | cairo_rectangle(m_cr, |
| 101 | rect->x, rect->y, rect->width, rect->height); |
| 102 | cairo_clip(m_cr); |
| 103 | } |
| 104 | |
| 105 | void |
| 106 | DrawingContext::unclip() |
| 107 | { |
| 108 | cairo_restore(m_cr); |
| 109 | } |
| 110 | |
| 111 | void |
| 112 | DrawingContext::set_source_color_alpha(bte::color::rgb const* color, |
| 113 | double alpha) |
| 114 | { |
| 115 | g_assert(m_cr)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_28 = 0; if (m_cr) _g_boolean_var_28 = 1; _g_boolean_var_28; }), 1)) ; else g_assertion_message_expr ("BTE", "../src/drawing-cairo.cc" , 115, ((const char*) (__PRETTY_FUNCTION__)), "m_cr"); } while (0); |
| 116 | cairo_set_source_rgba(m_cr, |
| 117 | color->red / 65535., |
| 118 | color->green / 65535., |
| 119 | color->blue / 65535., |
| 120 | alpha); |
| 121 | } |
| 122 | |
| 123 | void |
| 124 | DrawingContext::clear(int x, |
| 125 | int y, |
| 126 | int width, |
| 127 | int height, |
| 128 | bte::color::rgb const* color, |
| 129 | double alpha) |
| 130 | { |
| 131 | g_assert(m_cr)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_29 = 0; if (m_cr) _g_boolean_var_29 = 1; _g_boolean_var_29; }), 1)) ; else g_assertion_message_expr ("BTE", "../src/drawing-cairo.cc" , 131, ((const char*) (__PRETTY_FUNCTION__)), "m_cr"); } while (0); |
| 132 | cairo_rectangle(m_cr, x, y, width, height); |
| 133 | cairo_set_operator(m_cr, CAIRO_OPERATOR_SOURCE); |
| 134 | set_source_color_alpha(color, alpha); |
| 135 | cairo_fill(m_cr); |
| 136 | } |
| 137 | |
| 138 | void |
| 139 | DrawingContext::set_text_font(CtkWidget* widget, |
| 140 | PangoFontDescription const* fontdesc, |
| 141 | double cell_width_scale, |
| 142 | double cell_height_scale) |
| 143 | { |
| 144 | PangoFontDescription *bolddesc = nullptr; |
| 145 | PangoFontDescription *italicdesc = nullptr; |
| 146 | PangoFontDescription *bolditalicdesc = nullptr; |
| 147 | gint normal, bold, ratio; |
| 148 | |
| 149 | _bte_debug_print (BTE_DEBUG_DRAW, "draw_set_text_font\n")do { } while(0); |
| 150 | |
| 151 | clear_font_cache(); |
| 152 | |
| 153 | /* calculate bold font desc */ |
| 154 | bolddesc = pango_font_description_copy (fontdesc); |
| 155 | pango_font_description_set_weight (bolddesc, PANGO_WEIGHT_BOLD); |
| 156 | |
| 157 | /* calculate italic font desc */ |
| 158 | italicdesc = pango_font_description_copy (fontdesc); |
| 159 | pango_font_description_set_style (italicdesc, PANGO_STYLE_ITALIC); |
| 160 | |
| 161 | /* calculate bold italic font desc */ |
| 162 | bolditalicdesc = pango_font_description_copy (bolddesc); |
| 163 | pango_font_description_set_style (bolditalicdesc, PANGO_STYLE_ITALIC); |
| 164 | |
| 165 | m_fonts[BTE_DRAW_NORMAL0] = FontInfo::create_for_widget(widget, fontdesc); |
| 166 | m_fonts[BTE_DRAW_BOLD1] = FontInfo::create_for_widget(widget, bolddesc); |
| 167 | m_fonts[BTE_DRAW_ITALIC2] = FontInfo::create_for_widget(widget, italicdesc); |
| 168 | m_fonts[BTE_DRAW_ITALIC2 | BTE_DRAW_BOLD1] = |
| 169 | FontInfo::create_for_widget(widget, bolditalicdesc); |
| 170 | pango_font_description_free (bolddesc); |
| 171 | pango_font_description_free (italicdesc); |
| 172 | pango_font_description_free (bolditalicdesc); |
| 173 | |
| 174 | /* Decide if we should keep this bold font face, per bug 54926: |
| 175 | * - reject bold font if it is not within 10% of normal font width |
| 176 | */ |
| 177 | normal = BTE_DRAW_NORMAL0; |
| 178 | bold = normal | BTE_DRAW_BOLD1; |
| 179 | ratio = m_fonts[bold]->width() * 100 / m_fonts[normal]->width(); |
| 180 | if (abs(ratio - 100) > 10) { |
| 181 | _bte_debug_print (BTE_DEBUG_DRAW,do { } while(0) |
| 182 | "Rejecting bold font (%i%%).\n", ratio)do { } while(0); |
| 183 | m_fonts[bold]->unref(); |
| 184 | m_fonts[bold] = m_fonts[normal]->ref(); |
| 185 | } |
| 186 | normal = BTE_DRAW_ITALIC2; |
| 187 | bold = normal | BTE_DRAW_BOLD1; |
| 188 | ratio = m_fonts[bold]->width() * 100 / m_fonts[normal]->width(); |
| 189 | if (abs(ratio - 100) > 10) { |
| 190 | _bte_debug_print (BTE_DEBUG_DRAW,do { } while(0) |
| 191 | "Rejecting italic bold font (%i%%).\n", ratio)do { } while(0); |
| 192 | m_fonts[bold]->unref(); |
| 193 | m_fonts[bold] = m_fonts[normal]->ref(); |
| 194 | } |
| 195 | |
| 196 | /* Apply letter spacing and line spacing. */ |
| 197 | m_cell_width = m_fonts[BTE_DRAW_NORMAL0]->width() * cell_width_scale; |
| 198 | m_char_spacing.left = (m_cell_width - m_fonts[BTE_DRAW_NORMAL0]->width()) / 2; |
| 199 | m_char_spacing.right = (m_cell_width - m_fonts[BTE_DRAW_NORMAL0]->width() + 1) / 2; |
| 200 | m_cell_height = m_fonts[BTE_DRAW_NORMAL0]->height() * cell_height_scale; |
| 201 | m_char_spacing.top = (m_cell_height - m_fonts[BTE_DRAW_NORMAL0]->height() + 1) / 2; |
| 202 | m_char_spacing.bottom = (m_cell_height - m_fonts[BTE_DRAW_NORMAL0]->height()) / 2; |
| 203 | |
| 204 | m_undercurl_surface.reset(); |
| 205 | } |
| 206 | |
| 207 | void |
| 208 | DrawingContext::get_text_metrics(int* cell_width, |
| 209 | int* cell_height, |
| 210 | int* char_ascent, |
| 211 | int* char_descent, |
| 212 | CtkBorder* char_spacing) |
| 213 | { |
| 214 | g_return_if_fail (m_fonts[BTE_DRAW_NORMAL] != nullptr)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_30 = 0; if (m_fonts[0] != nullptr) _g_boolean_var_30 = 1; _g_boolean_var_30 ; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "m_fonts[BTE_DRAW_NORMAL] != nullptr" ); return; } } while (0); |
| 215 | |
| 216 | if (cell_width) |
| 217 | *cell_width = m_cell_width; |
| 218 | if (cell_height) |
| 219 | *cell_height = m_cell_height; |
| 220 | if (char_ascent) |
| 221 | *char_ascent = m_fonts[BTE_DRAW_NORMAL0]->ascent(); |
| 222 | if (char_descent) |
| 223 | *char_descent = m_fonts[BTE_DRAW_NORMAL0]->height() - m_fonts[BTE_DRAW_NORMAL0]->ascent(); |
| 224 | if (char_spacing) |
| 225 | *char_spacing = m_char_spacing; |
| 226 | } |
| 227 | |
| 228 | /* Stores the left and right edges of the given glyph, relative to the cell's left edge. */ |
| 229 | void |
| 230 | DrawingContext::get_char_edges(bteunistr c, |
| 231 | int columns, |
| 232 | uint32_t attr, |
| 233 | int& left, |
| 234 | int& right) |
| 235 | { |
| 236 | if (G_UNLIKELY(m_minifont.unistr_is_local_graphic (c))(__builtin_expect (__extension__ ({ int _g_boolean_var_31 = 0 ; if (m_minifont.unistr_is_local_graphic (c)) _g_boolean_var_31 = 1; _g_boolean_var_31; }), 0))) { |
| 237 | left = 0; |
| 238 | right = m_cell_width * columns; |
| 239 | return; |
| 240 | } |
| 241 | |
| 242 | int l, w, normal_width, fits_width; |
| 243 | |
| 244 | if (G_UNLIKELY (m_fonts[BTE_DRAW_NORMAL] == nullptr)(__builtin_expect (__extension__ ({ int _g_boolean_var_32 = 0 ; if (m_fonts[0] == nullptr) _g_boolean_var_32 = 1; _g_boolean_var_32 ; }), 0))) { |
| 245 | left = 0; |
| 246 | right = 0; |
| 247 | return; |
| 248 | } |
| 249 | |
| 250 | w = m_fonts[attr_to_style(attr)]->get_unistr_info(c)->width; |
| 251 | normal_width = m_fonts[BTE_DRAW_NORMAL0]->width() * columns; |
| 252 | fits_width = m_cell_width * columns; |
| 253 | |
| 254 | if (G_LIKELY (w <= normal_width)(__builtin_expect (__extension__ ({ int _g_boolean_var_33 = 0 ; if (w <= normal_width) _g_boolean_var_33 = 1; _g_boolean_var_33 ; }), 1))) { |
| 255 | /* The regular case: The glyph is not wider than one (CJK: two) regular character(s). |
| 256 | * Align to the left, after applying half (CJK: one) letter spacing. */ |
| 257 | l = m_char_spacing.left + (columns == 2 ? m_char_spacing.right : 0); |
| 258 | } else if (G_UNLIKELY (w <= fits_width)(__builtin_expect (__extension__ ({ int _g_boolean_var_34 = 0 ; if (w <= fits_width) _g_boolean_var_34 = 1; _g_boolean_var_34 ; }), 0))) { |
| 259 | /* Slightly wider glyph, but still fits in the cell (spacing included). This case can |
| 260 | * only happen with nonzero letter spacing. Center the glyph in the cell(s). */ |
| 261 | l = (fits_width - w) / 2; |
| 262 | } else { |
| 263 | /* Even wider glyph: doesn't fit in the cell. Align at left and overflow on the right. */ |
| 264 | l = 0; |
| 265 | } |
| 266 | |
| 267 | left = l; |
| 268 | right = l + w; |
| 269 | } |
| 270 | |
| 271 | void |
| 272 | DrawingContext::draw_text_internal(TextRequest* requests, |
| 273 | gsize n_requests, |
| 274 | uint32_t attr, |
| 275 | bte::color::rgb const* color, |
| 276 | double alpha) |
| 277 | { |
| 278 | gsize i; |
| 279 | cairo_scaled_font_t *last_scaled_font = nullptr; |
| 280 | int n_cr_glyphs = 0; |
| 281 | cairo_glyph_t cr_glyphs[MAX_RUN_LENGTH100]; |
| 282 | auto font = m_fonts[attr_to_style(attr)]; |
| 283 | |
| 284 | g_return_if_fail (font != nullptr)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_35 = 0; if (font != nullptr) _g_boolean_var_35 = 1; _g_boolean_var_35 ; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "font != nullptr"); return; } } while (0); |
| 285 | |
| 286 | g_assert(m_cr)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_36 = 0; if (m_cr) _g_boolean_var_36 = 1; _g_boolean_var_36; }), 1)) ; else g_assertion_message_expr ("BTE", "../src/drawing-cairo.cc" , 286, ((const char*) (__PRETTY_FUNCTION__)), "m_cr"); } while (0); |
| 287 | set_source_color_alpha(color, alpha); |
| 288 | cairo_set_operator(m_cr, CAIRO_OPERATOR_OVER); |
| 289 | |
| 290 | for (i = 0; i < n_requests; i++) { |
| 291 | bteunistr c = requests[i].c; |
| 292 | |
| 293 | if (G_UNLIKELY (requests[i].mirror)(__builtin_expect (__extension__ ({ int _g_boolean_var_37 = 0 ; if (requests[i].mirror) _g_boolean_var_37 = 1; _g_boolean_var_37 ; }), 0))) { |
| 294 | bte_bidi_get_mirror_char (c, requests[i].box_mirror, &c); |
| 295 | } |
| 296 | |
| 297 | if (m_minifont.unistr_is_local_graphic(c)) { |
| 298 | m_minifont.draw_graphic(*this, |
| 299 | c, |
| 300 | attr, |
| 301 | color, |
| 302 | requests[i].x, requests[i].y, |
| 303 | font->width(), requests[i].columns, font->height()); |
| 304 | continue; |
| 305 | } |
| 306 | |
| 307 | auto uinfo = font->get_unistr_info(c); |
| 308 | auto ufi = &uinfo->m_ufi; |
| 309 | int x, y, ye; |
| 310 | |
| 311 | get_char_edges(c, requests[i].columns, attr, x, ye /* unused */); |
| 312 | x += requests[i].x; |
| 313 | /* Bold/italic versions might have different ascents. In order to align their |
| 314 | * baselines, we offset by the normal font's ascent here. (Bug 137.) */ |
| 315 | y = requests[i].y + m_char_spacing.top + m_fonts[BTE_DRAW_NORMAL0]->ascent(); |
| 316 | |
| 317 | switch (uinfo->coverage()) { |
| 318 | default: |
| 319 | case FontInfo::UnistrInfo::Coverage::UNKNOWN: |
| 320 | g_assert_not_reached ()do { g_assertion_message_expr ("BTE", "../src/drawing-cairo.cc" , 320, ((const char*) (__PRETTY_FUNCTION__)), __null); } while (0); |
| 321 | break; |
| 322 | case FontInfo::UnistrInfo::Coverage::USE_PANGO_LAYOUT_LINE: |
| 323 | cairo_move_to(m_cr, x, y); |
| 324 | pango_cairo_show_layout_line(m_cr, |
| 325 | ufi->using_pango_layout_line.line); |
| 326 | break; |
| 327 | case FontInfo::UnistrInfo::Coverage::USE_PANGO_GLYPH_STRING: |
| 328 | cairo_move_to(m_cr, x, y); |
| 329 | pango_cairo_show_glyph_string(m_cr, |
| 330 | ufi->using_pango_glyph_string.font, |
| 331 | ufi->using_pango_glyph_string.glyph_string); |
| 332 | break; |
| 333 | case FontInfo::UnistrInfo::Coverage::USE_CAIRO_GLYPH: |
| 334 | if (last_scaled_font != ufi->using_cairo_glyph.scaled_font || n_cr_glyphs == MAX_RUN_LENGTH100) { |
| 335 | if (n_cr_glyphs) { |
| 336 | cairo_set_scaled_font(m_cr, last_scaled_font); |
| 337 | cairo_show_glyphs(m_cr, |
| 338 | cr_glyphs, |
| 339 | n_cr_glyphs); |
| 340 | n_cr_glyphs = 0; |
| 341 | } |
| 342 | last_scaled_font = ufi->using_cairo_glyph.scaled_font; |
| 343 | } |
| 344 | cr_glyphs[n_cr_glyphs].index = ufi->using_cairo_glyph.glyph_index; |
| 345 | cr_glyphs[n_cr_glyphs].x = x; |
| 346 | cr_glyphs[n_cr_glyphs].y = y; |
| 347 | n_cr_glyphs++; |
| 348 | break; |
| 349 | } |
| 350 | } |
| 351 | if (n_cr_glyphs) { |
| 352 | cairo_set_scaled_font(m_cr, last_scaled_font); |
| 353 | cairo_show_glyphs(m_cr, |
| 354 | cr_glyphs, |
| 355 | n_cr_glyphs); |
| 356 | n_cr_glyphs = 0; |
Value stored to 'n_cr_glyphs' is never read | |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | void |
| 361 | DrawingContext::draw_text(TextRequest* requests, |
| 362 | gsize n_requests, |
| 363 | uint32_t attr, |
| 364 | bte::color::rgb const* color, |
| 365 | double alpha) |
| 366 | { |
| 367 | g_assert(m_cr)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_38 = 0; if (m_cr) _g_boolean_var_38 = 1; _g_boolean_var_38; }), 1)) ; else g_assertion_message_expr ("BTE", "../src/drawing-cairo.cc" , 367, ((const char*) (__PRETTY_FUNCTION__)), "m_cr"); } while (0); |
| 368 | |
| 369 | if (_bte_debug_on (BTE_DEBUG_DRAW)) { |
| 370 | GString *string = g_string_new (""); |
| 371 | gchar *str; |
| 372 | gsize n; |
| 373 | for (n = 0; n < n_requests; n++) { |
| 374 | g_string_append_unichar (string, requests[n].c); |
| 375 | } |
| 376 | str = g_string_free (string, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((string ), ((0))) : g_string_free_and_steal (string)) : (g_string_free ) ((string), ((0)))); |
| 377 | g_printerr ("draw_text (\"%s\", len=%" G_GSIZE_FORMAT"lu" ", color=(%d,%d,%d,%.3f), %s - %s)\n", |
| 378 | str, n_requests, color->red, color->green, color->blue, alpha, |
| 379 | (attr & BTE_ATTR_BOLD(1U << (((0) + (4)) + (1)))) ? "bold" : "normal", |
| 380 | (attr & BTE_ATTR_ITALIC(1U << ((((0) + (4)) + (1)) + (1)))) ? "italic" : "regular"); |
| 381 | g_free (str); |
| 382 | } |
| 383 | |
| 384 | draw_text_internal(requests, n_requests, attr, color, alpha); |
| 385 | } |
| 386 | |
| 387 | /* The following two functions are unused since commit 154abade902850afb44115cccf8fcac51fc082f0, |
| 388 | * but let's keep them for now since they may become used again. |
| 389 | */ |
| 390 | bool |
| 391 | DrawingContext::has_char(bteunistr c, |
| 392 | uint32_t attr) |
| 393 | { |
| 394 | _bte_debug_print (BTE_DEBUG_DRAW, "draw_has_char ('0x%04X', %s - %s)\n", c,do { } while(0) |
| 395 | (attr & BTE_ATTR_BOLD) ? "bold" : "normal",do { } while(0) |
| 396 | (attr & BTE_ATTR_ITALIC) ? "italic" : "regular")do { } while(0); |
| 397 | |
| 398 | auto const style = attr_to_style(attr); |
| 399 | g_return_val_if_fail(m_fonts[style], false)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_39 = 0; if (m_fonts[style]) _g_boolean_var_39 = 1; _g_boolean_var_39 ; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "m_fonts[style]"); return (false ); } } while (0); |
| 400 | |
| 401 | auto uinfo = m_fonts[style]->get_unistr_info(c); |
| 402 | return !uinfo->has_unknown_chars; |
| 403 | } |
| 404 | |
| 405 | bool |
| 406 | DrawingContext::draw_char(TextRequest* request, |
| 407 | uint32_t attr, |
| 408 | bte::color::rgb const* color, |
| 409 | double alpha) |
| 410 | { |
| 411 | _bte_debug_print (BTE_DEBUG_DRAW,do { } while(0) |
| 412 | "draw_char ('%c', color=(%d,%d,%d,%.3f), %s, %s)\n",do { } while(0) |
| 413 | request->c,do { } while(0) |
| 414 | color->red, color->green, color->blue,do { } while(0) |
| 415 | alpha,do { } while(0) |
| 416 | (attr & BTE_ATTR_BOLD) ? "bold" : "normal",do { } while(0) |
| 417 | (attr & BTE_ATTR_ITALIC) ? "italic" : "regular")do { } while(0); |
| 418 | |
| 419 | auto const have_char = has_char(request->c, attr); |
| 420 | if (have_char) |
| 421 | draw_text(request, 1, attr, color, alpha); |
| 422 | |
| 423 | return have_char; |
| 424 | } |
| 425 | |
| 426 | void |
| 427 | DrawingContext::draw_rectangle(int x, |
| 428 | int y, |
| 429 | int width, |
| 430 | int height, |
| 431 | bte::color::rgb const* color, |
| 432 | double alpha) |
| 433 | { |
| 434 | g_assert(m_cr)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_40 = 0; if (m_cr) _g_boolean_var_40 = 1; _g_boolean_var_40; }), 1)) ; else g_assertion_message_expr ("BTE", "../src/drawing-cairo.cc" , 434, ((const char*) (__PRETTY_FUNCTION__)), "m_cr"); } while (0); |
| 435 | |
| 436 | _bte_debug_print (BTE_DEBUG_DRAW,do { } while(0) |
| 437 | "draw_rectangle (%d, %d, %d, %d, color=(%d,%d,%d,%.3f))\n",do { } while(0) |
| 438 | x,y,width,height,do { } while(0) |
| 439 | color->red, color->green, color->blue,do { } while(0) |
| 440 | alpha)do { } while(0); |
| 441 | |
| 442 | cairo_set_operator(m_cr, CAIRO_OPERATOR_OVER); |
| 443 | cairo_rectangle(m_cr, x+BTE_LINE_WIDTH1/2., y+BTE_LINE_WIDTH1/2., width-BTE_LINE_WIDTH1, height-BTE_LINE_WIDTH1); |
| 444 | set_source_color_alpha(color, alpha); |
| 445 | cairo_set_line_width(m_cr, BTE_LINE_WIDTH1); |
| 446 | cairo_stroke (m_cr); |
| 447 | } |
| 448 | |
| 449 | void |
| 450 | DrawingContext::fill_rectangle(int x, |
| 451 | int y, |
| 452 | int width, |
| 453 | int height, |
| 454 | bte::color::rgb const* color, |
| 455 | double alpha) |
| 456 | { |
| 457 | g_assert(m_cr)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_41 = 0; if (m_cr) _g_boolean_var_41 = 1; _g_boolean_var_41; }), 1)) ; else g_assertion_message_expr ("BTE", "../src/drawing-cairo.cc" , 457, ((const char*) (__PRETTY_FUNCTION__)), "m_cr"); } while (0); |
| 458 | |
| 459 | _bte_debug_print (BTE_DEBUG_DRAW,do { } while(0) |
| 460 | "draw_fill_rectangle (%d, %d, %d, %d, color=(%d,%d,%d,%.3f))\n",do { } while(0) |
| 461 | x,y,width,height,do { } while(0) |
| 462 | color->red, color->green, color->blue,do { } while(0) |
| 463 | alpha)do { } while(0); |
| 464 | |
| 465 | cairo_set_operator(m_cr, CAIRO_OPERATOR_OVER); |
| 466 | cairo_rectangle(m_cr, x, y, width, height); |
| 467 | set_source_color_alpha(color, alpha); |
| 468 | cairo_fill (m_cr); |
| 469 | } |
| 470 | |
| 471 | void |
| 472 | DrawingContext::draw_line(int x, |
| 473 | int y, |
| 474 | int xp, |
| 475 | int yp, |
| 476 | int line_width, |
| 477 | bte::color::rgb const *color, |
| 478 | double alpha) |
| 479 | { |
| 480 | fill_rectangle( |
| 481 | x, y, |
| 482 | MAX(line_width, xp - x + 1)(((line_width) > (xp - x + 1)) ? (line_width) : (xp - x + 1 )), MAX(line_width, yp - y + 1)(((line_width) > (yp - y + 1)) ? (line_width) : (yp - y + 1 )), |
| 483 | color, alpha); |
| 484 | } |
| 485 | |
| 486 | void |
| 487 | DrawingContext::draw_undercurl(int x, |
| 488 | double y, |
| 489 | double line_width, |
| 490 | int count, |
| 491 | bte::color::rgb const *color, |
| 492 | double alpha) |
| 493 | { |
| 494 | /* The end of the curly line slightly overflows to the next cell, so the canvas |
| 495 | * caching the rendered look has to be wider not to chop this off. */ |
| 496 | gint x_padding = line_width + 1; /* ceil, kind of */ |
| 497 | |
| 498 | gint surface_top = y; /* floor */ |
| 499 | |
| 500 | g_assert(m_cr)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_42 = 0; if (m_cr) _g_boolean_var_42 = 1; _g_boolean_var_42; }), 1)) ; else g_assertion_message_expr ("BTE", "../src/drawing-cairo.cc" , 500, ((const char*) (__PRETTY_FUNCTION__)), "m_cr"); } while (0); |
| 501 | |
| 502 | _bte_debug_print (BTE_DEBUG_DRAW,do { } while(0) |
| 503 | "draw_undercurl (x=%d, y=%f, count=%d, color=(%d,%d,%d,%.3f))\n",do { } while(0) |
| 504 | x, y, count,do { } while(0) |
| 505 | color->red, color->green, color->blue,do { } while(0) |
| 506 | alpha)do { } while(0); |
| 507 | |
| 508 | if (G_UNLIKELY (!m_undercurl_surface)(__builtin_expect (__extension__ ({ int _g_boolean_var_43 = 0 ; if (!m_undercurl_surface) _g_boolean_var_43 = 1; _g_boolean_var_43 ; }), 0))) { |
| 509 | /* Cache the undercurl's look. The design assumes that until the cached look is |
| 510 | * invalidated (the font is changed), this method is always called with the "y" |
| 511 | * parameter having the same fractional part, and the same "line_width" parameter. |
| 512 | * For caching, only the fractional part of "y" is used. */ |
| 513 | cairo_t *undercurl_cr; |
| 514 | |
| 515 | double rad = _bte_draw_get_undercurl_rad(m_cell_width); |
| 516 | double y_bottom = y + _bte_draw_get_undercurl_height(m_cell_width, line_width); |
| 517 | double y_center = (y + y_bottom) / 2.; |
| 518 | gint surface_bottom = y_bottom + 1; /* ceil, kind of */ |
| 519 | |
| 520 | _bte_debug_print (BTE_DEBUG_DRAW,do { } while(0) |
| 521 | "caching undercurl shape\n")do { } while(0); |
| 522 | |
| 523 | /* Add a line_width of margin horizontally on both sides, for nice antialias overflowing. */ |
| 524 | m_undercurl_surface.reset(cairo_surface_create_similar (cairo_get_target (m_cr), |
| 525 | CAIRO_CONTENT_ALPHA, |
| 526 | m_cell_width + 2 * x_padding, |
| 527 | surface_bottom - surface_top)); |
| 528 | undercurl_cr = cairo_create (m_undercurl_surface.get()); |
| 529 | cairo_set_operator (undercurl_cr, CAIRO_OPERATOR_OVER); |
| 530 | /* First quarter circle, similar to the left half of the tilde symbol. */ |
| 531 | cairo_arc (undercurl_cr, x_padding + m_cell_width / 4., y_center - surface_top + m_cell_width / 4., rad, M_PI3.14159265358979323846 * 5 / 4, M_PI3.14159265358979323846 * 7 / 4); |
| 532 | /* Second quarter circle, similar to the right half of the tilde symbol. */ |
| 533 | cairo_arc_negative (undercurl_cr, x_padding + m_cell_width * 3 / 4., y_center - surface_top - m_cell_width / 4., rad, M_PI3.14159265358979323846 * 3 / 4, M_PI3.14159265358979323846 / 4); |
| 534 | cairo_set_line_width (undercurl_cr, line_width); |
| 535 | cairo_stroke (undercurl_cr); |
| 536 | cairo_destroy (undercurl_cr); |
| 537 | } |
| 538 | |
| 539 | /* Paint the cached look of the undercurl using the desired look. |
| 540 | * The cached look takes the fractional part of "y" into account, |
| 541 | * here we only offset by its integer part. */ |
| 542 | cairo_save (m_cr); |
| 543 | cairo_set_operator(m_cr, CAIRO_OPERATOR_OVER); |
| 544 | set_source_color_alpha(color, alpha); |
| 545 | for (int i = 0; i < count; i++) { |
| 546 | cairo_mask_surface(m_cr, m_undercurl_surface.get(), x - x_padding + i * m_cell_width, surface_top); |
| 547 | } |
| 548 | cairo_restore (m_cr); |
| 549 | } |
| 550 | |
| 551 | } // namespace view |
| 552 | } // namespace bte |