@@ -198,6 +198,11 @@ class html_widget_notifier : public litebrowser::browser_notify_interface
198
198
}
199
199
};
200
200
201
+ // / @brief Draw Buffer Class
202
+ // /
203
+ // / This class performs the draw operations into the cairo surface.
204
+ // / The application draws everything to the buffer, then buffer are
205
+ // / drawn on widged or window.
201
206
class draw_buffer
202
207
{
203
208
cairo_surface_t * m_draw_buffer = nullptr ;
@@ -235,6 +240,9 @@ class draw_buffer
235
240
[[nodiscard]]
236
241
double get_scale_factor () const { return m_scale_factor; }
237
242
243
+ // / @brief Set scale factor for draw buffer
244
+ // / @param page the webpage to be redraw if required
245
+ // / @param scale the scale factor to be applied
238
246
void set_scale_factor (std::shared_ptr<litebrowser::web_page> page, double scale)
239
247
{
240
248
if (m_scale_factor != scale)
@@ -255,6 +263,22 @@ class draw_buffer
255
263
}
256
264
}
257
265
266
+ // / @brief Create cairo surface for draw buffer
267
+ // / @param width surface width (not scaled)
268
+ // / @param height surface height (not scaled)
269
+ // / @param scale_factor scale factor
270
+ // / @return poiter to the cairo surface
271
+ cairo_surface_t * make_surface (int width, int height, double scale_factor)
272
+ {
273
+ return cairo_image_surface_create (CAIRO_FORMAT_RGB24,
274
+ std::ceil ((double ) width * scale_factor),
275
+ std::ceil ((double ) height * scale_factor));
276
+ }
277
+
278
+ // / @brief Creates new buffer with specified size
279
+ // / @param width draw buffer width (not scaled)
280
+ // / @param height draw buffer height (not scaled)
281
+ // / @return true if new draw buffer was created, false if the old buffer was used
258
282
bool create_draw_buffer (int width, int height)
259
283
{
260
284
if (m_width != width || m_height != height || !m_draw_buffer)
@@ -268,14 +292,17 @@ class draw_buffer
268
292
m_draw_buffer = nullptr ;
269
293
if (m_width > 0 && m_height > 0 )
270
294
{
271
- m_draw_buffer = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
272
- std::ceil ((double ) m_width * m_scale_factor),
273
- std::ceil ((double ) m_height * m_scale_factor));
295
+ m_draw_buffer = make_surface (m_width, m_height, m_scale_factor);
274
296
}
297
+ return true ;
275
298
}
276
- return m_draw_buffer != nullptr ;
299
+ return false ;
277
300
}
278
301
302
+ // / @brief Call this function when widget size changed
303
+ // / @param page webpage to be redraw if buffer size changed
304
+ // / @param width new draw buffer width
305
+ // / @param height new draw buffer height
279
306
void on_size_allocate (std::shared_ptr<litebrowser::web_page> page, int width, int height)
280
307
{
281
308
if (create_draw_buffer (width, height))
@@ -284,6 +311,14 @@ class draw_buffer
284
311
}
285
312
}
286
313
314
+ // / @brief Scrolls draw buffer to the position (left, top).
315
+ // /
316
+ // / Note, the actual position of the draw buffer can be rounded according to the scale factor.
317
+ // / Use get_left() and get_top() to know the actual position.
318
+ // /
319
+ // / @param page webpage to be redraw if the position was changed
320
+ // / @param left new horizontal position
321
+ // / @param top new vertical position
287
322
void on_scroll (std::shared_ptr<litebrowser::web_page> page, int left, int top)
288
323
{
289
324
if (m_width <= 0 || m_height <= 0 || !m_draw_buffer) return ;
@@ -295,7 +330,7 @@ class draw_buffer
295
330
{
296
331
Gdk::Rectangle rec_current (m_left, m_top, m_width, m_height); // Current area
297
332
Gdk::Rectangle rec_clean (rec_current); // Clean area
298
- Gdk::Rectangle rec_new (left, top, m_width, m_height); // New area
333
+ Gdk::Rectangle rec_new (left, top, m_width, m_height); // New area
299
334
rec_clean.intersect (rec_new);
300
335
if (rec_clean.has_zero_area () || rec_new == rec_current)
301
336
{
@@ -304,13 +339,10 @@ class draw_buffer
304
339
redraw (page);
305
340
} else
306
341
{
307
- int scaled_width = (int ) std::ceil ((double ) m_width * m_scale_factor);
308
- int scaled_height = (int ) std::ceil ((double ) m_height * m_scale_factor);
309
342
int surface_shift_x = (int ) std::floor ((double ) (m_left - left) * m_scale_factor);
310
343
int surface_shift_y = (int ) std::floor ((double ) (m_top - top) * m_scale_factor);
311
- // printf("[surface_shift] top:%d m_top:%d x:%d y:%d\n", top, m_top, surface_shift_x, surface_shift_y);
312
344
313
- auto new_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, scaled_width, scaled_height );
345
+ auto new_surface = make_surface (m_width, m_height, m_scale_factor );
314
346
cairo_t * cr = cairo_create (new_surface);
315
347
cairo_rectangle (cr, (rec_clean.get_x () - left) * m_scale_factor - m_scale_factor,
316
348
(rec_clean.get_y () - top) * m_scale_factor - m_scale_factor,
@@ -326,55 +358,84 @@ class draw_buffer
326
358
m_left = left;
327
359
m_top = top;
328
360
329
- int right = m_left + m_width;
330
- int bottom = m_top + m_height;
331
- int clean_right = rec_clean.get_x () + rec_clean.get_width ();
332
- int clean_bottom = rec_clean.get_y () + rec_clean.get_height ();
361
+ int right = fix_position ( m_left + m_width) ;
362
+ int bottom = fix_position ( m_top + m_height) ;
363
+ int clean_right = fix_position ( rec_clean.get_x () + rec_clean.get_width () );
364
+ int clean_bottom = fix_position ( rec_clean.get_y () + rec_clean.get_height () );
333
365
334
366
if (rec_clean.get_x () > m_left)
335
367
{
336
- redraw_area (page, m_left - 1 , rec_clean.get_y () - 1 , rec_clean.get_x () - m_left + 2 , rec_clean.get_height () + 2 );
368
+ redraw_area (page, m_left,
369
+ rec_clean.get_y (),
370
+ rec_clean.get_x () - m_left,
371
+ rec_clean.get_height ());
337
372
}
338
373
if (clean_right < right)
339
374
{
340
- redraw_area (page, clean_right - 1 , rec_clean.get_y () - 1 , right - clean_right + 2 , rec_clean.get_height () + 2 );
375
+ redraw_area (page, clean_right,
376
+ rec_clean.get_y (),
377
+ right - clean_right,
378
+ rec_clean.get_height ());
341
379
}
342
380
343
381
if (rec_clean.get_y () > m_top)
344
382
{
345
383
redraw_area (page, m_left,
346
- m_top - 1 ,
384
+ m_top,
347
385
m_width,
348
- rec_clean.get_y () - m_top + 2 );
386
+ rec_clean.get_y () - m_top);
349
387
}
350
388
if (clean_bottom < bottom)
351
389
{
352
390
redraw_area (page, m_left,
353
- clean_bottom - 1 ,
391
+ clean_bottom,
354
392
m_width,
355
- bottom - clean_bottom + 2 );
393
+ bottom - clean_bottom);
356
394
}
357
395
}
358
396
}
359
397
}
360
398
399
+ // / @brief Reraw the defined area of the buffer
400
+ // /
401
+ // / All coordinated are not scaled. Actual rectangle could be different according to the scale factor,
402
+ // / but it must always cover the requested.
403
+ // /
404
+ // / @param page webpage to be redraw
405
+ // / @param x left position of the area
406
+ // / @param y top position of the area
407
+ // / @param width width of the area
408
+ // / @param height height of the area
361
409
void redraw_area (std::shared_ptr<litebrowser::web_page> page, int x, int y, int width, int height)
362
410
{
363
411
if (m_draw_buffer)
364
412
{
365
- // Calculate scaled position
366
- int s_x = std::floor ((double ) (x - m_left) * m_scale_factor);
367
- int s_y = std::floor ((double ) (y - m_top) * m_scale_factor);
368
- int s_width = std::ceil ((double ) width * m_scale_factor);
369
- int s_height = std::ceil ((double ) height * m_scale_factor);
413
+ int fixed_left = fix_position (x - m_left);
414
+ int fixed_right = fix_position (x - m_left + width);
415
+ int fixed_top = fix_position (y - m_top);
416
+ int fixed_bottom = fix_position (y - m_top + height);
417
+
418
+ if (fixed_right < x + width) fixed_right += m_min_int_position;
419
+ if (fixed_bottom < y + height) fixed_bottom += m_min_int_position;
420
+
421
+ int fixed_x = fixed_left;
422
+ int fixed_y = fixed_top;
423
+ int fixed_width = fixed_right - fixed_left;
424
+ int fixed_height = fixed_bottom - fixed_top;
425
+
426
+ int s_x = (int ) std::round ((double ) fixed_x * m_scale_factor);
427
+ int s_y = (int ) std::round ((double ) fixed_y * m_scale_factor);
428
+ int s_width = (int ) std::round ((double ) fixed_width * m_scale_factor);
429
+ int s_height = (int ) std::round ((double ) fixed_height * m_scale_factor);
370
430
371
- litehtml::position pos {x - m_left, y - m_top, width, height };
431
+ litehtml::position pos {fixed_x, fixed_y, fixed_width, fixed_height };
372
432
cairo_t * cr = cairo_create (m_draw_buffer);
373
433
374
434
// Apply clip with scaled position to avoid artifacts
375
435
cairo_rectangle (cr, s_x, s_y, s_width, s_height);
376
436
cairo_clip (cr);
377
437
438
+ // Clear rectangle with scaled position
378
439
cairo_rectangle (cr, s_x, s_y, s_width, s_height);
379
440
cairo_set_source_rgb (cr, 1.0 , 1.0 , 1.0 );
380
441
cairo_fill (cr);
@@ -392,6 +453,8 @@ class draw_buffer
392
453
}
393
454
}
394
455
456
+ // / @brief Redraw entire buffer
457
+ // / @param page webpage to be redraw
395
458
void redraw (std::shared_ptr<litebrowser::web_page> page)
396
459
{
397
460
redraw_area (page, m_left, m_top, m_width, m_height);
@@ -429,6 +492,7 @@ class html_widget : public Gtk::Widget,
429
492
public litebrowser::html_host_interface
430
493
{
431
494
int m_rendered_width = 0 ;
495
+ int m_rendered_height = 0 ;
432
496
std::mutex m_page_mutex;
433
497
std::shared_ptr<litebrowser::web_page> m_current_page;
434
498
std::shared_ptr<litebrowser::web_page> m_next_page;
0 commit comments