summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMavridis Philippe <mavridisf@gmail.com>2022-03-09 13:30:28 +0200
committerMavridis Philippe <mavridisf@gmail.com>2022-03-09 13:32:50 +0200
commit85cac902ac5ac768289546206827ee4368866c6d (patch)
treed54bded16b585e867762cb5aa5c6a384e20d2283
parentdbd8fb94cc95ecf5999a120e038916fb433d2fbf (diff)
downloadtdelibs-85cac902ac5ac768289546206827ee4368866c6d.tar.gz
tdelibs-85cac902ac5ac768289546206827ee4368866c6d.zip
TDEHTML: SVG rendering support for <img> tag.
Signed-off-by: Mavridis Philippe <mavridisf@gmail.com>
-rw-r--r--tdehtml/misc/CMakeLists.txt2
-rw-r--r--tdehtml/misc/loader.cpp107
-rw-r--r--tdehtml/misc/loader.h14
-rw-r--r--tdehtml/misc/svgrender.cpp74
-rw-r--r--tdehtml/misc/svgrender.h33
-rw-r--r--tdehtml/rendering/render_image.cpp46
6 files changed, 247 insertions, 29 deletions
diff --git a/tdehtml/misc/CMakeLists.txt b/tdehtml/misc/CMakeLists.txt
index 0babd6567..934953297 100644
--- a/tdehtml/misc/CMakeLists.txt
+++ b/tdehtml/misc/CMakeLists.txt
@@ -33,7 +33,7 @@ set( target tdehtmlmisc )
set( ${target}_SRCS
decoder.cpp loader.cpp loader_jpeg.cpp guess_ja.cpp
htmlhashes.cpp helper.cpp arena.cpp stringit.cpp
- knsplugininstaller.cpp
+ knsplugininstaller.cpp svgrender.cpp
)
tde_add_library( ${target} STATIC_PIC AUTOMOC
diff --git a/tdehtml/misc/loader.cpp b/tdehtml/misc/loader.cpp
index 7621b5e4f..c6fd83bf1 100644
--- a/tdehtml/misc/loader.cpp
+++ b/tdehtml/misc/loader.cpp
@@ -74,6 +74,8 @@
#include <tdetempfile.h>
#endif
+#include "svgrender.h"
+
#include "html/html_documentimpl.h"
#include "css/css_stylesheetimpl.h"
#include "xml/dom_docimpl.h"
@@ -461,7 +463,7 @@ private:
static TQString buildAcceptHeader()
{
- return "image/png, image/jpeg, video/x-mng, image/jp2, image/gif;q=0.5,*/*;q=0.1";
+ return "image/png, image/jpeg, image/svg+xml, video/x-mng, image/jp2, image/gif;q=0.5,*/*;q=0.1";
}
// -------------------------------------------------------------------------------------
@@ -490,6 +492,18 @@ CachedImage::CachedImage(DocLoader* dl, const DOMString &url, TDEIO::CacheContro
m_wasBlocked = true;
CachedObject::finish();
}
+
+ /* SVG support */
+ isSVGZ = url.string().lower().endsWith(".svgz"); // used for setting correct temp file extension
+ isSVG = url.string().lower().endsWith(".svg") || isSVGZ;
+ svgData = TQByteArray();
+ svgRender = new TQPixmap();
+#ifndef HAVE_LIBART
+ if(isSVG)
+ {
+ kdDebug(6060) << url.string() << " is a SVG(Z) file but tdelibs was compiled without LIBART support" << endl;
+ }
+#endif
}
CachedImage::~CachedImage()
@@ -654,6 +668,12 @@ const TQPixmap &CachedImage::pixmap( ) const
else
return m->framePixmap();
}
+
+ else if(isSVG)
+ {
+ return *svgRender;
+ }
+
else if(p)
return *p;
@@ -663,15 +683,56 @@ const TQPixmap &CachedImage::pixmap( ) const
TQSize CachedImage::pixmap_size() const
{
- if (m_wasBlocked) return Cache::blockedPixmap->size();
- return (m_hadError ? Cache::brokenPixmap->size() : m ? m->framePixmap().size() : ( p ? p->size() : TQSize()));
+ if(m_wasBlocked)
+ {
+ return Cache::blockedPixmap->size();
+ }
+ else if(m_hadError)
+ {
+ return Cache::brokenPixmap->size();
+ }
+ else if(isSVG)
+ {
+ return svgRender->size();
+ }
+ else if(m)
+ {
+ return m->framePixmap().size();
+ }
+ else if(p)
+ {
+ return p->size();
+ }
+ else
+ {
+ return TQSize();
+ }
}
TQRect CachedImage::valid_rect() const
{
- if (m_wasBlocked) return Cache::blockedPixmap->rect();
- return (m_hadError ? Cache::brokenPixmap->rect() : m ? TQRect(m->getValidRect()) : ( p ? TQRect(p->rect()) : TQRect()) );
+ if (m_wasBlocked)
+ {
+ return Cache::blockedPixmap->rect();
+ }
+ else if (m_hadError)
+ {
+ return Cache::brokenPixmap->rect();
+ }
+ else if(isSVG)
+ {
+ return TQRect(svgRender->rect());
+ }
+ else if(m)
+ {
+ return TQRect(m->getValidRect());
+ }
+ else if(p)
+ {
+ return TQRect(p->rect());
+ }
+ return TQRect();
}
@@ -681,7 +742,6 @@ void CachedImage::do_notify(const TQPixmap& p, const TQRect& r)
it()->setPixmap( p, r, this);
}
-
void CachedImage::movieUpdated( const TQRect& r )
{
#ifdef LOADER_DEBUG
@@ -820,6 +880,11 @@ void CachedImage::clear()
bgSize = TQSize(-1,-1);
delete pixPart; pixPart = 0;
+ isSVG = false;
+ isSVGZ = false;
+ svgData = TQByteArray();
+ svgRender = 0;
+
formatType = 0;
typeChecked = false;
setSize(0);
@@ -833,6 +898,32 @@ void CachedImage::data ( TQBuffer &_buffer, bool eof )
#ifdef LOADER_DEBUG
kdDebug( 6060 ) << this << "in CachedImage::data(buffersize " << _buffer.buffer().size() <<", eof=" << eof << endl;
#endif
+
+ if( isSVG && eof )
+ {
+ /* Store SVG data for later use */
+ svgData = _buffer.buffer();
+
+#ifdef HAVE_LIBART
+ /* Render and store SVG as pixmap */
+ TQImage i = renderSVG(svgData, svgExtension());
+ if(i.isNull())
+ {
+ m_hadError = true;
+ return;
+ }
+
+ if(!svgRender->convertFromImage(i))
+ {
+ kdDebug(6060) << "Could not convert TQImage of rendered SVG to TQPixmap!" << endl;
+ m_hadError = true;
+ }
+#else
+ m_hadError = true;
+#endif
+ return;
+ }
+
if ( !typeChecked )
{
// don't attempt incremental loading if we have all the data already
@@ -905,8 +996,8 @@ void CachedImage::finish()
Status oldStatus = m_status;
CachedObject::finish();
if ( oldStatus != m_status ) {
- const TQPixmap &pm = pixmap();
- do_notify( pm, pm.rect() );
+ const TQPixmap &pm = pixmap();
+ do_notify( pm, pm.rect() );
}
TQSize s = pixmap_size();
setSize( s.width() * s.height() * 2);
diff --git a/tdehtml/misc/loader.h b/tdehtml/misc/loader.h
index c60c13a98..087b28ffd 100644
--- a/tdehtml/misc/loader.h
+++ b/tdehtml/misc/loader.h
@@ -277,8 +277,11 @@ namespace tdehtml
bool isTransparent() const { return isFullyTransparent; }
bool isErrorImage() const { return m_hadError; }
bool isBlockedImage() const { return m_wasBlocked; }
+ bool isVectorImage() const { return isSVG; }
const TQString& suggestedFilename() const { return m_suggestedFilename; }
void setSuggestedFilename( const TQString& s ) { m_suggestedFilename = s; }
+ TQByteArray svg() const { return svgData; }
+ const TQString svgExtension() const { return (isSVGZ ? "svgz" : (isSVG ? "svg" : TQString::null)); }
#ifdef IMAGE_TITLES
const TQString& suggestedTitle() const { return m_suggestedTitle; }
void setSuggestedTitle( const TQString& s ) { m_suggestedTitle = s; }
@@ -313,10 +316,15 @@ namespace tdehtml
#ifdef IMAGE_TITLES
TQString m_suggestedTitle;
#endif
- TQMovie* m;
+ TQMovie* m;
TQPixmap* p;
- TQPixmap* scaled;
- TQPixmap* bg;
+ TQPixmap* scaled;
+ TQPixmap* bg;
+
+ bool isSVG, isSVGZ;
+ TQByteArray svgData;
+ TQPixmap *svgRender;
+
QRgb bgColor;
TQSize bgSize;
mutable TQPixmap* pixPart;
diff --git a/tdehtml/misc/svgrender.cpp b/tdehtml/misc/svgrender.cpp
new file mode 100644
index 000000000..94766cdcf
--- /dev/null
+++ b/tdehtml/misc/svgrender.cpp
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the Trinity libraries.
+ *
+ * Copyright (C) 2022 Mavridis Philippe <mavridisf@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "svgrender.h"
+
+#include <kdebug.h>
+
+#ifdef HAVE_LIBART
+#include <ksvgiconengine.h>
+#include <kstandarddirs.h>
+#include <tdetempfile.h>
+#endif
+
+
+TQImage renderSVG(TQByteArray ba, TQString svgExtension, int width, int height)
+{
+ if( svgExtension != TQString("svg") && svgExtension != TQString("svgz") )
+ {
+ return TQImage();
+ }
+
+#ifdef HAVE_LIBART
+ /* Write svg data to a temporary file so that we can process it with KSVGIconEngine */
+ KTempFile tf(locateLocal("tmp", "tdehtml"), TQString(".%1").arg(svgExtension));
+ if( tf.status() != 0 )
+ {
+ kdDebug(6060) << "[renderSVG] Cannot access temp file: " << tf.name() << endl;
+ return TQImage();
+ }
+ tf.dataStream()->writeRawBytes(ba, ba.size());
+ tf.sync();
+
+ /* Render the image */
+ TQImage *render = new TQImage();
+ KSVGIconEngine *svgEngine = new KSVGIconEngine();
+ if(svgEngine->load(width, height, tf.name()) )
+ {
+ render = svgEngine->image();
+ }
+ else
+ {
+ kdDebug(6060) << "[renderSVG] KSVGIconEngine could not load " << tf.name() << endl;
+ return TQImage();
+ }
+
+ /* Clean up */
+ tf.unlink();
+ delete svgEngine;
+
+ return *render;
+#else
+ kdDebug(6060) << "[renderSVG] tdelibs were built without libart support." << endl;
+ return TQImage();
+#endif
+} \ No newline at end of file
diff --git a/tdehtml/misc/svgrender.h b/tdehtml/misc/svgrender.h
new file mode 100644
index 000000000..93a9cd46d
--- /dev/null
+++ b/tdehtml/misc/svgrender.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the Trinity libraries.
+ *
+ * Copyright (C) 2022 Mavridis Philippe <mavridisf@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _tdehtml_svgrender_h
+#define _tdehtml_svgrender_h
+
+#include <tqcstring.h> // tqbytearray
+#include <tqimage.h>
+
+#include "config.h" // HAVE_LIBART
+
+TQImage renderSVG(TQByteArray ba, TQString svgExtension, int width = 0, int height = 0);
+
+#endif \ No newline at end of file
diff --git a/tdehtml/rendering/render_image.cpp b/tdehtml/rendering/render_image.cpp
index ad8f18bb3..18bc62aed 100644
--- a/tdehtml/rendering/render_image.cpp
+++ b/tdehtml/rendering/render_image.cpp
@@ -38,6 +38,7 @@
#include "misc/helper.h"
#include "misc/htmlattrs.h"
#include "misc/loader.h"
+#include "misc/svgrender.h"
#include "misc/htmltags.h"
#include "html/html_formimpl.h"
#include "html/html_imageimpl.h"
@@ -240,7 +241,7 @@ void RenderImage::paint(PaintInfo& paintInfo, int _tx, int _ty)
? m_oldImage : m_cachedImage;
// paint frame around image as long as it is not completely loaded from web.
- if (bUnfinishedImageFrame && paintInfo.phase == PaintActionForeground && cWidth > 2 && cHeight > 2 && !complete()) {
+ if (bUnfinishedImageFrame && paintInfo.phase == PaintActionForeground && cWidth > 2 && cHeight > 2 && !complete() && !i->isVectorImage()) {
static TQPixmap *loadingIcon;
TQColor bg = tdehtml::retrieveBackgroundColor(this);
TQColor fg = tdehtml::hasSufficientContrast(Qt::gray, bg) ? Qt::gray :
@@ -297,31 +298,42 @@ void RenderImage::paint(PaintInfo& paintInfo, int _tx, int _ty)
if (resizeCache.isNull() && cWidth && cHeight && intrinsicWidth() && intrinsicHeight())
{
TQRect scaledrect(i->valid_rect());
+ scaledrect.setWidth( ( cWidth*scaledrect.width() ) / intrinsicWidth() );
+ scaledrect.setHeight( ( cHeight*scaledrect.height() ) / intrinsicHeight() );
// kdDebug(6040) << "time elapsed: " << dt->elapsed() << endl;
// kdDebug( 6040 ) << "have to scale: " << endl;
// tqDebug("cw=%d ch=%d pw=%d ph=%d rcw=%d, rch=%d",
// cWidth, cHeight, intrinsicWidth(), intrinsicHeight(), resizeCache.width(), resizeCache.height());
- TQWMatrix matrix;
- matrix.scale( (float)(cWidth)/intrinsicWidth(),
- (float)(cHeight)/intrinsicHeight() );
- resizeCache = pix.xForm( matrix );
- scaledrect.setWidth( ( cWidth*scaledrect.width() ) / intrinsicWidth() );
- scaledrect.setHeight( ( cHeight*scaledrect.height() ) / intrinsicHeight() );
+ if(i->isVectorImage())
+ {
+ TQImage newRender = renderSVG(i->svg(), i->svgExtension(), cWidth, cHeight);
+ if(!resizeCache.convertFromImage(newRender))
+ {
+ kdDebug(6040) << "Could not convert TQImage of rendered SVG to TQPixmap!" << endl;
+ }
+ }
+ else
+ {
+ TQWMatrix matrix;
+ matrix.scale( (float)(cWidth)/intrinsicWidth(),
+ (float)(cHeight)/intrinsicHeight() );
+ resizeCache = pix.xForm( matrix );
// tqDebug("resizeCache size: %d/%d", resizeCache.width(), resizeCache.height());
// tqDebug("valid: %d/%d, scaled: %d/%d",
// i->valid_rect().width(), i->valid_rect().height(),
// scaledrect.width(), scaledrect.height());
- // sometimes scaledrect.width/height are off by one because
- // of rounding errors. if the i is fully loaded, we
- // make sure that we don't do unnecessary resizes during painting
- TQSize s(scaledrect.size());
- if(i->valid_rect().size() == TQSize( intrinsicWidth(), intrinsicHeight() )) // fully loaded
- s = TQSize(cWidth, cHeight);
- if(kAbs(s.width() - cWidth) < 2) // rounding errors
- s.setWidth(cWidth);
- if(resizeCache.size() != s)
- resizeCache.resize(s);
+ // sometimes scaledrect.width/height are off by one because
+ // of rounding errors. if the i is fully loaded, we
+ // make sure that we don't do unnecessary resizes during painting
+ TQSize s(scaledrect.size());
+ if(i->valid_rect().size() == TQSize( intrinsicWidth(), intrinsicHeight() )) // fully loaded
+ s = TQSize(cWidth, cHeight);
+ if(kAbs(s.width() - cWidth) < 2) // rounding errors
+ s.setWidth(cWidth);
+ if(resizeCache.size() != s)
+ resizeCache.resize(s);
+ }
paintInfo.p->drawPixmap( TQPoint( _tx + leftBorder + leftPad, _ty + topBorder + topPad),
resizeCache, scaledrect );