Bug Summary

File:/rootdir/_build/../src/drawing-cairo.cc
Warning:line 356, column 3
Value stored to 'n_cr_glyphs' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name drawing-cairo.cc -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/_build -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -I src/libbte-2.91.so.0.6500.0.p -I src -I ../src -I . -I .. -I src/bte -I ../src/bte -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/fribidi -I /usr/include/uuid -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/p11-kit-1 -I /usr/include/ctk-3.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -D _FILE_OFFSET_BITS=64 -D G_LOG_DOMAIN="BTE" -D LOCALEDIR="/usr/local/share/locale" -D BTE_DISABLE_DEPRECATION_WARNINGS -D BTE_COMPILATION -U PARSER_INCLUDE_NOP -D CDK_VERSION_MIN_REQUIRED=(G_ENCODE_VERSION(3,18)) -D CDK_VERSION_MAX_ALLOWED=(G_ENCODE_VERSION(3,20)) -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/x86_64-linux-gnu/c++/12 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-address-of-packed-member -Wno-missing-field-initializers -Wno-packed -Wno-switch-enum -Wno-unused-parameter -Wwrite-strings -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/rootdir/_build -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2022-12-29-230514-10783-1 -x c++ ../src/drawing-cairo.cc
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
41static unsigned
42attr_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
52static inline constexpr double
53_bte_draw_get_undercurl_rad(gint width)
54{
55 return width / 2. / M_SQRT21.41421356237309504880;
56}
57
58static 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
64double
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
70namespace bte {
71namespace view {
72
73DrawingContext::~DrawingContext()
74{
75 clear_font_cache();
76}
77
78void
79DrawingContext::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
90void
91DrawingContext::set_cairo(cairo_t* cr) noexcept
92{
93 m_cr = cr;
94}
95
96void
97DrawingContext::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
105void
106DrawingContext::unclip()
107{
108 cairo_restore(m_cr);
109}
110
111void
112DrawingContext::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_
; if (m_cr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 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
123void
124DrawingContext::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_
; if (m_cr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 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
138void
139DrawingContext::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
207void
208DrawingContext::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_
; if (m_fonts[0] != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 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. */
229void
230DrawingContext::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_; if (
m_minifont.unistr_is_local_graphic (c)) _g_boolean_var_ = 1; else
_g_boolean_var_ = 0; _g_boolean_var_; }), 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_; if (
m_fonts[0] == nullptr) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 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_; if (
w <= normal_width) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 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_; if (
w <= fits_width) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 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
271void
272DrawingContext::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_
; if (font != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 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_
; if (m_cr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 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_; if (
requests[i].mirror) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 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
360void
361DrawingContext::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_
; if (m_cr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 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 */
390bool
391DrawingContext::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_
; if (m_fonts[style]) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 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
405bool
406DrawingContext::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
426void
427DrawingContext::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_
; if (m_cr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 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
449void
450DrawingContext::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_
; if (m_cr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 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
471void
472DrawingContext::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
486void
487DrawingContext::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_
; if (m_cr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_
; }), 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_; if (
!m_undercurl_surface) _g_boolean_var_ = 1; else _g_boolean_var_
= 0; _g_boolean_var_; }), 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