File indexing completed on 2024-04-21 04:54:13

0001 /**
0002     This file belong to the KMPlayer project, a movie player plugin for Konqueror
0003     SPDX-FileCopyrightText: 2008 Koos Vriezen <koos.vriezen@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "config-kmplayer.h"
0009 
0010 #ifdef KMPLAYER_WITH_CAIRO
0011 # include <cairo.h>
0012 #endif
0013 
0014 #include <QWidget>
0015 
0016 #include "kmplayercommon_log.h"
0017 #include "surface.h"
0018 #include "viewarea.h"
0019 
0020 using namespace KMPlayer;
0021 
0022 
0023 Surface::Surface (ViewArea *widget)
0024   : bounds(SRect(0, 0,
0025                  widget->width() * widget->devicePixelRatioF(),
0026                  widget->height() * widget->devicePixelRatioF()
0027     )),
0028     xscale (1.0), yscale (1.0),
0029     background_color (0),
0030 #ifdef KMPLAYER_WITH_CAIRO
0031     surface (nullptr),
0032 #endif
0033     dirty (false),
0034     scroll (false),
0035     has_mouse (false),
0036     view_widget (widget)
0037 {}
0038 
0039 Surface::~Surface() {
0040 #ifdef KMPLAYER_WITH_CAIRO
0041     if (surface)
0042         cairo_surface_destroy (surface);
0043 #endif
0044 }
0045 
0046 template <> void TreeNode<Surface>::appendChild (Surface *c) {
0047     appendChildImpl (c);
0048 }
0049 
0050 template <> void TreeNode<Surface>::insertBefore (Surface *c, Surface *b) {
0051     insertBeforeImpl (c, b);
0052 }
0053 
0054 template <> void TreeNode<Surface>::removeChild (SurfacePtr c) {
0055     removeChildImpl (c);
0056 }
0057 
0058 void Surface::clear () {
0059     m_first_child = nullptr;
0060     background_color = 0;
0061 }
0062 
0063 void Surface::remove () {
0064     Surface *sp = parentNode ();
0065     if (sp) {
0066         sp->markDirty ();
0067         sp->removeChild (this);
0068     }
0069 }
0070 
0071 void Surface::resize (const SRect &rect, bool parent_resized) {
0072     SRect old_bounds = bounds;
0073     bounds = rect;
0074     if (parent_resized || old_bounds != rect) {
0075 
0076         if (parent_resized || old_bounds.size != rect.size) {
0077             virtual_size = SSize (); //FIXME try to preserve scroll on resize
0078             markDirty ();
0079 #ifdef KMPLAYER_WITH_CAIRO
0080             if (surface) {
0081                 cairo_surface_destroy (surface);
0082                 surface = nullptr;
0083             }
0084 #endif
0085             updateChildren (true);
0086         } else if (parentNode ()) {
0087             parentNode ()->markDirty ();
0088         }
0089         if (parentNode ())
0090             parentNode ()->repaint (old_bounds.unite (rect));
0091         else
0092             repaint ();
0093     }
0094 }
0095 
0096 void Surface::markDirty () {
0097     for (Surface *s = this; s && !s->dirty; s = s->parentNode ())
0098         s->dirty = true;
0099 }
0100 
0101 void Surface::updateChildren (bool parent_resized) {
0102     for (Surface *c = firstChild (); c; c = c->nextSibling ())
0103         if (c->node)
0104             c->node->message (MsgSurfaceBoundsUpdate, (void *) parent_resized);
0105         else
0106             qCCritical(LOG_KMPLAYER_COMMON) << "Surface without node";
0107 }
0108 
0109 Surface *Surface::createSurface (NodePtr owner, const SRect & rect) {
0110     Surface *surface = new Surface (view_widget);
0111     surface->node = owner;
0112     surface->bounds = rect;
0113     appendChild (surface);
0114     return surface;
0115 }
0116 
0117 IRect Surface::toScreen (const SSize &size) {
0118     //FIXME: handle scroll
0119     Matrix matrix (0, 0, xscale, yscale);
0120     matrix.translate (bounds.x (), bounds.y ());
0121     for (Surface *s = parentNode(); s; s = s->parentNode()) {
0122         matrix.transform(Matrix (0, 0, s->xscale, s->yscale));
0123         matrix.translate (s->bounds.x (), s->bounds.y ());
0124     }
0125     return matrix.toScreen (SRect (0, 0, size));
0126 }
0127 
0128 void Surface::setBackgroundColor (unsigned int argb) {
0129 #ifdef KMPLAYER_WITH_CAIRO
0130     if (surface &&
0131             ((background_color & 0xff000000) < 0xff000000) !=
0132             ((argb & 0xff000000) < 0xff000000)) {
0133         cairo_surface_destroy (surface);
0134         surface = nullptr;
0135     }
0136 #endif
0137     background_color = argb;
0138 }
0139 
0140 static void clipToScreen (Surface *s, Matrix &m, IRect &clip) {
0141     Surface *ps = s->parentNode ();
0142     if (!ps) {
0143         clip = IRect (s->bounds.x (), s->bounds.y (),
0144                 s->bounds.width (), s->bounds.height ());
0145         m = Matrix (s->bounds.x (), s->bounds.y (), s->xscale, s->yscale);
0146     } else {
0147         clipToScreen (ps, m, clip);
0148         IRect scr = m.toScreen (s->bounds);
0149         clip = clip.intersect (scr);
0150         Matrix m1 = m;
0151         m = Matrix (s->bounds.x (), s->bounds.y (), s->xscale, s->yscale);
0152         m.transform (m1);
0153         if (!s->virtual_size.isEmpty ())
0154             m.translate (-s->x_scroll, -s->y_scroll);
0155     }
0156 }
0157 
0158 
0159 void Surface::repaint (const SRect &rect) {
0160     Matrix matrix;
0161     IRect clip;
0162     clipToScreen (this, matrix, clip);
0163     IRect scr = matrix.toScreen (rect);
0164     clip = clip.intersect (scr);
0165     if (!clip.isEmpty ())
0166         view_widget->scheduleRepaint (clip);
0167 }
0168 
0169 void Surface::repaint () {
0170     Surface *ps = parentNode ();
0171     if (ps)
0172         ps->repaint (bounds);
0173     else
0174         view_widget->scheduleRepaint (IRect (bounds.x (), bounds.y (),
0175                 bounds.width (), bounds.height ()));
0176 }
0177