git clone git://gitorious.org/~antialize/qt/antializes-qt.git, then checkout 4.8.4 # check 4.8.4 commit ID on git://gitorious.org/qt/qt.git git diff 96311def2466dd44de64d77a1c815b22fbf68f71 # parts related to static QtWebkit build are disabled #diff --git a/configure b/configure #index e3d464b..114933e 100755 #--- a/configure #+++ b/configure #@@ -7749,12 +7749,12 @@ if [ "$CFG_GUI" = "no" ]; then # canBuildWebKit="no" # fi # #-if [ "$CFG_SHARED" = "no" ]; then #- echo #- echo "WARNING: Using static linking will disable the WebKit module." #- echo #- canBuildWebKit="no" #-fi #+#if [ "$CFG_SHARED" = "no" ]; then #+ # echo #+ # echo "WARNING: Using static linking will disable the WebKit module." #+ # echo #+ # canBuildWebKit="no" #+#fi # # CFG_CONCURRENT="yes" # if [ "$canBuildQtConcurrent" = "no" ]; then #diff --git a/src/3rdparty/webkit/Source/JavaScriptCore/JavaScriptCore.pro b/src/3rdparty/webkit/Source/JavaScriptCore/JavaScriptCore.pro #index a109179..146cb2d 100644 #--- a/src/3rdparty/webkit/Source/JavaScriptCore/JavaScriptCore.pro #+++ b/src/3rdparty/webkit/Source/JavaScriptCore/JavaScriptCore.pro #@@ -217,6 +217,12 @@ symbian: { # QMAKE_CXXFLAGS.ARMCC += -OTime -O3 # } # #+static { #+ !isEmpty(INSTALL_LIBS): target.path = $$INSTALL_LIBS #+ else: target.path = $$[QT_INSTALL_LIBS] #+ INSTALLS += target #+} #+ # lessThan(QT_GCC_MAJOR_VERSION, 5) { # # GCC 4.5 and before # lessThan(QT_GCC_MINOR_VERSION, 6) { diff --git a/src/3rdparty/webkit/Source/WebCore/page/FrameView.cpp b/src/3rdparty/webkit/Source/WebCore/page/FrameView.cpp index ef72fb7..54ff69c 100644 --- a/src/3rdparty/webkit/Source/WebCore/page/FrameView.cpp +++ b/src/3rdparty/webkit/Source/WebCore/page/FrameView.cpp @@ -1080,7 +1080,9 @@ void FrameView::adjustMediaTypeForPrinting(bool printing) if (printing) { if (m_mediaTypeWhenNotPrinting.isNull()) m_mediaTypeWhenNotPrinting = mediaType(); - setMediaType("print"); + + String mediaType = (m_frame && m_frame->settings())?m_frame->settings()->printingMediaType():"print"; + setMediaType(mediaType); } else { if (!m_mediaTypeWhenNotPrinting.isNull()) setMediaType(m_mediaTypeWhenNotPrinting); diff --git a/src/3rdparty/webkit/Source/WebCore/page/PrintContext.cpp b/src/3rdparty/webkit/Source/WebCore/page/PrintContext.cpp index 660ad11..8dffd52 100644 --- a/src/3rdparty/webkit/Source/WebCore/page/PrintContext.cpp +++ b/src/3rdparty/webkit/Source/WebCore/page/PrintContext.cpp @@ -26,6 +26,7 @@ #include "FrameView.h" #include "RenderLayer.h" #include "RenderView.h" +#include "Settings.h" #include namespace WebCore { @@ -182,11 +183,21 @@ void PrintContext::begin(float width, float height) // This function can be called multiple times to adjust printing parameters without going back to screen mode. m_isPrinting = true; - float minLayoutWidth = width * printingMinimumShrinkFactor; - float minLayoutHeight = height * printingMinimumShrinkFactor; + float minimumShrinkFactor = m_frame->settings() ? + m_frame->settings()->printingMinimumShrinkFactor() : 0.0f; + float maximumShrinkFactor = m_frame->settings() ? + m_frame->settings()->printingMaximumShrinkFactor() : 0.0f; + + if (maximumShrinkFactor < minimumShrinkFactor || minimumShrinkFactor <= 0.0f) { + minimumShrinkFactor = printingMinimumShrinkFactor; + maximumShrinkFactor = printingMaximumShrinkFactor; + } + + float minLayoutWidth = width * minimumShrinkFactor; + float minLayoutHeight = height * minimumShrinkFactor; // This changes layout, so callers need to make sure that they don't paint to screen while in printing mode. - m_frame->setPrinting(true, FloatSize(minLayoutWidth, minLayoutHeight), printingMaximumShrinkFactor / printingMinimumShrinkFactor, Frame::AdjustViewSize); + m_frame->setPrinting(true, FloatSize(minLayoutWidth, minLayoutHeight), maximumShrinkFactor / minimumShrinkFactor, Frame::AdjustViewSize); } float PrintContext::computeAutomaticScaleFactor(const FloatSize& availablePaperSize) diff --git a/src/3rdparty/webkit/Source/WebCore/page/PrintContext.h b/src/3rdparty/webkit/Source/WebCore/page/PrintContext.h index aadff47..19f378e 100644 --- a/src/3rdparty/webkit/Source/WebCore/page/PrintContext.h +++ b/src/3rdparty/webkit/Source/WebCore/page/PrintContext.h @@ -83,6 +83,8 @@ public: // (pageSizeInPixels.height() + 1) * number-of-pages - 1 static void spoolAllPagesWithBoundaries(Frame*, GraphicsContext&, const FloatSize& pageSizeInPixels); +public: + const Vector & getPageRects() const {return m_pageRects;} protected: Frame* m_frame; Vector m_pageRects; diff --git a/src/3rdparty/webkit/Source/WebCore/page/Settings.cpp b/src/3rdparty/webkit/Source/WebCore/page/Settings.cpp index 2025bd0..5414246 100644 --- a/src/3rdparty/webkit/Source/WebCore/page/Settings.cpp +++ b/src/3rdparty/webkit/Source/WebCore/page/Settings.cpp @@ -87,6 +87,7 @@ static EditingBehaviorType editingBehaviorTypeForPlatform() Settings::Settings(Page* page) : m_page(page) + , m_printingMediaType("print") , m_editableLinkBehavior(EditableLinkDefaultBehavior) , m_textDirectionSubmenuInclusionBehavior(TextDirectionSubmenuAutomaticallyIncluded) , m_passwordEchoDurationInSeconds(1) @@ -184,6 +185,8 @@ Settings::Settings(Page* page) , m_allowDisplayOfInsecureContent(true) , m_allowRunningOfInsecureContent(true) , m_passwordEchoEnabled(false) + , m_printingMinimumShrinkFactor(0.0) + , m_printingMaximumShrinkFactor(0.0) { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. @@ -569,6 +572,11 @@ void Settings::setApplicationChromeMode(bool mode) m_inApplicationChromeMode = mode; } +void Settings::setPrintingMediaType(const String& type) +{ + m_printingMediaType = type; +} + void Settings::setOfflineWebApplicationCacheEnabled(bool enabled) { m_offlineWebApplicationCacheEnabled = enabled; @@ -744,4 +752,15 @@ void Settings::setTiledBackingStoreEnabled(bool enabled) #endif } +void Settings::setPrintingMinimumShrinkFactor(float printingMinimumShrinkFactor) +{ + m_printingMinimumShrinkFactor = printingMinimumShrinkFactor; +} + +void Settings::setPrintingMaximumShrinkFactor(float printingMaximumShrinkFactor) +{ + m_printingMaximumShrinkFactor = printingMaximumShrinkFactor; +} + + } // namespace WebCore diff --git a/src/3rdparty/webkit/Source/WebCore/page/Settings.h b/src/3rdparty/webkit/Source/WebCore/page/Settings.h index 1d2a138..d827693 100644 --- a/src/3rdparty/webkit/Source/WebCore/page/Settings.h +++ b/src/3rdparty/webkit/Source/WebCore/page/Settings.h @@ -258,6 +258,9 @@ namespace WebCore { void setApplicationChromeMode(bool); bool inApplicationChromeMode() const { return m_inApplicationChromeMode; } + void setPrintingMediaType(const String&); + const String& printingMediaType() const { return m_printingMediaType; } + void setOfflineWebApplicationCacheEnabled(bool); bool offlineWebApplicationCacheEnabled() const { return m_offlineWebApplicationCacheEnabled; } @@ -349,6 +352,12 @@ namespace WebCore { void setTiledBackingStoreEnabled(bool); bool tiledBackingStoreEnabled() const { return m_tiledBackingStoreEnabled; } + + void setPrintingMinimumShrinkFactor(float); + float printingMinimumShrinkFactor() const { return m_printingMinimumShrinkFactor; } + + void setPrintingMaximumShrinkFactor(float); + float printingMaximumShrinkFactor() const { return m_printingMaximumShrinkFactor; } void setPaginateDuringLayoutEnabled(bool flag) { m_paginateDuringLayoutEnabled = flag; } bool paginateDuringLayoutEnabled() const { return m_paginateDuringLayoutEnabled; } @@ -419,6 +428,7 @@ namespace WebCore { String m_defaultTextEncodingName; String m_ftpDirectoryTemplatePath; String m_localStorageDatabasePath; + String m_printingMediaType; KURL m_userStyleSheetLocation; AtomicString m_standardFontFamily; AtomicString m_fixedFontFamily; @@ -429,6 +439,8 @@ namespace WebCore { EditableLinkBehavior m_editableLinkBehavior; TextDirectionSubmenuInclusionBehavior m_textDirectionSubmenuInclusionBehavior; double m_passwordEchoDurationInSeconds; + float m_printingMinimumShrinkFactor; + float m_printingMaximumShrinkFactor; int m_minimumFontSize; int m_minimumLogicalFontSize; int m_defaultFontSize; diff --git a/src/3rdparty/webkit/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/src/3rdparty/webkit/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp index c348870..4069687 100644 --- a/src/3rdparty/webkit/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp +++ b/src/3rdparty/webkit/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp @@ -73,7 +73,8 @@ FontPlatformData::FontPlatformData(const FontDescription& description, const Ato font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); const bool smallCaps = description.smallCaps(); font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); - font.setStyleStrategy(QFont::ForceIntegerMetrics); + // Commented out to work around webkit bug 93263 + //font.setStyleStrategy(QFont::ForceIntegerMetrics); m_data->bold = font.bold(); // WebKit allows font size zero but QFont does not. We will return diff --git a/src/3rdparty/webkit/Source/WebCore/platform/graphics/qt/ImageQt.cpp b/src/3rdparty/webkit/Source/WebCore/platform/graphics/qt/ImageQt.cpp index 0c8ce9e..5ba54d0 100644 --- a/src/3rdparty/webkit/Source/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/src/3rdparty/webkit/Source/WebCore/platform/graphics/qt/ImageQt.cpp @@ -41,6 +41,7 @@ #include "PlatformString.h" #include "StillImageQt.h" #include "qwebsettings.h" +#include "SharedBuffer.h" #include #include @@ -234,7 +235,8 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, } } - ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc); + QByteArray a = QByteArray::fromRawData(data()->data(), data()->size()); + ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc, &a); ctxt->setCompositeOperation(previousOperator); diff --git a/src/3rdparty/webkit/Source/WebCore/platform/qt/PlatformScreenQt.cpp b/src/3rdparty/webkit/Source/WebCore/platform/qt/PlatformScreenQt.cpp index 4db8bd1..0f405cb 100644 --- a/src/3rdparty/webkit/Source/WebCore/platform/qt/PlatformScreenQt.cpp +++ b/src/3rdparty/webkit/Source/WebCore/platform/qt/PlatformScreenQt.cpp @@ -53,11 +53,17 @@ static int screenNumber(Widget* w) int screenDepth(Widget* w) { + if (QApplication::type() == QApplication::Tty) + return 32; + return QApplication::desktop()->screen(screenNumber(w))->depth(); } int screenDepthPerComponent(Widget* w) { + if (QApplication::type() == QApplication::Tty) + return 8; + int depth = QApplication::desktop()->screen(0)->depth(); if (w) { QWebPageClient* client = w->root()->hostWindow()->platformPageClient(); @@ -86,17 +92,26 @@ int screenDepthPerComponent(Widget* w) bool screenIsMonochrome(Widget* w) { + if (QApplication::type() == QApplication::Tty) + return false; + return QApplication::desktop()->screen(screenNumber(w))->colorCount() == 2; } FloatRect screenRect(Widget* w) { + if (QApplication::type() == QApplication::Tty) + return FloatRect(0,0,800,600); + QRect r = QApplication::desktop()->screenGeometry(screenNumber(w)); return FloatRect(r.x(), r.y(), r.width(), r.height()); } FloatRect screenAvailableRect(Widget* w) { + if (QApplication::type() == QApplication::Tty) + return FloatRect(0,0,800,600); + QRect r = QApplication::desktop()->availableGeometry(screenNumber(w)); return FloatRect(r.x(), r.y(), r.width(), r.height()); } diff --git a/src/3rdparty/webkit/Source/WebCore/platform/qt/RenderThemeQt.cpp b/src/3rdparty/webkit/Source/WebCore/platform/qt/RenderThemeQt.cpp index f98df88..b1fe30d 100644 --- a/src/3rdparty/webkit/Source/WebCore/platform/qt/RenderThemeQt.cpp +++ b/src/3rdparty/webkit/Source/WebCore/platform/qt/RenderThemeQt.cpp @@ -178,7 +178,13 @@ RenderThemeQt::RenderThemeQt(Page* page) : RenderTheme() , m_page(page) , m_lineEdit(0) + , m_fallbackStyle(0) { + if (QApplication::type() == QApplication::Tty) { + m_buttonFontFamily = "sans-serif"; + return; + } + QPushButton button; button.setAttribute(Qt::WA_MacSmallSize); QFont defaultButtonFont = QApplication::font(&button); @@ -339,6 +345,9 @@ bool RenderThemeQt::supportsControlTints() const int RenderThemeQt::findFrameLineWidth(QStyle* style) const { + if (QApplication::type()==QApplication::Tty) + return 1; + #ifndef QT_NO_LINEEDIT if (!m_lineEdit) m_lineEdit = new QLineEdit(); @@ -445,6 +454,9 @@ Color RenderThemeQt::systemColor(int cssValueId) const int RenderThemeQt::minimumMenuListSize(RenderStyle*) const { + if (QApplication::type() == QApplication::Tty) + return 1; + const QFontMetrics &fm = QApplication::fontMetrics(); return fm.width(QLatin1Char('x')); } diff --git a/src/3rdparty/webkit/Source/WebCore/platform/qt/ScreenQt.cpp b/src/3rdparty/webkit/Source/WebCore/platform/qt/ScreenQt.cpp index d648c53..f844d54 100644 --- a/src/3rdparty/webkit/Source/WebCore/platform/qt/ScreenQt.cpp +++ b/src/3rdparty/webkit/Source/WebCore/platform/qt/ScreenQt.cpp @@ -54,6 +54,9 @@ static QWidget* qwidgetForPage(const Page* page) FloatRect screenRect(const Page* page) { + if (QApplication::type() == QApplication::Tty) + return FloatRect(0,0,800,600); + QWidget* qw = qwidgetForPage(page); if (!qw) return FloatRect(); @@ -68,6 +71,9 @@ FloatRect screenRect(const Page* page) int screenDepth(const Page* page) { + if (QApplication::type() == QApplication::Tty) + return 32; + QWidget* qw = qwidgetForPage(page); if (!qw) return 32; @@ -77,6 +83,9 @@ int screenDepth(const Page* page) FloatRect usableScreenRect(const Page* page) { + if (QApplication::type() == QApplication::Tty) + return FloatRect(); + QWidget* qw = qwidgetForPage(page); if (!qw) return FloatRect(); diff --git a/src/3rdparty/webkit/Source/WebCore/platform/qt/WidgetQt.cpp b/src/3rdparty/webkit/Source/WebCore/platform/qt/WidgetQt.cpp index 5215e66..e033279 100644 --- a/src/3rdparty/webkit/Source/WebCore/platform/qt/WidgetQt.cpp +++ b/src/3rdparty/webkit/Source/WebCore/platform/qt/WidgetQt.cpp @@ -41,6 +41,7 @@ #include "QWebPageClient.h" #include "ScrollView.h" +#include #include #include #include @@ -78,6 +79,9 @@ void Widget::setFocus(bool focused) void Widget::setCursor(const Cursor& cursor) { #ifndef QT_NO_CURSOR + if (QApplication::type() == QApplication::Tty) + return; + ScrollView* view = root(); if (!view) return; diff --git a/src/3rdparty/webkit/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/src/3rdparty/webkit/Source/WebCore/rendering/RenderBlockLineLayout.cpp index 2e92801..1690c2f 100644 --- a/src/3rdparty/webkit/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/src/3rdparty/webkit/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -956,7 +956,8 @@ void RenderBlock::layoutRunsAndFloats(bool fullLayout, bool hasInlineChild, Vect repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow()); } - if (paginated) { + // table cell pagination is handled in RenderTableSection + if (paginated && !isTableCell()) { int adjustment = 0; adjustLinePositionForPagination(lineBox, adjustment); if (adjustment) { diff --git a/src/3rdparty/webkit/Source/WebCore/rendering/RenderBox.cpp b/src/3rdparty/webkit/Source/WebCore/rendering/RenderBox.cpp index f052ee7..a5afea5 100644 --- a/src/3rdparty/webkit/Source/WebCore/rendering/RenderBox.cpp +++ b/src/3rdparty/webkit/Source/WebCore/rendering/RenderBox.cpp @@ -804,7 +804,8 @@ void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo) // The background of the box generated by the root element covers the entire canvas, so just use // the RenderView's docTop/Left/Width/Height accessors. - paintFillLayers(paintInfo, bgColor, bgLayer, view()->docLeft(), view()->docTop(), view()->docWidth(), view()->docHeight(), BackgroundBleedNone, CompositeSourceOver, bodyObject); + if (bgColor.rgb() != Color::white) + paintFillLayers(paintInfo, bgColor, bgLayer, view()->docLeft(), view()->docTop(), view()->docWidth(), view()->docHeight(), BackgroundBleedNone, CompositeSourceOver, bodyObject); } void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) diff --git a/src/3rdparty/webkit/Source/WebCore/rendering/RenderTable.cpp b/src/3rdparty/webkit/Source/WebCore/rendering/RenderTable.cpp index 73b0801..c34b1c2 100644 --- a/src/3rdparty/webkit/Source/WebCore/rendering/RenderTable.cpp +++ b/src/3rdparty/webkit/Source/WebCore/rendering/RenderTable.cpp @@ -302,11 +302,20 @@ void RenderTable::layout() bool collapsing = collapseBorders(); + // repeat header and footer on each page + int headHeight = 0; + int footHeight = 0; for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableSection()) { child->layoutIfNeeded(); RenderTableSection* section = toRenderTableSection(child); - totalSectionLogicalHeight += section->calcRowLogicalHeight(); + int rowHeight = section->calcRowLogicalHeight(); + if (child == m_head) { + headHeight = rowHeight; + } else if (child == m_foot) { + footHeight = rowHeight; + } + totalSectionLogicalHeight += rowHeight; if (collapsing) section->recalcOuterBorder(); ASSERT(!section->needsLayout()); @@ -320,6 +329,30 @@ void RenderTable::layout() if (m_caption) m_caption->layoutIfNeeded(); + // Bump table to next page if we can't fit the caption, thead and first body cell + setPaginationStrut(0); + if (view()->layoutState()->pageLogicalHeight()) { + LayoutState* layoutState = view()->layoutState(); + const int pageLogicalHeight = layoutState->m_pageLogicalHeight; + const int remainingLogicalHeight = pageLogicalHeight - layoutState->pageLogicalOffset(0) % pageLogicalHeight; + if (remainingLogicalHeight > 0) { + int requiredHeight = headHeight; + if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) { + requiredHeight += m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter(); + } + if (m_firstBody) { + // FIXME: Calculate maximum required height across all cells in first body row + RenderTableCell* firstCell = m_firstBody->primaryCellAt(0, 0); + if (firstCell) { + requiredHeight += firstCell->contentLogicalHeight() + firstCell->paddingTop(false) + firstCell->paddingBottom(false) + vBorderSpacing(); + } + } + if (requiredHeight > remainingLogicalHeight) { + setPaginationStrut(remainingLogicalHeight); + } + } + } + // If any table section moved vertically, we will just repaint everything from that // section down (it is quite unlikely that any of the following sections // did not shift). @@ -352,12 +385,6 @@ void RenderTable::layout() computedLogicalHeight = computePercentageLogicalHeight(logicalHeightLength); computedLogicalHeight = max(0, computedLogicalHeight); - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->isTableSection()) - // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one. - toRenderTableSection(child)->layoutRows(child == m_firstBody ? max(0, computedLogicalHeight - totalSectionLogicalHeight) : 0); - } - if (!m_firstBody && computedLogicalHeight > totalSectionLogicalHeight && !document()->inQuirksMode()) { // Completely empty tables (with no sections or anything) should at least honor specified height // in strict mode. @@ -377,6 +404,9 @@ void RenderTable::layout() } section->setLogicalLocation(sectionLogicalLeft, logicalHeight()); + // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one. + section->layoutRows(section == m_firstBody ? max(0, computedLogicalHeight - totalSectionLogicalHeight) : 0, section == m_head ? 0 : headHeight, section == m_foot ? 0 : footHeight); + setLogicalHeight(logicalHeight() + section->logicalHeight()); section = sectionBelow(section); } @@ -503,7 +533,59 @@ void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty) child->paint(info, childPoint.x(), childPoint.y()); } } - + + bool repaintedHead = false; + IntPoint repaintedHeadPoint; + bool repaintedFoot = false; + IntPoint repaintedFootPoint; + if (view()->pageLogicalHeight()) { + // re-paint header/footer if table is split over multiple pages + if (m_head) { + IntPoint childPoint = flipForWritingMode(m_head, IntPoint(tx, ty), ParentToChildFlippingAdjustment); + if (info.rect.y() > childPoint.y() + m_head->y()) { + repaintedHeadPoint = IntPoint(childPoint.x(), info.rect.y() - m_head->y()); + repaintedHead = true; + dynamic_cast(m_head)->paint(info, repaintedHeadPoint.x(), repaintedHeadPoint.y()); + } + } + if (m_foot) { + IntPoint childPoint = flipForWritingMode(m_foot, IntPoint(tx, ty), ParentToChildFlippingAdjustment); + if (info.rect.y() + info.rect.height() < childPoint.y() + m_foot->y()) { + // find actual end of table on current page + int dy = 0; + const int max_dy = info.rect.y() + info.rect.height(); + const int vspace = vBorderSpacing(); + for (RenderObject* section = firstChild(); section; section = section->nextSibling()) { + if (section->isTableSection()) { + if (toRenderBox(section)->y() > max_dy) { + continue; + } + int i = 0; + for(RenderObject* row = section->firstChild(); row; row = row->nextSibling()) { + if (!row->isTableRow()) { + continue; + } + // get actual bottom-y position of this row - pretty complicated, how could this be simplified? + // note how we have to take the rowPoint and section's y-offset into account, see e.g. + // RenderTableSection::paint where this is also done... + IntPoint rowPoint = flipForWritingMode(toRenderBox(row), IntPoint(tx, ty), ParentToChildFlippingAdjustment); + int row_dy = rowPoint.y() + toRenderBox(row)->y() + toRenderBox(row)->logicalHeight() + toRenderBox(section)->y(); + if (row_dy < max_dy && row_dy > dy) { + dy = row_dy; + } else if (row_dy > max_dy) { + break; + } + i++; + } + } + } + repaintedFoot = true; + repaintedFootPoint = IntPoint(childPoint.x(), dy - m_foot->y()); + dynamic_cast(m_foot)->paint(info, repaintedFootPoint.x(), repaintedFootPoint.y()); + } + } + } + if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) { // Collect all the unique border styles that we want to paint in a sorted list. Once we // have all the styles sorted, we then do individual passes, painting each style of border @@ -522,6 +604,12 @@ void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty) for (RenderObject* child = firstChild(); child; child = child->nextSibling()) if (child->isTableSection()) { IntPoint childPoint = flipForWritingMode(toRenderTableSection(child), IntPoint(tx, ty), ParentToChildFlippingAdjustment); + // also repaint borders of header/footer if required + if (child == m_head && repaintedHead) { + childPoint = repaintedHeadPoint; + } else if (child == m_foot && repaintedFoot) { + childPoint = repaintedFootPoint; + } child->paint(info, childPoint.x(), childPoint.y()); } } diff --git a/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.cpp b/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.cpp index 7d414a0..6c814b3 100644 --- a/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.cpp +++ b/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.cpp @@ -414,7 +414,7 @@ void RenderTableSection::layout() setNeedsLayout(false); } -int RenderTableSection::layoutRows(int toAdd) +int RenderTableSection::layoutRows(int toAdd, int headHeight, int footHeight) { #ifndef NDEBUG setNeedsLayoutIsForbidden(true); @@ -496,12 +496,47 @@ int RenderTableSection::layoutRows(int toAdd) LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), style()->isFlippedBlocksWritingMode()); + // Calculate logical row heights + Vector logicalRowHeights; + logicalRowHeights.resize(totalRows); + for (int r = 0; r < totalRows; r++) { + logicalRowHeights[r] = m_rowPos[r + 1] - m_rowPos[r] - vspacing; + } + + // Make sure that cell contents do not overlap a page break + if (view()->layoutState()->pageLogicalHeight()) { + LayoutState* layoutState = view()->layoutState(); + int pageLogicalHeight = layoutState->m_pageLogicalHeight; + int pageOffset = 0; + + for (int r = 0; r < totalRows; ++r) { + int rowLogicalOffset = m_rowPos[r] + pageOffset; + int remainingLogicalHeight = pageLogicalHeight - layoutState->pageLogicalOffset(rowLogicalOffset) % pageLogicalHeight; + + for (int c = 0; c < nEffCols; c++) { + CellStruct& cs = cellAt(r, c); + RenderTableCell* cell = cs.primaryCell(); + + if (!cell || cs.inColSpan || cell->row() != r) + continue; + + int cellRequiredHeight = cell->contentLogicalHeight() + cell->paddingTop(false) + cell->paddingBottom(false); + if (max(logicalRowHeights[r], cellRequiredHeight) > remainingLogicalHeight - footHeight - vspacing) { + pageOffset += remainingLogicalHeight + headHeight; + break; + } + } + m_rowPos[r] += pageOffset; + } + m_rowPos[totalRows] += pageOffset; + } + for (int r = 0; r < totalRows; r++) { // Set the row's x/y position and width/height. if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) { rowRenderer->setLocation(0, m_rowPos[r]); rowRenderer->setLogicalWidth(logicalWidth()); - rowRenderer->setLogicalHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing); + rowRenderer->setLogicalHeight(logicalRowHeights[r]); rowRenderer->updateLayerTransform(); } @@ -513,7 +548,11 @@ int RenderTableSection::layoutRows(int toAdd) continue; rindx = cell->row(); - rHeight = m_rowPos[rindx + cell->rowSpan()] - m_rowPos[rindx] - vspacing; + if (cell->rowSpan() == 1) { + rHeight = logicalRowHeights[rindx]; + } else { + rHeight = m_rowPos[rindx + cell->rowSpan()] - m_rowPos[rindx] - vspacing; + } // Force percent height children to lay themselves out again. // This will cause these children to grow to fill the cell. diff --git a/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.h b/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.h index db6edc2..9d912a0 100644 --- a/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.h +++ b/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.h @@ -49,7 +49,7 @@ public: void setCellLogicalWidths(); int calcRowLogicalHeight(); - int layoutRows(int logicalHeight); + int layoutRows(int logicalHeight, int headHeight, int footHeight); RenderTable* table() const { return toRenderTable(parent()); } diff --git a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebelement.h b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebelement.h index 4b1a758..2ad7f1f 100644 --- a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebelement.h +++ b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebelement.h @@ -170,6 +170,7 @@ private: friend class QWebHitTestResult; friend class QWebHitTestResultPrivate; friend class QWebPage; + friend class QWebPrinter; #if defined(WTF_USE_V8) && WTF_USE_V8 friend class V8::Bindings::QtWebElementRuntime; diff --git a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe.cpp b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe.cpp index 5ea7059..b0229ed 100644 --- a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe.cpp +++ b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe.cpp @@ -216,6 +216,114 @@ static inline ResourceRequestCachePolicy cacheLoadControlToCachePolicy(uint cach return WebCore::UseProtocolCachePolicy; } +#ifndef QT_NO_PRINTER +QWebPrinterPrivate::QWebPrinterPrivate(const QWebFrame *f, QPaintDevice *printer, QPainter &p) + : printContext(f->d->frame) + , painter(p) + , frame(f) + , graphicsContext(&p) +{ + const qreal zoomFactorX = printer->logicalDpiX() / qt_defaultDpi(); + const qreal zoomFactorY = printer->logicalDpiY() / qt_defaultDpi(); + IntRect pageRect(0, 0, + int(printer->width() / zoomFactorX), + int(printer->height() / zoomFactorY)); + + printContext.begin(pageRect.width(), pageRect.height()); + float pageHeight = 0; + printContext.computePageRects(pageRect, /* headerHeight */ 0, /* footerHeight */ 0, /* userScaleFactor */ 1.0, pageHeight); + + painter.scale(zoomFactorX, zoomFactorY); + printWidth = pageRect.width(); +} + +QWebPrinterPrivate::~QWebPrinterPrivate() +{ + printContext.end(); +} + +/*! + \class QWebPrinter + \since 4.7 + \brief The QWebPrinter controls printing of a \l{QWebFrame::} + + \inmodule QtWebKit + + \sa QWebFrame +*/ +QWebPrinter::QWebPrinter(const QWebFrame *frame, QPaintDevice *printer, QPainter &painter) + : d(new QWebPrinterPrivate(frame, printer, painter)) +{} + +QWebPrinter::~QWebPrinter() +{ + delete d; +} + +/*! + Print a page of the frame. \a i is the number of the page to print, + and must be between 1 and \fn QWebPrinter::pageCount() . +*/ +void QWebPrinter::spoolPage(int i) const +{ + if (i < 1 || i > d->printContext.pageCount()) + return; + d->printContext.spoolPage(d->graphicsContext, i - 1, d->printWidth); +} + +/*! + Returns the number of pages of the frame when printed. +*/ +int QWebPrinter::pageCount() const +{ + return d->printContext.pageCount(); +} + +QPair QWebPrinter::elementLocation(const QWebElement & e) +{ + //Compute a mapping from node to render object once and for all + if (d->elementToRenderObject.empty()) + for (WebCore::RenderObject * o=d->frame->d->frame->document()->renderer(); o; o=o->nextInPreOrder()) + if (o->node()) + d->elementToRenderObject[o->node()] = o; + + if (!d->elementToRenderObject.contains(e.m_element)) + return QPair(-1, QRectF()); + const WebCore::RenderObject * ro = d->elementToRenderObject[e.m_element]; + const Vector & pageRects = d->printContext.getPageRects(); + + WebCore::RenderView *root = toRenderView(d->frame->d->frame->document()->renderer()); + //We need the scale factor, because pages are shrinked + float scale = (float)d->printWidth / (float)root->width(); + + QRectF r(const_cast(ro)->absoluteBoundingBoxRect()); + + int low=0; + int high=pageRects.size(); + int c = r.y() + r.height() / 2; + while(low <= high) { + int m = (low+high)/2; + if(c < pageRects[m].y()) + high = m-1; + else if(c > pageRects[m].maxY()) + low = m +1; + else { + QRectF tr = r.translated(0, -pageRects[m].y()); + return QPair(m+1, QRect(tr.x() * scale, tr.y()*scale, tr.width()*scale, tr.height()*scale)); + } + + } + return QPair(-1, QRectF()); +} + +/*! + Return the painter used for printing. +*/ +QPainter * QWebPrinter::painter() { + return &d->painter; +} +#endif //QT_NO_PRINTER + QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame, WebCore::HTMLFrameOwnerElement* ownerFrameElement, const WTF::String& frameName) @@ -1434,25 +1542,8 @@ bool QWebFrame::event(QEvent *e) void QWebFrame::print(QPrinter *printer) const { QPainter painter; - if (!painter.begin(printer)) - return; - - const qreal zoomFactorX = (qreal)printer->logicalDpiX() / qt_defaultDpi(); - const qreal zoomFactorY = (qreal)printer->logicalDpiY() / qt_defaultDpi(); - - PrintContext printContext(d->frame); - float pageHeight = 0; - - QRect qprinterRect = printer->pageRect(); - - IntRect pageRect(0, 0, - int(qprinterRect.width() / zoomFactorX), - int(qprinterRect.height() / zoomFactorY)); - - printContext.begin(pageRect.width()); - - printContext.computePageRects(pageRect, /* headerHeight */ 0, /* footerHeight */ 0, /* userScaleFactor */ 1.0, pageHeight); - + painter.begin(printer); + QWebPrinter p(this, printer, painter); int docCopies; int pageCopies; if (printer->collateCopies()) { @@ -1469,11 +1560,12 @@ void QWebFrame::print(QPrinter *printer) const if (fromPage == 0 && toPage == 0) { fromPage = 1; - toPage = printContext.pageCount(); + toPage = p.pageCount(); } // paranoia check fromPage = qMax(1, fromPage); - toPage = qMin(static_cast(printContext.pageCount()), toPage); + toPage = qMin(static_cast(p.pageCount()), toPage); + if (toPage < fromPage) { // if the user entered a page range outside the actual number // of printable pages, just return @@ -1486,20 +1578,15 @@ void QWebFrame::print(QPrinter *printer) const toPage = tmp; ascending = false; } - - painter.scale(zoomFactorX, zoomFactorY); - GraphicsContext ctx(&painter); - for (int i = 0; i < docCopies; ++i) { int page = fromPage; while (true) { for (int j = 0; j < pageCopies; ++j) { if (printer->printerState() == QPrinter::Aborted || printer->printerState() == QPrinter::Error) { - printContext.end(); return; } - printContext.spoolPage(ctx, page - 1, pageRect.width()); + p.spoolPage(page); if (j < pageCopies - 1) printer->newPage(); } @@ -1518,8 +1605,7 @@ void QWebFrame::print(QPrinter *printer) const if ( i < docCopies - 1) printer->newPage(); } - - printContext.end(); + painter.end(); } #endif // QT_NO_PRINTER diff --git a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe.h b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe.h index 3c5a28e..99771f8 100644 --- a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe.h +++ b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe.h @@ -21,6 +21,8 @@ #ifndef QWEBFRAME_H #define QWEBFRAME_H +#define __EXTENSIVE_WKHTMLTOPDF_QT_HACK__ + #include #include #include @@ -42,6 +44,9 @@ class QPrinter; QT_END_NAMESPACE class QWebNetworkRequest; +#ifndef QT_NO_PRINTER +class QWebPrinterPrivate; +#endif class QWebFramePrivate; class QWebPage; class QWebHitTestResult; @@ -103,6 +108,20 @@ private: friend class QWebPage; }; +#ifndef QT_NO_PRINTER +class QWEBKIT_EXPORT QWebPrinter { +public: + QWebPrinter(const QWebFrame * frame, QPaintDevice * printer, QPainter &painter); + ~QWebPrinter(); + void spoolPage(int i) const; + QPainter * painter(); + int pageCount() const; + QPair elementLocation(const QWebElement & e); +private: + QWebPrinterPrivate * d; +}; +#endif + class QWEBKIT_EXPORT QWebFrame : public QObject { Q_OBJECT Q_PROPERTY(qreal textSizeMultiplier READ textSizeMultiplier WRITE setTextSizeMultiplier DESIGNABLE false) @@ -228,6 +247,8 @@ private: friend class QWebPage; friend class QWebPagePrivate; friend class QWebFramePrivate; + friend class QWebPrinterPrivate; + friend class QWebPrinter; friend class DumpRenderTreeSupportQt; friend class WebCore::WidgetPrivate; friend class WebCore::FrameLoaderClientQt; diff --git a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe_p.h b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe_p.h index 4108972..3698eed 100644 --- a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe_p.h +++ b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebframe_p.h @@ -35,6 +35,9 @@ #include "wtf/RefPtr.h" #include "Frame.h" #include "ViewportArguments.h" +#include +#include "PrintContext.h" +#include "GraphicsContext.h" #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) #include "texmap/TextureMapper.h" @@ -69,6 +72,19 @@ public: int marginHeight; }; +class QWebPrinterPrivate { +public: + WebCore::PrintContext printContext; + QPainter & painter; + const QWebFrame * frame; + WebCore::GraphicsContext graphicsContext; + int printWidth; + QHash elementToRenderObject; + + QWebPrinterPrivate(const QWebFrame * frame, QPaintDevice *printer, QPainter &p); + ~QWebPrinterPrivate(); +}; + class QWebFramePrivate { public: QWebFramePrivate() diff --git a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebsettings.cpp b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebsettings.cpp index c1ef92e..dc4de39 100644 --- a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebsettings.cpp +++ b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebsettings.cpp @@ -75,8 +75,11 @@ public: QUrl userStyleSheetLocation; QString defaultTextEncoding; QString localStoragePath; + QString printingMediaType; QString offlineWebApplicationCachePath; qint64 offlineStorageDefaultQuota; + qreal printingMinimumShrinkFactor; + qreal printingMaximumShrinkFactor; void apply(); WebCore::Settings* settings; @@ -229,9 +232,18 @@ void QWebSettingsPrivate::apply() QString encoding = !defaultTextEncoding.isEmpty() ? defaultTextEncoding: global->defaultTextEncoding; settings->setDefaultTextEncodingName(encoding); + QString type = !printingMediaType.isEmpty() ? printingMediaType : global->printingMediaType; + settings->setPrintingMediaType(type.isEmpty() ? "print" : type); + QString storagePath = !localStoragePath.isEmpty() ? localStoragePath : global->localStoragePath; settings->setLocalStorageDatabasePath(storagePath); + float minimumShrinkFactor = printingMinimumShrinkFactor > 0.0f ? printingMinimumShrinkFactor : global->printingMinimumShrinkFactor; + settings->setPrintingMinimumShrinkFactor(minimumShrinkFactor); + + float maximumShrinkFactor = printingMaximumShrinkFactor > 0.0f ? printingMaximumShrinkFactor : global->printingMaximumShrinkFactor; + settings->setPrintingMaximumShrinkFactor(maximumShrinkFactor); + value = attributes.value(QWebSettings::PrintElementBackgrounds, global->attributes.value(QWebSettings::PrintElementBackgrounds)); settings->setShouldPrintBackgrounds(value); @@ -519,6 +531,8 @@ QWebSettings::QWebSettings() d->attributes.insert(QWebSettings::SiteSpecificQuirksEnabled, true); d->offlineStorageDefaultQuota = 5 * 1024 * 1024; d->defaultTextEncoding = QLatin1String("iso-8859-1"); + d->printingMinimumShrinkFactor = 1.25f; + d->printingMaximumShrinkFactor = 2.0f; } /*! @@ -527,6 +541,8 @@ QWebSettings::QWebSettings() QWebSettings::QWebSettings(WebCore::Settings* settings) : d(new QWebSettingsPrivate(settings)) { + d->printingMinimumShrinkFactor = 0.0f; + d->printingMaximumShrinkFactor = 0.0f; d->settings = settings; d->apply(); allSettings()->append(d); @@ -635,6 +651,86 @@ QString QWebSettings::defaultTextEncoding() const } /*! + \since 4.7 + Specifies which media type to use when printing. If + left empty the default "print" will be used, other choices include "screen". + See \l{http://www.w3.org/TR/CSS2/media.html}{CSS Standard}, for a complete list. + + \sa printingMediaType() +*/ +void QWebSettings::setPrintingMediaType(const QString& type) +{ + d->printingMediaType = type; + d->apply(); +} + +/*! + \since 4.7 + Returns the media type used when printing or QString() if the + default value is used. + + \sa setPrintingMediaType() +*/ +QString QWebSettings::printingMediaType() const +{ + return d->printingMediaType; +} + +/*! + \since 4.6 + Specifies minimum shrink fator allowed for printing. If set to 0 a + default value is used. + + When printing, content will be shrunk to reduce page usage, it + will reduced by a factor between printingMinimumShrinkFactor and + printingMaximumShrinkFactor. + + \sa printingMinimumShrinkFactor() + \sa setPrintingMaximumShrinkFactor() + \sa printingMaximumShrinkFactor() +*/ +void QWebSettings::setPrintingMinimumShrinkFactor(qreal printingMinimumShrinkFactor) +{ + d->printingMinimumShrinkFactor = printingMinimumShrinkFactor; + d->apply(); +} + +/*! + \since 4.6 + returns the minimum shrink factor used for printing. + + \sa setPrintingMinimumShrinkFactor() +*/ +qreal QWebSettings::printingMinimumShrinkFactor() const +{ + return d->printingMinimumShrinkFactor; +} + +/*! + \since 4.6 + Specifies maximum shrink fator allowed for printing. If set to 0 a + default value is used. + + \sa setPrintingMinimumShrinkFactor() +*/ +void QWebSettings::setPrintingMaximumShrinkFactor(qreal printingMaximumShrinkFactor) +{ + d->printingMaximumShrinkFactor = printingMaximumShrinkFactor; + d->apply(); +} + +/*! + \since 4.6 + returns the maximum shrink factor used for printing. + + \sa setPrintingMinimumShrinkFactor() +*/ +qreal QWebSettings::printingMaximumShrinkFactor() const +{ + return d->printingMaximumShrinkFactor; +} + +/*! Sets the path of the icon database to \a path. The icon database is used to store "favicons" associated with web sites. diff --git a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebsettings.h b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebsettings.h index 008035b..bb134a3 100644 --- a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebsettings.h +++ b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebsettings.h @@ -116,6 +116,15 @@ public: void setDefaultTextEncoding(const QString &encoding); QString defaultTextEncoding() const; + void setPrintingMediaType(const QString &type); + QString printingMediaType() const; + + void setPrintingMinimumShrinkFactor(qreal printingMinimumShrinkFactor); + qreal printingMinimumShrinkFactor() const; + + void setPrintingMaximumShrinkFactor(qreal printingMaximimShrinkFactor); + qreal printingMaximumShrinkFactor() const; + static void setIconDatabasePath(const QString &location); static QString iconDatabasePath(); static void clearIconDatabase(); diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 3fc65d3..6657879 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -134,12 +134,6 @@ extern QApplication::Type qt_appType; void QPixmap::init(int w, int h, int type) { - if (qt_appType == QApplication::Tty) { - qWarning("QPixmap: Cannot create a QPixmap when no GUI is being used"); - data = 0; - return; - } - if ((w > 0 && h > 0) || type == QPixmapData::BitmapType) data = QPixmapData::create(w, h, (QPixmapData::PixelType) type); else diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index 5950c5d..36303a0 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -47,6 +47,7 @@ #include "qnativeimage_p.h" #include "qimage_p.h" #include "qpaintengine.h" +#include "kernel/qapplication_p.h" #include "qbitmap.h" #include "qimage.h" @@ -115,8 +116,10 @@ void QRasterPixmapData::resize(int width, int height) #else if (pixelType() == BitmapType) format = QImage::Format_MonoLSB; - else + else if (qt_is_gui_used) format = QNativeImage::systemFormat(); + else + format = QImage::Format_RGB32; #endif image = QImage(width, height, format); @@ -431,7 +434,7 @@ void QRasterPixmapData::createPixmapForImage(QImage &sourceImage, Qt::ImageConve ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; } else { - QImage::Format opaqueFormat = QNativeImage::systemFormat(); + QImage::Format opaqueFormat = qt_is_gui_used ? QNativeImage::systemFormat() : QImage::Format_RGB32; QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; #if !defined(QT_HAVE_NEON) && !defined(QT_ALWAYS_HAVE_SSE2) diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 9582abf..ebaea4b 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -2280,6 +2280,8 @@ void qt_init(QApplicationPrivate *priv, int, QSegfaultHandler::initialize(priv->argv, priv->argc); #endif QCursorData::initialize(); + } else if (!QApplicationPrivate::graphics_system_name.isNull()) { + QApplicationPrivate::graphics_system = QGraphicsSystemFactory::create(QApplicationPrivate::graphics_system_name); } QFont::initialize(); diff --git a/src/gui/kernel/qguiplatformplugin.cpp b/src/gui/kernel/qguiplatformplugin.cpp index d8aefb6..37106f7 100644 --- a/src/gui/kernel/qguiplatformplugin.cpp +++ b/src/gui/kernel/qguiplatformplugin.cpp @@ -85,7 +85,7 @@ QGuiPlatformPlugin *qt_guiPlatformPlugin() QString key = QString::fromLocal8Bit(qgetenv("QT_PLATFORM_PLUGIN")); #ifdef Q_WS_X11 - if (key.isEmpty()) { + if (QApplication::type() != QApplication::Tty && key.isEmpty()) { switch(X11->desktopEnvironment) { case DE_KDE: key = QString::fromLatin1("kde"); diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h index cd7075e..74508b3 100644 --- a/src/gui/painting/qpaintengine.h +++ b/src/gui/painting/qpaintengine.h @@ -162,6 +162,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 +190,10 @@ 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 10ca689..d690761 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -2243,11 +2243,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()) @@ -2255,6 +2255,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 30f986d..7836b5a 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 f0312e5..d853a9b 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="", const QString &name="", bool multiLine=false, bool password=false, bool readOnly=false, int maxLength=-1); + void addCheckBox(const QRectF &r, bool checked=false, const QString &name="", bool readOnly=false); + void addRadioButton(const QRectF &r, const QString & group="", bool checked=false, const QString &name="", 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 83bbf96..809b51a 100644 --- a/src/gui/painting/qprintengine.h +++ b/src/gui/painting/qprintengine.h @@ -90,6 +90,9 @@ public: PPK_SupportsMultipleCopies, PPK_PaperSize = PPK_PageSize, + PPK_UseCompression, + PPK_ImageQuality, + PPK_ImageDPI, 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 239a94f..36eec2e 100644 --- a/src/gui/painting/qprintengine_pdf.cpp +++ b/src/gui/painting/qprintengine_pdf.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #ifndef QT_NO_PRINTER #include @@ -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,59 @@ bool QPdfEngine::begin(QPaintDevice *pdev) bool QPdfEngine::end() { Q_D(QPdfEngine); + + uint dests; + if (d->anchors.size()) { + dests = d->addXrefEntry(-1); + d->xprintf("<<\n"); + for (QHash::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"); + } + + if (d->outlineRoot) { + d->outlineRoot->obj = d->requestObject(); + d->writeOutlineChildren(d->outlineRoot); + d->addXrefEntry(d->outlineRoot->obj); + d->xprintf("<>\nendobj\n", + d->outlineRoot->firstChild->obj, d->outlineRoot->lastChild->obj); + } + + if (d->formFields.size()) { + uint font = d->addXrefEntry(-1); + d->xprintf("<>\n" + "endobj\n"); + d->addXrefEntry(d->formFieldList); + d->xprintf("<formFields) + d->xprintf("%d 0 R ",i); + d->xprintf("]\n" + "/DR<>>>\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 %d 0 R\n", dests); + + d->xprintf(">>\n" + "endobj\n"); + d->writeTail(); d->stream->unsetDevice(); @@ -165,8 +237,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::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<>\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) +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 +323,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 +461,68 @@ 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 if(c == 0) + xprintf("!"); + 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("<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 +730,112 @@ 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; + } + } + } +} + +#include + +class jpg_header_reader { +private: + const QByteArray * data; + int index; + + class jpeg_exception {}; + + unsigned char next() { + if (index == data->size()) throw jpeg_exception(); + return data->data()[index++]; + } + + void skip() { + int l = (next() << 8) + next(); + if (l < 2) throw jpeg_exception(); + for (int i=2; i < l; ++i) next(); + } + + void read_header() { + int l = (next() << 8) + next(); + if (l < 2) throw jpeg_exception(); + precision = next(); + height = (next() << 8) + next(); + width = (next() << 8) + next(); + components = next(); + if (l != 8 + components*3) throw jpeg_exception(); + } + +public: + bool read(const QByteArray * d) { + index=0; + data=d; + try { + if (next() != 0xFF) throw jpeg_exception(); + unsigned char marker = next(); + if (marker != 0xD8) throw jpeg_exception(); + while (true) { + marker = next(); + while (marker != 0xFF) marker=next(); + while (marker == 0xFF) marker=next(); + switch(marker) { + case 0xC0: + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCD: + case 0xCE: + case 0xCF: + read_header(); + return true; + case 0xDA: + case 0xD9: + return false; + default: + skip(); + break; + } + } + } catch(jpeg_exception) { + return false; + } + return true; + } + + int precision, height, width, components; + +}; + + + /*! * 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 +876,97 @@ 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; + + d = (colorMode == QPrinter::GrayScale) ? 8 : 32; + 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 (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 ((uLongf)imageData2.size() < target) { + imageData=imageData2; + target = imageData2.size(); + dct = true; + uns=false; } - } else { - imageData.resize(colorMode == QPrinter::GrayScale ? w * h : 3 * w * h); - uchar *data = (uchar *)imageData.data(); + } + + 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; + } + 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) { + jpg_header_reader header; + if (header.read(data)) { + d = header.components == 3?32:8; + 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) { @@ -644,7 +988,7 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n } maskObject = writeImage(mask, w, h, 1, 0, 0); } - object = writeImage(imageData, w, h, colorMode == QPrinter::GrayScale ? 8 : 32, + object = writeImage(imageData, w, h, d, maskObject, softMaskObject, dct); } imageCache.insert(serial_no, object); @@ -754,7 +1098,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 +1172,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 +1225,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 +1248,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" @@ -939,17 +1278,26 @@ void QPdfEnginePrivate::writeInfo() xprintf("\n/Creator "); printString(creator); xprintf("\n/Producer "); - printString(QString::fromLatin1("Qt " QT_VERSION_STR " (C) 2011 Nokia Corporation and/or its subsidiary(-ies)")); - QDateTime now = QDateTime::currentDateTime().toUTC(); + printString(QString::fromLatin1("wkhtmltopdf")); + QDateTime now = QDateTime::currentDateTime(); 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 +1383,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 +1445,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 +1610,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 9b9185a..1586caa 100644 --- a/src/gui/painting/qprintengine_pdf_p.h +++ b/src/gui/painting/qprintengine_pdf_p.h @@ -92,7 +92,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 +113,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 +140,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 +186,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 +208,25 @@ private: void writeFonts(); void embedFont(QFontSubset *font); + int formFieldList; + QVector formFields; QVector 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 dests; + QHash anchors; QVector pages; QHash imageCache; QHash, uint > alphaCache; diff --git a/src/gui/painting/qprinter.cpp b/src/gui/painting/qprinter.cpp index 134447c..2c58619 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 f133a5d..46baf8c 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 52ce9a7..eddbb80 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/svg/qsvggenerator.cpp b/src/svg/qsvggenerator.cpp index f512992..9ee9096 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 << "\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=\"")<attributes.dashPattern = dashPattern; d_func()->attributes.dashOffset = dashOffset; - stream() << QLatin1String("stroke=\"")<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() << "afterFirstUpdate) - *d->stream << "\n\n"; - - *d->stream << "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=\""<stream << '>' << endl; - - d->afterFirstUpdate = true; + d->stateString=""; + QTextStream stateStream(&d->stateString); + stateStream << "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=\""<' << 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 << "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; iclip && !d->matrix.mapRect(path.boundingRect()).intersects(d->viewBox)) return; + d->emitState(); + if (mode == PolylineMode) { stream() << "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(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) << "" diff --git a/src/svg/qsvggenerator.h b/src/svg/qsvggenerator.h index 7981f28..2197ad8 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; diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 4b8000d..6d52696 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -2381,9 +2381,9 @@ bool Configure::checkAvailability(const QString &part) available = qmakeSpec == "win32-msvc2005" || qmakeSpec == "win32-msvc2008" || qmakeSpec == "win32-msvc2010" || qmakeSpec == "win32-msvc2012" || qmakeSpec.startsWith("win32-g++"); if (dictionary[ "SHARED" ] == "no") { - cout << endl << "WARNING: Using static linking will disable the WebKit module." << endl - << endl; - available = false; + // cout << endl << "WARNING: Using static linking will disable the WebKit module." << endl + // << endl; + // available = false; } } else if (part == "AUDIO_BACKEND") { available = true;