phantomjs/deploy/qt48_headless_and_pdf_fixes...

2453 lines
84 KiB
Diff

diff --git a/src/3rdparty/webkit/Source/WebKit.pri b/src/3rdparty/webkit/Source/WebKit.pri
index 5bd9577..ceeff95 100644
--- a/src/3rdparty/webkit/Source/WebKit.pri
+++ b/src/3rdparty/webkit/Source/WebKit.pri
@@ -93,7 +93,6 @@ CONFIG -= warn_on
# Treat warnings as errors on x86/Linux/GCC
linux-g++* {
- isEqual(QT_ARCH,x86_64)|isEqual(QT_ARCH,i386): QMAKE_CXXFLAGS += -Werror
greaterThan(QT_GCC_MAJOR_VERSION, 3):greaterThan(QT_GCC_MINOR_VERSION, 5) {
if (!contains(QMAKE_CXXFLAGS, -std=c++0x) && !contains(QMAKE_CXXFLAGS, -std=gnu++0x)) {
diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h
index 6befdd8..c175b73 100644
--- a/src/gui/painting/qpaintengine.h
+++ b/src/gui/painting/qpaintengine.h
@@ -46,6 +46,7 @@
#include <QtCore/qobjectdefs.h>
#include <QtCore/qscopedpointer.h>
#include <QtGui/qpainter.h>
+#include <QtCore/qurl.h>
QT_BEGIN_HEADER
@@ -162,6 +163,19 @@ public:
virtual void drawRects(const QRect *rects, int rectCount);
virtual void drawRects(const QRectF *rects, int rectCount);
+ virtual void addHyperlink(const QRectF &r, const QUrl &url) {Q_UNUSED(r); Q_UNUSED(url);}
+ virtual void addAnchor(const QRectF &r, const QString &name) {Q_UNUSED(r); Q_UNUSED(name);}
+ virtual void addLink(const QRectF &r, const QString &anchor) {Q_UNUSED(r); Q_UNUSED(anchor);}
+ virtual void addTextField(const QRectF &r, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength) {
+ Q_UNUSED(r); Q_UNUSED(text); Q_UNUSED(name); Q_UNUSED(multiLine); Q_UNUSED(password); Q_UNUSED(readOnly); Q_UNUSED(maxLength);
+ }
+ virtual void addCheckBox(const QRectF &r, bool checked, const QString &name, bool readOnly) {
+ Q_UNUSED(r); Q_UNUSED(checked); Q_UNUSED(name); Q_UNUSED(readOnly);
+ }
+ virtual void addRadioButton(const QRectF &r, const QString & group="", bool checked=false, const QString &name="", bool readOnly=false) {
+ Q_UNUSED(r); Q_UNUSED(checked); Q_UNUSED(name); Q_UNUSED(readOnly); Q_UNUSED(group);
+ }
+
virtual void drawLines(const QLine *lines, int lineCount);
virtual void drawLines(const QLineF *lines, int lineCount);
@@ -177,6 +191,11 @@ public:
virtual void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode);
virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) = 0;
+ virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr, const QByteArray * data) {
+ Q_UNUSED(data);
+ drawPixmap(r,pm,sr);
+ }
+
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index bcc5f9d..c50640b 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -2248,11 +2248,11 @@ namespace {
/*!
\reimp
*/
-void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
+void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &_img, const QRectF &_sr,
Qt::ImageConversionFlags)
{
#ifdef QT_DEBUG_DRAW
- qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
+ qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << _sr << " image=" << _img.size() << "depth=" << img.depth();
#endif
if (r.isEmpty())
@@ -2260,6 +2260,17 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
+
+ QImage img;
+ QRectF sr=_sr;
+ if (s->matrix.isAffine()) {
+ img = _img.copy(sr.toRect()).scaled(
+ s->matrix.mapRect(r).size().toSize(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ sr = img.rect();
+ } else {
+ img=_img;
+ }
+
int sr_l = qFloor(sr.left());
int sr_r = qCeil(sr.right()) - 1;
int sr_t = qFloor(sr.top());
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index efb016e..4952b4b 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -5393,7 +5393,7 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
}
}
-void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
+void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr, const QByteArray * data)
{
#if defined QT_DEBUG_DRAW
if (qt_show_painter_debug_output)
@@ -5518,7 +5518,7 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
x += d->state->matrix.dx();
y += d->state->matrix.dy();
}
- d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
+ d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh), data);
}
}
@@ -7254,6 +7254,200 @@ void QPainter::fillRect(const QRectF &r, const QColor &color)
\since 4.5
*/
+
+/*!
+ \fn void QPainter::addAnchor(int x, int y, int w, int h, const QString &name);
+
+ \overload
+
+ Add an anchor to the current page at the rect specified by \a x, \a y, \a w and \a h
+ named \a name.
+
+ Note that for output formats not supporting links, currently all other then PDF,
+ this call has no effect.
+
+ \sa addLink()
+
+ \since 4.7
+*/
+
+/*!
+ \fn void QPainter::addAnchor(const QRect &r, const QString &name);
+
+ \overload
+
+ Add an anchor to the current page at the rect specified by \a r named \a name.
+
+ Note that for output formats not supporting links, currently all other then PDF,
+ this call has no effect.
+
+ \sa addLink()
+
+ \since 4.7
+*/
+
+/*!
+ \fn void addAnchor(const QRectF &r, const QString &name);
+
+ \overload
+
+ Add an anchor to the current page at the rect specified by \a r named \a name.
+
+ Note that for output formats not supporting links, currently all other then PDF,
+ this call has no effect.
+
+ \sa addLink()
+
+ \since 4.7
+*/
+void QPainter::addAnchor(const QRectF &r, const QString &name)
+{
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::addAnchor: Painter not active");
+ return;
+ }
+ d->engine->addAnchor(worldTransform().mapRect(r), name);
+}
+
+/*!
+ \fn void QPainter::addLink(int x, int y, int w, int h, const QString &anchor);
+
+ \overload
+
+ Add a link to the current page at the rect specified by \a x, \a y, \a w and \a h
+ linking to the anchor named \a anchor.
+
+ Note that for output formats not supporting links, currently all other then PDF,
+ this call has no effect.
+
+ \sa addAnchor()
+
+ \since 4.7
+*/
+
+/*!
+ \fn void QPainter::addLink(const QRect &r, const QString &anchor);
+
+ \overload
+
+ Add a link to the current page at the rect specified by \a r
+ linking to the anchor named \a anchor.
+
+ Note that for output formats not supporting links, currently all other then PDF,
+ this call has no effect.
+
+ \sa addAnchor()
+
+ \since 4.7
+*/
+
+/*!
+ \fn void QPainter::addLink(const QRectF &r, const QString &anchor);
+
+ \overload
+
+ Add a link to the current page at the rect specified by \a r
+ linking to the anchor named \a anchor.
+
+ Note that for output formats not supporting links, currently all other then PDF,
+ this call has no effect.
+
+ \sa addAnchor()
+
+ \since 4.7
+*/
+void QPainter::addLink(const QRectF &r, const QString &anchor)
+{
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::addLink: Painter not active");
+ return;
+ }
+
+ d->engine->addLink(worldTransform().mapRect(r), anchor);
+}
+
+
+/*!
+ \fn void QPainter::addHyperlink(int x, int y, int w, int h, const QUrl &url);
+
+ \overload
+
+ Add a link to the current page at the rect specified by \a x, \a y, \a w and \a h
+ linking to \a url.
+
+ Note that for output formats not supporting links, currently all other then PDF,
+ this call has no effect.
+
+ \since 4.7
+*/
+
+/*!
+ \fn void QPainter::addHyperlink(const QRect &r, const QUrl &url);
+
+ \overload
+
+ Add a link to the current page at the rect specified by \a r
+ linking to \a url.
+
+ Note that for output formats not supporting links, currently all other then PDF,
+ this call has no effect.
+
+ \since 4.7
+*/
+
+/*!
+ \fn void QPainter::addHyperlink(const QRectF &r, const QUrl &url);
+
+ \overload
+
+ Add a link to the current page at the rect specified by \a r
+ linking to \a url.
+
+ Note that for output formats not supporting links, currently all other then PDF,
+ this call has no effect.
+
+ \since 4.7
+*/
+void QPainter::addHyperlink(const QRectF &r, const QUrl &url)
+{
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::addHyperlink: Painter not active");
+ return;
+ }
+ d->engine->addHyperlink(worldTransform().mapRect(r), url);
+}
+
+void QPainter::addTextField(const QRectF &r, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength) {
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::addTextField: Painter not active");
+ return;
+ }
+ d->engine->addTextField(worldTransform().mapRect(r), text, name, multiLine, password, readOnly, maxLength);
+}
+
+void QPainter::addCheckBox(const QRectF &r, bool checked, const QString &name, bool readOnly) {
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::addCheckBox: Painter not active");
+ return;
+ }
+ d->engine->addCheckBox(worldTransform().mapRect(r), checked, name, readOnly);
+}
+
+
+void QPainter::addRadioButton(const QRectF &r, const QString & group, bool checked, const QString &name, bool readOnly) {
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::addRadioButton: Painter not active");
+ return;
+ }
+ d->engine->addRadioButton(worldTransform().mapRect(r), group, checked, name, readOnly);
+}
+
/*!
Sets the given render \a hint on the painter if \a on is true;
otherwise clears the render hint.
diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h
index 12a14a2..9a8845d 100644
--- a/src/gui/painting/qpainter.h
+++ b/src/gui/painting/qpainter.h
@@ -364,7 +364,7 @@ public:
inline void drawPicture(const QPoint &p, const QPicture &picture);
#endif
- void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect);
+ void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect, const QByteArray * data=0);
inline void drawPixmap(const QRect &targetRect, const QPixmap &pixmap, const QRect &sourceRect);
inline void drawPixmap(int x, int y, int w, int h, const QPixmap &pm,
int sx, int sy, int sw, int sh);
@@ -447,6 +447,22 @@ public:
inline void fillRect(const QRect &r, Qt::BrushStyle style);
inline void fillRect(const QRectF &r, Qt::BrushStyle style);
+ inline void addAnchor(int x, int y, int w, int h, const QString &name);
+ inline void addAnchor(const QRect &r, const QString &name);
+ void addAnchor(const QRectF &r, const QString &name);
+
+ inline void addLink(int x, int y, int w, int h, const QString &anchor);
+ inline void addLink(const QRect &r, const QString &anchor);
+ void addLink(const QRectF &r, const QString &anchor);
+
+ void addTextField(const QRectF &r, const QString &text=QString(), const QString &name=QString(), bool multiLine=false, bool password=false, bool readOnly=false, int maxLength=-1);
+ void addCheckBox(const QRectF &r, bool checked=false, const QString &name=QString(), bool readOnly=false);
+ void addRadioButton(const QRectF &r, const QString & group=QString(), bool checked=false, const QString &name=QString(), bool readOnly=false);;
+
+ inline void addHyperlink(int x, int y, int w, int h, const QUrl &url);
+ inline void addHyperlink(const QRect &r, const QUrl &url);
+ void addHyperlink(const QRectF &r, const QUrl &url);
+
void eraseRect(const QRectF &);
inline void eraseRect(int x, int y, int w, int h);
inline void eraseRect(const QRect &);
@@ -821,6 +837,35 @@ inline void QPainter::fillRect(const QRectF &r, Qt::BrushStyle style)
fillRect(r, QBrush(style));
}
+inline void QPainter::addAnchor(int x, int y, int w, int h, const QString &name)
+{
+ addAnchor(QRectF(x, y, w, h), name);
+}
+
+inline void QPainter::addAnchor(const QRect &r, const QString &name)
+{
+ addAnchor(QRectF(r), name);
+}
+
+inline void QPainter::addLink(int x, int y, int w, int h, const QString &anchor)
+{
+ addLink(QRectF(x, y, w, h), anchor);
+}
+
+inline void QPainter::addLink(const QRect &r, const QString &anchor)
+{
+ addLink(QRectF(r), anchor);
+}
+
+inline void QPainter::addHyperlink(int x, int y, int w, int h, const QUrl &url)
+{
+ addHyperlink(QRectF(x, y, w, h), url);
+}
+
+inline void QPainter::addHyperlink(const QRect &r, const QUrl &url)
+{
+ addHyperlink(QRectF(r), url);
+}
inline void QPainter::setBrushOrigin(int x, int y)
{
diff --git a/src/gui/painting/qprintengine.h b/src/gui/painting/qprintengine.h
index da4fe2a..53015ec 100644
--- a/src/gui/painting/qprintengine.h
+++ b/src/gui/painting/qprintengine.h
@@ -88,8 +88,11 @@ public:
PPK_PageMargins,
PPK_CopyCount,
PPK_SupportsMultipleCopies,
- PPK_PaperSize = PPK_PageSize,
+ PPK_UseCompression,
+ PPK_ImageQuality,
+ PPK_ImageDPI,
+ PPK_PaperSize = PPK_PageSize,
PPK_CustomBase = 0xff00
};
@@ -97,6 +100,8 @@ public:
virtual QVariant property(PrintEnginePropertyKey key) const = 0;
virtual bool newPage() = 0;
+ virtual void beginSectionOutline(const QString &text, const QString &anchor) {Q_UNUSED(text); Q_UNUSED(anchor);}
+ virtual void endSectionOutline() {}
virtual bool abort() = 0;
virtual int metric(QPaintDevice::PaintDeviceMetric) const = 0;
diff --git a/src/gui/painting/qprintengine_pdf.cpp b/src/gui/painting/qprintengine_pdf.cpp
index 2b0bca8..c44dd1b 100644
--- a/src/gui/painting/qprintengine_pdf.cpp
+++ b/src/gui/painting/qprintengine_pdf.cpp
@@ -51,6 +51,7 @@
#include <qimagewriter.h>
#include <qbuffer.h>
#include <qdatetime.h>
+#include <QCryptographicHash>
#ifndef QT_NO_PRINTER
#include <limits.h>
@@ -77,12 +78,6 @@ extern qint64 qt_image_id(const QImage &image);
// Can't use it though, as gs generates completely wrong images if this is true.
static const bool interpolateImages = false;
-#ifdef QT_NO_COMPRESS
-static const bool do_compress = false;
-#else
-static const bool do_compress = true;
-#endif
-
QPdfPage::QPdfPage()
: QPdf::ByteStream(true) // Enable file backing
{
@@ -109,6 +104,30 @@ inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features()
return f;
}
+void QPdfEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value) {
+ Q_D(QPdfEngine);
+ if (key==PPK_UseCompression)
+ d->doCompress = value.toBool();
+ else if (key==PPK_ImageQuality)
+ d->imageQuality = value.toInt();
+ else if (key==PPK_ImageDPI)
+ d->imageDPI = value.toInt();
+ else
+ QPdfBaseEngine::setProperty(key, value);
+}
+
+QVariant QPdfEngine::property(PrintEnginePropertyKey key) const {
+ Q_D(const QPdfEngine);
+ if (key==PPK_UseCompression)
+ return d->doCompress;
+ else if (key==PPK_ImageQuality)
+ return d->imageQuality;
+ else if (key==PPK_ImageDPI)
+ return d->imageDPI;
+ else
+ return QPdfBaseEngine::property(key);
+}
+
QPdfEngine::QPdfEngine(QPrinter::PrinterMode m)
: QPdfBaseEngine(*new QPdfEnginePrivate(m), qt_pdf_decide_features())
{
@@ -156,6 +175,51 @@ bool QPdfEngine::begin(QPaintDevice *pdev)
bool QPdfEngine::end()
{
Q_D(QPdfEngine);
+
+ if (d->outlineRoot) {
+ d->outlineRoot->obj = d->requestObject();
+ d->writeOutlineChildren(d->outlineRoot);
+ d->addXrefEntry(d->outlineRoot->obj);
+ d->xprintf("<</Type /Outlines /First %d 0 R\n/Last %d 0 R>>\nendobj\n",
+ d->outlineRoot->firstChild->obj, d->outlineRoot->lastChild->obj);
+ }
+
+ if (d->formFields.size()) {
+ uint font = d->addXrefEntry(-1);
+ d->xprintf("<</Type/Font/Name/Helv/BaseFont/Helvetica/Subtype/Type1>>\n"
+ "endobj\n");
+ d->addXrefEntry(d->formFieldList);
+ d->xprintf("<</Fields[");
+ foreach(const uint & i, d->formFields)
+ d->xprintf("%d 0 R ",i);
+ d->xprintf("]\n"
+ "/DR<</Font<</Helv %d 0 R>>>>\n"
+ "/DA(/Helv 0 Tf 0 g)\n"
+ ">>\n"
+ "endobj\n", font);
+ }
+
+ d->catalog = d->addXrefEntry(-1);
+ d->xprintf("<<\n"
+ "/Type /Catalog\n"
+ "/Pages %d 0 R\n", d->pageRoot);
+ if (d->outlineRoot)
+ d->xprintf("/Outlines %d 0 R\n"
+ "/PageMode /UseOutlines\n", d->outlineRoot->obj);
+ if (d->formFields.size())
+ d->xprintf("/AcroForm %d 0 R\n", d->formFieldList);
+ if (d->anchors.size()) {
+ d->xprintf("/Dests <<\n");
+ for (QHash<QString, uint>::iterator i=d->anchors.begin();
+ i != d->anchors.end(); ++i) {
+ d->printAnchor(i.key());
+ d->xprintf(" %d 0 R\n", i.value());
+ }
+ d->xprintf(">>\n");
+ }
+ d->xprintf(">>\n"
+ "endobj\n");
+
d->writeTail();
d->stream->unsetDevice();
@@ -165,8 +229,83 @@ bool QPdfEngine::end()
return true;
}
+void QPdfEngine::addCheckBox(const QRectF &r, bool checked, const QString &name, bool readOnly) {
+ Q_D(QPdfEngine);
+ uint obj = d->addXrefEntry(-1);
+ char buf[256];
+ QRectF rr = d->pageMatrix().mapRect(r);
+ //Note that the pdf spec sayes that we should add some sort of default appearence atleast for yes, which we dont ghost script provides one, however acroread does not
+ if (d->formFieldList == -1) d->formFieldList = d->requestObject();
+ d->xprintf("<<\n"
+ "/Type /Annot\n"
+ "/Parrent %d 0 R\n"
+ "/Rect[", d->formFieldList);
+ d->xprintf("%s ", qt_real_to_string(rr.left(),buf));
+ d->xprintf("%s ", qt_real_to_string(rr.top(),buf));
+ d->xprintf("%s ", qt_real_to_string(rr.right(),buf));
+ d->xprintf("%s", qt_real_to_string(rr.bottom(),buf));
+ d->xprintf("]\n"
+ "/FT/Btn\n"
+ "/Subtype/Widget\n"
+ "/P %d 0 R\n", d->pages.back());
+ if (checked)
+ d->xprintf("/AS /Yes\n");
+ if (!name.isEmpty()) {
+ d->xprintf("/T");
+ d->printString(name);
+ d->xprintf("\n");
+ }
+ d->xprintf("/Ff %d\n"
+ ">>\n"
+ "endobj\n",
+ (readOnly?1:0)<<0);
+ d->currentPage->annotations.push_back(obj);
+ d->formFields.push_back(obj);
+}
-void QPdfEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, const QRectF &sr)
+void QPdfEngine::addTextField(const QRectF &r, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength)
+{
+ Q_D(QPdfEngine);
+ uint obj = d->addXrefEntry(-1);
+ char buf[256];
+ QRectF rr = d->pageMatrix().mapRect(r);
+ if (d->formFieldList == -1) d->formFieldList = d->requestObject();
+ d->xprintf("<<\n"
+ "/Type /Annot\n"
+ "/Parrent %d 0 R\n"
+ "/Rect[", d->formFieldList);
+ d->xprintf("%s ", qt_real_to_string(rr.left(),buf));
+ d->xprintf("%s ", qt_real_to_string(rr.top(),buf));
+ d->xprintf("%s ", qt_real_to_string(rr.right(),buf));
+ d->xprintf("%s", qt_real_to_string(rr.bottom(),buf));
+ d->xprintf("]\n"
+ "/BS<</S/I>>\n"
+ "/FT/Tx\n"
+ "/Subtype/Widget\n"
+ "/P %d 0 R\n", d->pages.back());
+ if (!text.isEmpty()) {
+ d->xprintf("/V");
+ d->printString(text);
+ d->xprintf("\n");
+ }
+ if (!name.isEmpty()) {
+ d->xprintf("/T");
+ d->printString(name);
+ d->xprintf("\n");
+ }
+ if (maxLength >= 0)
+ d->xprintf("/MaxLen %d\n",maxLength);
+ d->xprintf("/DA(/Helv 12 Tf 0 g)\n"
+ "/Ff %d\n"
+ ">>\n"
+ "endobj\n",
+ (readOnly?1:0)<<0 | (password?1:0)<<13 | (multiLine?1:0)<<12
+ );
+ d->currentPage->annotations.push_back(obj);
+ d->formFields.push_back(obj);
+}
+
+void QPdfEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, const QRectF &sr, const QByteArray * data)
{
if (sr.isEmpty() || rectangle.isEmpty() || pixmap.isNull())
return;
@@ -176,22 +315,35 @@ void QPdfEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, con
QRect sourceRect = sr.toRect();
QPixmap pm = sourceRect != pixmap.rect() ? pixmap.copy(sourceRect) : pixmap;
- QImage image = pm.toImage();
+ QImage unscaled = pm.toImage();
+ QImage image = unscaled;
+
+ QRectF a = d->stroker.matrix.mapRect(rectangle);
+ QRectF c = d->paperRect();
+ int maxWidth = int(a.width() / c.width() * d->width() / 72.0 * d->imageDPI);
+ int maxHeight = int(a.height() / c.height() * d->height() / 72.0 * d->imageDPI);
+ if (image.width() > maxWidth || image.height() > maxHeight)
+ image = unscaled.scaled( image.size().boundedTo( QSize(maxWidth, maxHeight) ), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+ bool useScaled=true;
bool bitmap = true;
- const int object = d->addImage(image, &bitmap, pm.cacheKey());
+ const int object = d->addImage(image, &bitmap, pm.cacheKey(), &unscaled, (sr == pixmap.rect()?data:0), &useScaled );
+ int width = useScaled?image.width():unscaled.width();
+ int height = useScaled?image.height():unscaled.height();
+
if (object < 0)
return;
*d->currentPage << "q\n/GSa gs\n";
*d->currentPage
- << QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(),
+ << QPdf::generateMatrix(QTransform(rectangle.width() / width, 0, 0, rectangle.height() / height,
rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix));
if (bitmap) {
// set current pen as d->brush
d->brush = d->pen.brush();
}
setBrush();
- d->currentPage->streamImage(image.width(), image.height(), object);
+ d->currentPage->streamImage(width, height, object);
*d->currentPage << "Q\n";
d->brush = b;
@@ -301,18 +453,67 @@ QPdfEnginePrivate::QPdfEnginePrivate(QPrinter::PrinterMode m)
: QPdfBaseEnginePrivate(m)
{
streampos = 0;
+ doCompress = true;
+ imageDPI = 1400;
+ imageQuality = 94;
stream = new QDataStream;
pageOrder = QPrinter::FirstPageFirst;
orientation = QPrinter::Portrait;
+ outlineRoot = NULL;
+ outlineCurrent = NULL;
fullPage = false;
}
QPdfEnginePrivate::~QPdfEnginePrivate()
{
+ if (outlineRoot)
+ delete outlineRoot;
delete stream;
}
+void QPdfEnginePrivate::printAnchor(const QString &name) {
+ QByteArray a = name.toUtf8();
+ if (a.size() >= 127)
+ a = QCryptographicHash::hash(a,QCryptographicHash::Sha1);
+ xprintf("/");
+ for (int i=0; i < a.size(); ++i) {
+ unsigned char c = a[i];
+ if (('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z') ||
+ ('0' <= c && c <= '9') ||
+ c == '.' || c == '_')
+ xprintf("%c", c);
+ else
+ xprintf("#%02x", c);
+ }
+}
+
+void QPdfEnginePrivate::writeOutlineChildren(OutlineItem * node) {
+ for (OutlineItem * i = node->firstChild; i != NULL; i = i->next)
+ i->obj = requestObject();
+ for (OutlineItem * i = node->firstChild; i != NULL; i = i->next) {
+ QPdfEnginePrivate::writeOutlineChildren(i);
+ addXrefEntry(i->obj);
+ xprintf("<</Title ");
+ printString(i->text);
+ xprintf("\n"
+ " /Parent %d 0 R\n"
+ " /Dest ", i->parent->obj);
+ printAnchor(i->anchor);
+ xprintf("\n /Count 0\n");
+ if (i->next)
+ xprintf(" /Next %d 0 R\n", i->next->obj);
+ if (i->prev)
+ xprintf(" /Prev %d 0 R\n", i->prev->obj);
+ if (i->firstChild)
+ xprintf(" /First %d 0 R\n", i->firstChild->obj);
+ if (i->lastChild)
+ xprintf(" /Last %d 0 R\n", i->lastChild->obj);
+ xprintf(">>\n"
+ "endobj\n");
+ }
+}
#ifdef USE_NATIVE_GRADIENTS
int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject)
@@ -520,10 +721,34 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor,
return patternObj;
}
+
+void QPdfEnginePrivate::convertImage(const QImage & image, QByteArray & imageData) {
+ int w = image.width();
+ int h = image.height();
+ imageData.resize(colorMode == QPrinter::GrayScale ? w * h : 3 * w * h);
+ uchar *data = (uchar *)imageData.data();
+ for (int y = 0; y < h; ++y) {
+ const QRgb *rgb = (const QRgb *)image.scanLine(y);
+ if (colorMode == QPrinter::GrayScale) {
+ for (int x = 0; x < w; ++x) {
+ *(data++) = qGray(*rgb);
+ ++rgb;
+ }
+ } else {
+ for (int x = 0; x < w; ++x) {
+ *(data++) = qRed(*rgb);
+ *(data++) = qGreen(*rgb);
+ *(data++) = qBlue(*rgb);
+ ++rgb;
+ }
+ }
+ }
+}
+
/*!
* Adds an image to the pdf and return the pdf-object id. Returns -1 if adding the image failed.
*/
-int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_no)
+int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_no, const QImage * noneScaled, const QByteArray * data, bool * useScaled)
{
if (img.isNull())
return -1;
@@ -564,65 +789,91 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n
}
object = writeImage(data, w, h, d, 0, 0);
} else {
- QByteArray softMaskData;
- bool dct = false;
QByteArray imageData;
- bool hasAlpha = false;
- bool hasMask = false;
-
+ uLongf target=1024*1024*1024;
+ bool uns=false;
+ bool dct = false;
if (QImageWriter::supportedImageFormats().contains("jpeg") && colorMode != QPrinter::GrayScale) {
- QBuffer buffer(&imageData);
+ QByteArray imageData2;
+
+ QBuffer buffer(&imageData2);
QImageWriter writer(&buffer, "jpeg");
- writer.setQuality(94);
+ writer.setQuality(imageQuality);
writer.write(image);
- dct = true;
+
+ if ((uLongf)imageData2.size() < target) {
+ imageData=imageData2;
+ target = imageData2.size();
+ dct = true;
+ uns=false;
+ }
+ }
- if (format != QImage::Format_RGB32) {
- softMaskData.resize(w * h);
- uchar *sdata = (uchar *)softMaskData.data();
- for (int y = 0; y < h; ++y) {
- const QRgb *rgb = (const QRgb *)image.scanLine(y);
- for (int x = 0; x < w; ++x) {
- uchar alpha = qAlpha(*rgb);
- *sdata++ = alpha;
- hasMask |= (alpha < 255);
- hasAlpha |= (alpha != 0 && alpha != 255);
- ++rgb;
- }
- }
+ if (noneScaled && noneScaled->rect() != image.rect()) {
+ QByteArray imageData2;
+ convertImage(*noneScaled, imageData2);
+ uLongf len = imageData2.size();
+ uLongf destLen = len + len/100 + 13; // zlib requirement
+ Bytef* dest = new Bytef[destLen];
+ if (Z_OK == ::compress(dest, &destLen, (const Bytef*) imageData2.data(), (uLongf)len) &&
+ (uLongf)destLen < target) {
+ imageData=imageData2;
+ target=destLen;
+ dct=false;
+ uns=true;
}
- } else {
- imageData.resize(colorMode == QPrinter::GrayScale ? w * h : 3 * w * h);
- uchar *data = (uchar *)imageData.data();
+ delete[] dest;
+ }
+
+ {
+ QByteArray imageData2;
+ convertImage(image, imageData2);
+ uLongf len = imageData2.size();
+ uLongf destLen = len + len/100 + 13; // zlib requirement
+ Bytef* dest = new Bytef[destLen];
+ if (Z_OK == ::compress(dest, &destLen, (const Bytef*) imageData2.data(), (uLongf)len) &&
+ (uLongf)destLen < target) {
+ imageData=imageData2;
+ target=destLen;
+ dct=false;
+ uns=false;
+ }
+ delete[] dest;
+ }
+
+ if (colorMode != QPrinter::GrayScale && noneScaled != 0 && data != 0 &&
+ data->size() > 2 && (unsigned char)data->data()[0] == 0xff && (unsigned char)data->data()[1] == 0xd8 &&
+ (uLongf)data->size()*10 < target*13) {
+ imageData = *data;
+ target=data->size();
+ dct=true;
+ uns=true;
+ }
+
+ if (uns) {
+ w = noneScaled->width();
+ h = noneScaled->height();
+ }
+ if (useScaled) *useScaled = (uns?false:true);
+ QByteArray softMaskData;
+ bool hasAlpha = false;
+ bool hasMask = false;
+
+ if (format != QImage::Format_RGB32) {
softMaskData.resize(w * h);
uchar *sdata = (uchar *)softMaskData.data();
for (int y = 0; y < h; ++y) {
- const QRgb *rgb = (const QRgb *)image.scanLine(y);
- if (colorMode == QPrinter::GrayScale) {
- for (int x = 0; x < w; ++x) {
- *(data++) = qGray(*rgb);
- uchar alpha = qAlpha(*rgb);
- *sdata++ = alpha;
- hasMask |= (alpha < 255);
- hasAlpha |= (alpha != 0 && alpha != 255);
- ++rgb;
- }
- } else {
- for (int x = 0; x < w; ++x) {
- *(data++) = qRed(*rgb);
- *(data++) = qGreen(*rgb);
- *(data++) = qBlue(*rgb);
- uchar alpha = qAlpha(*rgb);
- *sdata++ = alpha;
- hasMask |= (alpha < 255);
- hasAlpha |= (alpha != 0 && alpha != 255);
- ++rgb;
- }
+ const QRgb *rgb = (const QRgb *)(uns?noneScaled->scanLine(y):image.scanLine(y));
+ for (int x = 0; x < w; ++x) {
+ uchar alpha = qAlpha(*rgb);
+ *sdata++ = alpha;
+ hasMask |= (alpha < 255);
+ hasAlpha |= (alpha != 0 && alpha != 255);
+ ++rgb;
}
}
- if (format == QImage::Format_RGB32)
- hasAlpha = hasMask = false;
}
+
int maskObject = 0;
int softMaskObject = 0;
if (hasAlpha) {
@@ -754,7 +1005,7 @@ void QPdfEnginePrivate::xprintf(const char* fmt, ...)
int QPdfEnginePrivate::writeCompressed(QIODevice *dev)
{
#ifndef QT_NO_COMPRESS
- if (do_compress) {
+ if (doCompress) {
int size = QPdfPage::chunkSize();
int sum = 0;
::z_stream zStruct;
@@ -828,7 +1079,7 @@ int QPdfEnginePrivate::writeCompressed(QIODevice *dev)
int QPdfEnginePrivate::writeCompressed(const char *src, int len)
{
#ifndef QT_NO_COMPRESS
- if(do_compress) {
+ if(doCompress) {
uLongf destLen = len + len/100 + 13; // zlib requirement
Bytef* dest = new Bytef[destLen];
if (Z_OK == ::compress(dest, &destLen, (const Bytef*) src, (uLongf)len)) {
@@ -881,7 +1132,7 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height,
write(data);
len = data.length();
} else {
- if (do_compress)
+ if (doCompress)
xprintf("/Filter /FlateDecode\n>>\nstream\n");
else
xprintf(">>\nstream\n");
@@ -904,14 +1155,9 @@ void QPdfEnginePrivate::writeHeader()
writeInfo();
- catalog = addXrefEntry(-1);
pageRoot = requestObject();
- xprintf("<<\n"
- "/Type /Catalog\n"
- "/Pages %d 0 R\n"
- ">>\n"
- "endobj\n", pageRoot);
-
+
+ formFieldList = -1;
// graphics state
graphicsState = addXrefEntry(-1);
xprintf("<<\n"
@@ -943,13 +1189,22 @@ void QPdfEnginePrivate::writeInfo()
QDateTime now = QDateTime::currentDateTime().toUTC();
QTime t = now.time();
QDate d = now.date();
- xprintf("\n/CreationDate (D:%d%02d%02d%02d%02d%02d)\n",
+ xprintf("\n/CreationDate (D:%d%02d%02d%02d%02d%02d)",
d.year(),
d.month(),
d.day(),
t.hour(),
t.minute(),
t.second());
+ QDateTime fake=now;
+ fake.setTimeSpec(Qt::UTC);
+ int offset = now.secsTo(fake);
+ if (offset == 0)
+ xprintf("Z)\n");
+ else if (offset < 0)
+ xprintf("-%02d'%02d')\n", (-offset)/60/60 , ((-offset)/60) % 60);
+ else if (offset > 0)
+ xprintf("+%02d'%02d')\n", offset/60/60 , (offset/60) % 60);
xprintf(">>\n"
"endobj\n");
}
@@ -1035,7 +1290,7 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font)
s << "<<\n"
"/Length1 " << fontData.size() << "\n"
"/Length " << length_object << "0 R\n";
- if (do_compress)
+ if (doCompress)
s << "/Filter /FlateDecode\n";
s << ">>\n"
"stream\n";
@@ -1097,6 +1352,101 @@ void QPdfEnginePrivate::writeFonts()
fonts.clear();
}
+
+void QPdfEngine::addHyperlink(const QRectF &r, const QUrl &url)
+{
+ Q_D(QPdfEngine);
+ char buf[256];
+ QRectF rr = d->pageMatrix().mapRect(r);
+ uint annot = d->addXrefEntry(-1);
+ QByteArray urlascii = url.toString().toLatin1();
+ int len = urlascii.size();
+ char *url_esc = new char[len * 2 + 1];
+ const char * urldata = urlascii.constData();
+ int k = 0;
+ for (int j = 0; j < len; j++, k++){
+ if (urldata[j] == '(' ||
+ urldata[j] == ')' ||
+ urldata[j] == '\\'){
+ url_esc[k] = '\\';
+ k++;
+ }
+ url_esc[k] = urldata[j];
+ }
+ url_esc[k] = 0;
+ d->xprintf("<<\n/Type /Annot\n/Subtype /Link\n/Rect [");
+ d->xprintf("%s ", qt_real_to_string(rr.left(),buf));
+ d->xprintf("%s ", qt_real_to_string(rr.top(),buf));
+ d->xprintf("%s ", qt_real_to_string(rr.right(),buf));
+ d->xprintf("%s", qt_real_to_string(rr.bottom(),buf));
+ d->xprintf("]\n/Border [0 0 0]\n/A <<\n");
+ d->xprintf("/Type /Action\n/S /URI\n/URI (%s)\n", url_esc);
+ d->xprintf(">>\n>>\n");
+ d->xprintf("endobj\n");
+ d->currentPage->annotations.append(annot);
+ delete[] url_esc;
+}
+
+void QPdfEngine::addLink(const QRectF &r, const QString &anchor)
+{
+ Q_D(QPdfEngine);
+ char buf[256];
+ QRectF rr = d->pageMatrix().mapRect(r);
+ uint annot = d->addXrefEntry(-1);
+ d->xprintf("<<\n/Type /Annot\n/Subtype /Link\n/Rect [");
+ d->xprintf("%s ", qt_real_to_string(rr.left(),buf));
+ d->xprintf("%s ", qt_real_to_string(rr.top(),buf));
+ d->xprintf("%s ", qt_real_to_string(rr.right(),buf));
+ d->xprintf("%s", qt_real_to_string(rr.bottom(),buf));
+ d->xprintf("]\n/Border [0 0 0]\n/Dest ");
+ d->printAnchor(anchor);
+ d->xprintf("\n>>\n");
+ d->xprintf("endobj\n");
+ d->currentPage->annotations.append(annot);
+}
+
+void QPdfEngine::addAnchor(const QRectF &r, const QString &name)
+{
+ Q_D(QPdfEngine);
+ char buf[256];
+ QRectF rr = d->pageMatrix().mapRect(r);
+ uint anchor = d->addXrefEntry(-1);
+ d->xprintf("[%d /XYZ %s \n",
+ d->pages.size() - 1,
+ qt_real_to_string(rr.left(), buf));
+ d->xprintf("%s 0]\n",
+ qt_real_to_string(rr.bottom(), buf));
+ d->xprintf("endobj\n");
+ d->anchors[name] = anchor;
+}
+
+void QPdfEngine::beginSectionOutline(const QString &text, const QString &anchor)
+{
+ Q_D(QPdfEngine);
+ if (d->outlineCurrent == NULL) {
+ if (d->outlineRoot)
+ delete d->outlineRoot;
+ d->outlineCurrent = d->outlineRoot = new QPdfEnginePrivate::OutlineItem(QString(), QString());
+ }
+
+ QPdfEnginePrivate::OutlineItem *i = new QPdfEnginePrivate::OutlineItem(text, anchor);
+ i->parent = d->outlineCurrent;
+ i->prev = d->outlineCurrent->lastChild;
+ if (d->outlineCurrent->firstChild)
+ d->outlineCurrent->lastChild->next = i;
+ else
+ d->outlineCurrent->firstChild = i;
+ d->outlineCurrent->lastChild = i;
+ d->outlineCurrent = i;
+}
+
+void QPdfEngine::endSectionOutline()
+{
+ Q_D(QPdfEngine);
+ if (d->outlineCurrent)
+ d->outlineCurrent = d->outlineCurrent->parent;
+}
+
void QPdfEnginePrivate::writePage()
{
if (pages.empty())
@@ -1167,7 +1517,7 @@ void QPdfEnginePrivate::writePage()
addXrefEntry(pageStream);
xprintf("<<\n"
"/Length %d 0 R\n", pageStreamLength); // object number for stream length object
- if (do_compress)
+ if (doCompress)
xprintf("/Filter /FlateDecode\n");
xprintf(">>\n");
diff --git a/src/gui/painting/qprintengine_pdf_p.h b/src/gui/painting/qprintengine_pdf_p.h
index ee77e15..d0d87fd 100644
--- a/src/gui/painting/qprintengine_pdf_p.h
+++ b/src/gui/painting/qprintengine_pdf_p.h
@@ -1,3 +1,4 @@
+
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
@@ -92,7 +93,12 @@ public:
// reimplementations QPaintEngine
bool begin(QPaintDevice *pdev);
bool end();
- void drawPixmap (const QRectF & rectangle, const QPixmap & pixmap, const QRectF & sr);
+
+ void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr, const QByteArray * data=0);
+ void drawPixmap(const QRectF & rectangle, const QPixmap & pixmap, const QRectF & sr) {
+ drawPixmap(rectangle, pixmap, sr, 0);
+ }
+
void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
Qt::ImageConversionFlags flags = Qt::AutoColor);
void drawTiledPixmap (const QRectF & rectangle, const QPixmap & pixmap, const QPointF & point);
@@ -108,12 +114,23 @@ public:
void setBrush();
+ virtual void addHyperlink(const QRectF &r, const QUrl &url);
+ virtual void addAnchor(const QRectF &r, const QString &name);
+ virtual void addLink(const QRectF &r, const QString &anchor);
+ virtual void addTextField(const QRectF &r, const QString &text, const QString &name, bool multiLine, bool password, bool readOnly, int maxLength);
+ virtual void addCheckBox(const QRectF &r, bool checked, const QString &name, bool readOnly);
+
// ### unused, should have something for this in QPrintEngine
void setAuthor(const QString &author);
QString author() const;
void setDevice(QIODevice* dev);
+ void beginSectionOutline(const QString &text, const QString &anchor);
+ void endSectionOutline();
+
+ void setProperty(PrintEnginePropertyKey key, const QVariant &value);
+ QVariant property(PrintEnginePropertyKey key) const;
private:
Q_DISABLE_COPY(QPdfEngine)
@@ -124,6 +141,35 @@ class QPdfEnginePrivate : public QPdfBaseEnginePrivate
{
Q_DECLARE_PUBLIC(QPdfEngine)
public:
+
+ class OutlineItem {
+ public:
+ OutlineItem *parent;
+ OutlineItem *next;
+ OutlineItem *prev;
+ OutlineItem *firstChild;
+ OutlineItem *lastChild;
+ uint obj;
+ QString text;
+ QString anchor;
+
+ OutlineItem(const QString &t, const QString &a):
+ parent(NULL), next(NULL), prev(NULL), firstChild(NULL), lastChild(NULL),
+ obj(0), text(t), anchor(a) {}
+ ~OutlineItem() {
+ OutlineItem *i = firstChild;
+ while(i != NULL) {
+ OutlineItem *n = i->next;
+ delete i;
+ i=n;
+ }
+ }
+ };
+
+ OutlineItem *outlineRoot;
+ OutlineItem *outlineCurrent;
+ void writeOutlineChildren(OutlineItem *node);
+
QPdfEnginePrivate(QPrinter::PrinterMode m);
~QPdfEnginePrivate();
@@ -141,7 +187,9 @@ public:
void writeHeader();
void writeTail();
- int addImage(const QImage &image, bool *bitmap, qint64 serial_no);
+ void convertImage(const QImage & image, QByteArray & imageData);
+
+ int addImage(const QImage &image, bool *bitmap, qint64 serial_no, const QImage * noneScaled=0, const QByteArray * data=0, bool * useScaled=0);
int addConstantAlphaObject(int brushAlpha, int penAlpha = 255);
int addBrushPattern(const QTransform &matrix, bool *specifyColor, int *gStateObject);
@@ -161,16 +209,24 @@ private:
void writeFonts();
void embedFont(QFontSubset *font);
+ int formFieldList;
+ QVector<uint> formFields;
QVector<int> xrefPositions;
QDataStream* stream;
int streampos;
+ bool doCompress;
+ int imageDPI;
+ int imageQuality;
int writeImage(const QByteArray &data, int width, int height, int depth,
int maskObject, int softMaskObject, bool dct = false);
void writePage();
int addXrefEntry(int object, bool printostr = true);
+
void printString(const QString &string);
+ void printAnchor(const QString &name);
+
void xprintf(const char* fmt, ...);
inline void write(const QByteArray &data) {
stream->writeRawData(data.constData(), data.size());
@@ -183,6 +239,8 @@ private:
// various PDF objects
int pageRoot, catalog, info, graphicsState, patternColorSpace;
+ QVector<uint> dests;
+ QHash<QString, uint> anchors;
QVector<uint> pages;
QHash<qint64, uint> imageCache;
QHash<QPair<uint, uint>, uint > alphaCache;
diff --git a/src/gui/painting/qprinter.cpp b/src/gui/painting/qprinter.cpp
index 74a8f6a..e8b40fa 100644
--- a/src/gui/painting/qprinter.cpp
+++ b/src/gui/painting/qprinter.cpp
@@ -933,6 +933,39 @@ void QPrinter::setOutputFileName(const QString &fileName)
d->addToManualSetList(QPrintEngine::PPK_OutputFileName);
}
+/*!
+ Add a section to the document outline. All following sections will be added
+ to as subsections to this section, until endSectionOutline() has been called.
+
+ \a name is the name of the added section. \a anchor is the name of an anchor
+ indicating the beginning of the section. This anchor must be added by calling
+ QPainter::addAnchor().
+
+ Note that for output formats not supporting outlines, currently all other then PDF,
+ this call has no effect.
+
+ \sa endSectionOutline() QPainter::addAnchor()
+
+ \since 4.7
+*/
+void QPrinter::beginSectionOutline(const QString &name, const QString &anchor)
+{
+ Q_D(QPrinter);
+ d->printEngine->beginSectionOutline(name, anchor);
+}
+
+/*!
+ End the current section.
+
+ \sa beginSectionOutline()
+
+ \since 4.7
+*/
+void QPrinter::endSectionOutline()
+{
+ Q_D(QPrinter);
+ d->printEngine->endSectionOutline();
+}
/*!
Returns the name of the program that sends the print output to the
diff --git a/src/gui/painting/qprinter.h b/src/gui/painting/qprinter.h
index 58db612..457bd13 100644
--- a/src/gui/painting/qprinter.h
+++ b/src/gui/painting/qprinter.h
@@ -147,6 +147,9 @@ public:
enum PrinterOption { PrintToFile, PrintSelection, PrintPageRange };
#endif // QT3_SUPPORT
+ void beginSectionOutline(const QString &text, const QString &anchor);
+ void endSectionOutline();
+
void setOutputFormat(OutputFormat format);
OutputFormat outputFormat() const;
diff --git a/src/gui/styles/qstyle.cpp b/src/gui/styles/qstyle.cpp
index c5eb330..cf3a2f7 100644
--- a/src/gui/styles/qstyle.cpp
+++ b/src/gui/styles/qstyle.cpp
@@ -47,6 +47,7 @@
#include "qpixmapcache.h"
#include "qstyleoption.h"
#include "private/qstyle_p.h"
+#include "private/qapplication_p.h"
#ifndef QT_NO_DEBUG
#include "qdebug.h"
#endif
@@ -2229,7 +2230,7 @@ QPalette QStyle::standardPalette() const
{
#ifdef Q_WS_X11
QColor background;
- if (QX11Info::appDepth() > 8)
+ if (!qt_is_gui_used || QX11Info::appDepth() > 8)
background = QColor(0xd4, 0xd0, 0xc8); // win 2000 grey
else
background = QColor(192, 192, 192);
diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro
index 438a88e..2886996 100644
--- a/src/plugins/platforms/minimal/minimal.pro
+++ b/src/plugins/platforms/minimal/minimal.pro
@@ -5,9 +5,15 @@ QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
SOURCES = main.cpp \
qminimalintegration.cpp \
- qminimalwindowsurface.cpp
+ qminimalwindowsurface.cpp \
+ qfontconfigdatabase.cpp
+
HEADERS = qminimalintegration.h \
- qminimalwindowsurface.h
+ qminimalwindowsurface.h \
+ qfontconfigdatabase.h
+
+include(../fontdatabases/basicunix/basicunix.pri)
target.path += $$[QT_INSTALL_PLUGINS]/platforms
INSTALLS += target
+LIBS += -lfontconfig
\ No newline at end of file
diff --git a/src/plugins/platforms/minimal/qfontconfigdatabase.cpp b/src/plugins/platforms/minimal/qfontconfigdatabase.cpp
new file mode 100644
index 0000000..377d655
--- /dev/null
+++ b/src/plugins/platforms/minimal/qfontconfigdatabase.cpp
@@ -0,0 +1,601 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfontconfigdatabase.h"
+
+#include <QtCore/QList>
+#include <QtGui/private/qfont_p.h>
+
+#include <QtCore/QElapsedTimer>
+
+#include <QtGui/private/qapplication_p.h>
+#include <QtGui/QPlatformScreen>
+
+#include <QtGui/private/qfontengine_ft_p.h>
+#include <QtGui/private/qfontengine_p.h>
+
+
+
+#include <ft2build.h>
+#include FT_TRUETYPE_TABLES_H
+
+#include <fontconfig/fontconfig.h>
+
+#define SimplifiedChineseCsbBit 18
+#define TraditionalChineseCsbBit 20
+#define JapaneseCsbBit 17
+#define KoreanCsbBit 21
+
+static inline bool requiresOpenType(int writingSystem)
+{
+ return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala)
+ || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko);
+}
+static inline bool scriptRequiresOpenType(int script)
+{
+ return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
+ || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko);
+}
+
+static int getFCWeight(int fc_weight)
+{
+ int qtweight = QFont::Black;
+ if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2)
+ qtweight = QFont::Light;
+ else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2)
+ qtweight = QFont::Normal;
+ else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2)
+ qtweight = QFont::DemiBold;
+ else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2)
+ qtweight = QFont::Bold;
+
+ return qtweight;
+}
+
+static const char *specialLanguages[] = {
+ "en", // Common
+ "el", // Greek
+ "ru", // Cyrillic
+ "hy", // Armenian
+ "he", // Hebrew
+ "ar", // Arabic
+ "syr", // Syriac
+ "div", // Thaana
+ "hi", // Devanagari
+ "bn", // Bengali
+ "pa", // Gurmukhi
+ "gu", // Gujarati
+ "or", // Oriya
+ "ta", // Tamil
+ "te", // Telugu
+ "kn", // Kannada
+ "ml", // Malayalam
+ "si", // Sinhala
+ "th", // Thai
+ "lo", // Lao
+ "bo", // Tibetan
+ "my", // Myanmar
+ "ka", // Georgian
+ "ko", // Hangul
+ "", // Ogham
+ "", // Runic
+ "km", // Khmer
+ "" // N'Ko
+};
+enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) };
+
+static const ushort specialChars[] = {
+ 0, // English
+ 0, // Greek
+ 0, // Cyrillic
+ 0, // Armenian
+ 0, // Hebrew
+ 0, // Arabic
+ 0, // Syriac
+ 0, // Thaana
+ 0, // Devanagari
+ 0, // Bengali
+ 0, // Gurmukhi
+ 0, // Gujarati
+ 0, // Oriya
+ 0, // Tamil
+ 0xc15, // Telugu
+ 0xc95, // Kannada
+ 0xd15, // Malayalam
+ 0xd9a, // Sinhala
+ 0, // Thai
+ 0, // Lao
+ 0, // Tibetan
+ 0x1000, // Myanmar
+ 0, // Georgian
+ 0, // Hangul
+ 0x1681, // Ogham
+ 0x16a0, // Runic
+ 0, // Khmer
+ 0x7ca // N'Ko
+};
+enum { SpecialCharCount = sizeof(specialChars) / sizeof(ushort) };
+
+// this could become a list of all languages used for each writing
+// system, instead of using the single most common language.
+static const char *languageForWritingSystem[] = {
+ 0, // Any
+ "en", // Latin
+ "el", // Greek
+ "ru", // Cyrillic
+ "hy", // Armenian
+ "he", // Hebrew
+ "ar", // Arabic
+ "syr", // Syriac
+ "div", // Thaana
+ "hi", // Devanagari
+ "bn", // Bengali
+ "pa", // Gurmukhi
+ "gu", // Gujarati
+ "or", // Oriya
+ "ta", // Tamil
+ "te", // Telugu
+ "kn", // Kannada
+ "ml", // Malayalam
+ "si", // Sinhala
+ "th", // Thai
+ "lo", // Lao
+ "bo", // Tibetan
+ "my", // Myanmar
+ "ka", // Georgian
+ "km", // Khmer
+ "zh-cn", // SimplifiedChinese
+ "zh-tw", // TraditionalChinese
+ "ja", // Japanese
+ "ko", // Korean
+ "vi", // Vietnamese
+ 0, // Symbol
+ 0, // Ogham
+ 0, // Runic
+ 0 // N'Ko
+};
+enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) };
+
+// Unfortunately FontConfig doesn't know about some languages. We have to test these through the
+// charset. The lists below contain the systems where we need to do this.
+static const ushort sampleCharForWritingSystem[] = {
+ 0, // Any
+ 0, // Latin
+ 0, // Greek
+ 0, // Cyrillic
+ 0, // Armenian
+ 0, // Hebrew
+ 0, // Arabic
+ 0, // Syriac
+ 0, // Thaana
+ 0, // Devanagari
+ 0, // Bengali
+ 0, // Gurmukhi
+ 0, // Gujarati
+ 0, // Oriya
+ 0, // Tamil
+ 0xc15, // Telugu
+ 0xc95, // Kannada
+ 0xd15, // Malayalam
+ 0xd9a, // Sinhala
+ 0, // Thai
+ 0, // Lao
+ 0, // Tibetan
+ 0x1000, // Myanmar
+ 0, // Georgian
+ 0, // Khmer
+ 0, // SimplifiedChinese
+ 0, // TraditionalChinese
+ 0, // Japanese
+ 0, // Korean
+ 0, // Vietnamese
+ 0, // Symbol
+ 0x1681, // Ogham
+ 0x16a0, // Runic
+ 0x7ca // N'Ko
+};
+enum { SampleCharCount = sizeof(sampleCharForWritingSystem) / sizeof(ushort) };
+
+// Newer FontConfig let's us sort out fonts that contain certain glyphs, but no
+// open type tables for is directly. Do this so we don't pick some strange
+// pseudo unicode font
+static const char *openType[] = {
+ 0, // Any
+ 0, // Latin
+ 0, // Greek
+ 0, // Cyrillic
+ 0, // Armenian
+ 0, // Hebrew
+ 0, // Arabic
+ "syrc", // Syriac
+ "thaa", // Thaana
+ "deva", // Devanagari
+ "beng", // Bengali
+ "guru", // Gurmukhi
+ "gurj", // Gujarati
+ "orya", // Oriya
+ "taml", // Tamil
+ "telu", // Telugu
+ "knda", // Kannada
+ "mlym", // Malayalam
+ "sinh", // Sinhala
+ 0, // Thai
+ 0, // Lao
+ "tibt", // Tibetan
+ "mymr", // Myanmar
+ 0, // Georgian
+ "khmr", // Khmer
+ 0, // SimplifiedChinese
+ 0, // TraditionalChinese
+ 0, // Japanese
+ 0, // Korean
+ 0, // Vietnamese
+ 0, // Symbol
+ 0, // Ogham
+ 0, // Runic
+ "nko " // N'Ko
+};
+
+static const char *getFcFamilyForStyleHint(const QFont::StyleHint style)
+{
+ const char *stylehint = 0;
+ switch (style) {
+ case QFont::SansSerif:
+ stylehint = "sans-serif";
+ break;
+ case QFont::Serif:
+ stylehint = "serif";
+ break;
+ case QFont::TypeWriter:
+ stylehint = "monospace";
+ break;
+ default:
+ break;
+ }
+ return stylehint;
+}
+
+void QFontconfigDatabase::populateFontDatabase()
+{
+ FcFontSet *fonts;
+
+ QString familyName;
+ FcChar8 *value = 0;
+ int weight_value;
+ int slant_value;
+ int spacing_value;
+ FcChar8 *file_value;
+ int indexValue;
+ FcChar8 *foundry_value;
+ FcBool scalable;
+ FcBool antialias;
+
+ {
+ FcObjectSet *os = FcObjectSetCreate();
+ FcPattern *pattern = FcPatternCreate();
+ const char *properties [] = {
+ FC_FAMILY, FC_WEIGHT, FC_SLANT,
+ FC_SPACING, FC_FILE, FC_INDEX,
+ FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT,
+ FC_WIDTH,
+#if FC_VERSION >= 20297
+ FC_CAPABILITY,
+#endif
+ (const char *)0
+ };
+ const char **p = properties;
+ while (*p) {
+ FcObjectSetAdd(os, *p);
+ ++p;
+ }
+ fonts = FcFontList(0, pattern, os);
+ FcObjectSetDestroy(os);
+ FcPatternDestroy(pattern);
+ }
+
+ for (int i = 0; i < fonts->nfont; i++) {
+ if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
+ continue;
+ // capitalize(value);
+ familyName = QString::fromUtf8((const char *)value);
+ slant_value = FC_SLANT_ROMAN;
+ weight_value = FC_WEIGHT_MEDIUM;
+ spacing_value = FC_PROPORTIONAL;
+ file_value = 0;
+ indexValue = 0;
+ scalable = FcTrue;
+
+
+ if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch)
+ slant_value = FC_SLANT_ROMAN;
+ if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch)
+ weight_value = FC_WEIGHT_MEDIUM;
+ if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch)
+ spacing_value = FC_PROPORTIONAL;
+ if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch)
+ file_value = 0;
+ if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &indexValue) != FcResultMatch)
+ indexValue = 0;
+ if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch)
+ scalable = FcTrue;
+ if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
+ foundry_value = 0;
+ if(FcPatternGetBool(fonts->fonts[i],FC_ANTIALIAS,0,&antialias) != FcResultMatch)
+ antialias = true;
+
+ QSupportedWritingSystems writingSystems;
+ FcLangSet *langset = 0;
+ FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset);
+ if (res == FcResultMatch) {
+ for (int i = 1; i < LanguageCount; ++i) {
+ const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i];
+ if (lang) {
+ FcLangResult langRes = FcLangSetHasLang(langset, lang);
+ if (langRes != FcLangDifferentLang)
+ writingSystems.setSupported(QFontDatabase::WritingSystem(i));
+ }
+ }
+ } else {
+ // we set Other to supported for symbol fonts. It makes no
+ // sense to merge these with other ones, as they are
+ // special in a way.
+ writingSystems.setSupported(QFontDatabase::Other);
+ }
+
+ FcCharSet *cs = 0;
+ res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs);
+ if (res == FcResultMatch) {
+ // some languages are not supported by FontConfig, we rather check the
+ // charset to detect these
+ for (int i = 1; i < SampleCharCount; ++i) {
+ if (!sampleCharForWritingSystem[i])
+ continue;
+ if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i]))
+ writingSystems.setSupported(QFontDatabase::WritingSystem(i));
+ }
+ }
+
+#if FC_VERSION >= 20297
+ for (int j = 1; j < LanguageCount; ++j) {
+ if (writingSystems.supported(QFontDatabase::WritingSystem(j))
+ && requiresOpenType(j) && openType[j]) {
+ FcChar8 *cap;
+ res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap);
+ if (res != FcResultMatch || !strstr((const char *)cap, openType[j]))
+ writingSystems.setSupported(QFontDatabase::WritingSystem(j),false);
+ }
+ }
+#endif
+
+ FontFile *fontFile = new FontFile;
+ fontFile->fileName = QLatin1String((const char *)file_value);
+ fontFile->indexValue = indexValue;
+
+ QFont::Style style = (slant_value == FC_SLANT_ITALIC)
+ ? QFont::StyleItalic
+ : ((slant_value == FC_SLANT_OBLIQUE)
+ ? QFont::StyleOblique
+ : QFont::StyleNormal);
+ QFont::Weight weight = QFont::Weight(getFCWeight(weight_value));
+
+ double pixel_size = 0;
+ if (!scalable) {
+ int width = 100;
+ FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width);
+ FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size);
+ }
+
+ QFont::Stretch stretch = QFont::Unstretched;
+ QPlatformFontDatabase::registerFont(familyName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,writingSystems,fontFile);
+// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size;
+ }
+
+ FcFontSetDestroy (fonts);
+
+ struct FcDefaultFont {
+ const char *qtname;
+ const char *rawname;
+ bool fixed;
+ };
+ const FcDefaultFont defaults[] = {
+ { "Serif", "serif", false },
+ { "Sans Serif", "sans-serif", false },
+ { "Monospace", "monospace", true },
+ { 0, 0, false }
+ };
+ const FcDefaultFont *f = defaults;
+ // aliases only make sense for 'common', not for any of the specials
+ QSupportedWritingSystems ws;
+ ws.setSupported(QFontDatabase::Latin);
+
+
+ while (f->qtname) {
+ registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,ws,0);
+ registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,ws,0);
+ registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,ws,0);
+ ++f;
+ }
+
+ //Lighthouse has very lazy population of the font db. We want it to be initialized when
+ //QApplication is constructed, so that the population procedure can do something like this to
+ //set the default font
+// const FcDefaultFont *s = defaults;
+// QFont font("Sans Serif");
+// font.setPointSize(9);
+// QApplication::setFont(font);
+}
+
+QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QUnicodeTables::Script script, void *usrPtr)
+{
+ if (!usrPtr)
+ return 0;
+ QFontDef fontDef = f;
+
+ QFontEngineFT *engine;
+ FontFile *fontfile = static_cast<FontFile *> (usrPtr);
+ QFontEngine::FaceId fid;
+ fid.filename = fontfile->fileName.toLocal8Bit();
+ fid.index = fontfile->indexValue;
+
+ //try and get the pattern
+ FcPattern *pattern = FcPatternCreate();
+
+ bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
+ QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono;
+
+ engine = new QFontEngineFT(fontDef);
+
+ FcValue value;
+ value.type = FcTypeString;
+ QByteArray cs = fontDef.family.toUtf8();
+ value.u.s = (const FcChar8 *)cs.data();
+ FcPatternAdd(pattern,FC_FAMILY,value,true);
+
+
+ value.u.s = (const FcChar8 *)fid.filename.data();
+ FcPatternAdd(pattern,FC_FILE,value,true);
+
+ value.type = FcTypeInteger;
+ value.u.i = fid.index;
+ FcPatternAdd(pattern,FC_INDEX,value,true);
+
+ QFontEngineFT::HintStyle default_hint_style;
+
+ if (FcConfigSubstitute(0,pattern,FcMatchPattern)) {
+
+ //hinting
+ int hint_style = 0;
+ if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch)
+ hint_style = QFontEngineFT::HintFull;
+ switch (hint_style) {
+ case FC_HINT_NONE:
+ default_hint_style = QFontEngineFT::HintNone;
+ break;
+ case FC_HINT_SLIGHT:
+ default_hint_style = QFontEngineFT::HintLight;
+ break;
+ case FC_HINT_MEDIUM:
+ default_hint_style = QFontEngineFT::HintMedium;
+ break;
+ default:
+ default_hint_style = QFontEngineFT::HintFull;
+ break;
+ }
+ }
+
+ engine->setDefaultHintStyle(default_hint_style);
+ if (!engine->init(fid,antialias,format)) {
+ delete engine;
+ engine = 0;
+ return engine;
+ }
+ if (engine->invalid()) {
+ delete engine;
+ engine = 0;
+ } else if (scriptRequiresOpenType(script)) {
+ HB_Face hbFace = engine->harfbuzzFace();
+ if (!hbFace || !hbFace->supported_scripts[script]) {
+ delete engine;
+ engine = 0;
+ }
+ }
+
+ return engine;
+}
+
+QStringList QFontconfigDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const
+{
+ QStringList fallbackFamilies;
+ FcPattern *pattern = FcPatternCreate();
+ if (!pattern)
+ return fallbackFamilies;
+
+ FcValue value;
+ value.type = FcTypeString;
+ QByteArray cs = family.toUtf8();
+ value.u.s = (const FcChar8 *)cs.data();
+ FcPatternAdd(pattern,FC_FAMILY,value,true);
+
+ int slant_value = FC_SLANT_ROMAN;
+ if (style == QFont::StyleItalic)
+ slant_value = FC_SLANT_ITALIC;
+ else if (style == QFont::StyleOblique)
+ slant_value = FC_SLANT_OBLIQUE;
+ FcPatternAddInteger(pattern, FC_SLANT, slant_value);
+
+ if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') {
+ Q_ASSERT(script < QUnicodeTables::ScriptCount);
+ FcLangSet *ls = FcLangSetCreate();
+ FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
+ FcPatternAddLangSet(pattern, FC_LANG, ls);
+ FcLangSetDestroy(ls);
+ }
+
+ const char *stylehint = getFcFamilyForStyleHint(styleHint);
+ if (stylehint) {
+ value.u.s = (const FcChar8 *)stylehint;
+ FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
+ }
+
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ FcConfigSubstitute(0, pattern, FcMatchFont);
+
+ FcResult result = FcResultMatch;
+ FcFontSet *fontSet = FcFontSort(0,pattern,FcFalse,0,&result);
+
+ if (fontSet && result == FcResultMatch)
+ {
+ for (int i = 0; i < fontSet->nfont; i++) {
+ FcChar8 *value = 0;
+ if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
+ continue;
+ // capitalize(value);
+ QString familyName = QString::fromUtf8((const char *)value);
+ if (!fallbackFamilies.contains(familyName,Qt::CaseInsensitive)) {
+ fallbackFamilies << familyName;
+ }
+
+ }
+ }
+// qDebug() << "fallbackFamilies for:" << family << fallbackFamilies;
+
+ return fallbackFamilies;
+}
diff --git a/src/plugins/platforms/minimal/qfontconfigdatabase.h b/src/plugins/platforms/minimal/qfontconfigdatabase.h
new file mode 100644
index 0000000..61700e3
--- /dev/null
+++ b/src/plugins/platforms/minimal/qfontconfigdatabase.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFONTCONFIGDATABASE_H
+#define QFONTCONFIGDATABASE_H
+
+#include <QPlatformFontDatabase>
+#include "qbasicunixfontdatabase.h"
+
+class QFontconfigDatabase : public QBasicUnixFontDatabase
+{
+public:
+ void populateFontDatabase();
+ QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle);
+ QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const;
+};
+
+#endif // QFONTCONFIGDATABASE_H
diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp
index b9ab528..b6028ff 100644
--- a/src/plugins/platforms/minimal/qminimalintegration.cpp
+++ b/src/plugins/platforms/minimal/qminimalintegration.cpp
@@ -41,11 +41,22 @@
#include "qminimalintegration.h"
#include "qminimalwindowsurface.h"
+#include "qfontconfigdatabase.h"
#include <QtGui/private/qpixmap_raster_p.h>
#include <QtGui/QPlatformWindow>
+
+QSize QMinimalScreen::physicalSize() const
+{
+ static const int dpi = 85;
+ int width = geometry().width() / dpi * qreal(25.4) ;
+ int height = geometry().height() / dpi * qreal(25.4) ;
+ return QSize(width,height);
+}
+
QMinimalIntegration::QMinimalIntegration()
+ : mFontDb(new QFontconfigDatabase())
{
QMinimalScreen *mPrimaryScreen = new QMinimalScreen();
@@ -56,6 +67,11 @@ QMinimalIntegration::QMinimalIntegration()
mScreens.append(mPrimaryScreen);
}
+QPlatformFontDatabase *QMinimalIntegration::fontDatabase() const
+{
+ return mFontDb;
+}
+
bool QMinimalIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
diff --git a/src/plugins/platforms/minimal/qminimalintegration.h b/src/plugins/platforms/minimal/qminimalintegration.h
index d1fcc42..13dd8a4 100644
--- a/src/plugins/platforms/minimal/qminimalintegration.h
+++ b/src/plugins/platforms/minimal/qminimalintegration.h
@@ -47,6 +47,8 @@
QT_BEGIN_NAMESPACE
+class QPlatformFontDatabase;
+
class QMinimalScreen : public QPlatformScreen
{
public:
@@ -56,6 +58,7 @@ public:
QRect geometry() const { return mGeometry; }
int depth() const { return mDepth; }
QImage::Format format() const { return mFormat; }
+ QSize physicalSize() const;
public:
QRect mGeometry;
@@ -74,11 +77,14 @@ public:
QPixmapData *createPixmapData(QPixmapData::PixelType type) const;
QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const;
QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const;
+
+ QPlatformFontDatabase *fontDatabase() const;
QList<QPlatformScreen *> screens() const { return mScreens; }
private:
QList<QPlatformScreen *> mScreens;
+ QPlatformFontDatabase *mFontDb;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/minimal/qminimalwindowsurface.cpp b/src/plugins/platforms/minimal/qminimalwindowsurface.cpp
index 91c68d1..c24fbaf 100644
--- a/src/plugins/platforms/minimal/qminimalwindowsurface.cpp
+++ b/src/plugins/platforms/minimal/qminimalwindowsurface.cpp
@@ -68,10 +68,12 @@ void QMinimalWindowSurface::flush(QWidget *widget, const QRegion &region, const
Q_UNUSED(region);
Q_UNUSED(offset);
+/* Don't save to a temporary file
static int c = 0;
QString filename = QString("output%1.png").arg(c++, 4, 10, QLatin1Char('0'));
qDebug() << "QMinimalWindowSurface::flush() saving contents to" << filename.toLocal8Bit().constData();
mImage.save(filename);
+*/
}
void QMinimalWindowSurface::resize(const QSize &size)
diff --git a/src/svg/qsvggenerator.cpp b/src/svg/qsvggenerator.cpp
index 746e2b3..ba23360 100644
--- a/src/svg/qsvggenerator.cpp
+++ b/src/svg/qsvggenerator.cpp
@@ -103,6 +103,7 @@ public:
afterFirstUpdate = false;
numGradients = 0;
+ clip = false;
}
QSize size;
@@ -129,6 +130,9 @@ public:
QString currentGradientName;
int numGradients;
+ QString stateString;
+ QString oldStateString;
+ bool clip;
struct _attributes {
QString document_title;
@@ -141,6 +145,18 @@ public:
QString dashPattern, dashOffset;
QString fill, fillOpacity;
} attributes;
+
+ void emitState() {
+ if (stateString == oldStateString) return;
+
+ // close old state and start a new one...
+ if (afterFirstUpdate)
+ *stream << "</g>\n\n";
+
+ *stream << stateString;
+ afterFirstUpdate = true;
+ oldStateString = stateString;
+ }
};
static inline QPaintEngine::PaintEngineFeatures svgEngineFeatures()
@@ -322,7 +338,7 @@ public:
}
- void qpenToSvg(const QPen &spen)
+ void qpenToSvg(const QPen &spen, QTextStream & s)
{
QString width;
@@ -330,7 +346,7 @@ public:
switch (spen.style()) {
case Qt::NoPen:
- stream() << QLatin1String("stroke=\"none\" ");
+ s << QLatin1String("stroke=\"none\" ");
d_func()->attributes.stroke = QLatin1String("none");
d_func()->attributes.strokeOpacity = QString();
@@ -344,8 +360,8 @@ public:
d_func()->attributes.stroke = color;
d_func()->attributes.strokeOpacity = colorOpacity;
- stream() << QLatin1String("stroke=\"")<<color<< QLatin1String("\" ");
- stream() << QLatin1String("stroke-opacity=\"")<<colorOpacity<< QLatin1String("\" ");
+ s << QLatin1String("stroke=\"")<<color<< QLatin1String("\" ");
+ s << QLatin1String("stroke-opacity=\"")<<colorOpacity<< QLatin1String("\" ");
}
break;
case Qt::DashLine:
@@ -368,10 +384,10 @@ public:
d_func()->attributes.dashPattern = dashPattern;
d_func()->attributes.dashOffset = dashOffset;
- stream() << QLatin1String("stroke=\"")<<color<< QLatin1String("\" ");
- stream() << QLatin1String("stroke-opacity=\"")<<colorOpacity<< QLatin1String("\" ");
- stream() << QLatin1String("stroke-dasharray=\"")<<dashPattern<< QLatin1String("\" ");
- stream() << QLatin1String("stroke-dashoffset=\"")<<dashOffset<< QLatin1String("\" ");
+ s << QLatin1String("stroke=\"")<<color<< QLatin1String("\" ");
+ s << QLatin1String("stroke-opacity=\"")<<colorOpacity<< QLatin1String("\" ");
+ s << QLatin1String("stroke-dasharray=\"")<<dashPattern<< QLatin1String("\" ");
+ s << QLatin1String("stroke-dashoffset=\"")<<dashOffset<< QLatin1String("\" ");
break;
}
default:
@@ -380,50 +396,50 @@ public:
}
if (spen.widthF() == 0)
- stream() <<"stroke-width=\"1\" ";
+ s <<"stroke-width=\"1\" ";
else
- stream() <<"stroke-width=\"" << spen.widthF() << "\" ";
+ s <<"stroke-width=\"" << spen.widthF() << "\" ";
switch (spen.capStyle()) {
case Qt::FlatCap:
- stream() << "stroke-linecap=\"butt\" ";
+ s << "stroke-linecap=\"butt\" ";
break;
case Qt::SquareCap:
- stream() << "stroke-linecap=\"square\" ";
+ s << "stroke-linecap=\"square\" ";
break;
case Qt::RoundCap:
- stream() << "stroke-linecap=\"round\" ";
+ s << "stroke-linecap=\"round\" ";
break;
default:
qWarning("Unhandled cap style");
}
switch (spen.joinStyle()) {
case Qt::MiterJoin:
- stream() << "stroke-linejoin=\"miter\" "
+ s << "stroke-linejoin=\"miter\" "
"stroke-miterlimit=\""<<spen.miterLimit()<<"\" ";
break;
case Qt::BevelJoin:
- stream() << "stroke-linejoin=\"bevel\" ";
+ s << "stroke-linejoin=\"bevel\" ";
break;
case Qt::RoundJoin:
- stream() << "stroke-linejoin=\"round\" ";
+ s << "stroke-linejoin=\"round\" ";
break;
case Qt::SvgMiterJoin:
- stream() << "stroke-linejoin=\"miter\" "
+ s << "stroke-linejoin=\"miter\" "
"stroke-miterlimit=\""<<spen.miterLimit()<<"\" ";
break;
default:
qWarning("Unhandled join style");
}
}
- void qbrushToSvg(const QBrush &sbrush)
+ void qbrushToSvg(const QBrush &sbrush, QTextStream & s)
{
d_func()->brush = sbrush;
switch (sbrush.style()) {
case Qt::SolidPattern: {
QString color, colorOpacity;
translate_color(sbrush.color(), &color, &colorOpacity);
- stream() << "fill=\"" << color << "\" "
+ s << "fill=\"" << color << "\" "
"fill-opacity=\""
<< colorOpacity << "\" ";
d_func()->attributes.fill = color;
@@ -434,22 +450,22 @@ public:
saveLinearGradientBrush(sbrush.gradient());
d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName);
d_func()->attributes.fillOpacity = QString();
- stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" ");
+ s << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" ");
break;
case Qt::RadialGradientPattern:
saveRadialGradientBrush(sbrush.gradient());
d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName);
d_func()->attributes.fillOpacity = QString();
- stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" ");
+ s << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" ");
break;
case Qt::ConicalGradientPattern:
saveConicalGradientBrush(sbrush.gradient());
d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName);
d_func()->attributes.fillOpacity = QString();
- stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" ");
+ s << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" ");
break;
case Qt::NoBrush:
- stream() << QLatin1String("fill=\"none\" ");
+ s << QLatin1String("fill=\"none\" ");
d_func()->attributes.fill = QLatin1String("none");
d_func()->attributes.fillOpacity = QString();
return;
@@ -458,7 +474,7 @@ public:
break;
}
}
- void qfontToSvg(const QFont &sfont)
+ void qfontToSvg(const QFont &sfont, QTextStream & s)
{
Q_D(QSvgPaintEngine);
@@ -488,12 +504,23 @@ public:
d->attributes.font_family = d->font.family();
d->attributes.font_style = d->font.italic() ? QLatin1String("italic") : QLatin1String("normal");
- *d->stream << "font-family=\"" << d->attributes.font_family << "\" "
- "font-size=\"" << d->attributes.font_size << "\" "
- "font-weight=\"" << d->attributes.font_weight << "\" "
- "font-style=\"" << d->attributes.font_style << "\" "
- << endl;
+ s << "font-family=\"" << d->attributes.font_family << "\" "
+ "font-size=\"" << d->attributes.font_size << "\" "
+ "font-weight=\"" << d->attributes.font_weight << "\" "
+ "font-style=\"" << d->attributes.font_style << "\" "
+ << endl;
+ }
+
+ void setViewBoxClip(bool clip) {
+ Q_D(QSvgPaintEngine);
+ d->clip = clip;
}
+
+ bool viewBoxClip() const {
+ Q_D(const QSvgPaintEngine);
+ return d->clip;
+ }
+
};
class QSvgGeneratorPrivate
@@ -808,6 +835,27 @@ int QSvgGenerator::metric(QPaintDevice::PaintDeviceMetric metric) const
return 0;
}
+/*!
+ \property QSvgGenerator::resolution
+ \brief do not draw objects outside the viewBox
+ \since 4.7
+
+ When specified objects drawn compleatly outsite the viewBox
+ are not include in the output SVG.
+
+ \sa viewBox
+*/
+
+bool QSvgGenerator::viewBoxClip() const {
+ Q_D(const QSvgGenerator);
+ return d->engine->viewBoxClip();
+}
+
+void QSvgGenerator::setViewBoxClip(bool clip) {
+ Q_D(QSvgGenerator);
+ d->engine->setViewBoxClip(clip);
+}
+
/*****************************************************************************
* class QSvgPaintEngine
*/
@@ -908,10 +956,13 @@ void QSvgPaintEngine::drawImage(const QRectF &r, const QImage &image,
const QRectF &sr,
Qt::ImageConversionFlag flags)
{
- //Q_D(QSvgPaintEngine);
+ Q_D(QSvgPaintEngine);
Q_UNUSED(sr);
Q_UNUSED(flags);
+ if (d->clip && !d->matrix.mapRect(r).intersects(d->viewBox)) return;
+ d->emitState();
+
stream() << "<image ";
stream() << "x=\""<<r.x()<<"\" "
"y=\""<<r.y()<<"\" "
@@ -932,53 +983,35 @@ void QSvgPaintEngine::drawImage(const QRectF &r, const QImage &image,
void QSvgPaintEngine::updateState(const QPaintEngineState &state)
{
Q_D(QSvgPaintEngine);
- QPaintEngine::DirtyFlags flags = state.state();
-
- // always stream full gstate, which is not required, but...
- flags |= QPaintEngine::AllDirty;
-
- // close old state and start a new one...
- if (d->afterFirstUpdate)
- *d->stream << "</g>\n\n";
-
- *d->stream << "<g ";
- if (flags & QPaintEngine::DirtyBrush) {
- qbrushToSvg(state.brush());
- }
-
- if (flags & QPaintEngine::DirtyPen) {
- qpenToSvg(state.pen());
- }
-
- if (flags & QPaintEngine::DirtyTransform) {
- d->matrix = state.matrix();
- *d->stream << "transform=\"matrix(" << d->matrix.m11() << ','
- << d->matrix.m12() << ','
- << d->matrix.m21() << ',' << d->matrix.m22() << ','
- << d->matrix.dx() << ',' << d->matrix.dy()
- << ")\""
- << endl;
- }
-
- if (flags & QPaintEngine::DirtyFont) {
- qfontToSvg(state.font());
- }
-
- if (flags & QPaintEngine::DirtyOpacity) {
- if (!qFuzzyIsNull(state.opacity() - 1))
- stream() << "opacity=\""<<state.opacity()<<"\" ";
- }
-
- *d->stream << '>' << endl;
-
- d->afterFirstUpdate = true;
+ d->stateString="";
+ QTextStream stateStream(&d->stateString);
+ stateStream << "<g ";
+ qbrushToSvg(state.brush(), stateStream);
+ qpenToSvg(state.pen(), stateStream);
+
+ d->matrix = state.matrix();
+ stateStream << "transform=\"matrix(" << d->matrix.m11() << ','
+ << d->matrix.m12() << ','
+ << d->matrix.m21() << ',' << d->matrix.m22() << ','
+ << d->matrix.dx() << ',' << d->matrix.dy()
+ << ")\""
+ << endl;
+ qfontToSvg(state.font(), stateStream);
+
+ if (!qFuzzyIsNull(state.opacity() - 1))
+ stateStream << "opacity=\""<<state.opacity()<<"\" ";
+
+ stateStream << '>' << endl;
}
void QSvgPaintEngine::drawPath(const QPainterPath &p)
{
Q_D(QSvgPaintEngine);
+ if (d->clip && !d->matrix.mapRect(p.boundingRect()).intersects(d->viewBox)) return;
+ d->emitState();
+
*d->stream << "<path vector-effect=\""
<< (state->pen().isCosmetic() ? "non-scaling-stroke" : "none")
<< "\" fill-rule=\""
@@ -1024,12 +1057,15 @@ void QSvgPaintEngine::drawPolygon(const QPointF *points, int pointCount,
{
Q_ASSERT(pointCount >= 2);
- //Q_D(QSvgPaintEngine);
+ Q_D(QSvgPaintEngine);
QPainterPath path(points[0]);
for (int i=1; i<pointCount; ++i)
path.lineTo(points[i]);
+ if (d->clip && !d->matrix.mapRect(path.boundingRect()).intersects(d->viewBox)) return;
+ d->emitState();
+
if (mode == PolylineMode) {
stream() << "<polyline fill=\"none\" vector-effect=\""
<< (state->pen().isCosmetic() ? "non-scaling-stroke" : "none")
@@ -1051,6 +1087,12 @@ void QSvgPaintEngine::drawTextItem(const QPointF &pt, const QTextItem &textItem)
if (d->pen.style() == Qt::NoPen)
return;
+ if (d->clip) {
+ QRectF b=painter()->boundingRect( QRectF(pt, QSize()) , Qt::AlignLeft, textItem.text());
+ if (!d->matrix.mapRect(b).intersects(d->viewBox)) return;
+ }
+ d->emitState();
+
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
QString s = QString::fromRawData(ti.chars, ti.num_chars);
@@ -1060,7 +1102,7 @@ void QSvgPaintEngine::drawTextItem(const QPointF &pt, const QTextItem &textItem)
"stroke=\"none\" "
"xml:space=\"preserve\" "
"x=\"" << pt.x() << "\" y=\"" << pt.y() << "\" ";
- qfontToSvg(textItem.font());
+ qfontToSvg(textItem.font(), *d->stream);
*d->stream << " >"
<< Qt::escape(s)
<< "</text>"
diff --git a/src/svg/qsvggenerator.h b/src/svg/qsvggenerator.h
index dd51235..b207552 100644
--- a/src/svg/qsvggenerator.h
+++ b/src/svg/qsvggenerator.h
@@ -96,6 +96,9 @@ public:
void setResolution(int dpi);
int resolution() const;
+
+ void setViewBoxClip(bool clip);
+ bool viewBoxClip() const;
protected:
QPaintEngine *paintEngine() const;
int metric(QPaintDevice::PaintDeviceMetric metric) const;