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