diff options
Diffstat (limited to 'WebCore/platform/graphics/qt')
-rw-r--r-- | WebCore/platform/graphics/qt/FloatRectQt.cpp | 15 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/FontQt.cpp | 2 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/GradientQt.cpp | 4 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp | 2 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/GraphicsContextQt.cpp | 18 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/GraphicsLayerQt.cpp | 135 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/ImageQt.cpp | 17 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/PathQt.cpp | 43 |
8 files changed, 178 insertions, 58 deletions
diff --git a/WebCore/platform/graphics/qt/FloatRectQt.cpp b/WebCore/platform/graphics/qt/FloatRectQt.cpp index 1c918e3..063876b 100644 --- a/WebCore/platform/graphics/qt/FloatRectQt.cpp +++ b/WebCore/platform/graphics/qt/FloatRectQt.cpp @@ -44,6 +44,21 @@ FloatRect::operator QRectF() const return QRectF(x(), y(), width(), height()); } +FloatRect FloatRect::normalized() const +{ + FloatRect normalizedRect = *this; + + if (width() < 0) { + normalizedRect.setX(x() + width()); + normalizedRect.setWidth(-width()); + } + if (height() < 0) { + normalizedRect.setY(y() + height()); + normalizedRect.setHeight(-height()); + } + return normalizedRect; +} + } // vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index 0c1d271..59320cb 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -234,7 +234,7 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon return 0; if (run.length() == 1 && treatAsSpace(run[0])) - return QFontMetrics(font()).width(run[0]) + run.padding(); + return QFontMetrics(font()).width(space) + run.padding(); String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); QString string = fromRawDataWithoutRef(sanitized); diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp index 8b9e2d7..1f05a15 100644 --- a/WebCore/platform/graphics/qt/GradientQt.cpp +++ b/WebCore/platform/graphics/qt/GradientQt.cpp @@ -51,6 +51,8 @@ QGradient* Gradient::platformGradient() else m_gradient = new QLinearGradient(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y()); + m_gradient->setInterpolationMode(QGradient::ComponentInterpolation); + sortStopsIfNecessary(); QColor stopColor; @@ -65,7 +67,7 @@ QGradient* Gradient::platformGradient() lastStop = stopIterator->stop; if (m_radial && m_r0) lastStop = m_r0 / m_r1 + lastStop * (1.0f - m_r0 / m_r1); - m_gradient->setColorAt(lastStop, stopColor); + m_gradient->setColorAt(qMin(lastStop, qreal(1.0f)), stopColor); // Keep the lastStop as orginal value, since the following stopColor depend it lastStop = stopIterator->stop; ++stopIterator; diff --git a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index 1a51910..002765f 100644 --- a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -1637,7 +1637,7 @@ bool GraphicsContext3D::getImageData(Image* image, neededAlphaOp = kAlphaDoUnmultiply; QImage nativeImage = nativePixmap->toImage().convertToFormat(QImage::Format_ARGB32); outputVector.resize(nativeImage.byteCount()); - return packPixels(nativeImage.rgbSwapped().bits(), kSourceFormatRGBA8, image->width(), image->height(), + return packPixels(nativeImage.rgbSwapped().bits(), kSourceFormatRGBA8, image->width(), image->height(), 0, format, type, neededAlphaOp, outputVector.data()); } diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 13608b2..9d23340 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -528,6 +528,17 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points p->restore(); } +void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points) +{ + if (paintingDisabled()) + return; + + if (numPoints <= 1) + return; + + // FIXME: IMPLEMENT!! +} + QPen GraphicsContext::pen() { if (paintingDisabled()) @@ -1056,7 +1067,12 @@ void GraphicsContext::clip(const Path& path) void GraphicsContext::canvasClip(const Path& path) { - clip(path); + if (paintingDisabled()) + return; + + QPainterPath clipPath = path.platformPath(); + clipPath.setFillRule(Qt::WindingFill); + m_data->p()->setClipPath(clipPath, Qt::IntersectClip); } void GraphicsContext::clipOut(const Path& path) diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp index 8ed0d89..226f1fb 100644 --- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp @@ -41,6 +41,10 @@ #include <QtGui/qpixmapcache.h> #include <QtGui/qstyleoption.h> + +#define QT_DEBUG_RECACHE 0 +#define QT_DEBUG_CACHEDUMP 0 + namespace WebCore { #ifndef QT_NO_GRAPHICSEFFECT @@ -225,7 +229,10 @@ public: int m_changeMask; QSizeF m_size; - QPixmapCache::Key m_backingStoreKey; + struct { + QPixmapCache::Key key; + QSizeF size; + } m_backingStore; #ifndef QT_NO_ANIMATION QList<QWeakPointer<QAbstractAnimation> > m_animations; #endif @@ -283,7 +290,6 @@ inline GraphicsLayerQtImpl* toGraphicsLayerQtImpl(QGraphicsItem* item) inline GraphicsLayerQtImpl* toGraphicsLayerQtImpl(QGraphicsObject* item) { - ASSERT(item); return qobject_cast<GraphicsLayerQtImpl*>(item); } @@ -339,36 +345,109 @@ const GraphicsLayerQtImpl* GraphicsLayerQtImpl::rootLayer() const QPixmap GraphicsLayerQtImpl::recache(const QRegion& regionToUpdate) { - if (!m_layer->drawsContent() || m_size.isEmpty() ||!m_size.isValid()) + if (!m_layer->drawsContent() || m_size.isEmpty() || !m_size.isValid()) return QPixmap(); - QRegion region = regionToUpdate; QPixmap pixmap; + QRegion region = regionToUpdate; + if (QPixmapCache::find(m_backingStore.key, &pixmap)) { + if (region.isEmpty()) + return pixmap; + QPixmapCache::remove(m_backingStore.key); // Remove the reference to the pixmap in the cache to avoid a detach. + } - // We might be drawing into an existing cache. - if (!QPixmapCache::find(m_backingStoreKey, &pixmap)) - region = QRegion(QRect(0, 0, m_size.width(), m_size.height())); + { + bool erased = false; - if (m_size != pixmap.size()) { - pixmap = QPixmap(m_size.toSize()); - if (!m_layer->contentsOpaque()) - pixmap.fill(Qt::transparent); - m_pendingContent.regionToUpdate = QRegion(QRect(QPoint(0, 0), m_size.toSize())); - } + // If the pixmap is not in the cache or the view has grown since last cached. + if (pixmap.isNull() || m_size != m_backingStore.size) { +#if QT_DEBUG_RECACHE + if (pixmap.isNull()) + qDebug() << "CacheMiss" << this << m_size; +#endif + bool fill = true; + QRegion newRegion; + QPixmap oldPixmap = pixmap; + + // If the pixmap is two small to hold the view contents we enlarge, otherwise just use the old (large) pixmap. + if (pixmap.width() < m_size.width() || pixmap.height() < m_size.height()) { +#if QT_DEBUG_RECACHE + qDebug() << "CacheGrow" << this << m_size; +#endif + pixmap = QPixmap(m_size.toSize()); + pixmap.fill(Qt::transparent); + newRegion = QRegion(0, 0, m_size.width(), m_size.height()); + } + +#if 1 + // Blit the contents of oldPixmap back into the cached pixmap as we are just adding new pixels. + if (!oldPixmap.isNull()) { + const QRegion cleanRegion = (QRegion(0, 0, m_size.width(), m_size.height()) + & QRegion(0, 0, m_backingStore.size.width(), m_backingStore.size.height())) - regionToUpdate; + if (!cleanRegion.isEmpty()) { +#if QT_DEBUG_RECACHE + qDebug() << "CacheBlit" << this << cleanRegion; +#endif + const QRect cleanBounds(cleanRegion.boundingRect()); + QPainter painter(&pixmap); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.drawPixmap(cleanBounds.topLeft(), oldPixmap, cleanBounds); + newRegion -= cleanRegion; + fill = false; // We cannot just fill the pixmap. + } + oldPixmap = QPixmap(); + } +#endif + region += newRegion; + if (fill && !region.isEmpty()) { // Clear the entire pixmap with the background. +#if QT_DEBUG_RECACHE + qDebug() << "CacheErase" << this << m_size << background; +#endif + erased = true; + pixmap.fill(Qt::transparent); + } + } + region &= QRegion(0, 0, m_size.width(), m_size.height()); + + // If we have something to draw its time to erase it and render the contents. + if (!region.isEmpty()) { +#if QT_DEBUG_CACHEDUMP + static int recacheCount = 0; + ++recacheCount; + qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size; + pixmap.save(QString().sprintf("/tmp/%05d_A.png", recacheCount), "PNG"); +#endif + + QPainter painter(&pixmap); + GraphicsContext gc(&painter); - QPainter painter(&pixmap); - GraphicsContext gc(&painter); + painter.setClipRegion(region); - // Clear the area in cache that we're drawing into - painter.setCompositionMode(QPainter::CompositionMode_Clear); - painter.fillRect(region.boundingRect(), Qt::transparent); + if (!erased) { // Erase the area in cache that we're drawing into. + painter.setCompositionMode(QPainter::CompositionMode_Clear); + painter.fillRect(region.boundingRect(), Qt::transparent); - // Render the actual contents into the cache - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - m_layer->paintGraphicsLayerContents(gc, region.boundingRect()); - painter.end(); +#if QT_DEBUG_CACHEDUMP + qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size; + pixmap.save(QString().sprintf("/tmp/%05d_B.png", recacheCount), "PNG"); +#endif + } - m_backingStoreKey = QPixmapCache::insert(pixmap); + // Render the actual contents into the cache. + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + m_layer->paintGraphicsLayerContents(gc, region.boundingRect()); + painter.end(); + +#if QT_DEBUG_CACHEDUMP + qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size; + pixmap.save(QString().sprintf("/tmp/%05d_C.png", recacheCount), "PNG"); +#endif + } + m_backingStore.size = m_size; // Store the used size of the pixmap. + } + + // Finally insert into the cache and allow a reference there. + m_backingStore.key = QPixmapCache::insert(pixmap); return pixmap; } @@ -487,8 +566,9 @@ void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsIte if (m_state.drawsContent) { QPixmap backingStore; // We might need to recache, in case we try to paint and the cache was purged (e.g. if it was full). - if (!QPixmapCache::find(m_backingStoreKey, &backingStore) || backingStore.size() != m_size.toSize()) + if (!QPixmapCache::find(m_backingStore.key, &backingStore) || backingStore.size() != m_size.toSize()) backingStore = recache(QRegion(m_state.contentsRect)); + const QRectF bounds(0, 0, m_backingStore.size.width(), m_backingStore.size.height()); painter->drawPixmap(0, 0, backingStore); } break; @@ -674,11 +754,13 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform else #endif if (m_changeMask & DisplayChange) { +#ifndef QT_GRAPHICS_LAYER_NO_RECACHE_ON_DISPLAY_CHANGE // Recache now: all the content is ready and we don't want to wait until the paint event. // We only need to do this for HTML content, there's no point in caching directly composited // content like images or solid rectangles. if (m_pendingContent.contentType == HTMLContentType) recache(m_pendingContent.regionToUpdate); +#endif update(m_pendingContent.regionToUpdate.boundingRect()); m_pendingContent.regionToUpdate = QRegion(); } @@ -1441,10 +1523,7 @@ bool GraphicsLayerQt::addAnimation(const KeyframeValueList& values, const IntSiz if (anim->fillsBackwards()) newAnim->setCurrentTime(0); - if (anim->delay()) - QTimer::singleShot(anim->delay() * 1000, newAnim, SLOT(start())); - else - newAnim->start(); + newAnim->start(); // We synchronize the animation's clock to WebCore's timeOffset. newAnim->setCurrentTime(timeOffset * 1000); diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp index af94f55..dd97873 100644 --- a/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -64,6 +64,8 @@ static QPixmap loadResourcePixmap(const char *name) pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic); else if (qstrcmp(name, "deleteButton") == 0) pixmap = QWebSettings::webGraphic(QWebSettings::DeleteButtonGraphic); + else if (!qstrcmp(name, "inputSpeech")) + pixmap = QWebSettings::webGraphic(QWebSettings::InputSpeechButtonGraphic); return pixmap; } @@ -164,6 +166,9 @@ void BitmapImage::invalidatePlatformData() void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { + FloatRect normalizedDst = dst.normalized(); + FloatRect normalizedSrc = src.normalized(); + startAnimation(); QPixmap* image = nativeImageForCurrentFrame(); @@ -171,7 +176,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); + fillWithSolidColor(ctxt, normalizedDst, solidColor(), styleColorSpace, op); return; } @@ -191,22 +196,22 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, float shadowBlur; Color shadowColor; if (ctxt->getShadow(shadowSize, shadowBlur, shadowColor)) { - FloatRect shadowImageRect(dst); + FloatRect shadowImageRect(normalizedDst); shadowImageRect.move(shadowSize.width(), shadowSize.height()); - QImage shadowImage(QSize(static_cast<int>(src.width()), static_cast<int>(src.height())), QImage::Format_ARGB32_Premultiplied); + QImage shadowImage(QSize(static_cast<int>(normalizedSrc.width()), static_cast<int>(normalizedSrc.height())), QImage::Format_ARGB32_Premultiplied); QPainter p(&shadowImage); p.setCompositionMode(QPainter::CompositionMode_Source); p.fillRect(shadowImage.rect(), shadowColor); p.setCompositionMode(QPainter::CompositionMode_DestinationIn); - p.drawPixmap(dst, *image, src); + p.drawPixmap(normalizedDst, *image, normalizedSrc); p.end(); - painter->drawImage(shadowImageRect, shadowImage, src); + painter->drawImage(shadowImageRect, shadowImage, normalizedSrc); } // Test using example site at // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html - painter->drawPixmap(dst, *image, src); + painter->drawPixmap(normalizedDst, *image, normalizedSrc); painter->setCompositionMode(lastCompositionMode); diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp index 8f1f912..a367212 100644 --- a/WebCore/platform/graphics/qt/PathQt.cpp +++ b/WebCore/platform/graphics/qt/PathQt.cpp @@ -69,8 +69,19 @@ Path& Path::operator=(const Path& other) return *this; } +static inline bool areCollinear(const QPointF& a, const QPointF& b, const QPointF& c) +{ + // Solved from comparing the slopes of a to b and b to c: (ay-by)/(ax-bx) == (cy-by)/(cx-bx) + return qFuzzyCompare((c.y() - b.y()) * (a.x() - b.x()), (a.y() - b.y()) * (c.x() - b.x())); +} + +static inline bool withinRange(qreal p, qreal a, qreal b) +{ + return (p >= a && p <= b) || (p >= b && p <= a); +} + // Check whether a point is on the border -bool isPointOnPathBorder(const QPolygonF& border, const QPointF& p) +static bool isPointOnPathBorder(const QPolygonF& border, const QPointF& p) { // null border doesn't contain points if (border.isEmpty()) @@ -81,15 +92,12 @@ bool isPointOnPathBorder(const QPolygonF& border, const QPointF& p) for (int i = 1; i < border.size(); ++i) { p2 = border.at(i); - // (x1<=x<=x2||x1=>x>=x2) && (y1<=y<=y2||y1=>y>=y2) && (y2-y1)(x-x1) == (y-y1)(x2-x1) - // In which, (y2-y1)(x-x1) == (y-y1)(x2-x1) is from (y2-y1)/(x2-x1) == (y-y1)/(x-x1) - // it want to check the slope between p1 and p2 is same with slope between p and p1, - // if so then the three points lie on the same line. - // In which, (x1<=x<=x2||x1=>x>=x2) && (y1<=y<=y2||y1=>y>=y2) want to make sure p is - // between p1 and p2, not outside. - if (((p.x() <= p1.x() && p.x() >= p2.x()) || (p.x() >= p1.x() && p.x() <= p2.x())) - && ((p.y() <= p1.y() && p.y() >= p2.y()) || (p.y() >= p1.y() && p.y() <= p2.y())) - && (p2.y() - p1.y()) * (p.x() - p1.x()) == (p.y() - p1.y()) * (p2.x() - p1.x())) { + if (areCollinear(p, p1, p2) + // Once we know that the points are collinear we + // only need to check one of the coordinates + && (qAbs(p2.x() - p1.x()) > qAbs(p2.y() - p1.y()) ? + withinRange(p.x(), p1.x(), p2.x()) : + withinRange(p.y(), p1.y(), p2.y()))) { return true; } p1 = p2; @@ -212,19 +220,14 @@ void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) float p1p2_length = sqrtf(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y()); double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length); - // all points on a line logic - if (cos_phi == -1) { + + // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8) + // We could have used areCollinear() here, but since we're reusing + // the variables computed above later on we keep this logic. + if (qFuzzyCompare(qAbs(cos_phi), 1.0)) { m_path.lineTo(p1); return; } - if (cos_phi == 1) { - // add infinite far away point - unsigned int max_length = 65535; - double factor_max = max_length / p1p0_length; - FloatPoint ep((p0.x() + factor_max * p1p0.x()), (p0.y() + factor_max * p1p0.y())); - m_path.lineTo(ep); - return; - } float tangent = radius / tan(acos(cos_phi) / 2); float factor_p1p0 = tangent / p1p0_length; |