TDEHTML: SVG rendering support for <img> tag.

Signed-off-by: Mavridis Philippe <mavridisf@gmail.com>
feat/tdehtml+svg
Mavridis Philippe 3 years ago
parent dbd8fb94cc
commit 85cac902ac
No known key found for this signature in database
GPG Key ID: F8D2D7E2F989A494

@ -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

@ -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);

@ -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;

@ -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
}

@ -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

@ -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 );

Loading…
Cancel
Save