diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:15 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:15 -0800 |
commit | 1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch) | |
tree | 4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /WebCore/platform/graphics/qt/GraphicsContextQt.cpp | |
parent | 9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff) | |
download | external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2 |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'WebCore/platform/graphics/qt/GraphicsContextQt.cpp')
-rw-r--r-- | WebCore/platform/graphics/qt/GraphicsContextQt.cpp | 390 |
1 files changed, 313 insertions, 77 deletions
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index cf097c8..600d77c 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -5,6 +5,9 @@ * 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. * @@ -32,20 +35,32 @@ #include "config.h" +#ifdef Q_WS_WIN +#include <windows.h> +#endif + #include "AffineTransform.h" -#include "Path.h" #include "Color.h" -#include "GraphicsContext.h" +#include "FloatConversion.h" #include "Font.h" +#include "GraphicsContext.h" +#include "GraphicsContextPrivate.h" +#include "ImageBuffer.h" +#include "Path.h" +#include "Pattern.h" #include "Pen.h" #include "NotImplemented.h" -#include <QStack> +#include <QDebug> +#include <QGradient> #include <QPainter> -#include <QPolygonF> -#include <QPainterPath> #include <QPaintDevice> -#include <QDebug> +#include <QPaintEngine> +#include <QPainterPath> +#include <QPixmap> +#include <QPolygonF> +#include <QStack> +#include <QVector> #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -137,6 +152,22 @@ static Qt::PenStyle toQPenStyle(StrokeStyle style) return Qt::NoPen; } +static inline QGradient applySpreadMethod(QGradient gradient, GradientSpreadMethod spreadMethod) +{ + switch (spreadMethod) { + case SpreadMethodPad: + gradient.setSpread(QGradient::PadSpread); + break; + case SpreadMethodReflect: + gradient.setSpread(QGradient::ReflectSpread); + break; + case SpreadMethodRepeat: + gradient.setSpread(QGradient::RepeatSpread); + break; + } + return gradient; +} + struct TransparencyLayer { TransparencyLayer(const QPainter* p, const QRect &rect) @@ -145,13 +176,15 @@ struct TransparencyLayer 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()); - painter.setCompositionMode(p->compositionMode()); + if (painter.paintEngine()->hasFeature(QPaintEngine::PorterDuff)) + painter.setCompositionMode(p->compositionMode()); painter.setClipPath(p->clipPath()); } @@ -168,24 +201,6 @@ private: TransparencyLayer & operator=(const TransparencyLayer &) { return *this; } }; -struct TextShadow -{ - TextShadow() - : x(0) - , y(0) - , blur(0) - { - } - - bool isNull() { return !x && !y && !blur; } - - int x; - int y; - int blur; - - Color color; -}; - class GraphicsContextPlatformPrivate { public: @@ -203,12 +218,12 @@ public: return &layers.top()->painter; } - QPaintDevice* device; + bool antiAliasingForRectsAndLines; QStack<TransparencyLayer *> layers; QPainter* redirect; - TextShadow shadow; + QBrush solidColor; // Only used by SVG for now. QPainterPath currentPath; @@ -221,12 +236,18 @@ private: GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p) { painter = p; - device = painter ? painter->device() : 0; redirect = 0; - // FIXME: Maybe only enable in SVG mode? - if (painter) - painter->setRenderHint(QPainter::Antialiasing); + solidColor = QBrush(Qt::black); + + if (painter) { + // use the default the QPainter was constructed with + antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing); + // FIXME: Maybe only enable in SVG mode? + painter->setRenderHint(QPainter::Antialiasing, true); + } else { + antiAliasingForRectsAndLines = false; + } } GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() @@ -386,7 +407,13 @@ void GraphicsContext::drawRect(const IntRect& rect) if (paintingDisabled()) return; - m_data->p()->drawRect(rect); + QPainter *p = m_data->p(); + const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); + p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); + + p->drawRect(rect); + + p->setRenderHint(QPainter::Antialiasing, antiAlias); } // FIXME: Now that this is refactored, it should be shared by all contexts. @@ -429,8 +456,25 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) FloatPoint p1 = point1; FloatPoint p2 = point2; + QPainter *p = m_data->p(); + const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); + p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); adjustLineToPixelBoundaries(p1, p2, strokeThickness(), strokeStyle()); - m_data->p()->drawLine(p1, p2); + + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (textDrawingMode() == cTextFill && getShadow(shadowSize, shadowBlur, shadowColor)) { + p->save(); + p->translate(shadowSize.width(), shadowSize.height()); + p->setPen(QColor(shadowColor)); + p->drawLine(p1, p2); + p->restore(); + } + + p->drawLine(p1, p2); + + p->setRenderHint(QPainter::Antialiasing, antiAlias); } // This method is only used to draw the little circles used in lists. @@ -447,7 +491,13 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha()) return; - m_data->p()->drawArc(rect, startAngle * 16, angleSpan * 16); + QPainter *p = m_data->p(); + const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); + p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); + + p->drawArc(rect, startAngle * 16, angleSpan * 16); + + p->setRenderHint(QPainter::Antialiasing, antiAlias); } void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) @@ -470,12 +520,80 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points p->restore(); } -void GraphicsContext::fillRect(const IntRect& rect, const Color& c) +void GraphicsContext::fillPath() +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QPainterPath path = m_data->currentPath; + + switch (m_common->state.fillColorSpace) { + case SolidColorSpace: + if (fillColor().alpha()) + p->fillPath(path, p->brush()); + break; + case PatternColorSpace: + p->fillPath(path, QBrush(m_common->state.fillPattern.get()->createPlatformPattern(getCTM()))); + break; + case GradientColorSpace: + QGradient* gradient = m_common->state.fillGradient.get()->platformGradient(); + *gradient = applySpreadMethod(*gradient, spreadMethod()); + p->fillPath(path, QBrush(*gradient)); + break; + } +} + +void GraphicsContext::strokePath() +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QPen pen = p->pen(); + QPainterPath path = m_data->currentPath; + + switch (m_common->state.strokeColorSpace) { + case SolidColorSpace: + if (strokeColor().alpha()) + p->strokePath(path, pen); + break; + case PatternColorSpace: { + pen.setBrush(QBrush(m_common->state.strokePattern.get()->createPlatformPattern(getCTM()))); + p->setPen(pen); + p->strokePath(path, pen); + break; + } + case GradientColorSpace: { + QGradient* gradient = m_common->state.strokeGradient.get()->platformGradient(); + *gradient = applySpreadMethod(*gradient, spreadMethod()); + pen.setBrush(QBrush(*gradient)); + p->setPen(pen); + p->strokePath(path, pen); + break; + } + } +} + +void GraphicsContext::fillRect(const FloatRect& rect) { if (paintingDisabled()) return; - m_data->p()->fillRect(rect, QColor(c)); + QPainter *p = m_data->p(); + + switch (m_common->state.fillColorSpace) { + case SolidColorSpace: + if (fillColor().alpha()) + p->fillRect(rect, p->brush()); + break; + case PatternColorSpace: + p->fillRect(rect, QBrush(m_common->state.fillPattern.get()->createPlatformPattern(getCTM()))); + break; + case GradientColorSpace: + p->fillRect(rect, QBrush(*(m_common->state.fillGradient.get()->platformGradient()))); + break; + } } void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) @@ -483,7 +601,8 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) if (paintingDisabled()) return; - m_data->p()->fillRect(rect, QColor(c)); + m_data->solidColor.setColor(QColor(c)); + m_data->p()->fillRect(rect, m_data->solidColor); } void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) @@ -505,9 +624,9 @@ void GraphicsContext::addPath(const Path& path) m_data->currentPath = *(path.platformPath()); } -void GraphicsContext::setFillRule(WindRule rule) +bool GraphicsContext::inTransparencyLayer() const { - m_data->currentPath.setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); + return !m_data->layers.isEmpty(); } PlatformPath* GraphicsContext::currentPath() @@ -515,7 +634,7 @@ PlatformPath* GraphicsContext::currentPath() return &m_data->currentPath; } -void GraphicsContext::clip(const IntRect& rect) +void GraphicsContext::clip(const FloatRect& rect) { if (paintingDisabled()) return; @@ -531,7 +650,6 @@ void GraphicsContext::clip(const IntRect& rect) * RenderTheme handles drawing focus on widgets which * need it. */ -void setFocusRingColorChangeFunction(void (*)()) { } Color focusRingColor() { return Color(0, 0, 0); } void GraphicsContext::drawFocusRing(const Color& color) { @@ -545,6 +663,8 @@ void GraphicsContext::drawFocusRing(const Color& color) return; QPainter *p = m_data->p(); + const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); + p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); const QPen oldPen = p->pen(); const QBrush oldBrush = p->brush(); @@ -568,6 +688,8 @@ void GraphicsContext::drawFocusRing(const Color& color) #endif p->setPen(oldPen); p->setBrush(oldBrush); + + p->setRenderHint(QPainter::Antialiasing, antiAlias); } void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) @@ -597,23 +719,16 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) return FloatRect(QRectF(result)); } -void GraphicsContext::setShadow(const IntSize& pos, int blur, const Color &color) +void GraphicsContext::setPlatformShadow(const IntSize& pos, int blur, const Color &color) { - if (paintingDisabled()) - return; - - m_data->shadow.x = pos.width(); - m_data->shadow.y = pos.height(); - m_data->shadow.blur = blur; - m_data->shadow.color = color; + // Qt doesn't support shadows natively, they are drawn manually in the draw* + // functions } -void GraphicsContext::clearShadow() +void GraphicsContext::clearPlatformShadow() { - if (paintingDisabled()) - return; - - m_data->shadow = TextShadow(); + // Qt doesn't support shadows natively, they are drawn manually in the draw* + // functions } void GraphicsContext::beginTransparencyLayer(float opacity) @@ -623,20 +738,18 @@ void GraphicsContext::beginTransparencyLayer(float opacity) int x, y, w, h; x = y = 0; - w = m_data->device->width(); - h = m_data->device->height(); - QPainter *p = m_data->p(); + const QPaintDevice *device = p->device(); + w = device->width(); + h = device->height(); + QRectF clip = p->clipPath().boundingRect(); - bool ok; - QTransform transform = p->transform().inverted(&ok); - if (ok) { - QRectF deviceClip = transform.mapRect(clip); - x = int(qBound(qreal(0), deviceClip.x(), (qreal)w)); - y = int(qBound(qreal(0), deviceClip.y(), (qreal)h)); - w = int(qBound(qreal(0), deviceClip.width(), (qreal)w) + 2); - h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2); - } + QRectF deviceClip = p->transform().mapRect(clip); + x = int(qBound(qreal(0), deviceClip.x(), (qreal)w)); + y = int(qBound(qreal(0), deviceClip.y(), (qreal)h)); + w = int(qBound(qreal(0), deviceClip.width(), (qreal)w) + 2); + h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2); + TransparencyLayer * layer = new TransparencyLayer(m_data->p(), QRect(x, y, w, h)); layer->opacity = opacity; @@ -668,9 +781,11 @@ void GraphicsContext::clearRect(const FloatRect& rect) QPainter *p = m_data->p(); QPainter::CompositionMode currentCompositionMode = p->compositionMode(); - p->setCompositionMode(QPainter::CompositionMode_Source); + if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) + p->setCompositionMode(QPainter::CompositionMode_Source); p->eraseRect(rect); - p->setCompositionMode(currentCompositionMode); + if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) + p->setCompositionMode(currentCompositionMode); } void GraphicsContext::strokeRect(const FloatRect& rect, float width) @@ -678,12 +793,12 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width) if (paintingDisabled()) return; - QPainter *p = m_data->p(); QPainterPath path; path.addRect(rect); - QPen nPen = p->pen(); - nPen.setWidthF(width); - p->strokePath(path, nPen); + setStrokeThickness(width); + m_data->currentPath = path; + + strokePath(); } void GraphicsContext::setLineCap(LineCap lc) @@ -697,6 +812,26 @@ void GraphicsContext::setLineCap(LineCap lc) p->setPen(nPen); } +void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) +{ + QPainter* p = m_data->p(); + QPen pen = p->pen(); + unsigned dashLength = dashes.size(); + if (dashLength) { + QVector<qreal> pattern; + unsigned count = dashLength; + if (dashLength % 2) + count *= 2; + + for (unsigned i = 0; i < count; i++) + pattern.append(dashes[i % dashLength] / narrowPrecisionToFloat(pen.widthF())); + + pen.setDashPattern(pattern); + pen.setDashOffset(dashOffset); + } + p->setPen(pen); +} + void GraphicsContext::setLineJoin(LineJoin lj) { if (paintingDisabled()) @@ -732,7 +867,8 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op) if (paintingDisabled()) return; - m_data->p()->setCompositionMode(toQtCompositionMode(op)); + if (m_data->p()->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) + m_data->p()->setCompositionMode(toQtCompositionMode(op)); } void GraphicsContext::clip(const Path& path) @@ -780,7 +916,7 @@ void GraphicsContext::rotate(float radians) if (paintingDisabled()) return; - m_data->p()->rotate(radians); + m_data->p()->rotate(180/M_PI*radians); } void GraphicsContext::scale(const FloatSize& s) @@ -795,7 +931,7 @@ void GraphicsContext::clipOut(const IntRect& rect) { if (paintingDisabled()) return; - + QPainter *p = m_data->p(); QRectF clipBounds = p->clipPath().boundingRect(); QPainterPath newClip; @@ -810,7 +946,7 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) { if (paintingDisabled()) return; - + QPainter *p = m_data->p(); QRectF clipBounds = p->clipPath().boundingRect(); QPainterPath newClip; @@ -821,6 +957,11 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) p->setClipPath(newClip, Qt::IntersectClip); } +void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) +{ + notImplemented(); +} + void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) { @@ -872,7 +1013,7 @@ void GraphicsContext::setPlatformStrokeColor(const Color& color) } void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle) -{ +{ if (paintingDisabled()) return; QPainter *p = m_data->p(); @@ -905,6 +1046,101 @@ void GraphicsContext::setUseAntialiasing(bool enable) m_data->p()->setRenderHint(QPainter::Antialiasing, enable); } +#ifdef Q_WS_WIN +#include <windows.h> + +HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + // painting through native HDC is only supported for plugin, where mayCreateBitmap is always TRUE + Q_ASSERT(mayCreateBitmap == TRUE); + + if (dstRect.isEmpty()) + return 0; + + // Create a bitmap DC in which to draw. + BITMAPINFO bitmapInfo; + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = dstRect.width(); + bitmapInfo.bmiHeader.biHeight = dstRect.height(); + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = 0; + bitmapInfo.bmiHeader.biXPelsPerMeter = 0; + bitmapInfo.bmiHeader.biYPelsPerMeter = 0; + bitmapInfo.bmiHeader.biClrUsed = 0; + bitmapInfo.bmiHeader.biClrImportant = 0; + + void* pixels = 0; + HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); + if (!bitmap) + return 0; + + HDC displayDC = ::GetDC(0); + HDC bitmapDC = ::CreateCompatibleDC(displayDC); + ::ReleaseDC(0, displayDC); + + ::SelectObject(bitmapDC, bitmap); + + // Fill our buffer with clear if we're going to alpha blend. + if (supportAlphaBlend) { + BITMAP bmpInfo; + GetObject(bitmap, sizeof(bmpInfo), &bmpInfo); + int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + memset(bmpInfo.bmBits, 0, bufferSize); + } + + // Make sure we can do world transforms. + SetGraphicsMode(bitmapDC, GM_ADVANCED); + + // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap. + XFORM xform; + xform.eM11 = 1.0f; + xform.eM12 = 0.0f; + xform.eM21 = 0.0f; + xform.eM22 = 1.0f; + xform.eDx = -dstRect.x(); + xform.eDy = -dstRect.y(); + ::SetWorldTransform(bitmapDC, &xform); + + + return bitmapDC; +} + +void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + // painting through native HDC is only supported for plugin, where mayCreateBitmap is always TRUE + Q_ASSERT(mayCreateBitmap == TRUE); + + if (hdc) { + + if (!dstRect.isEmpty()) { + + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap, supportAlphaBlend ? QPixmap::PremultipliedAlpha : QPixmap::NoAlpha); + m_data->p()->drawPixmap(dstRect, pixmap); + + ::DeleteObject(bitmap); + } + + ::DeleteDC(hdc); + } +} +#endif + +void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) +{ +} + +InterpolationQuality GraphicsContext::imageInterpolationQuality() const +{ + return InterpolationDefault; +} + } // vim: ts=4 sw=4 et |