diff options
Diffstat (limited to 'WebCore/platform/graphics/qt')
-rw-r--r-- | WebCore/platform/graphics/qt/ContextShadow.cpp | 256 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/ContextShadow.h | 71 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/FontCacheQt.cpp | 2 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp | 9 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/GraphicsContextQt.cpp | 208 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/ImageBufferData.h | 4 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/ImageBufferQt.cpp | 53 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/ImageDecoderQt.cpp | 25 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp | 4 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp | 66 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h | 10 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/PathQt.cpp | 27 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/TransparencyLayer.h | 89 |
13 files changed, 628 insertions, 196 deletions
diff --git a/WebCore/platform/graphics/qt/ContextShadow.cpp b/WebCore/platform/graphics/qt/ContextShadow.cpp new file mode 100644 index 0000000..0511218 --- /dev/null +++ b/WebCore/platform/graphics/qt/ContextShadow.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2010 Sencha, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ContextShadow.h" + +namespace WebCore { + +ContextShadow::ContextShadow() + : type(NoShadow) + , blurRadius(0) +{ +} + +ContextShadow::ContextShadow(const QColor& c, float r, qreal dx, qreal dy) + : color(c) + , blurRadius(qRound(r)) + , offset(dx, dy) +{ + // The type of shadow is decided by the blur radius, shadow offset, and shadow color. + if (!color.isValid() || !color.alpha()) { + // Can't paint the shadow with invalid or invisible color. + type = NoShadow; + } else if (r > 0) { + // Shadow is always blurred, even the offset is zero. + type = BlurShadow; + } else if (offset.isNull()) { + // Without blur and zero offset means the shadow is fully hidden. + type = NoShadow; + } else { + if (color.alpha() > 0) + type = AlphaSolidShadow; + else + type = OpaqueSolidShadow; + } +} + +void ContextShadow::clear() +{ + type = NoShadow; + color = QColor(); + blurRadius = 0; + offset = QPointF(0, 0); +} + +// Instead of integer division, we use 18.14 for fixed-point division. +static const int BlurSumShift = 14; + +// Note: image must be RGB32 format +static void blurHorizontal(QImage& image, int radius, bool swap = false) +{ + Q_ASSERT(image.format() == QImage::Format_ARGB32_Premultiplied); + + // See comments in http://webkit.org/b/40793, it seems sensible + // to follow Skia's limit of 128 pixels of blur radius + radius = qMin(128, radius); + + int imgWidth = image.width(); + int imgHeight = image.height(); + + // Check http://www.w3.org/TR/SVG/filters.html#feGaussianBlur + // for the approaches when the box-blur radius is even vs odd. + int dmax = radius >> 1; + int dmin = qMax(0, dmax - 1 + (radius & 1)); + + for (int y = 0; y < imgHeight; ++y) { + + unsigned char* pixels = image.scanLine(y); + + int left; + int right; + int pixelCount; + int prev; + int next; + int firstAlpha; + int lastAlpha; + int totalAlpha; + unsigned char* target; + unsigned char* prevPtr; + unsigned char* nextPtr; + + int invCount; + + static const int alphaChannel = 3; + static const int blueChannel = 0; + static const int greenChannel = 1; + + // For each step, we use sliding window algorithm. This is much more + // efficient than computing the sum of each pixels covered by the box + // kernel size for each x. + + // As noted in the SVG filter specification, running box blur 3x + // approximates a real gaussian blur nicely. + + // Step 1: blur alpha channel and store the result in the blue channel. + left = swap ? dmax : dmin; + right = swap ? dmin : dmax; + pixelCount = left + 1 + right; + invCount = (1 << BlurSumShift) / pixelCount; + prev = -left; + next = 1 + right; + firstAlpha = pixels[alphaChannel]; + lastAlpha = pixels[(imgWidth - 1) * 4 + alphaChannel]; + totalAlpha = 0; + for (int i = 0; i < pixelCount; ++i) + totalAlpha += pixels[qBound(0, i - left, imgWidth - 1) * 4 + alphaChannel]; + target = pixels + blueChannel; + prevPtr = pixels + prev * 4 + alphaChannel; + nextPtr = pixels + next * 4 + alphaChannel; + for (int x = 0; x < imgWidth; ++x, ++prev, ++next, target += 4, prevPtr += 4, nextPtr += 4) { + *target = (totalAlpha * invCount) >> BlurSumShift; + int delta = ((next < imgWidth) ? *nextPtr : lastAlpha) - + ((prev > 0) ? *prevPtr : firstAlpha); + totalAlpha += delta; + } + + // Step 2: blur blue channel and store the result in the green channel. + left = swap ? dmin : dmax; + right = swap ? dmax : dmin; + pixelCount = left + 1 + right; + invCount = (1 << BlurSumShift) / pixelCount; + prev = -left; + next = 1 + right; + firstAlpha = pixels[blueChannel]; + lastAlpha = pixels[(imgWidth - 1) * 4 + blueChannel]; + totalAlpha = 0; + for (int i = 0; i < pixelCount; ++i) + totalAlpha += pixels[qBound(0, i - left, imgWidth - 1) * 4 + blueChannel]; + target = pixels + greenChannel; + prevPtr = pixels + prev * 4 + blueChannel; + nextPtr = pixels + next * 4 + blueChannel; + for (int x = 0; x < imgWidth; ++x, ++prev, ++next, target += 4, prevPtr += 4, nextPtr += 4) { + *target = (totalAlpha * invCount) >> BlurSumShift; + int delta = ((next < imgWidth) ? *nextPtr : lastAlpha) - + ((prev > 0) ? *prevPtr : firstAlpha); + totalAlpha += delta; + } + + // Step 3: blur green channel and store the result in the alpha channel. + left = dmax; + right = dmax; + pixelCount = left + 1 + right; + invCount = (1 << BlurSumShift) / pixelCount; + prev = -left; + next = 1 + right; + firstAlpha = pixels[greenChannel]; + lastAlpha = pixels[(imgWidth - 1) * 4 + greenChannel]; + totalAlpha = 0; + for (int i = 0; i < pixelCount; ++i) + totalAlpha += pixels[qBound(0, i - left, imgWidth - 1) * 4 + greenChannel]; + target = pixels + alphaChannel; + prevPtr = pixels + prev * 4 + greenChannel; + nextPtr = pixels + next * 4 + greenChannel; + for (int x = 0; x < imgWidth; ++x, ++prev, ++next, target += 4, prevPtr += 4, nextPtr += 4) { + *target = (totalAlpha * invCount) >> BlurSumShift; + int delta = ((next < imgWidth) ? *nextPtr : lastAlpha) - + ((prev > 0) ? *prevPtr : firstAlpha); + totalAlpha += delta; + } + } +} + +static void shadowBlur(QImage& image, int radius, const QColor& shadowColor) +{ + blurHorizontal(image, radius); + + QTransform transform; + transform.rotate(90); + image = image.transformed(transform); + blurHorizontal(image, radius, true); + transform.reset(); + transform.rotate(270); + image = image.transformed(transform); + + // "Colorize" with the right shadow color. + QPainter p(&image); + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + p.fillRect(image.rect(), shadowColor.rgb()); + p.end(); +} + +void ContextShadow::drawShadowRect(QPainter* p, const QRectF& rect) +{ + if (type == NoShadow) + return; + + if (type == BlurShadow) { + QRectF shadowRect = rect.translated(offset); + + // We expand the area by the blur radius * 2 to give extra space + // for the blur transition. + int extra = blurRadius * 2; + QRectF bufferRect = shadowRect.adjusted(-extra, -extra, extra, extra); + QRect alignedBufferRect = bufferRect.toAlignedRect(); + + QRect clipRect; + if (p->hasClipping()) + clipRect = p->clipRegion().boundingRect(); + else + clipRect = p->transform().inverted().mapRect(p->window()); + + if (!clipRect.contains(alignedBufferRect)) { + + // No need to have the buffer larger that the clip. + alignedBufferRect = alignedBufferRect.intersected(clipRect); + if (alignedBufferRect.isEmpty()) + return; + + // We adjust again because the pixels at the borders are still + // potentially affected by the pixels outside the buffer. + alignedBufferRect.adjust(-extra, -extra, extra, extra); + } + + QImage shadowImage(alignedBufferRect.size(), QImage::Format_ARGB32_Premultiplied); + shadowImage.fill(Qt::transparent); + QPainter shadowPainter(&shadowImage); + + shadowPainter.fillRect(shadowRect.translated(-alignedBufferRect.topLeft()), color); + shadowPainter.end(); + + shadowBlur(shadowImage, blurRadius, color); + + p->drawImage(alignedBufferRect.topLeft(), shadowImage); + + return; + } + + p->fillRect(rect.translated(offset), color); +} + + +} diff --git a/WebCore/platform/graphics/qt/ContextShadow.h b/WebCore/platform/graphics/qt/ContextShadow.h new file mode 100644 index 0000000..e114ebc --- /dev/null +++ b/WebCore/platform/graphics/qt/ContextShadow.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 Sencha, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ContextShadow_h +#define ContextShadow_h + +#include <QPainter> + +namespace WebCore { + +// This is to track and keep the shadow state. We use this rather than +// using GraphicsContextState to allow possible optimizations (right now +// only to determine the shadow type, but in future it might covers things +// like cached scratch image, persistent shader, etc). + +// This class should be copyable since GraphicsContextQt keeps a stack of +// the shadow state for savePlatformState and restorePlatformState. + +class ContextShadow { +public: + enum { + NoShadow, + OpaqueSolidShadow, + AlphaSolidShadow, + BlurShadow + } type; + + QColor color; + int blurRadius; + QPointF offset; + + ContextShadow(); + ContextShadow(const QColor& c, float r, qreal dx, qreal dy); + + void clear(); + + // Draws the shadow for colored rectangle (can't be filled with pattern + // or gradient) according to the shadow parameters. + // Note: 'rect' specifies the rectangle which casts the shadow, + // NOT the bounding box of the shadow. + void drawShadowRect(QPainter* p, const QRectF& rect); + +}; + +} // namespace WebCore + +#endif // ContextShadow_h diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp index bfcc5c3..c59c523 100644 --- a/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -29,10 +29,10 @@ #include "FontPlatformData.h" #include "Font.h" #include "PlatformString.h" -#include "StringHash.h" #include <utility> #include <wtf/ListHashSet.h> #include <wtf/StdLibExtras.h> +#include <wtf/text/StringHash.h> #include <QFont> diff --git a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index 273e2dd..d5e7b3f 100644 --- a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -512,15 +512,6 @@ void GraphicsContext3D::makeContextCurrent() m_internal->m_glWidget->makeCurrent(); } -void GraphicsContext3D::beginPaint(CanvasRenderingContext* context) -{ - paintRenderingResultsToCanvas(); -} - -void GraphicsContext3D::endPaint() -{ -} - void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* context) { m_internal->m_glWidget->makeCurrent(); diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index d4a145f..1632804 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -8,6 +8,7 @@ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de> + * Copyright (C) 2010 Sencha, Inc. * * All rights reserved. * @@ -42,6 +43,7 @@ #include "AffineTransform.h" #include "Color.h" +#include "ContextShadow.h" #include "FloatConversion.h" #include "Font.h" #include "GraphicsContextPrivate.h" @@ -50,6 +52,7 @@ #include "Path.h" #include "Pattern.h" #include "Pen.h" +#include "TransparencyLayer.h" #include <QBrush> #include <QDebug> @@ -166,48 +169,6 @@ static inline Qt::FillRule toQtFillRule(WindRule rule) return Qt::OddEvenFill; } -struct TransparencyLayer : FastAllocBase { - TransparencyLayer(const QPainter* p, const QRect &rect, qreal opacity, QPixmap& alphaMask) - : pixmap(rect.width(), rect.height()) - , opacity(opacity) - , alphaMask(alphaMask) - , saveCounter(1) // see the comment for saveCounter - { - offset = rect.topLeft(); - pixmap.fill(Qt::transparent); - painter.begin(&pixmap); - painter.setRenderHint(QPainter::Antialiasing, p->testRenderHint(QPainter::Antialiasing)); - painter.translate(-offset); - painter.setPen(p->pen()); - painter.setBrush(p->brush()); - painter.setTransform(p->transform(), true); - painter.setOpacity(p->opacity()); - painter.setFont(p->font()); - if (painter.paintEngine()->hasFeature(QPaintEngine::PorterDuff)) - painter.setCompositionMode(p->compositionMode()); - // if the path is an empty region, this assignment disables all painting - if (!p->clipPath().isEmpty()) - painter.setClipPath(p->clipPath()); - } - - TransparencyLayer() - { - } - - QPixmap pixmap; - QPoint offset; - QPainter painter; - qreal opacity; - // for clipToImageBuffer - QPixmap alphaMask; - // saveCounter is only used in combination with alphaMask - // otherwise, its value is unspecified - int saveCounter; -private: - TransparencyLayer(const TransparencyLayer &) {} - TransparencyLayer & operator=(const TransparencyLayer &) { return *this; } -}; - class GraphicsContextPlatformPrivate : public Noncopyable { public: GraphicsContextPlatformPrivate(QPainter* painter); @@ -240,6 +201,14 @@ public: // Only used by SVG for now. QPainterPath currentPath; + ContextShadow shadow; + QStack<ContextShadow> shadowStack; + + bool hasShadow() const + { + return shadow.type != ContextShadow::NoShadow; + } + private: QPainter* painter; }; @@ -307,6 +276,7 @@ void GraphicsContext::savePlatformState() if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull()) ++m_data->layers.top()->saveCounter; m_data->p()->save(); + m_data->shadowStack.push(m_data->shadow); } void GraphicsContext::restorePlatformState() @@ -321,9 +291,16 @@ void GraphicsContext::restorePlatformState() QTransform matrix = m_common->state.pathTransform; m_data->currentPath = m_data->currentPath * matrix; } + + if (m_data->shadowStack.isEmpty()) + m_data->shadow = ContextShadow(); + else + m_data->shadow = m_data->shadowStack.pop(); } // Draws a filled rectangle with a stroked border. +// This is only used to draw borders (real fill is done via fillRect), and +// thus it must not cast any shadow. void GraphicsContext::drawRect(const IntRect& rect) { if (paintingDisabled()) @@ -333,24 +310,13 @@ void GraphicsContext::drawRect(const IntRect& rect) const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); - if (m_common->state.shadowColor.isValid()) { - FloatSize shadowSize; - float shadowBlur; - Color shadowColor; - if (getShadow(shadowSize, shadowBlur, shadowColor)) { - IntRect shadowRect = rect; - shadowRect.move(shadowSize.width(), shadowSize.height()); - shadowRect.inflate(static_cast<int>(p->pen().widthF())); - p->fillRect(shadowRect, QColor(shadowColor)); - } - } - p->drawRect(rect); p->setRenderHint(QPainter::Antialiasing, antiAlias); } // This is only used to draw borders. +// Must not cast any shadow. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { if (paintingDisabled()) @@ -372,17 +338,6 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); adjustLineToPixelBoundaries(p1, p2, width, style); - FloatSize shadowSize; - float shadowBlur; - Color shadowColor; - if (textDrawingMode() == cTextFill && getShadow(shadowSize, shadowBlur, shadowColor)) { - p->save(); - p->translate(shadowSize.width(), shadowSize.height()); - p->setPen(shadowColor); - p->drawLine(p1, p2); - p->restore(); - } - int patWidth = 0; switch (style) { case NoStroke: @@ -474,16 +429,14 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, true); - FloatSize shadowSize; - float shadowBlur; - Color shadowColor; startAngle *= 16; angleSpan *= 16; - if (getShadow(shadowSize, shadowBlur, shadowColor)) { + + if (m_data->hasShadow()) { p->save(); - p->translate(shadowSize.width(), shadowSize.height()); + p->translate(m_data->shadow.offset); QPen pen(p->pen()); - pen.setColor(shadowColor); + pen.setColor(m_data->shadow.color); p->setPen(pen); p->drawArc(rect, startAngle, angleSpan); p->restore(); @@ -509,17 +462,14 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points QPainter* p = m_data->p(); p->save(); p->setRenderHint(QPainter::Antialiasing, shouldAntialias); - FloatSize shadowSize; - float shadowBlur; - Color shadowColor; - if (getShadow(shadowSize, shadowBlur, shadowColor)) { + if (m_data->hasShadow()) { p->save(); - p->translate(shadowSize.width(), shadowSize.height()); + p->translate(m_data->shadow.offset); if (p->brush().style() != Qt::NoBrush) - p->setBrush(QBrush(shadowColor)); + p->setBrush(QBrush(m_data->shadow.color)); QPen pen(p->pen()); if (pen.style() != Qt::NoPen) { - pen.setColor(shadowColor); + pen.setColor(m_data->shadow.color); p->setPen(pen); } p->drawConvexPolygon(polygon); @@ -553,18 +503,6 @@ QPen GraphicsContext::pen() return p->pen(); } -static void inline drawFilledShadowPath(GraphicsContext* context, QPainter* p, const QPainterPath& path) -{ - FloatSize shadowSize; - float shadowBlur; - Color shadowColor; - if (context->getShadow(shadowSize, shadowBlur, shadowColor)) { - p->translate(shadowSize.width(), shadowSize.height()); - p->fillPath(path, QBrush(shadowColor)); - p->translate(-shadowSize.width(), -shadowSize.height()); - } -} - void GraphicsContext::fillPath() { if (paintingDisabled()) @@ -574,7 +512,11 @@ void GraphicsContext::fillPath() QPainterPath& path = m_data->currentPath; // Avoid detaching the QPainterPath path.setFillRule(toQtFillRule(fillRule())); - drawFilledShadowPath(this, p, path); + if (m_data->hasShadow()) { + p->translate(m_data->shadow.offset); + p->fillPath(path, m_data->shadow.color); + p->translate(-m_data->shadow.offset); + } if (m_common->state.fillPattern) { AffineTransform affine; p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); @@ -598,16 +540,12 @@ void GraphicsContext::strokePath() QPainterPath& path = m_data->currentPath; // Avoid detaching the QPainterPath path.setFillRule(toQtFillRule(fillRule())); - FloatSize shadowSize; - float shadowBlur; - Color shadowColor; - if (getShadow(shadowSize, shadowBlur, shadowColor)) { - QTransform t(p->worldTransform()); - p->translate(shadowSize.width(), shadowSize.height()); + if (m_data->hasShadow()) { + p->translate(m_data->shadow.offset); QPen shadowPen(pen); - shadowPen.setColor(shadowColor); + shadowPen.setColor(m_data->shadow.color); p->strokePath(path, shadowPen); - p->setWorldTransform(t); + p->translate(-m_data->shadow.offset); } if (m_common->state.strokePattern) { AffineTransform affine; @@ -625,18 +563,6 @@ void GraphicsContext::strokePath() m_data->currentPath = QPainterPath(); } -static inline void drawBorderlessRectShadow(GraphicsContext* context, QPainter* p, const FloatRect& rect) -{ - FloatSize shadowSize; - float shadowBlur; - Color shadowColor; - if (context->getShadow(shadowSize, shadowBlur, shadowColor)) { - FloatRect shadowRect(rect); - shadowRect.move(shadowSize.width(), shadowSize.height()); - p->fillRect(shadowRect, QColor(shadowColor)); - } -} - static inline void drawRepeatPattern(QPainter* p, QPixmap* image, const FloatRect& rect, const bool repeatX, const bool repeatY) { // Patterns must be painted so that the top left of the first image is anchored at @@ -712,22 +638,18 @@ void GraphicsContext::fillRect(const FloatRect& rect) QPainter* p = m_data->p(); FloatRect normalizedRect = rect.normalized(); - FloatSize shadowSize; - float shadowBlur; - Color shadowColor; - bool hasShadow = getShadow(shadowSize, shadowBlur, shadowColor); - FloatRect shadowDestRect; + QRectF shadowDestRect; QImage* shadowImage = 0; QPainter* pShadow = 0; - if (hasShadow) { + if (m_data->hasShadow()) { shadowImage = new QImage(roundedIntSize(normalizedRect.size()), QImage::Format_ARGB32_Premultiplied); pShadow = new QPainter(shadowImage); shadowDestRect = normalizedRect; - shadowDestRect.move(shadowSize.width(), shadowSize.height()); + shadowDestRect.translate(m_data->shadow.offset); pShadow->setCompositionMode(QPainter::CompositionMode_Source); - pShadow->fillRect(shadowImage->rect(), shadowColor); + pShadow->fillRect(shadowImage->rect(), m_data->shadow.color); pShadow->setCompositionMode(QPainter::CompositionMode_DestinationIn); } @@ -737,7 +659,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) QBrush brush(m_common->state.fillPattern->createPlatformPattern(affine)); QPixmap* image = m_common->state.fillPattern->tileImage()->nativeImageForCurrentFrame(); - if (hasShadow) { + if (m_data->hasShadow()) { drawRepeatPattern(pShadow, image, FloatRect(static_cast<QRectF>(shadowImage->rect())), m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY()); pShadow->end(); p->drawImage(shadowDestRect, *shadowImage, shadowImage->rect()); @@ -747,14 +669,14 @@ void GraphicsContext::fillRect(const FloatRect& rect) QBrush brush(*m_common->state.fillGradient->platformGradient()); brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); - if (hasShadow) { + if (m_data->hasShadow()) { pShadow->fillRect(shadowImage->rect(), brush); pShadow->end(); p->drawImage(shadowDestRect, *shadowImage, shadowImage->rect()); } p->fillRect(normalizedRect, brush); } else { - if (hasShadow) { + if (m_data->hasShadow()) { pShadow->fillRect(shadowImage->rect(), p->brush()); pShadow->end(); p->drawImage(shadowDestRect, *shadowImage, shadowImage->rect()); @@ -774,8 +696,10 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS m_data->solidColor.setColor(color); QPainter* p = m_data->p(); - if (m_common->state.shadowColor.isValid()) - drawBorderlessRectShadow(this, p, rect); + + if (m_data->hasShadow()) + m_data->shadow.drawShadowRect(p, rect); + p->fillRect(rect, m_data->solidColor); } @@ -786,7 +710,11 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight); QPainter* p = m_data->p(); - drawFilledShadowPath(this, p, path.platformPath()); + if (m_data->hasShadow()) { + p->translate(m_data->shadow.offset); + p->fillPath(path.platformPath(), m_data->shadow.color); + p->translate(-m_data->shadow.offset); + } p->fillPath(path.platformPath(), QColor(color)); } @@ -928,7 +856,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin); } -void GraphicsContext::setPlatformShadow(const FloatSize& size, float, const Color&, ColorSpace) +void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const Color& color, ColorSpace) { // Qt doesn't support shadows natively, they are drawn manually in the draw* // functions @@ -937,13 +865,20 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, float, const Colo // Meaning that this graphics context is associated with a CanvasRenderingContext // We flip the height since CG and HTML5 Canvas have opposite Y axis m_common->state.shadowSize = FloatSize(size.width(), -size.height()); + m_data->shadow = ContextShadow(color, blur, size.width(), -size.height()); + } else { + m_data->shadow = ContextShadow(color, blur, size.width(), size.height()); } } void GraphicsContext::clearPlatformShadow() { - // Qt doesn't support shadows natively, they are drawn manually in the draw* - // functions + m_data->shadow.clear(); +} + +void GraphicsContext::pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask) +{ + m_data->layers.push(new TransparencyLayer(m_data->p(), m_data->p()->transform().mapRect(rect), 1.0, alphaMask)); } void GraphicsContext::beginTransparencyLayer(float opacity) @@ -1226,23 +1161,6 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) } } -void GraphicsContext::clipToImageBuffer(const FloatRect& floatRect, const ImageBuffer* image) -{ - if (paintingDisabled()) - return; - - QPixmap* nativeImage = image->image()->nativeImageForCurrentFrame(); - if (!nativeImage) - return; - - IntRect rect(floatRect); - QPixmap alphaMask = *nativeImage; - if (alphaMask.width() != rect.width() || alphaMask.height() != rect.height()) - alphaMask = alphaMask.scaled(rect.width(), rect.height()); - - m_data->layers.push(new TransparencyLayer(m_data->p(), m_data->p()->transform().mapRect(rect), 1.0, alphaMask)); -} - void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) { diff --git a/WebCore/platform/graphics/qt/ImageBufferData.h b/WebCore/platform/graphics/qt/ImageBufferData.h index 222dabe..aa32253 100644 --- a/WebCore/platform/graphics/qt/ImageBufferData.h +++ b/WebCore/platform/graphics/qt/ImageBufferData.h @@ -26,6 +26,9 @@ #ifndef ImageBufferData_h #define ImageBufferData_h +#include "Image.h" +#include <wtf/RefPtr.h> + #include <QPainter> #include <QPixmap> @@ -41,6 +44,7 @@ public: QPixmap m_pixmap; OwnPtr<QPainter> m_painter; + RefPtr<Image> m_image; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp index 761a4fe..11ca377 100644 --- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -33,6 +33,7 @@ #include "ImageData.h" #include "MIMETypeRegistry.h" #include "StillImageQt.h" +#include "TransparencyLayer.h" #include <wtf/text/CString.h> #include <QBuffer> @@ -74,6 +75,8 @@ ImageBufferData::ImageBufferData(const IntSize& size) brush.setColor(Qt::black); painter->setBrush(brush); painter->setCompositionMode(QPainter::CompositionMode_SourceOver); + + m_image = StillImage::createForRendering(&m_pixmap); } ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace, bool& success) @@ -98,24 +101,50 @@ GraphicsContext* ImageBuffer::context() const return m_context.get(); } -Image* ImageBuffer::imageForRendering() const +bool ImageBuffer::drawsUsingCopy() const { - if (!m_image) - m_image = StillImage::createForRendering(&m_data.m_pixmap); + return false; +} - return m_image.get(); +PassRefPtr<Image> ImageBuffer::copyImage() const +{ + return StillImage::create(m_data.m_pixmap); } -Image* ImageBuffer::image() const +void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, + CompositeOperator op, bool useLowQualityScale) { - if (!m_image) { - // It's assumed that if image() is called, the actual rendering to the - // GraphicsContext must be done. - ASSERT(context()); - m_image = StillImage::create(m_data.m_pixmap); - } + if (destContext == context()) { + // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. + RefPtr<Image> copy = copyImage(); + destContext->drawImage(copy.get(), DeviceColorSpace, destRect, srcRect, op, useLowQualityScale); + } else + destContext->drawImage(m_data.m_image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); +} + +void ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) +{ + if (destContext == context()) { + // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. + RefPtr<Image> copy = copyImage(); + copy->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect); + } else + m_data.m_image->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect); +} + +void ImageBuffer::clip(GraphicsContext* context, const FloatRect& floatRect) const +{ + QPixmap* nativeImage = m_data.m_image->nativeImageForCurrentFrame(); + if (!nativeImage) + return; + + IntRect rect(floatRect); + QPixmap alphaMask = *nativeImage; + if (alphaMask.width() != rect.width() || alphaMask.height() != rect.height()) + alphaMask = alphaMask.scaled(rect.width(), rect.height()); - return m_image.get(); + context->pushTransparencyLayerInternal(rect, 1.0, alphaMask); } void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index fb3d621..858cc44 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -78,6 +78,9 @@ void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived) m_buffer->open(QIODevice::ReadOnly | QIODevice::Unbuffered); m_reader.set(new QImageReader(m_buffer.get(), m_format)); + // This will force the JPEG decoder to use JDCT_IFAST + m_reader->setQuality(49); + // QImageReader only allows retrieving the format before reading the image m_format = m_reader->format(); } @@ -186,20 +189,16 @@ void ImageDecoderQt::internalReadImage(size_t frameIndex) bool ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) { QPixmap pixmap; - bool pixmapLoaded; - const int imageCount = m_reader->imageCount(); - if (imageCount == 0 || imageCount == 1) - pixmapLoaded = pixmap.loadFromData((const uchar*)(m_data->data()), m_data->size(), m_format); - else { - QImage img; - const bool imageLoaded = m_reader->read(&img); - if (imageLoaded) { - pixmap = QPixmap::fromImage(img); - pixmapLoaded = true; - } - } - if (!pixmapLoaded) { +#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) + pixmap = QPixmap::fromImageReader(m_reader.get()); +#else + QImage img; + if (m_reader->read(&img)) + pixmap = QPixmap::fromImage(img); +#endif + + if (pixmap.isNull()) { frameCount(); repetitionCount(); clearPointers(); diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp index 3c6c5aa..08eb816 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -534,7 +534,11 @@ void MediaPlayerPrivate::aboutToFinish() void MediaPlayerPrivate::totalTimeChanged(qint64 totalTime) { +#if OS(WINDOWS) + LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%I64d)", totalTime); +#else LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%lld)", totalTime); +#endif LOG_MEDIAOBJECT(); } diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp index 525aaf4..4ad5571 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -25,6 +25,7 @@ #include "GraphicsContext.h" #include "HTMLMediaElement.h" #include "HTMLVideoElement.h" +#include "NotImplemented.h" #include "TimeRanges.h" #include "Widget.h" #include "qwebframe.h" @@ -95,6 +96,7 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_isSeeking(false) , m_composited(false) , m_queuedSeek(-1) + , m_preload(MediaPlayer::Auto) { m_mediaPlayer->bind(m_videoItem); m_videoScene->addItem(m_videoItem); @@ -106,6 +108,8 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) this, SLOT(stateChanged(QMediaPlayer::State))); connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(handleError(QMediaPlayer::Error))); + connect(m_mediaPlayer, SIGNAL(bufferStatusChanged(int)), + this, SLOT(bufferStatusChanged(int))); connect(m_mediaPlayer, SIGNAL(durationChanged(qint64)), this, SLOT(durationChanged(qint64))); connect(m_mediaPlayer, SIGNAL(positionChanged(qint64)), @@ -145,6 +149,20 @@ bool MediaPlayerPrivate::hasAudio() const void MediaPlayerPrivate::load(const String& url) { + m_mediaUrl = url; + + // QtMultimedia does not have an API to throttle loading + // so we handle this ourselves by delaying the load + if (m_preload == MediaPlayer::None) { + m_delayingLoad = true; + return; + } + + commitLoad(url); +} + +void MediaPlayerPrivate::commitLoad(const String& url) +{ // We are now loading if (m_networkState != MediaPlayer::Loading) { m_networkState = MediaPlayer::Loading; @@ -208,6 +226,21 @@ void MediaPlayerPrivate::load(const String& url) // engine which does. m_mediaPlayer->setMuted(element->muted()); m_mediaPlayer->setVolume(static_cast<int>(element->volume() * 100.0)); + + // Setting a media source will start loading the media, but we need + // to pre-roll as well to get video size-hints and buffer-status + if (element->paused()) + m_mediaPlayer->pause(); + else + m_mediaPlayer->play(); +} + +void MediaPlayerPrivate::resumeLoad() +{ + m_delayingLoad = false; + + if (!m_mediaUrl.isNull()) + commitLoad(m_mediaUrl); } void MediaPlayerPrivate::cancelLoad() @@ -216,6 +249,12 @@ void MediaPlayerPrivate::cancelLoad() updateStates(); } +void MediaPlayerPrivate::prepareToPlay() +{ + if (m_mediaPlayer->media().isNull() || m_delayingLoad) + resumeLoad(); +} + void MediaPlayerPrivate::play() { if (m_mediaPlayer->state() != QMediaPlayer::PlayingState) @@ -322,24 +361,11 @@ float MediaPlayerPrivate::maxTimeSeekable() const unsigned MediaPlayerPrivate::bytesLoaded() const { - unsigned percentage = m_mediaPlayer->bufferStatus(); - - if (percentage == 100) { - if (m_networkState != MediaPlayer::Idle) { - m_networkState = MediaPlayer::Idle; - m_player->networkStateChanged(); - } - if (m_readyState != MediaPlayer::HaveEnoughData) { - m_readyState = MediaPlayer::HaveEnoughData; - m_player->readyStateChanged(); - } - } - QLatin1String bytesLoadedKey("bytes-loaded"); if (m_mediaPlayer->availableExtendedMetaData().contains(bytesLoadedKey)) return m_mediaPlayer->extendedMetaData(bytesLoadedKey).toInt(); - return percentage; + return m_mediaPlayer->bufferStatus(); } unsigned MediaPlayerPrivate::totalBytes() const @@ -350,6 +376,13 @@ unsigned MediaPlayerPrivate::totalBytes() const return 100; } +void MediaPlayerPrivate::setPreload(MediaPlayer::Preload preload) +{ + m_preload = preload; + if (m_delayingLoad && m_preload != MediaPlayer::None) + resumeLoad(); +} + void MediaPlayerPrivate::setRate(float rate) { m_mediaPlayer->setPlaybackRate(rate); @@ -439,6 +472,11 @@ void MediaPlayerPrivate::positionChanged(qint64) } } +void MediaPlayerPrivate::bufferStatusChanged(int) +{ + notImplemented(); +} + void MediaPlayerPrivate::durationChanged(qint64) { m_player->durationChanged(); diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h index d72404c..165efde 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h @@ -50,10 +50,13 @@ public: bool hasAudio() const; void load(const String &url); + void commitLoad(const String& url); + void resumeLoad(); void cancelLoad(); void play(); void pause(); + void prepareToPlay(); bool paused() const; bool seeking() const; @@ -68,6 +71,8 @@ public: bool supportsMuting() const; void setMuted(bool); + void setPreload(MediaPlayer::Preload); + MediaPlayer::NetworkState networkState() const; MediaPlayer::ReadyState readyState() const; @@ -103,6 +108,7 @@ private slots: void seekTimeout(); void positionChanged(qint64); void durationChanged(qint64); + void bufferStatusChanged(int); void volumeChanged(int); void mutedChanged(bool); void repaint(); @@ -127,6 +133,10 @@ private: bool m_isSeeking; bool m_composited; qint64 m_queuedSeek; + MediaPlayer::Preload m_preload; + bool m_delayingLoad; + String m_mediaUrl; + }; } diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp index de9de07..ce5da2e 100644 --- a/WebCore/platform/graphics/qt/PathQt.cpp +++ b/WebCore/platform/graphics/qt/PathQt.cpp @@ -51,6 +51,7 @@ namespace WebCore { Path::Path() + : m_lastMoveToIndex(0) { } @@ -60,12 +61,14 @@ Path::~Path() Path::Path(const Path& other) : m_path(other.m_path) + , m_lastMoveToIndex(other.m_lastMoveToIndex) { } Path& Path::operator=(const Path& other) { m_path = other.m_path; + m_lastMoveToIndex = other.m_lastMoveToIndex; return *this; } @@ -180,6 +183,7 @@ FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) void Path::moveTo(const FloatPoint& point) { + m_lastMoveToIndex = m_path.elementCount(); m_path.moveTo(point); } @@ -260,7 +264,26 @@ void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) void Path::closeSubpath() { - m_path.closeSubpath(); + const int elementCount = m_path.elementCount(); + + if (!elementCount) + return; + + QPointF lastMoveToPoint = m_path.elementAt(m_lastMoveToIndex); + int elementsInLastSubpath = 0; + + for (int i = m_lastMoveToIndex; i < elementCount; ++i) { + QPainterPath::Element element = m_path.elementAt(i); + if (element.isLineTo() || element.isCurveTo()) { + // All we need to know is if there are 1 or more elements in the last subpath. + if (++elementsInLastSubpath == 2) { + m_path.lineTo(lastMoveToPoint); + return; + } + } + } + + moveTo(lastMoveToPoint); } #define DEGREES(t) ((t) * 180.0 / M_PI) @@ -440,7 +463,7 @@ void Path::transform(const AffineTransform& transform) // QTransform.map doesn't handle the MoveTo element because of the isEmpty issue if (m_path.isEmpty() && m_path.elementCount()) { QPointF point = qTransform.map(m_path.currentPosition()); - m_path.moveTo(point); + moveTo(point); } else #endif m_path = qTransform.map(m_path); diff --git a/WebCore/platform/graphics/qt/TransparencyLayer.h b/WebCore/platform/graphics/qt/TransparencyLayer.h new file mode 100644 index 0000000..0d9c121 --- /dev/null +++ b/WebCore/platform/graphics/qt/TransparencyLayer.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2006 George Staikos <staikos@kde.org> + * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org> + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TransparencyLayer_h +#define TransparencyLayer_h + +#include <QPaintEngine> +#include <QPainter> +#include <QPixmap> + +namespace WebCore { + +struct TransparencyLayer : FastAllocBase { + TransparencyLayer(const QPainter* p, const QRect &rect, qreal opacity, QPixmap& alphaMask) + : pixmap(rect.width(), rect.height()) + , opacity(opacity) + , alphaMask(alphaMask) + , saveCounter(1) // see the comment for saveCounter + { + offset = rect.topLeft(); + pixmap.fill(Qt::transparent); + painter.begin(&pixmap); + painter.setRenderHint(QPainter::Antialiasing, p->testRenderHint(QPainter::Antialiasing)); + painter.translate(-offset); + painter.setPen(p->pen()); + painter.setBrush(p->brush()); + painter.setTransform(p->transform(), true); + painter.setOpacity(p->opacity()); + painter.setFont(p->font()); + if (painter.paintEngine()->hasFeature(QPaintEngine::PorterDuff)) + painter.setCompositionMode(p->compositionMode()); + // if the path is an empty region, this assignment disables all painting + if (!p->clipPath().isEmpty()) + painter.setClipPath(p->clipPath()); + } + + TransparencyLayer() + { + } + + QPixmap pixmap; + QPoint offset; + QPainter painter; + qreal opacity; + // for clipToImageBuffer + QPixmap alphaMask; + // saveCounter is only used in combination with alphaMask + // otherwise, its value is unspecified + int saveCounter; +private: + TransparencyLayer(const TransparencyLayer &) {} + TransparencyLayer & operator=(const TransparencyLayer &) { return *this; } +}; + +} // namespace WebCore + +#endif // TransparencyLayer_h |