|
|
|
/**
|
|
|
|
This file belong to the KMPlayer project, a movie player plugin for Konqueror
|
|
|
|
Copyright (C) 2007 Koos Vriezen <koos.vriezen@gmail.com>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <tqapplication.h>
|
|
|
|
#include <tqwidgetstack.h>
|
|
|
|
#include <tqslider.h>
|
|
|
|
#include <tqcursor.h>
|
|
|
|
#include <tqimage.h>
|
|
|
|
#include <tqmap.h>
|
|
|
|
|
|
|
|
#include <tdeactioncollection.h>
|
|
|
|
#include <kstaticdeleter.h>
|
|
|
|
#include <kstatusbar.h>
|
|
|
|
#include <kstdaction.h>
|
|
|
|
#include <tdeshortcut.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include "kmplayerview.h"
|
|
|
|
#include "kmplayercontrolpanel.h"
|
|
|
|
#include "playlistview.h"
|
|
|
|
#include "viewarea.h"
|
|
|
|
#ifdef HAVE_CAIRO
|
|
|
|
# include <cairo-xlib.h>
|
|
|
|
# include <cairo-xlib-xrender.h>
|
|
|
|
#endif
|
|
|
|
#include "kmplayer_smil.h"
|
|
|
|
#include "kmplayer_rp.h"
|
|
|
|
|
|
|
|
using namespace KMPlayer;
|
|
|
|
|
|
|
|
extern const char * normal_window_xpm[];
|
|
|
|
extern const char * playlist_xpm[];
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
|
|
namespace KMPlayer {
|
|
|
|
typedef TQMap <TQString, ImageDataPtrW> ImageDataMap;
|
|
|
|
static KStaticDeleter <ImageDataMap> imageCacheDeleter;
|
|
|
|
static ImageDataMap * image_data_map;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImageData::ImageData( const TQString & img) :
|
|
|
|
image (0L),
|
|
|
|
url (img) {
|
|
|
|
//if (img.isEmpty ())
|
|
|
|
// //kdDebug() << "New ImageData for " << this << endl;
|
|
|
|
//else
|
|
|
|
// //kdDebug() << "New ImageData for " << img << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImageData::~ImageData() {
|
|
|
|
if (!url.isEmpty ())
|
|
|
|
image_data_map->erase (url);
|
|
|
|
delete image;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_CAIRO
|
|
|
|
static void copyImage (Surface *s, int w, int h, TQImage *img, cairo_surface_t *similar) {
|
|
|
|
int iw = img->width ();
|
|
|
|
int ih = img->height ();
|
|
|
|
|
|
|
|
if (img->depth () < 24) {
|
|
|
|
TQImage qi = img->convertDepth (32, 0);
|
|
|
|
*img = qi;
|
|
|
|
}
|
|
|
|
cairo_surface_t *sf = cairo_image_surface_create_for_data (
|
|
|
|
img->bits (),
|
|
|
|
img->hasAlphaBuffer () ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
|
|
|
|
iw, ih, img->bytesPerLine ());
|
|
|
|
cairo_pattern_t *img_pat = cairo_pattern_create_for_surface (sf);
|
|
|
|
cairo_pattern_set_extend (img_pat, CAIRO_EXTEND_NONE);
|
|
|
|
if (w != iw && h != ih) {
|
|
|
|
cairo_matrix_t mat;
|
|
|
|
cairo_matrix_init_scale (&mat, 1.0 * iw/w, 1.0 * ih/h);
|
|
|
|
cairo_pattern_set_matrix (img_pat, &mat);
|
|
|
|
}
|
|
|
|
if (!s->surface)
|
|
|
|
s->surface = cairo_surface_create_similar (similar,
|
|
|
|
img->hasAlphaBuffer () ?
|
|
|
|
CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR, w, h);
|
|
|
|
cairo_t *cr = cairo_create (s->surface);
|
|
|
|
cairo_set_source (cr, img_pat);
|
|
|
|
cairo_paint (cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
|
|
|
|
cairo_pattern_destroy (img_pat);
|
|
|
|
cairo_surface_destroy (sf);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool CachedImage::isEmpty () {
|
|
|
|
return !data || !data->image;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CachedImage::setUrl (const TQString & url) {
|
|
|
|
if (url.isEmpty ()) {
|
|
|
|
data = ImageDataPtr (new ImageData (url));
|
|
|
|
} else {
|
|
|
|
ImageDataMap::iterator i = image_data_map->find (url);
|
|
|
|
if (i == image_data_map->end ()) {
|
|
|
|
data = ImageDataPtr (new ImageData (url));
|
|
|
|
image_data_map->insert (url, ImageDataPtrW (data));
|
|
|
|
} else {
|
|
|
|
ImageDataPtr safe = i.data ();
|
|
|
|
data = safe;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
|
|
namespace KMPlayer {
|
|
|
|
|
|
|
|
class KMPLAYER_NO_EXPORT ViewSurface : public Surface {
|
|
|
|
public:
|
|
|
|
ViewSurface (ViewArea * widget);
|
|
|
|
ViewSurface (ViewArea * widget, NodePtr owner, const SRect & rect);
|
|
|
|
~ViewSurface ();
|
|
|
|
|
|
|
|
void clear () { m_first_child = 0L; }
|
|
|
|
|
|
|
|
SurfacePtr createSurface (NodePtr owner, const SRect & rect);
|
|
|
|
IRect toScreen (Single x, Single y, Single w, Single h);
|
|
|
|
void resize (const SRect & rect);
|
|
|
|
void repaint ();
|
|
|
|
void repaint (const SRect &rect);
|
|
|
|
void video ();
|
|
|
|
|
|
|
|
NodePtrW current_video;
|
|
|
|
ViewArea * view_widget;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
KDE_NO_CDTOR_EXPORT ViewSurface::ViewSurface (ViewArea * widget)
|
|
|
|
: Surface (NULL, SRect (0, 0, widget->width (), widget->height ())),
|
|
|
|
view_widget (widget)
|
|
|
|
{}
|
|
|
|
|
|
|
|
KDE_NO_CDTOR_EXPORT
|
|
|
|
ViewSurface::ViewSurface (ViewArea * widget, NodePtr owner, const SRect & rect)
|
|
|
|
: Surface (owner, rect), view_widget (widget) {}
|
|
|
|
|
|
|
|
KDE_NO_CDTOR_EXPORT ViewSurface::~ViewSurface() {
|
|
|
|
//kdDebug() << "~ViewSurface" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
SurfacePtr ViewSurface::createSurface (NodePtr owner, const SRect & rect) {
|
|
|
|
SurfacePtr surface = new ViewSurface (view_widget, owner, rect);
|
|
|
|
appendChild (surface);
|
|
|
|
return surface;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewSurface::resize (const SRect &r) {
|
|
|
|
bounds = r;
|
|
|
|
#ifdef HAVE_CAIRO
|
|
|
|
if (surface)
|
|
|
|
cairo_xlib_surface_set_size (surface, (int)r.width(), (int)r.height ());
|
|
|
|
#endif
|
|
|
|
/*if (rect == nrect)
|
|
|
|
;//return;
|
|
|
|
SRect pr = rect.unite (nrect); // for repaint
|
|
|
|
rect = nrect;*/
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT IRect ViewSurface::toScreen (Single x, Single y, Single w, Single h) {
|
|
|
|
Matrix matrix (0, 0, xscale, yscale);
|
|
|
|
matrix.translate (bounds.x (), bounds.y ());
|
|
|
|
for (SurfacePtr s = parentNode(); s; s = s->parentNode()) {
|
|
|
|
matrix.transform(Matrix (0, 0, s->xscale, s->yscale));
|
|
|
|
matrix.translate (s->bounds.x (), s->bounds.y ());
|
|
|
|
}
|
|
|
|
matrix.getXYWH (x, y, w, h);
|
|
|
|
return IRect (x, y, w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT
|
|
|
|
void ViewSurface::repaint (const SRect &r) {
|
|
|
|
markDirty ();
|
|
|
|
view_widget->scheduleRepaint (toScreen (r.x (), r.y (), r.width (), r.height ()));
|
|
|
|
//kdDebug() << "Surface::repaint x:" << (int)x << " y:" << (int)y << " w:" << (int)w << " h:" << (int)h << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT
|
|
|
|
void ViewSurface::repaint () {
|
|
|
|
markDirty ();
|
|
|
|
view_widget->scheduleRepaint (toScreen (0, 0, bounds.width (), bounds.height ()));
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewSurface::video () {
|
|
|
|
view_widget->setAudioVideoNode (node);
|
|
|
|
kdDebug() << "Surface::video:" << background_color << " " << (background_color & 0xff000000) << endl;
|
|
|
|
xscale = yscale = 1; // either scale width/heigt or use bounds
|
|
|
|
view_widget->setAudioVideoGeometry (toScreen (0, 0, bounds.width(), bounds.height ()),
|
|
|
|
(background_color & 0xff000000 ? &background_color : 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#ifdef HAVE_CAIRO
|
|
|
|
|
|
|
|
static cairo_surface_t * cairoCreateSurface (Window id, int w, int h) {
|
|
|
|
Display * display = tqt_xdisplay ();
|
|
|
|
return cairo_xlib_surface_create (display, id,
|
|
|
|
DefaultVisual (display, DefaultScreen (display)), w, h);
|
|
|
|
/*return cairo_xlib_surface_create_with_xrender_format (
|
|
|
|
tqt_xdisplay (),
|
|
|
|
id,
|
|
|
|
DefaultScreenOfDisplay (tqt_xdisplay ()),
|
|
|
|
XRenderFindVisualFormat (tqt_xdisplay (),
|
|
|
|
DefaultVisual (tqt_xdisplay (),
|
|
|
|
DefaultScreen (tqt_xdisplay ()))),
|
|
|
|
w, h);*/
|
|
|
|
}
|
|
|
|
|
|
|
|
# define CAIRO_SET_SOURCE_RGB(cr,c) \
|
|
|
|
cairo_set_source_rgb ((cr), \
|
|
|
|
1.0 * (((c) >> 16) & 0xff) / 255, \
|
|
|
|
1.0 * (((c) >> 8) & 0xff) / 255, \
|
|
|
|
1.0 * (((c)) & 0xff) / 255)
|
|
|
|
|
|
|
|
class KMPLAYER_NO_EXPORT CairoPaintVisitor : public Visitor {
|
|
|
|
IRect clip;
|
|
|
|
cairo_surface_t * cairo_surface;
|
|
|
|
Matrix matrix;
|
|
|
|
// stack vars need for transitions
|
|
|
|
SMIL::MediaType *cur_media;
|
|
|
|
cairo_pattern_t * cur_pat;
|
|
|
|
cairo_matrix_t cur_mat;
|
|
|
|
float opacity;
|
|
|
|
bool toplevel;
|
|
|
|
|
|
|
|
void traverseRegion (SMIL::RegionBase * reg);
|
|
|
|
void updateExternal (SMIL::MediaType *av, SurfacePtr s);
|
|
|
|
void paint(SMIL::MediaType *, Surface *, int x, int y, const IRect &);
|
|
|
|
public:
|
|
|
|
cairo_t * cr;
|
|
|
|
CairoPaintVisitor (cairo_surface_t * cs, Matrix m,
|
|
|
|
const IRect & rect, TQColor c=TQColor(), bool toplevel=false);
|
|
|
|
~CairoPaintVisitor ();
|
|
|
|
using Visitor::visit;
|
|
|
|
void visit (Node * n);
|
|
|
|
void visit (SMIL::Layout *);
|
|
|
|
void visit (SMIL::Region *);
|
|
|
|
void visit (SMIL::Transition *);
|
|
|
|
void visit (SMIL::ImageMediaType *);
|
|
|
|
void visit (SMIL::TextMediaType *);
|
|
|
|
void visit (SMIL::Brush *);
|
|
|
|
void visit (SMIL::RefMediaType *);
|
|
|
|
void visit (SMIL::AVMediaType *);
|
|
|
|
void visit (RP::Imfl *);
|
|
|
|
void visit (RP::Fill *);
|
|
|
|
void visit (RP::Fadein *);
|
|
|
|
void visit (RP::Fadeout *);
|
|
|
|
void visit (RP::Crossfade *);
|
|
|
|
void visit (RP::Wipe *);
|
|
|
|
void visit (RP::ViewChange *);
|
|
|
|
};
|
|
|
|
|
|
|
|
KDE_NO_CDTOR_EXPORT
|
|
|
|
CairoPaintVisitor::CairoPaintVisitor (cairo_surface_t * cs, Matrix m,
|
|
|
|
const IRect & rect, TQColor c, bool top)
|
|
|
|
: clip (rect), cairo_surface (cs), matrix (m), toplevel (top) {
|
|
|
|
cr = cairo_create (cs);
|
|
|
|
if (toplevel) {
|
|
|
|
cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
|
|
|
|
cairo_clip (cr);
|
|
|
|
//cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
|
|
|
cairo_set_tolerance (cr, 0.5 );
|
|
|
|
cairo_push_group (cr);
|
|
|
|
cairo_set_source_rgb (cr,
|
|
|
|
1.0 * c.red () / 255, 1.0 * c.green () / 255, 1.0 * c.blue () / 255);
|
|
|
|
cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
|
|
|
|
cairo_fill (cr);
|
|
|
|
} else {
|
|
|
|
cairo_save (cr);
|
|
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
|
|
|
cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
|
|
|
|
cairo_fill (cr);
|
|
|
|
cairo_restore (cr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_CDTOR_EXPORT CairoPaintVisitor::~CairoPaintVisitor () {
|
|
|
|
if (toplevel) {
|
|
|
|
cairo_pattern_t * pat = cairo_pop_group (cr);
|
|
|
|
//cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
|
|
|
|
cairo_set_source (cr, pat);
|
|
|
|
cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
|
|
|
|
cairo_fill (cr);
|
|
|
|
cairo_pattern_destroy (pat);
|
|
|
|
}
|
|
|
|
cairo_destroy (cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (Node * n) {
|
|
|
|
kdWarning() << "Paint called on " << n->nodeName() << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::traverseRegion (SMIL::RegionBase * reg) {
|
|
|
|
// next visit listeners
|
|
|
|
NodeRefListPtr nl = reg->listeners (mediatype_attached);
|
|
|
|
if (nl) {
|
|
|
|
for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ())
|
|
|
|
if (c->data)
|
|
|
|
c->data->accept (this);
|
|
|
|
}
|
|
|
|
// finally visit children, accounting for z-order FIXME optimize
|
|
|
|
NodeRefList sorted;
|
|
|
|
for (NodePtr n = reg->firstChild (); n; n = n->nextSibling ()) {
|
|
|
|
if (n->id != SMIL::id_node_region)
|
|
|
|
continue;
|
|
|
|
SMIL::Region * r = static_cast <SMIL::Region *> (n.ptr ());
|
|
|
|
NodeRefItemPtr rn = sorted.first ();
|
|
|
|
for (; rn; rn = rn->nextSibling ())
|
|
|
|
if (r->z_order < convertNode <SMIL::Region> (rn->data)->z_order) {
|
|
|
|
sorted.insertBefore (new NodeRefItem (n), rn);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!rn)
|
|
|
|
sorted.append (new NodeRefItem (n));
|
|
|
|
}
|
|
|
|
for (NodeRefItemPtr r = sorted.first (); r; r = r->nextSibling ())
|
|
|
|
r->data->accept (this);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Layout * reg) {
|
|
|
|
//kdDebug() << "Visit " << reg->nodeName() << endl;
|
|
|
|
SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (reg->rootLayout);
|
|
|
|
if (reg->surface () && rb) {
|
|
|
|
//cairo_save (cr);
|
|
|
|
Matrix m = matrix;
|
|
|
|
|
|
|
|
SRect rect = reg->region_surface->bounds;
|
|
|
|
Single x, y, w = rect.width(), h = rect.height();
|
|
|
|
matrix.getXYWH (x, y, w, h);
|
|
|
|
|
|
|
|
IRect clip_save = clip;
|
|
|
|
clip = clip.intersect (IRect (x, y, w, h));
|
|
|
|
|
|
|
|
rb->region_surface = reg->region_surface;
|
|
|
|
rb->region_surface->background_color = rb->background_color;
|
|
|
|
|
|
|
|
if (reg->region_surface->background_color & 0xff000000) {
|
|
|
|
CAIRO_SET_SOURCE_RGB (cr, reg->region_surface->background_color);
|
|
|
|
cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
|
|
|
|
cairo_fill (cr);
|
|
|
|
}
|
|
|
|
//cairo_rectangle (cr, xoff, yoff, w, h);
|
|
|
|
//cairo_clip (cr);
|
|
|
|
|
|
|
|
matrix = Matrix (0, 0, reg->region_surface->xscale, reg->region_surface->yscale);
|
|
|
|
matrix.transform (m);
|
|
|
|
traverseRegion (reg);
|
|
|
|
//cairo_restore (cr);
|
|
|
|
matrix = m;
|
|
|
|
clip = clip_save;
|
|
|
|
|
|
|
|
rb->region_surface = 0L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Region * reg) {
|
|
|
|
Surface *s = reg->surface ();
|
|
|
|
if (s) {
|
|
|
|
SRect rect = s->bounds;
|
|
|
|
|
|
|
|
Matrix m = matrix;
|
|
|
|
Single x = rect.x(), y = rect.y(), w = rect.width(), h = rect.height();
|
|
|
|
matrix.getXYWH (x, y, w, h);
|
|
|
|
if (clip.intersect (IRect (x, y, w, h)).isEmpty ())
|
|
|
|
return;
|
|
|
|
matrix = Matrix (rect.x(), rect.y(), 1.0, 1.0);
|
|
|
|
matrix.transform (m);
|
|
|
|
IRect clip_save = clip;
|
|
|
|
clip = clip.intersect (IRect (x, y, w, h));
|
|
|
|
cairo_save (cr);
|
|
|
|
if ((SMIL::RegionBase::ShowAlways == reg->show_background ||
|
|
|
|
reg->m_AttachedMediaTypes->first ()) &&
|
|
|
|
(s->background_color & 0xff000000 ||
|
|
|
|
!reg->cached_img.isEmpty ())) {
|
|
|
|
cairo_save (cr);
|
|
|
|
if (s->background_color & 0xff000000) {
|
|
|
|
CAIRO_SET_SOURCE_RGB (cr, s->background_color);
|
|
|
|
cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
|
|
|
|
cairo_fill (cr);
|
|
|
|
}
|
|
|
|
if (!reg->cached_img.isEmpty ()) {
|
|
|
|
Single x1, y1;
|
|
|
|
Single w = reg->cached_img.data->image->width ();
|
|
|
|
Single h = reg->cached_img.data->image->height();
|
|
|
|
matrix.getXYWH (x1, y1, w, h);
|
|
|
|
if (!s->surface)
|
|
|
|
copyImage (s, w, h, reg->cached_img.data->image, cairo_surface);
|
|
|
|
cairo_pattern_t *pat = cairo_pattern_create_for_surface (s->surface);
|
|
|
|
cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT);
|
|
|
|
cairo_matrix_t mat;
|
|
|
|
cairo_matrix_init_translate (&mat, (int) -x, (int) -y);
|
|
|
|
cairo_pattern_set_matrix (pat, &mat);
|
|
|
|
cairo_set_source (cr, pat);
|
|
|
|
cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
|
|
|
|
cairo_fill (cr);
|
|
|
|
cairo_pattern_destroy (pat);
|
|
|
|
}
|
|
|
|
cairo_restore (cr);
|
|
|
|
}
|
|
|
|
traverseRegion (reg);
|
|
|
|
cairo_restore (cr);
|
|
|
|
matrix = m;
|
|
|
|
clip = clip_save;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CAIRO_SET_PATTERN_COND(cr,pat,mat) \
|
|
|
|
if (pat) { \
|
|
|
|
cairo_pattern_set_extend (cur_pat, CAIRO_EXTEND_NONE); \
|
|
|
|
cairo_pattern_set_matrix (pat, &mat); \
|
|
|
|
cairo_pattern_set_filter (pat, CAIRO_FILTER_FAST); \
|
|
|
|
cairo_set_source (cr, pat); \
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Transition *trans) {
|
|
|
|
float perc = trans->start_progress + (trans->end_progress - trans->start_progress)*cur_media->trans_step / cur_media->trans_steps;
|
|
|
|
if (cur_media->trans_out_active)
|
|
|
|
perc = 1.0 - perc;
|
|
|
|
if (SMIL::Transition::Fade == trans->type) {
|
|
|
|
CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
|
|
|
|
cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
|
|
|
|
opacity = perc;
|
|
|
|
} else if (SMIL::Transition::BarWipe == trans->type) {
|
|
|
|
IRect rect;
|
|
|
|
if (SMIL::Transition::SubTopToBottom == trans->sub_type) {
|
|
|
|
if (SMIL::Transition::dir_reverse == trans->direction) {
|
|
|
|
int dy = (int) ((1.0 - perc) * clip.h);
|
|
|
|
rect = IRect (clip.x, clip.y + dy, clip.w, clip.h - dy);
|
|
|
|
} else {
|
|
|
|
rect = IRect (clip.x, clip.y, clip.w, (int) (perc * clip.h));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (SMIL::Transition::dir_reverse == trans->direction) {
|
|
|
|
int dx = (int) ((1.0 - perc) * clip.w);
|
|
|
|
rect = IRect (clip.x + dx, clip.y, clip.w - dx, clip.h);
|
|
|
|
} else {
|
|
|
|
rect = IRect (clip.x, clip.y, (int) (perc * clip.w), clip.h);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
|
|
|
|
CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
|
|
|
|
} else if (SMIL::Transition::PushWipe == trans->type) {
|
|
|
|
int dx = 0, dy = 0;
|
|
|
|
if (SMIL::Transition::SubFromTop == trans->sub_type)
|
|
|
|
dy = -(int) ((1.0 - perc) * clip.h);
|
|
|
|
else if (SMIL::Transition::SubFromRight == trans->sub_type)
|
|
|
|
dx = (int) ((1.0 - perc) * clip.w);
|
|
|
|
else if (SMIL::Transition::SubFromBottom == trans->sub_type)
|
|
|
|
dy = (int) ((1.0 - perc) * clip.h);
|
|
|
|
else //if (SMIL::Transition::SubFromLeft == trans->sub_type)
|
|
|
|
dx = -(int) ((1.0 - perc) * clip.w);
|
|
|
|
cairo_matrix_translate (&cur_mat, -dx, -dy);
|
|
|
|
IRect rect = clip.intersect (IRect (clip.x + dx, clip.y + dy,
|
|
|
|
clip.w - dx, clip.h - dy));
|
|
|
|
cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
|
|
|
|
CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
|
|
|
|
} else if (SMIL::Transition::IrisWipe == trans->type) {
|
|
|
|
CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
|
|
|
|
if (SMIL::Transition::SubDiamond == trans->sub_type) {
|
|
|
|
cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
|
|
|
|
cairo_clip (cr);
|
|
|
|
int dx = (int) (perc * clip.w);
|
|
|
|
int dy = (int) (perc * clip.h);
|
|
|
|
int mx = clip.x + clip.w/2;
|
|
|
|
int my = clip.y + clip.h/2;
|
|
|
|
cairo_new_path (cr);
|
|
|
|
cairo_move_to (cr, mx, my - dy);
|
|
|
|
cairo_line_to (cr, mx + dx, my);
|
|
|
|
cairo_line_to (cr, mx, my + dy);
|
|
|
|
cairo_line_to (cr, mx - dx, my);
|
|
|
|
cairo_close_path (cr);
|
|
|
|
} else { // SubRectangle
|
|
|
|
int dx = (int) (0.5 * (1 - perc) * clip.w);
|
|
|
|
int dy = (int) (0.5 * (1 - perc) * clip.h);
|
|
|
|
cairo_rectangle (cr, clip.x + dx, clip.y + dy,
|
|
|
|
clip.w - 2 * dx, clip.h -2 * dy);
|
|
|
|
}
|
|
|
|
} else if (SMIL::Transition::ClockWipe == trans->type) {
|
|
|
|
cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
|
|
|
|
cairo_clip (cr);
|
|
|
|
int mx = clip.x + clip.w/2;
|
|
|
|
int my = clip.y + clip.h/2;
|
|
|
|
cairo_new_path (cr);
|
|
|
|
cairo_move_to (cr, mx, my);
|
|
|
|
float hw = 1.0 * clip.w/2;
|
|
|
|
float hh = 1.0 * clip.h/2;
|
|
|
|
float radius = sqrtf (hw * hw + hh * hh);
|
|
|
|
float phi;
|
|
|
|
switch (trans->sub_type) {
|
|
|
|
case SMIL::Transition::SubClockwiseThree:
|
|
|
|
phi = 0;
|
|
|
|
break;
|
|
|
|
case SMIL::Transition::SubClockwiseSix:
|
|
|
|
phi = M_PI / 2;
|
|
|
|
break;
|
|
|
|
case SMIL::Transition::SubClockwiseNine:
|
|
|
|
phi = M_PI;
|
|
|
|
break;
|
|
|
|
default: // Twelve
|
|
|
|
phi = -M_PI / 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (SMIL::Transition::dir_reverse == trans->direction)
|
|
|
|
cairo_arc_negative (cr, mx, my, radius, phi, phi - 2 * M_PI * perc);
|
|
|
|
else
|
|
|
|
cairo_arc (cr, mx, my, radius, phi, phi + 2 * M_PI * perc);
|
|
|
|
cairo_close_path (cr);
|
|
|
|
CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
|
|
|
|
} else if (SMIL::Transition::BowTieWipe == trans->type) {
|
|
|
|
cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
|
|
|
|
cairo_clip (cr);
|
|
|
|
int mx = clip.x + clip.w/2;
|
|
|
|
int my = clip.y + clip.h/2;
|
|
|
|
cairo_new_path (cr);
|
|
|
|
cairo_move_to (cr, mx, my);
|
|
|
|
float hw = 1.0 * clip.w/2;
|
|
|
|
float hh = 1.0 * clip.h/2;
|
|
|
|
float radius = sqrtf (hw * hw + hh * hh);
|
|
|
|
float phi;
|
|
|
|
switch (trans->sub_type) {
|
|
|
|
case SMIL::Transition::SubHorizontal:
|
|
|
|
phi = 0;
|
|
|
|
break;
|
|
|
|
default: // Vertical
|
|
|
|
phi = -M_PI / 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
float dphi = 0.5 * M_PI * perc;
|
|
|
|
cairo_arc (cr, mx, my, radius, phi - dphi, phi + dphi);
|
|
|
|
cairo_close_path (cr);
|
|
|
|
cairo_new_sub_path (cr);
|
|
|
|
cairo_move_to (cr, mx, my);
|
|
|
|
if (SMIL::Transition::SubHorizontal == trans->sub_type)
|
|
|
|
cairo_arc (cr, mx, my, radius, M_PI + phi - dphi, M_PI + phi +dphi);
|
|
|
|
else
|
|
|
|
cairo_arc (cr, mx, my, radius, -phi - dphi, -phi + dphi);
|
|
|
|
cairo_close_path (cr);
|
|
|
|
CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
|
|
|
|
} else if (SMIL::Transition::EllipseWipe == trans->type) {
|
|
|
|
cairo_rectangle (cr, clip.x, clip.y, clip.w, clip.h);
|
|
|
|
cairo_clip (cr);
|
|
|
|
int mx = clip.x + clip.w/2;
|
|
|
|
int my = clip.y + clip.h/2;
|
|
|
|
float hw = (double) clip.w/2;
|
|
|
|
float hh = (double) clip.h/2;
|
|
|
|
float radius = sqrtf (hw * hw + hh * hh);
|
|
|
|
cairo_save (cr);
|
|
|
|
cairo_new_path (cr);
|
|
|
|
cairo_translate (cr, (int) mx, (int) my);
|
|
|
|
cairo_move_to (cr, - Single (radius), 0);
|
|
|
|
if (SMIL::Transition::SubHorizontal == trans->sub_type)
|
|
|
|
cairo_scale (cr, 1.0, 0.6);
|
|
|
|
else if (SMIL::Transition::SubVertical == trans->sub_type)
|
|
|
|
cairo_scale (cr, 0.6, 1.0);
|
|
|
|
cairo_arc (cr, 0, 0, perc * radius, 0, 2 * M_PI);
|
|
|
|
cairo_close_path (cr);
|
|
|
|
cairo_restore (cr);
|
|
|
|
CAIRO_SET_PATTERN_COND(cr, cur_pat, cur_mat)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::RefMediaType *ref) {
|
|
|
|
Surface *s = ref->surface ();
|
|
|
|
if (s) {
|
|
|
|
if (ref->external_tree)
|
|
|
|
updateExternal (ref, s);
|
|
|
|
else if (ref->needsVideoWidget ())
|
|
|
|
s->video ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::paint (SMIL::MediaType *mt, Surface *s,
|
|
|
|
int x, int y, const IRect &rect) {
|
|
|
|
cairo_save (cr);
|
|
|
|
opacity = 1.0;
|
|
|
|
cairo_matrix_init_translate (&cur_mat, -x, -y);
|
|
|
|
cur_pat = cairo_pattern_create_for_surface (s->surface);
|
|
|
|
if (mt->active_trans) {
|
|
|
|
IRect clip_save = clip;
|
|
|
|
clip = rect;
|
|
|
|
cur_media = mt;
|
|
|
|
mt->active_trans->accept (this);
|
|
|
|
clip = clip_save;
|
|
|
|
} else {
|
|
|
|
cairo_pattern_set_extend (cur_pat, CAIRO_EXTEND_NONE);
|
|
|
|
cairo_pattern_set_matrix (cur_pat, &cur_mat);
|
|
|
|
cairo_pattern_set_filter (cur_pat, CAIRO_FILTER_FAST);
|
|
|
|
cairo_set_source (cr, cur_pat);
|
|
|
|
cairo_rectangle (cr, rect.x, rect.y, rect.w, rect.h);
|
|
|
|
}
|
|
|
|
opacity *= mt->opacity / 100.0;
|
|
|
|
if (opacity < 0.99) {
|
|
|
|
cairo_clip (cr);
|
|
|
|
cairo_paint_with_alpha (cr, opacity);
|
|
|
|
} else {
|
|
|
|
cairo_fill (cr);
|
|
|
|
}
|
|
|
|
cairo_pattern_destroy (cur_pat);
|
|
|
|
cairo_restore (cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT
|
|
|
|
void CairoPaintVisitor::updateExternal (SMIL::MediaType *av, SurfacePtr s) {
|
|
|
|
SRect rect = s->bounds;
|
|
|
|
Single x = rect.x ();
|
|
|
|
Single y = rect.y ();
|
|
|
|
Single w = rect.width();
|
|
|
|
Single h = rect.height();
|
|
|
|
matrix.getXYWH (x, y, w, h);
|
|
|
|
IRect clip_rect = clip.intersect (IRect (x, y, w, h));
|
|
|
|
if (!clip_rect.isValid ())
|
|
|
|
return;
|
|
|
|
if (!s->surface || s->dirty) {
|
|
|
|
Matrix m = matrix;
|
|
|
|
m.translate (-x, -y);
|
|
|
|
IRect r (clip_rect.x - (int) x - 1, clip_rect.y - (int) y - 1,
|
|
|
|
clip_rect.w + 3, clip_rect.h + 3);
|
|
|
|
if (!s->surface) {
|
|
|
|
s->surface = cairo_surface_create_similar (cairo_surface,
|
|
|
|
CAIRO_CONTENT_COLOR_ALPHA, (int) w, (int) h);
|
|
|
|
r = IRect (0, 0, w, h);
|
|
|
|
}
|
|
|
|
CairoPaintVisitor visitor (s->surface, m, r);
|
|
|
|
av->external_tree->accept (&visitor);
|
|
|
|
s->dirty = false;
|
|
|
|
}
|
|
|
|
paint (av, s.ptr (), x, y, clip_rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::AVMediaType *av) {
|
|
|
|
Surface *s = av->surface ();
|
|
|
|
if (s) {
|
|
|
|
if (av->external_tree)
|
|
|
|
updateExternal (av, s);
|
|
|
|
else if (av->needsVideoWidget ())
|
|
|
|
s->video ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::ImageMediaType * img) {
|
|
|
|
//kdDebug() << "Visit " << img->nodeName() << " " << img->src << endl;
|
|
|
|
Surface *s = img->surface ();
|
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
if (img->external_tree) {
|
|
|
|
updateExternal (img, s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ImageRuntime * ir = static_cast <ImageRuntime *> (img->runtime ());
|
|
|
|
ImageData * id = ir->cached_img.data.ptr ();
|
|
|
|
if (!id || !id->image || img->width <= 0 || img->height <= 0) {
|
|
|
|
s->remove();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SRect rect = s->bounds;
|
|
|
|
Single x = rect.x ();
|
|
|
|
Single y = rect.y ();
|
|
|
|
Single w = rect.width();
|
|
|
|
Single h = rect.height();
|
|
|
|
matrix.getXYWH (x, y, w, h);
|
|
|
|
IRect clip_rect = clip.intersect (IRect (x, y, w, h));
|
|
|
|
if (clip_rect.isEmpty ())
|
|
|
|
return;
|
|
|
|
if (!s->surface || s->dirty)
|
|
|
|
copyImage (s, w, h, id->image, cairo_surface);
|
|
|
|
paint (img, s, x, y, clip_rect);
|
|
|
|
s->dirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::TextMediaType * txt) {
|
|
|
|
TextRuntime * td = static_cast <TextRuntime *> (txt->runtime ());
|
|
|
|
Surface *s = txt->surface ();
|
|
|
|
//kdDebug() << "Visit " << txt->nodeName() << " " << td->text << endl;
|
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
SRect rect = s->bounds;
|
|
|
|
Single x = rect.x (), y = rect.y(), w = rect.width(), h = rect.height();
|
|
|
|
matrix.getXYWH (x, y, w, h);
|
|
|
|
if (!s->surface) {
|
|
|
|
//kdDebug() << "new txt surface " << td->text << endl;
|
|
|
|
/* TQTextEdit * edit = new TQTextEdit;
|
|
|
|
edit->setReadOnly (true);
|
|
|
|
edit->setHScrollBarMode (TQScrollView::AlwaysOff);
|
|
|
|
edit->setVScrollBarMode (TQScrollView::AlwaysOff);
|
|
|
|
edit->setFrameShape (TQFrame::NoFrame);
|
|
|
|
edit->setFrameShadow (TQFrame::Plain);
|
|
|
|
edit->setGeometry (0, 0, w, h);
|
|
|
|
if (edit->length () == 0)
|
|
|
|
edit->setText (text);
|
|
|
|
if (w0 > 0)
|
|
|
|
font.setPointSize (int (1.0 * w * font_size / w0));
|
|
|
|
edit->setFont (font);
|
|
|
|
TQRect rect = p.clipRegion (TQPainter::CoordPainter).boundingRect ();
|
|
|
|
rect = rect.intersect (TQRect (xoff, yoff, w, h));
|
|
|
|
TQPixmap pix = TQPixmap::grabWidget (edit, rect.x () - (int) xoff,
|
|
|
|
rect.y () - (int) yoff, rect.width (), rect.height ());*/
|
|
|
|
|
|
|
|
float scale = 1.0 * w / rect.width (); // TODO: make an image
|
|
|
|
cairo_set_font_size (cr, scale * td->font_size);
|
|
|
|
cairo_font_extents_t txt_fnt;
|
|
|
|
cairo_font_extents (cr, &txt_fnt);
|
|
|
|
TQString str = td->text;
|
|
|
|
struct Line {
|
|
|
|
Line (const TQString & ln) : txt (ln), next(0) {}
|
|
|
|
TQString txt;
|
|
|
|
cairo_text_extents_t txt_ext;
|
|
|
|
Single xoff;
|
|
|
|
Line * next;
|
|
|
|
} *lines = 0, *last_line = 0;
|
|
|
|
Single y1 = y;
|
|
|
|
Single max_width;
|
|
|
|
int line_count = 0;
|
|
|
|
Single min_xoff = w;
|
|
|
|
while (!str.isEmpty ()) {
|
|
|
|
int len = str.find (TQChar ('\n'));
|
|
|
|
bool skip_cr = false;
|
|
|
|
if (len > 1 && str[len-1] == TQChar ('\r')) {
|
|
|
|
--len;
|
|
|
|
skip_cr = true;
|
|
|
|
}
|
|
|
|
TQString para = len > -1 ? str.left (len) : str;
|
|
|
|
Line * line = new Line (para);
|
|
|
|
++line_count;
|
|
|
|
if (!lines)
|
|
|
|
lines = line;
|
|
|
|
else
|
|
|
|
last_line->next = line;
|
|
|
|
last_line = line;
|
|
|
|
int ppos = 0;
|
|
|
|
while (true) {
|
|
|
|
cairo_text_extents (cr, line->txt.utf8 ().data (), &line->txt_ext);
|
|
|
|
float frag = line->txt_ext.width > 0.1
|
|
|
|
? w / line->txt_ext.width : 1.1;
|
|
|
|
if (frag < 1.0) {
|
|
|
|
int br_pos = int (line->txt.length () * frag); //educated guess
|
|
|
|
while (br_pos > 0) {
|
|
|
|
line->txt.truncate (br_pos);
|
|
|
|
br_pos = line->txt.findRev (TQChar (' '));
|
|
|
|
if (br_pos < 1)
|
|
|
|
break;
|
|
|
|
line->txt.truncate (br_pos);
|
|
|
|
cairo_text_extents (cr, line->txt.utf8 ().data (), &line->txt_ext);
|
|
|
|
if (line->txt_ext.width < (double)w)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (line->txt_ext.width > (double)max_width)
|
|
|
|
max_width = line->txt_ext.width;
|
|
|
|
|
|
|
|
if (td->halign == TextRuntime::align_center)
|
|
|
|
line->xoff = (w - Single (line->txt_ext.width)) / 2;
|
|
|
|
else if (td->halign == TextRuntime::align_right)
|
|
|
|
line->xoff = w - Single (line->txt_ext.width);
|
|
|
|
if (line->xoff < min_xoff)
|
|
|
|
min_xoff = line->xoff;
|
|
|
|
|
|
|
|
y1 += Single (txt_fnt.height);
|
|
|
|
ppos += line->txt.length () + 1;
|
|
|
|
if (ppos >= para.length ())
|
|
|
|
break;
|
|
|
|
|
|
|
|
line->next = new Line (para.mid (ppos));
|
|
|
|
++line_count;
|
|
|
|
line = line->next;
|
|
|
|
last_line = line;
|
|
|
|
}
|
|
|
|
if (len < 0)
|
|
|
|
break;
|
|
|
|
str = str.mid (len + (skip_cr ? 2 : 1));
|
|
|
|
}
|
|
|
|
// new coord in screen space
|
|
|
|
x += min_xoff;
|
|
|
|
w = (double)max_width + txt_fnt.max_x_advance / 2;
|
|
|
|
h = y1 - y /*txt_fnt.height + txt_fnt.descent*/;
|
|
|
|
|
|
|
|
s->surface = cairo_surface_create_similar (cairo_surface,
|
|
|
|
CAIRO_CONTENT_COLOR, (int) w, (int) h);
|
|
|
|
cairo_t * cr_txt = cairo_create (s->surface);
|
|
|
|
cairo_set_font_size (cr_txt, scale * td->font_size);
|
|
|
|
if (td->bg_opacity) { // TODO real alpha
|
|
|
|
CAIRO_SET_SOURCE_RGB (cr_txt, td->background_color);
|
|
|
|
cairo_paint (cr_txt);
|
|
|
|
}
|
|
|
|
CAIRO_SET_SOURCE_RGB (cr_txt, td->font_color);
|
|
|
|
y1 = 0;
|
|
|
|
while (lines) {
|
|
|
|
Line * line = lines;
|
|
|
|
line->xoff += Single (txt_fnt.max_x_advance / 4);
|
|
|
|
cairo_move_to (cr_txt, line->xoff - min_xoff, y1 + Single (txt_fnt.ascent));
|
|
|
|
cairo_show_text (cr_txt, line->txt.utf8 ().data ());
|
|
|
|
y1 += Single (txt_fnt.height);
|
|
|
|
lines = lines->next;
|
|
|
|
delete line;
|
|
|
|
}
|
|
|
|
//cairo_stroke (cr);
|
|
|
|
cairo_destroy (cr_txt);
|
|
|
|
|
|
|
|
// update bounds rect
|
|
|
|
Single sx = x, sy = y, sw = w, sh = h;
|
|
|
|
matrix.invXYWH (sx, sy, sw, sh);
|
|
|
|
txt->width = sw;
|
|
|
|
txt->height = sh;
|
|
|
|
s->bounds = txt->calculateBounds ();
|
|
|
|
|
|
|
|
// update coord. for painting below
|
|
|
|
x = s->bounds.x ();
|
|
|
|
y = s->bounds.y();
|
|
|
|
w = s->bounds.width();
|
|
|
|
h = s->bounds.height();
|
|
|
|
matrix.getXYWH (x, y, w, h);
|
|
|
|
}
|
|
|
|
IRect clip_rect = clip.intersect (IRect (x, y, w, h));
|
|
|
|
if (!clip_rect.isEmpty ())
|
|
|
|
paint (txt, s, x, y, clip_rect);
|
|
|
|
s->dirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (SMIL::Brush * brush) {
|
|
|
|
//kdDebug() << "Visit " << brush->nodeName() << endl;
|
|
|
|
Surface *s = brush->surface ();
|
|
|
|
if (s) {
|
|
|
|
cairo_save (cr);
|
|
|
|
opacity = 1.0;
|
|
|
|
SRect rect = s->bounds;
|
|
|
|
Single x, y, w = rect.width(), h = rect.height();
|
|
|
|
matrix.getXYWH (x, y, w, h);
|
|
|
|
unsigned int color = TQColor (brush->param ("color")).rgb ();
|
|
|
|
if (brush->active_trans) {
|
|
|
|
cur_media = brush;
|
|
|
|
cur_pat = NULL;
|
|
|
|
brush->active_trans->accept (this);
|
|
|
|
} else {
|
|
|
|
cairo_rectangle (cr, (int) x, (int) y, (int) w, (int) h);
|
|
|
|
}
|
|
|
|
opacity *= brush->opacity / 100.0;
|
|
|
|
if (opacity < 0.99)
|
|
|
|
cairo_set_source_rgba (cr,
|
|
|
|
1.0 * ((color >> 16) & 0xff) / 255,
|
|
|
|
1.0 * ((color >> 8) & 0xff) / 255,
|
|
|
|
1.0 * (color & 0xff) / 255,
|
|
|
|
opacity);
|
|
|
|
else
|
|
|
|
CAIRO_SET_SOURCE_RGB (cr, color);
|
|
|
|
cairo_fill (cr);
|
|
|
|
s->dirty = false;
|
|
|
|
cairo_restore (cr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Imfl * imfl) {
|
|
|
|
if (imfl->surface ()) {
|
|
|
|
cairo_save (cr);
|
|
|
|
Matrix m = matrix;
|
|
|
|
Single x, y;
|
|
|
|
Single w = imfl->rp_surface->bounds.width();
|
|
|
|
Single h = imfl->rp_surface->bounds.height();
|
|
|
|
matrix.getXYWH (x, y, w, h);
|
|
|
|
cairo_rectangle (cr, x, y, w, h);
|
|
|
|
//cairo_clip (cr);
|
|
|
|
cairo_translate (cr, x, y);
|
|
|
|
cairo_scale (cr, w/imfl->width, h/imfl->height);
|
|
|
|
if (imfl->needs_scene_img)
|
|
|
|
cairo_push_group (cr);
|
|
|
|
for (NodePtr n = imfl->firstChild (); n; n = n->nextSibling ())
|
|
|
|
if (n->state >= Node::state_began &&
|
|
|
|
n->state < Node::state_deactivated) {
|
|
|
|
RP::TimingsBase * tb = convertNode<RP::TimingsBase>(n);
|
|
|
|
switch (n->id) {
|
|
|
|
case RP::id_node_viewchange:
|
|
|
|
if (!(int)tb->srcw)
|
|
|
|
tb->srcw = imfl->width;
|
|
|
|
if (!(int)tb->srch)
|
|
|
|
tb->srch = imfl->height;
|
|
|
|
// fall through
|
|
|
|
case RP::id_node_crossfade:
|
|
|
|
case RP::id_node_fadein:
|
|
|
|
case RP::id_node_fadeout:
|
|
|
|
case RP::id_node_fill:
|
|
|
|
case RP::id_node_wipe:
|
|
|
|
if (!(int)tb->w)
|
|
|
|
tb->w = imfl->width;
|
|
|
|
if (!(int)tb->h)
|
|
|
|
tb->h = imfl->height;
|
|
|
|
n->accept (this);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (imfl->needs_scene_img) {
|
|
|
|
cairo_pattern_t * pat = cairo_pop_group (cr);
|
|
|
|
cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
|
|
|
|
cairo_set_source (cr, pat);
|
|
|
|
cairo_paint (cr);
|
|
|
|
cairo_pattern_destroy (pat);
|
|
|
|
}
|
|
|
|
cairo_restore (cr);
|
|
|
|
matrix = m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Fill * fi) {
|
|
|
|
//kdDebug() << "Visit " << fi->nodeName() << endl;
|
|
|
|
CAIRO_SET_SOURCE_RGB (cr, fi->color);
|
|
|
|
if ((int)fi->w && (int)fi->h) {
|
|
|
|
cairo_rectangle (cr, fi->x, fi->y, fi->w, fi->h);
|
|
|
|
cairo_fill (cr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Fadein * fi) {
|
|
|
|
//kdDebug() << "Visit " << fi->nodeName() << endl;
|
|
|
|
if (fi->target && fi->target->id == RP::id_node_image) {
|
|
|
|
RP::Image *img = convertNode <RP::Image> (fi->target);
|
|
|
|
if (img->surface ()) {
|
|
|
|
Single sx = fi->srcx, sy = fi->srcy, sw = fi->srcw, sh = fi->srch;
|
|
|
|
if (!(int)sw)
|
|
|
|
sw = img->width;
|
|
|
|
if (!(int)sh)
|
|
|
|
sh = img->height;
|
|
|
|
if ((int)fi->w && (int)fi->h && (int)sw && (int)sh) {
|
|
|
|
if (!img->img_surface->surface)
|
|
|
|
copyImage (img->img_surface, img->width, img->height, img->cached_img.data->image, cairo_surface);
|
|
|
|
cairo_matrix_t matrix;
|
|
|
|
cairo_matrix_init_identity (&matrix);
|
|
|
|
float scalex = 1.0 * sw / fi->w;
|
|
|
|
float scaley = 1.0 * sh / fi->h;
|
|
|
|
cairo_matrix_scale (&matrix, scalex, scaley);
|
|
|
|
cairo_matrix_translate (&matrix,
|
|
|
|
1.0*sx/scalex - (double)fi->x,
|
|
|
|
1.0*sy/scaley - (double)fi->y);
|
|
|
|
cairo_save (cr);
|
|
|
|
cairo_rectangle (cr, fi->x, fi->y, fi->w, fi->h);
|
|
|
|
cairo_pattern_t *pat = cairo_pattern_create_for_surface (img->img_surface->surface);
|
|
|
|
cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
|
|
|
|
cairo_pattern_set_matrix (pat, &matrix);
|
|
|
|
cairo_set_source (cr, pat);
|
|
|
|
cairo_clip (cr);
|
|
|
|
cairo_paint_with_alpha (cr, 1.0 * fi->progress / 100);
|
|
|
|
cairo_restore (cr);
|
|
|
|
cairo_pattern_destroy (pat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Fadeout * fo) {
|
|
|
|
//kdDebug() << "Visit " << fo->nodeName() << endl;
|
|
|
|
if (fo->progress > 0) {
|
|
|
|
CAIRO_SET_SOURCE_RGB (cr, fo->to_color);
|
|
|
|
if ((int)fo->w && (int)fo->h) {
|
|
|
|
cairo_save (cr);
|
|
|
|
cairo_rectangle (cr, fo->x, fo->y, fo->w, fo->h);
|
|
|
|
cairo_clip (cr);
|
|
|
|
cairo_paint_with_alpha (cr, 1.0 * fo->progress / 100);
|
|
|
|
cairo_restore (cr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Crossfade * cf) {
|
|
|
|
//kdDebug() << "Visit " << cf->nodeName() << endl;
|
|
|
|
if (cf->target && cf->target->id == RP::id_node_image) {
|
|
|
|
RP::Image *img = convertNode <RP::Image> (cf->target);
|
|
|
|
if (img->surface ()) {
|
|
|
|
Single sx = cf->srcx, sy = cf->srcy, sw = cf->srcw, sh = cf->srch;
|
|
|
|
if (!(int)sw)
|
|
|
|
sw = img->width;
|
|
|
|
if (!(int)sh)
|
|
|
|
sh = img->height;
|
|
|
|
if ((int)cf->w && (int)cf->h && (int)sw && (int)sh) {
|
|
|
|
if (!img->img_surface->surface)
|
|
|
|
copyImage (img->img_surface, img->width, img->height, img->cached_img.data->image, cairo_surface);
|
|
|
|
cairo_save (cr);
|
|
|
|
cairo_matrix_t matrix;
|
|
|
|
cairo_matrix_init_identity (&matrix);
|
|
|
|
float scalex = 1.0 * sw / cf->w;
|
|
|
|
float scaley = 1.0 * sh / cf->h;
|
|
|
|
cairo_matrix_scale (&matrix, scalex, scaley);
|
|
|
|
cairo_matrix_translate (&matrix,
|
|
|
|
1.0*sx/scalex - (double)cf->x,
|
|
|
|
1.0*sy/scaley - (double)cf->y);
|
|
|
|
cairo_rectangle (cr, cf->x, cf->y, cf->w, cf->h);
|
|
|
|
cairo_pattern_t *pat = cairo_pattern_create_for_surface (img->img_surface->surface);
|
|
|
|
cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
|
|
|
|
cairo_pattern_set_matrix (pat, &matrix);
|
|
|
|
cairo_set_source (cr, pat);
|
|
|
|
cairo_clip (cr);
|
|
|
|
cairo_paint_with_alpha (cr, 1.0 * cf->progress / 100);
|
|
|
|
cairo_restore (cr);
|
|
|
|
cairo_pattern_destroy (pat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::Wipe * wipe) {
|
|
|
|
//kdDebug() << "Visit " << wipe->nodeName() << endl;
|
|
|
|
if (wipe->target && wipe->target->id == RP::id_node_image) {
|
|
|
|
RP::Image *img = convertNode <RP::Image> (wipe->target);
|
|
|
|
if (img->surface ()) {
|
|
|
|
Single x = wipe->x, y = wipe->y;
|
|
|
|
Single tx = x, ty = y;
|
|
|
|
Single w = wipe->w, h = wipe->h;
|
|
|
|
Single sx = wipe->srcx, sy = wipe->srcy, sw = wipe->srcw, sh = wipe->srch;
|
|
|
|
if (!(int)sw)
|
|
|
|
sw = img->width;
|
|
|
|
if (!(int)sh)
|
|
|
|
sh = img->height;
|
|
|
|
if (wipe->direction == RP::Wipe::dir_right) {
|
|
|
|
Single dx = w * 1.0 * wipe->progress / 100;
|
|
|
|
tx = x -w + dx;
|
|
|
|
w = dx;
|
|
|
|
} else if (wipe->direction == RP::Wipe::dir_left) {
|
|
|
|
Single dx = w * 1.0 * wipe->progress / 100;
|
|
|
|
tx = x + w - dx;
|
|
|
|
x = tx;
|
|
|
|
w = dx;
|
|
|
|
} else if (wipe->direction == RP::Wipe::dir_down) {
|
|
|
|
Single dy = h * 1.0 * wipe->progress / 100;
|
|
|
|
ty = y - h + dy;
|
|
|
|
h = dy;
|
|
|
|
} else if (wipe->direction == RP::Wipe::dir_up) {
|
|
|
|
Single dy = h * 1.0 * wipe->progress / 100;
|
|
|
|
ty = y + h - dy;
|
|
|
|
y = ty;
|
|
|
|
h = dy;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((int)w && (int)h) {
|
|
|
|
if (!img->img_surface->surface)
|
|
|
|
copyImage (img->img_surface, img->width, img->height, img->cached_img.data->image, cairo_surface);
|
|
|
|
cairo_matrix_t matrix;
|
|
|
|
cairo_matrix_init_identity (&matrix);
|
|
|
|
float scalex = 1.0 * sw / wipe->w;
|
|
|
|
float scaley = 1.0 * sh / wipe->h;
|
|
|
|
cairo_matrix_scale (&matrix, scalex, scaley);
|
|
|
|
cairo_matrix_translate (&matrix,
|
|
|
|
1.0*sx/scalex - (double)tx,
|
|
|
|
1.0*sy/scaley - (double)ty);
|
|
|
|
cairo_pattern_t *pat = cairo_pattern_create_for_surface (img->img_surface->surface);
|
|
|
|
cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
|
|
|
|
cairo_pattern_set_matrix (pat, &matrix);
|
|
|
|
cairo_set_source (cr, pat);
|
|
|
|
cairo_rectangle (cr, x, y, w, h);
|
|
|
|
cairo_fill (cr);
|
|
|
|
cairo_pattern_destroy (pat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void CairoPaintVisitor::visit (RP::ViewChange * vc) {
|
|
|
|
//kdDebug() << "Visit " << vc->nodeName() << endl;
|
|
|
|
if (vc->unfinished () || vc->progress < 100) {
|
|
|
|
cairo_pattern_t * pat = cairo_pop_group (cr); // from imfl
|
|
|
|
cairo_pattern_set_extend (pat, CAIRO_EXTEND_NONE);
|
|
|
|
cairo_push_group (cr);
|
|
|
|
cairo_save (cr);
|
|
|
|
cairo_set_source (cr, pat);
|
|
|
|
cairo_paint (cr);
|
|
|
|
if ((int)vc->w && (int)vc->h && (int)vc->srcw && (int)vc->srch) {
|
|
|
|
cairo_matrix_t matrix;
|
|
|
|
cairo_matrix_init_identity (&matrix);
|
|
|
|
float scalex = 1.0 * vc->srcw / vc->w;
|
|
|
|
float scaley = 1.0 * vc->srch / vc->h;
|
|
|
|
cairo_matrix_scale (&matrix, scalex, scaley);
|
|
|
|
cairo_matrix_translate (&matrix,
|
|
|
|
1.0*vc->srcx/scalex - (double)vc->x,
|
|
|
|
1.0*vc->srcy/scaley - (double)vc->y);
|
|
|
|
cairo_pattern_set_matrix (pat, &matrix);
|
|
|
|
cairo_set_source (cr, pat);
|
|
|
|
cairo_rectangle (cr, vc->x, vc->y, vc->w, vc->h);
|
|
|
|
cairo_fill (cr);
|
|
|
|
}
|
|
|
|
cairo_pattern_destroy (pat);
|
|
|
|
cairo_restore (cr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
namespace KMPlayer {
|
|
|
|
|
|
|
|
class KMPLAYER_NO_EXPORT MouseVisitor : public Visitor {
|
|
|
|
Matrix matrix;
|
|
|
|
NodePtr node;
|
|
|
|
unsigned int event;
|
|
|
|
int x, y;
|
|
|
|
bool handled;
|
|
|
|
bool bubble_up;
|
|
|
|
public:
|
|
|
|
MouseVisitor (unsigned int evt, int x, int y);
|
|
|
|
KDE_NO_CDTOR_EXPORT ~MouseVisitor () {}
|
|
|
|
using Visitor::visit;
|
|
|
|
void visit (Node * n);
|
|
|
|
void visit (SMIL::Layout *);
|
|
|
|
void visit (SMIL::Region *);
|
|
|
|
void visit (SMIL::TimedMrl * n);
|
|
|
|
void visit (SMIL::MediaType * n);
|
|
|
|
void visit (SMIL::Anchor *);
|
|
|
|
void visit (SMIL::Area *);
|
|
|
|
TQCursor cursor;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
KDE_NO_CDTOR_EXPORT
|
|
|
|
MouseVisitor::MouseVisitor (unsigned int evt, int a, int b)
|
|
|
|
: event (evt), x (a), y (b), handled (false), bubble_up (false) {
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void MouseVisitor::visit (Node * n) {
|
|
|
|
kdDebug () << "Mouse event ignored for " << n->nodeName () << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Layout * layout) {
|
|
|
|
if (layout->surface ()) {
|
|
|
|
Matrix m = matrix;
|
|
|
|
SRect rect = layout->region_surface->bounds;
|
|
|
|
matrix = Matrix (rect.x(), rect.y(),
|
|
|
|
layout->region_surface->xscale, layout->region_surface->yscale);
|
|
|
|
matrix.transform (m);
|
|
|
|
|
|
|
|
NodePtr node_save = node;
|
|
|
|
node = layout;
|
|
|
|
for (NodePtr r = layout->firstChild (); r; r = r->nextSibling ()) {
|
|
|
|
if (r->id == SMIL::id_node_region)
|
|
|
|
r->accept (this);
|
|
|
|
if (!node->active ())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
node = node_save;
|
|
|
|
|
|
|
|
matrix = m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Region * region) {
|
|
|
|
if (region->surface ()) {
|
|
|
|
SRect rect = region->region_surface->bounds;
|
|
|
|
Single rx = rect.x(), ry = rect.y(), rw = rect.width(), rh = rect.height();
|
|
|
|
matrix.getXYWH (rx, ry, rw, rh);
|
|
|
|
handled = false;
|
|
|
|
bool inside = x > rx && x < rx+rw && y > ry && y< ry+rh;
|
|
|
|
if (!inside && (event == event_pointer_clicked || !region->has_mouse))
|
|
|
|
return;
|
|
|
|
Matrix m = matrix;
|
|
|
|
matrix = Matrix (rect.x(), rect.y(), 1.0, 1.0);
|
|
|
|
matrix.transform (m);
|
|
|
|
bubble_up = false;
|
|
|
|
|
|
|
|
bool child_handled = false;
|
|
|
|
if (inside)
|
|
|
|
for (NodePtr r = region->firstChild (); r; r = r->nextSibling ()) {
|
|
|
|
r->accept (this);
|
|
|
|
child_handled |= handled;
|
|
|
|
if (!node->active ())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
child_handled &= !bubble_up;
|
|
|
|
bubble_up = false;
|
|
|
|
|
|
|
|
int saved_event = event;
|
|
|
|
if (node->active ()) {
|
|
|
|
bool propagate_listeners = !child_handled;
|
|
|
|
if (event == event_pointer_moved) {
|
|
|
|
propagate_listeners = true; // always pass move events
|
|
|
|
if (region->has_mouse && (!inside || child_handled)) {
|
|
|
|
region->has_mouse = false;
|
|
|
|
event = event_outbounds;
|
|
|
|
} else if (inside && !child_handled && !region->has_mouse) {
|
|
|
|
region->has_mouse = true;
|
|
|
|
event = event_inbounds;
|
|
|
|
}
|
|
|
|
}// else // event_pointer_clicked
|
|
|
|
if (propagate_listeners) {
|
|
|
|
NodeRefListPtr nl = region->listeners (
|
|
|
|
event == event_pointer_moved ? mediatype_attached : event);
|
|
|
|
if (nl) {
|
|
|
|
for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) {
|
|
|
|
if (c->data)
|
|
|
|
c->data->accept (this);
|
|
|
|
if (!node->active ())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
event = saved_event;
|
|
|
|
handled = inside;
|
|
|
|
matrix = m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void followLink (SMIL::LinkingBase * link) {
|
|
|
|
kdDebug() << "link to " << link->href << " clicked" << endl;
|
|
|
|
NodePtr n = link;
|
|
|
|
if (link->href.startsWith ("#")) {
|
|
|
|
SMIL::Smil * s = SMIL::Smil::findSmilNode (link);
|
|
|
|
if (s)
|
|
|
|
s->jump (link->href.mid (1));
|
|
|
|
else
|
|
|
|
kdError() << "In document jumps smil not found" << endl;
|
|
|
|
} else
|
|
|
|
for (NodePtr p = link->parentNode (); p; p = p->parentNode ()) {
|
|
|
|
if (n->mrl () && n->mrl ()->opener == p) {
|
|
|
|
p->setState (Node::state_deferred);
|
|
|
|
p->mrl ()->setParam (StringPool::attr_src, link->href, 0L);
|
|
|
|
p->activate ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
n = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Anchor * anchor) {
|
|
|
|
if (event == event_pointer_moved)
|
|
|
|
cursor.setShape (TQt::PointingHandCursor);
|
|
|
|
else if (event == event_pointer_clicked)
|
|
|
|
followLink (anchor);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void MouseVisitor::visit (SMIL::Area * area) {
|
|
|
|
NodePtr n = area->parentNode ();
|
|
|
|
if (n->id >= SMIL::id_node_first_mediatype &&
|
|
|
|
n->id < SMIL::id_node_last_mediatype) {
|
|
|
|
SMIL::MediaType * mt = convertNode <SMIL::MediaType> (n);
|
|
|
|
Surface *s = mt->surface ();
|
|
|
|
if (s) {
|
|
|
|
SRect rect = s->bounds;
|
|
|
|
Single x1 = rect.x (), x2 = rect.y ();
|
|
|
|
Single w = rect.width (), h = rect.height ();
|
|
|
|
matrix.getXYWH (x1, x2, w, h);
|
|
|
|
if (area->nr_coords > 1) {
|
|
|
|
Single left = area->coords[0].size (rect.width ());
|
|
|
|
Single top = area->coords[1].size (rect.height ());
|
|
|
|
matrix.getXY (left, top);
|
|
|
|
if (x < left || x > left + w || y < top || y > top + h)
|
|
|
|
return;
|
|
|
|
if (area->nr_coords > 3) {
|
|
|
|
Single right = area->coords[2].size (rect.width ());
|
|
|
|
Single bottom = area->coords[3].size (rect.height ());
|
|
|
|
matrix.getXY (right, bottom);
|
|
|
|
if (x > right || y > bottom)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (event == event_pointer_moved)
|
|
|
|
cursor.setShape (TQt::PointingHandCursor);
|
|
|
|
else {
|
|
|
|
NodeRefListPtr nl = area->listeners (event);
|
|
|
|
if (nl)
|
|
|
|
for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) {
|
|
|
|
if (c->data)
|
|
|
|
c->data->accept (this);
|
|
|
|
if (!node->active ())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (event == event_pointer_clicked && !area->href.isEmpty ())
|
|
|
|
followLink (area);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void MouseVisitor::visit (SMIL::TimedMrl * timedmrl) {
|
|
|
|
timedmrl->runtime ()->processEvent (event);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void MouseVisitor::visit (SMIL::MediaType * mediatype) {
|
|
|
|
if (mediatype->sensitivity == SMIL::MediaType::sens_transparent) {
|
|
|
|
bubble_up = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Surface *s = mediatype->surface ();
|
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
if (s->node && s->node.ptr () != mediatype) {
|
|
|
|
s->node->accept (this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SRect rect = s->bounds;
|
|
|
|
Single rx = rect.x(), ry = rect.y(), rw = rect.width(), rh = rect.height();
|
|
|
|
matrix.getXYWH (rx, ry, rw, rh);
|
|
|
|
bool inside = x > rx && x < rx+rw && y > ry && y< ry+rh;
|
|
|
|
if (!inside && event == event_pointer_clicked)
|
|
|
|
return; // FIXME, also in/outbounds are bounds related
|
|
|
|
|
|
|
|
NodeRefListPtr nl = mediatype->listeners (
|
|
|
|
event == event_pointer_moved ? mediatype_attached : event);
|
|
|
|
if (nl)
|
|
|
|
for (NodeRefItemPtr c = nl->first(); c; c = c->nextSibling ()) {
|
|
|
|
if (c->data)
|
|
|
|
c->data->accept (this);
|
|
|
|
if (!node->active ())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (event != event_pointer_moved)
|
|
|
|
visit (static_cast <SMIL::TimedMrl *> (mediatype));
|
|
|
|
if (event != event_inbounds && event != event_outbounds) {
|
|
|
|
SMIL::RegionBase *r=convertNode<SMIL::RegionBase>(mediatype->region_node);
|
|
|
|
if (r && r->surface () &&
|
|
|
|
r->id != SMIL::id_node_smil &&
|
|
|
|
r->region_surface->node && r != r->region_surface->node.ptr ())
|
|
|
|
return r->region_surface->node->accept (this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
KDE_NO_CDTOR_EXPORT ViewArea::ViewArea (TQWidget * parent, View * view)
|
|
|
|
: TQWidget (parent, "kde_kmplayer_viewarea", WResizeNoErase | WRepaintNoErase),
|
|
|
|
m_parent (parent),
|
|
|
|
m_view (view),
|
|
|
|
m_collection (new TDEActionCollection (this)),
|
|
|
|
surface (new ViewSurface (this)),
|
|
|
|
m_mouse_invisible_timer (0),
|
|
|
|
m_repaint_timer (0),
|
|
|
|
m_fullscreen_scale (100),
|
|
|
|
scale_lbl_id (-1),
|
|
|
|
scale_slider_id (-1),
|
|
|
|
m_fullscreen (false),
|
|
|
|
m_minimal (false) {
|
|
|
|
setEraseColor (TQColor (0, 0, 0));
|
|
|
|
setAcceptDrops (true);
|
|
|
|
new TDEAction (i18n ("Fullscreen"), TDEShortcut (TQt::Key_F), TQT_TQOBJECT(this), TQT_SLOT (accelActivated ()), m_collection, "view_fullscreen_toggle");
|
|
|
|
setMouseTracking (true);
|
|
|
|
if (!image_data_map)
|
|
|
|
imageCacheDeleter.setObject (image_data_map, new ImageDataMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_CDTOR_EXPORT ViewArea::~ViewArea () {
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::fullScreen () {
|
|
|
|
TQT_TQOBJECT(this)->killTimers ();
|
|
|
|
m_mouse_invisible_timer = m_repaint_timer = 0;
|
|
|
|
if (m_fullscreen) {
|
|
|
|
showNormal ();
|
|
|
|
reparent (m_parent, 0, TQPoint (0, 0), true);
|
|
|
|
static_cast <KDockWidget *> (m_parent)->setWidget (this);
|
|
|
|
for (unsigned i = 0; i < m_collection->count (); ++i)
|
|
|
|
m_collection->action (i)->setEnabled (false);
|
|
|
|
if (scale_lbl_id != -1) {
|
|
|
|
m_view->controlPanel ()->popupMenu ()->removeItem (scale_lbl_id);
|
|
|
|
m_view->controlPanel ()->popupMenu ()->removeItem (scale_slider_id);
|
|
|
|
scale_lbl_id = scale_slider_id = -1;
|
|
|
|
}
|
|
|
|
m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (TQIconSet (TQPixmap (playlist_xpm)));
|
|
|
|
} else {
|
|
|
|
m_topwindow_rect = topLevelWidget ()->geometry ();
|
|
|
|
reparent (0L, 0, tqApp->desktop()->screenGeometry(this).topLeft(), true);
|
|
|
|
showFullScreen ();
|
|
|
|
for (unsigned i = 0; i < m_collection->count (); ++i)
|
|
|
|
m_collection->action (i)->setEnabled (true);
|
|
|
|
TQPopupMenu * menu = m_view->controlPanel ()->popupMenu ();
|
|
|
|
TQLabel * lbl = new TQLabel (i18n ("Scale:"), menu);
|
|
|
|
scale_lbl_id = menu->insertItem (lbl, -1, 4);
|
|
|
|
TQSlider * slider = new TQSlider (50, 150, 10, m_fullscreen_scale, TQt::Horizontal, menu);
|
|
|
|
connect (slider, TQT_SIGNAL (valueChanged (int)), this, TQT_SLOT (scale (int)));
|
|
|
|
scale_slider_id = menu->insertItem (slider, -1, 5);
|
|
|
|
m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (TQIconSet (TQPixmap (normal_window_xpm)));
|
|
|
|
}
|
|
|
|
m_fullscreen = !m_fullscreen;
|
|
|
|
m_view->controlPanel()->popupMenu ()->setItemChecked (ControlPanel::menu_fullscreen, m_fullscreen);
|
|
|
|
|
|
|
|
#ifdef HAVE_CAIRO
|
|
|
|
if (surface->surface) {
|
|
|
|
cairo_surface_destroy (surface->surface);
|
|
|
|
surface->surface = 0L;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (m_fullscreen) {
|
|
|
|
m_mouse_invisible_timer = startTimer(MOUSE_INVISIBLE_DELAY);
|
|
|
|
} else {
|
|
|
|
if (m_mouse_invisible_timer) {
|
|
|
|
killTimer (m_mouse_invisible_timer);
|
|
|
|
m_mouse_invisible_timer = 0;
|
|
|
|
}
|
|
|
|
unsetCursor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewArea::minimalMode () {
|
|
|
|
m_minimal = !m_minimal;
|
|
|
|
TQT_TQOBJECT(this)->killTimers ();
|
|
|
|
m_mouse_invisible_timer = m_repaint_timer = 0;
|
|
|
|
if (m_minimal) {
|
|
|
|
m_view->setViewOnly ();
|
|
|
|
m_view->setControlPanelMode (KMPlayer::View::CP_AutoHide);
|
|
|
|
m_view->setNoInfoMessages (true);
|
|
|
|
m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (TQIconSet (TQPixmap (normal_window_xpm)));
|
|
|
|
} else {
|
|
|
|
m_view->setControlPanelMode (KMPlayer::View::CP_Show);
|
|
|
|
m_view->setNoInfoMessages (false);
|
|
|
|
m_view->controlPanel ()->button (ControlPanel::button_playlist)->setIconSet (TQIconSet (TQPixmap (playlist_xpm)));
|
|
|
|
}
|
|
|
|
m_topwindow_rect = topLevelWidget ()->geometry ();
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::accelActivated () {
|
|
|
|
m_view->controlPanel()->popupMenu ()->activateItemAt (m_view->controlPanel()->popupMenu ()->indexOf (ControlPanel::menu_fullscreen));
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::mousePressEvent (TQMouseEvent * e) {
|
|
|
|
if (surface->node) {
|
|
|
|
MouseVisitor visitor (event_pointer_clicked, e->x(), e->y());
|
|
|
|
surface->node->accept (&visitor);
|
|
|
|
}
|
|
|
|
e->accept ();
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::mouseDoubleClickEvent (TQMouseEvent *) {
|
|
|
|
m_view->fullScreen (); // screensaver stuff
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::mouseMoveEvent (TQMouseEvent * e) {
|
|
|
|
if (e->state () == TQt::NoButton) {
|
|
|
|
int vert_buttons_pos = height () - m_view->statusBarHeight ();
|
|
|
|
int cp_height = m_view->controlPanel ()->maximumSize ().height ();
|
|
|
|
m_view->delayedShowButtons (e->y() > vert_buttons_pos-cp_height &&
|
|
|
|
e->y() < vert_buttons_pos);
|
|
|
|
}
|
|
|
|
if (surface->node) {
|
|
|
|
MouseVisitor visitor (event_pointer_moved, e->x(), e->y());
|
|
|
|
surface->node->accept (&visitor);
|
|
|
|
setCursor (visitor.cursor);
|
|
|
|
}
|
|
|
|
e->accept ();
|
|
|
|
mouseMoved (); // for m_mouse_invisible_timer
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::syncVisual (const IRect & rect) {
|
|
|
|
#ifdef HAVE_CAIRO
|
|
|
|
int ex = rect.x;
|
|
|
|
if (ex > 0)
|
|
|
|
ex--;
|
|
|
|
int ey = rect.y;
|
|
|
|
if (ey > 0)
|
|
|
|
ey--;
|
|
|
|
int ew = rect.w + 2;
|
|
|
|
int eh = rect.h + 2;
|
|
|
|
if (!surface->surface)
|
|
|
|
surface->surface = cairoCreateSurface (winId (), width (), height ());
|
|
|
|
if (surface->node && (!video_node ||
|
|
|
|
!convertNode <SMIL::MediaType> (video_node)->needsVideoWidget()))
|
|
|
|
setAudioVideoGeometry (IRect (), NULL);
|
|
|
|
CairoPaintVisitor visitor (surface->surface,
|
|
|
|
Matrix (surface->bounds.x(), surface->bounds.y(), 1.0, 1.0),
|
|
|
|
IRect (ex, ey, ew, eh), paletteBackgroundColor (), true);
|
|
|
|
if (surface->node)
|
|
|
|
surface->node->accept (&visitor);
|
|
|
|
#else
|
|
|
|
repaint (TQRect(rect.x, rect.y, rect.w, rect.h), false);
|
|
|
|
#endif
|
|
|
|
if (m_repaint_timer) {
|
|
|
|
killTimer (m_repaint_timer);
|
|
|
|
m_repaint_timer = 0;
|
|
|
|
}
|
|
|
|
//XFlush (tqt_xdisplay ());
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::paintEvent (TQPaintEvent * pe) {
|
|
|
|
#ifdef HAVE_CAIRO
|
|
|
|
if (surface->node)
|
|
|
|
scheduleRepaint (IRect (pe->rect ().x (), pe->rect ().y (), pe->rect ().width (), pe->rect ().height ()));
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
TQWidget::paintEvent (pe);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::scale (int val) {
|
|
|
|
m_fullscreen_scale = val;
|
|
|
|
resizeEvent (0L);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::updateSurfaceBounds () {
|
|
|
|
Single x, y, w = width (), h = height ();
|
|
|
|
h -= m_view->statusBarHeight ();
|
|
|
|
h -= m_view->controlPanel ()->isVisible ()
|
|
|
|
? (m_view->controlPanelMode () == View::CP_Only
|
|
|
|
? h
|
|
|
|
: (Single) m_view->controlPanel()->maximumSize ().height ())
|
|
|
|
: Single (0);
|
|
|
|
surface->resize (SRect (x, y, w, h));
|
|
|
|
Mrl *mrl = surface->node ? surface->node->mrl () : NULL;
|
|
|
|
if (m_view->keepSizeRatio () &&
|
|
|
|
w > 0 && h > 0 &&
|
|
|
|
mrl && mrl->width > 0 && mrl->height > 0) {
|
|
|
|
double wasp = (double) w / h;
|
|
|
|
double masp = (double) mrl->width / mrl->height;
|
|
|
|
if (wasp > masp) {
|
|
|
|
Single tmp = w;
|
|
|
|
w = masp * h;
|
|
|
|
x += (tmp - w) / 2;
|
|
|
|
} else {
|
|
|
|
Single tmp = h;
|
|
|
|
h = Single (w / masp);
|
|
|
|
y += (tmp - h) / 2;
|
|
|
|
}
|
|
|
|
surface->xscale = 1.0 * w / mrl->width;
|
|
|
|
surface->yscale = 1.0 * h / mrl->height;
|
|
|
|
} else {
|
|
|
|
surface->xscale = 1.0;
|
|
|
|
surface->yscale = 1.0;
|
|
|
|
}
|
|
|
|
surface->bounds = SRect (x, y, w, h);
|
|
|
|
scheduleRepaint (IRect (0, 0, width (), height ()));
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::resizeEvent (TQResizeEvent *) {
|
|
|
|
if (!m_view->controlPanel ()) return;
|
|
|
|
Single x, y, w = width (), h = height ();
|
|
|
|
Single hsb = m_view->statusBarHeight ();
|
|
|
|
Single hcp = m_view->controlPanel ()->isVisible ()
|
|
|
|
? (m_view->controlPanelMode () == View::CP_Only
|
|
|
|
? h-hsb
|
|
|
|
: (Single) m_view->controlPanel()->maximumSize ().height ())
|
|
|
|
: Single (0);
|
|
|
|
Single wws = w;
|
|
|
|
// move controlpanel over video when autohiding and playing
|
|
|
|
Single hws = h - (m_view->controlPanelMode () == View::CP_AutoHide &&
|
|
|
|
m_view->widgetStack ()->visibleWidget () == m_view->viewer ()
|
|
|
|
? Single (0)
|
|
|
|
: hcp) - hsb;
|
|
|
|
// now scale the regions and check if video region is already sized
|
|
|
|
if (surface->node) {
|
|
|
|
NodePtr n = surface->node;
|
|
|
|
surface = new ViewSurface (this);
|
|
|
|
surface->node = n;
|
|
|
|
}
|
|
|
|
updateSurfaceBounds ();
|
|
|
|
|
|
|
|
// finally resize controlpanel and video widget
|
|
|
|
if (m_view->controlPanel ()->isVisible ())
|
|
|
|
m_view->controlPanel ()->setGeometry (0, h-hcp-hsb, w, hcp);
|
|
|
|
if (m_view->statusBar ()->isVisible ())
|
|
|
|
m_view->statusBar ()->setGeometry (0, h-hsb, w, hsb);
|
|
|
|
if (m_fullscreen && wws == w && hws == h) {
|
|
|
|
wws = wws * m_fullscreen_scale / 100;
|
|
|
|
hws = hws * m_fullscreen_scale / 100;
|
|
|
|
x += (w - wws) / 2;
|
|
|
|
y += (h - hws) / 2;
|
|
|
|
}
|
|
|
|
if (!surface->node)
|
|
|
|
setAudioVideoGeometry (IRect (x, y, wws, hws), 0L);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT
|
|
|
|
void ViewArea::setAudioVideoGeometry (const IRect &rect, unsigned int * bg_color) {
|
|
|
|
int x = rect.x, y = rect.y, w = rect.w, h = rect.h;
|
|
|
|
if (m_view->controlPanelMode() == View::CP_Only) {
|
|
|
|
w = h = 0;
|
|
|
|
} else if (!surface->node && m_view->keepSizeRatio ()) { // scale video widget inside region
|
|
|
|
int hfw = m_view->viewer ()->heightForWidth (w);
|
|
|
|
if (hfw > 0)
|
|
|
|
if (hfw > h) {
|
|
|
|
int old_w = w;
|
|
|
|
w = int ((1.0 * h * w)/(1.0 * hfw));
|
|
|
|
x += (old_w - w) / 2;
|
|
|
|
} else {
|
|
|
|
y += (h - hfw) / 2;
|
|
|
|
h = hfw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_av_geometry = TQRect (x, y, w, h);
|
|
|
|
TQRect wrect = m_view->widgetStack ()->geometry ();
|
|
|
|
if (m_av_geometry != wrect &&
|
|
|
|
!(m_av_geometry.width() <= 0 &&
|
|
|
|
wrect.width() <= 1 && wrect.height() <= 1)) {
|
|
|
|
m_view->widgetStack ()->setGeometry (x, y, w, h);
|
|
|
|
wrect.unite (m_av_geometry);
|
|
|
|
scheduleRepaint (IRect (wrect.x (), wrect.y (), wrect.width (), wrect.height ()));
|
|
|
|
}
|
|
|
|
if (bg_color)
|
|
|
|
if (TQColor (TQRgb (*bg_color)) != (m_view->viewer ()->paletteBackgroundColor ())) {
|
|
|
|
m_view->viewer()->setCurrentBackgroundColor (TQColor (TQRgb (*bg_color)));
|
|
|
|
scheduleRepaint (IRect (x, y, w, h));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::setAudioVideoNode (NodePtr n) {
|
|
|
|
video_node = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT SurfacePtr ViewArea::getSurface (NodePtr node) {
|
|
|
|
static_cast <ViewSurface *> (surface.ptr ())->clear ();
|
|
|
|
surface->node = node;
|
|
|
|
m_view->viewer()->resetBackgroundColor ();
|
|
|
|
if (node) {
|
|
|
|
updateSurfaceBounds ();
|
|
|
|
return surface;
|
|
|
|
}
|
|
|
|
scheduleRepaint (IRect (0, 0, width (), height ()));
|
|
|
|
return 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::showEvent (TQShowEvent *) {
|
|
|
|
resizeEvent (0L);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::dropEvent (TQDropEvent * de) {
|
|
|
|
m_view->dropEvent (de);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::dragEnterEvent (TQDragEnterEvent* dee) {
|
|
|
|
m_view->dragEnterEvent (dee);
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::contextMenuEvent (TQContextMenuEvent * e) {
|
|
|
|
m_view->controlPanel ()->popupMenu ()->exec (e->globalPos ());
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::mouseMoved () {
|
|
|
|
if (m_fullscreen) {
|
|
|
|
if (m_mouse_invisible_timer)
|
|
|
|
killTimer (m_mouse_invisible_timer);
|
|
|
|
unsetCursor ();
|
|
|
|
m_mouse_invisible_timer = startTimer (MOUSE_INVISIBLE_DELAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::scheduleRepaint (const IRect &rect) {
|
|
|
|
if (m_repaint_timer) {
|
|
|
|
m_repaint_rect = m_repaint_rect.unite (rect);
|
|
|
|
} else {
|
|
|
|
m_repaint_rect = rect;
|
|
|
|
m_repaint_timer = startTimer (10); // 100 per sec should do
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::timerEvent (TQTimerEvent * e) {
|
|
|
|
if (e->timerId () == m_mouse_invisible_timer) {
|
|
|
|
killTimer (m_mouse_invisible_timer);
|
|
|
|
m_mouse_invisible_timer = 0;
|
|
|
|
if (m_fullscreen)
|
|
|
|
setCursor (BlankCursor);
|
|
|
|
} else if (e->timerId () == m_repaint_timer) {
|
|
|
|
killTimer (m_repaint_timer);
|
|
|
|
m_repaint_timer = 0;
|
|
|
|
//repaint (m_repaint_rect, false);
|
|
|
|
syncVisual (m_repaint_rect.intersect (IRect (0, 0, width (), height ())));
|
|
|
|
} else {
|
|
|
|
kdError () << "unknown timer " << e->timerId () << " " << m_repaint_timer << endl;
|
|
|
|
killTimer (e->timerId ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_NO_EXPORT void ViewArea::closeEvent (TQCloseEvent * e) {
|
|
|
|
//kdDebug () << "closeEvent" << endl;
|
|
|
|
if (m_fullscreen) {
|
|
|
|
fullScreen ();
|
|
|
|
if (!m_parent->topLevelWidget ()->isVisible ())
|
|
|
|
m_parent->topLevelWidget ()->show ();
|
|
|
|
e->ignore ();
|
|
|
|
} else
|
|
|
|
TQWidget::closeEvent (e);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "viewarea.moc"
|