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 ; if (m_cr) _g_boolean_var_28 = 1; else _g_boolean_var_28 = 0 ; _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 ; if (m_cr) _g_boolean_var_29 = 1; else _g_boolean_var_29 = 0 ; _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 ; if (m_fonts[0] != nullptr) _g_boolean_var_30 = 1; else _g_boolean_var_30 = 0; _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; if (m_minifont.unistr_is_local_graphic (c)) _g_boolean_var_31 = 1; else _g_boolean_var_31 = 0; _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; if (m_fonts[0] == nullptr) _g_boolean_var_32 = 1; else _g_boolean_var_32 = 0; _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; if (w <= normal_width) _g_boolean_var_33 = 1; else _g_boolean_var_33 = 0; _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; if (w <= fits_width) _g_boolean_var_34 = 1; else _g_boolean_var_34 = 0; _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 ; if (font != nullptr) _g_boolean_var_35 = 1; else _g_boolean_var_35 = 0; _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 ; if (m_cr) _g_boolean_var_36 = 1; else _g_boolean_var_36 = 0 ; _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; if (requests[i].mirror) _g_boolean_var_37 = 1; else _g_boolean_var_37 = 0; _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 ; if (m_cr) _g_boolean_var_38 = 1; else _g_boolean_var_38 = 0 ; _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(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 ; if (m_fonts[style]) _g_boolean_var_39 = 1; else _g_boolean_var_39 = 0; _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 ; if (m_cr) _g_boolean_var_40 = 1; else _g_boolean_var_40 = 0 ; _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 ; if (m_cr) _g_boolean_var_41 = 1; else _g_boolean_var_41 = 0 ; _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 ; if (m_cr) _g_boolean_var_42 = 1; else _g_boolean_var_42 = 0 ; _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; if (!m_undercurl_surface) _g_boolean_var_43 = 1; else _g_boolean_var_43 = 0; _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 |