File indexing completed on 2024-04-14 15:01:16

0001 /**
0002   This file belong to the KMPlayer project, a movie player plugin for Konqueror
0003   Copyright (C) 2008  Koos Vriezen <koos.vriezen@gmail.com>
0004 
0005   This library is free software; you can redistribute it and/or
0006   modify it under the terms of the GNU Lesser General Public
0007   License as published by the Free Software Foundation; either
0008   version 2 of the License, or (at your option) any later version.
0009 
0010   This library is distributed in the hope that it will be useful,
0011   but WITHOUT ANY WARRANTY; without even the implied warranty of
0012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013   Lesser General Public License for more details.
0014 
0015   You should have received a copy of the GNU Lesser General Public
0016   License along with this library; if not, write to the Free Software
0017   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0018 **/
0019 
0020 #include "config-kmplayer.h"
0021 
0022 #ifdef KMPLAYER_WITH_CAIRO
0023 # include <cairo.h>
0024 #endif
0025 
0026 #include <qwidget.h>
0027 
0028 #include <kdebug.h>
0029 
0030 #include "surface.h"
0031 #include "viewarea.h"
0032 
0033 using namespace KMPlayer;
0034 
0035 
0036 KDE_NO_CDTOR_EXPORT Surface::Surface (ViewArea *widget)
0037   : bounds(SRect(0, 0,
0038 #if QT_VERSION >= 0x050600
0039                  widget->width() * widget->devicePixelRatioF(),
0040                  widget->height() * widget->devicePixelRatioF()
0041 #else
0042                  widget->width(), widget->height()
0043 #endif
0044     )),
0045     xscale (1.0), yscale (1.0),
0046     background_color (0),
0047 #ifdef KMPLAYER_WITH_CAIRO
0048     surface (0L),
0049 #endif
0050     dirty (false),
0051     scroll (false),
0052     has_mouse (false),
0053     view_widget (widget)
0054 {}
0055 
0056 Surface::~Surface() {
0057 #ifdef KMPLAYER_WITH_CAIRO
0058     if (surface)
0059         cairo_surface_destroy (surface);
0060 #endif
0061 }
0062 
0063 template <> void TreeNode<Surface>::appendChild (Surface *c) {
0064     appendChildImpl (c);
0065 }
0066 
0067 template <> void TreeNode<Surface>::insertBefore (Surface *c, Surface *b) {
0068     insertBeforeImpl (c, b);
0069 }
0070 
0071 template <> void TreeNode<Surface>::removeChild (SurfacePtr c) {
0072     removeChildImpl (c);
0073 }
0074 
0075 void Surface::clear () {
0076     m_first_child = 0L;
0077     background_color = 0;
0078 }
0079 
0080 void Surface::remove () {
0081     Surface *sp = parentNode ();
0082     if (sp) {
0083         sp->markDirty ();
0084         sp->removeChild (this);
0085     }
0086 }
0087 
0088 void Surface::resize (const SRect &rect, bool parent_resized) {
0089     SRect old_bounds = bounds;
0090     bounds = rect;
0091     if (parent_resized || old_bounds != rect) {
0092 
0093         if (parent_resized || old_bounds.size != rect.size) {
0094             virtual_size = SSize (); //FIXME try to preserve scroll on resize
0095             markDirty ();
0096 #ifdef KMPLAYER_WITH_CAIRO
0097             if (surface) {
0098                 cairo_surface_destroy (surface);
0099                 surface = NULL;
0100             }
0101 #endif
0102             updateChildren (true);
0103         } else if (parentNode ()) {
0104             parentNode ()->markDirty ();
0105         }
0106         if (parentNode ())
0107             parentNode ()->repaint (old_bounds.unite (rect));
0108         else
0109             repaint ();
0110     }
0111 }
0112 
0113 void Surface::markDirty () {
0114     for (Surface *s = this; s && !s->dirty; s = s->parentNode ())
0115         s->dirty = true;
0116 }
0117 
0118 void Surface::updateChildren (bool parent_resized) {
0119     for (Surface *c = firstChild (); c; c = c->nextSibling ())
0120         if (c->node)
0121             c->node->message (MsgSurfaceBoundsUpdate, (void *) parent_resized);
0122         else
0123             kError () << "Surface without node";
0124 }
0125 
0126 Surface *Surface::createSurface (NodePtr owner, const SRect & rect) {
0127     Surface *surface = new Surface (view_widget);
0128     surface->node = owner;
0129     surface->bounds = rect;
0130     appendChild (surface);
0131     return surface;
0132 }
0133 
0134 KDE_NO_EXPORT IRect Surface::toScreen (const SSize &size) {
0135     //FIXME: handle scroll
0136     Matrix matrix (0, 0, xscale, yscale);
0137     matrix.translate (bounds.x (), bounds.y ());
0138     for (Surface *s = parentNode(); s; s = s->parentNode()) {
0139         matrix.transform(Matrix (0, 0, s->xscale, s->yscale));
0140         matrix.translate (s->bounds.x (), s->bounds.y ());
0141     }
0142     return matrix.toScreen (SRect (0, 0, size));
0143 }
0144 
0145 void Surface::setBackgroundColor (unsigned int argb) {
0146 #ifdef KMPLAYER_WITH_CAIRO
0147     if (surface &&
0148             ((background_color & 0xff000000) < 0xff000000) !=
0149             ((argb & 0xff000000) < 0xff000000)) {
0150         cairo_surface_destroy (surface);
0151         surface = NULL;
0152     }
0153 #endif
0154     background_color = argb;
0155 }
0156 
0157 static void clipToScreen (Surface *s, Matrix &m, IRect &clip) {
0158     Surface *ps = s->parentNode ();
0159     if (!ps) {
0160         clip = IRect (s->bounds.x (), s->bounds.y (),
0161                 s->bounds.width (), s->bounds.height ());
0162         m = Matrix (s->bounds.x (), s->bounds.y (), s->xscale, s->yscale);
0163     } else {
0164         clipToScreen (ps, m, clip);
0165         IRect scr = m.toScreen (s->bounds);
0166         clip = clip.intersect (scr);
0167         Matrix m1 = m;
0168         m = Matrix (s->bounds.x (), s->bounds.y (), s->xscale, s->yscale);
0169         m.transform (m1);
0170         if (!s->virtual_size.isEmpty ())
0171             m.translate (-s->x_scroll, -s->y_scroll);
0172     }
0173 }
0174 
0175 
0176 KDE_NO_EXPORT void Surface::repaint (const SRect &rect) {
0177     Matrix matrix;
0178     IRect clip;
0179     clipToScreen (this, matrix, clip);
0180     IRect scr = matrix.toScreen (rect);
0181     clip = clip.intersect (scr);
0182     if (!clip.isEmpty ())
0183         view_widget->scheduleRepaint (clip);
0184 }
0185 
0186 KDE_NO_EXPORT void Surface::repaint () {
0187     Surface *ps = parentNode ();
0188     if (ps)
0189         ps->repaint (bounds);
0190     else
0191         view_widget->scheduleRepaint (IRect (bounds.x (), bounds.y (),
0192                 bounds.width (), bounds.height ()));
0193 }
0194