diff options
Diffstat (limited to 'WebCore/platform/graphics/qt')
29 files changed, 4824 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/qt/AffineTransformQt.cpp b/WebCore/platform/graphics/qt/AffineTransformQt.cpp new file mode 100644 index 0000000..2793043 --- /dev/null +++ b/WebCore/platform/graphics/qt/AffineTransformQt.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * + * 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 "AffineTransform.h" + +#include "IntRect.h" +#include "FloatRect.h" + +namespace WebCore { + +AffineTransform::AffineTransform() + : m_transform() +{ +} + +AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty) + : m_transform(a, b, c, d, tx, ty) +{ +} + +AffineTransform::AffineTransform(const PlatformAffineTransform& matrix) + : m_transform(matrix) +{ +} + +void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty) +{ + m_transform.setMatrix(a, b, c, d, tx, ty); +} + +void AffineTransform::map(double x, double y, double* x2, double* y2) const +{ + qreal tx2, ty2; + m_transform.map(qreal(x), qreal(y), &tx2, &ty2); + *x2 = tx2; + *y2 = ty2; +} + +IntRect AffineTransform::mapRect(const IntRect& rect) const +{ + return m_transform.mapRect(rect); +} + +FloatRect AffineTransform::mapRect(const FloatRect& rect) const +{ + return m_transform.mapRect(rect); +} + +bool AffineTransform::isIdentity() const +{ + return m_transform.isIdentity(); +} + +double AffineTransform::a() const +{ + return m_transform.m11(); +} + +void AffineTransform::setA(double a) +{ + m_transform.setMatrix(a, b(), c(), d(), e(), f()); +} + +double AffineTransform::b() const +{ + return m_transform.m12(); +} + +void AffineTransform::setB(double b) +{ + m_transform.setMatrix(a(), b, c(), d(), e(), f()); +} + +double AffineTransform::c() const +{ + return m_transform.m21(); +} + +void AffineTransform::setC(double c) +{ + m_transform.setMatrix(a(), b(), c, d(), e(), f()); +} + +double AffineTransform::d() const +{ + return m_transform.m22(); +} + +void AffineTransform::setD(double d) +{ + m_transform.setMatrix(a(), b(), c(), d, e(), f()); +} + +double AffineTransform::e() const +{ + return m_transform.dx(); +} + +void AffineTransform::setE(double e) +{ + m_transform.setMatrix(a(), b(), c(), d(), e, f()); +} + +double AffineTransform::f() const +{ + return m_transform.dy(); +} + +void AffineTransform::setF(double f) +{ + m_transform.setMatrix(a(), b(), c(), d(), e(), f); +} + +void AffineTransform::reset() +{ + m_transform.reset(); +} + +AffineTransform& AffineTransform::scale(double sx, double sy) +{ + m_transform.scale(sx, sy); + return *this; +} + +AffineTransform& AffineTransform::rotate(double d) +{ + m_transform.rotate(d); + return *this; +} + +AffineTransform& AffineTransform::translate(double tx, double ty) +{ + m_transform.translate(tx, ty); + return *this; +} + +AffineTransform& AffineTransform::shear(double sx, double sy) +{ + m_transform.shear(sx, sy); + return *this; +} + +double AffineTransform::det() const +{ + return m_transform.det(); +} + +AffineTransform AffineTransform::inverse() const +{ + if(!isInvertible()) + return AffineTransform(); + + return m_transform.inverted(); +} + +AffineTransform::operator QMatrix() const +{ + return m_transform; +} + +bool AffineTransform::operator==(const AffineTransform& other) const +{ + return m_transform == other.m_transform; +} + +AffineTransform& AffineTransform::operator*=(const AffineTransform& other) +{ + m_transform *= other.m_transform; + return *this; +} + +AffineTransform AffineTransform::operator*(const AffineTransform& other) +{ + return m_transform * other.m_transform; +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/ColorQt.cpp b/WebCore/platform/graphics/qt/ColorQt.cpp new file mode 100644 index 0000000..5d16740 --- /dev/null +++ b/WebCore/platform/graphics/qt/ColorQt.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * 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 "Color.h" + +#include <QColor> + +namespace WebCore { + +Color::Color(const QColor& c) + : m_color(makeRGBA(c.red(), c.green(), c.blue(), c.alpha())) +{ + m_valid = c.isValid(); +} + +Color::operator QColor() const +{ + return QColor(red(), green(), blue(), alpha()); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/FloatPointQt.cpp b/WebCore/platform/graphics/qt/FloatPointQt.cpp new file mode 100644 index 0000000..82093d8 --- /dev/null +++ b/WebCore/platform/graphics/qt/FloatPointQt.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * 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 "FloatPoint.h" + +#include <QPointF> + +namespace WebCore { + +FloatPoint::FloatPoint(const QPointF& p) + : m_x(p.x()) + , m_y(p.y()) +{ +} + +FloatPoint::operator QPointF() const +{ + return QPointF(m_x, m_y); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/FloatRectQt.cpp b/WebCore/platform/graphics/qt/FloatRectQt.cpp new file mode 100644 index 0000000..1c918e3 --- /dev/null +++ b/WebCore/platform/graphics/qt/FloatRectQt.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * 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 "FloatRect.h" + +#include <QRectF> + +namespace WebCore { + +FloatRect::FloatRect(const QRectF& r) + : m_location(r.topLeft()) + , m_size(r.width() + , r.height()) +{ +} + +FloatRect::operator QRectF() const +{ + return QRectF(x(), y(), width(), height()); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp new file mode 100644 index 0000000..be31d96 --- /dev/null +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -0,0 +1,56 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#include "config.h" +#include "FontCache.h" +#include "FontDescription.h" +#include "Font.h" + +namespace WebCore { + +void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) +{ +} + +FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName) +{ + return 0; +} + +SimpleFontData* FontCache::getCachedFontData(const FontPlatformData*) +{ + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&) +{ + return 0; +} + +void FontCache::addClient(FontSelector*) +{ +} + +void FontCache::removeClient(FontSelector*) +{ +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp new file mode 100644 index 0000000..8fc3ea0 --- /dev/null +++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp @@ -0,0 +1,56 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#include "config.h" +#include "FontCustomPlatformData.h" + +#include "FontPlatformData.h" +#include "SharedBuffer.h" +#include <QFontDatabase> + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ + QFontDatabase::removeApplicationFont(handle); +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode) +{ + FontPlatformData result; + result.handle = handle; + return result; +} + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + ASSERT_ARG(buffer, buffer); + + int id = QFontDatabase::addApplicationFontFromData(QByteArray(buffer->data(), buffer->size())); + if (id == -1) + return 0; + FontCustomPlatformData *data = new FontCustomPlatformData; + data->handle = id; + return data; +} + +} + diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.h b/WebCore/platform/graphics/qt/FontCustomPlatformData.h new file mode 100644 index 0000000..da5159d --- /dev/null +++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#ifndef FontCustomPlatformData_h_ +#define FontCustomPlatformData_h_ + +#include "FontRenderingMode.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class SharedBuffer; +class FontPlatformData; + +struct FontCustomPlatformData : Noncopyable { + ~FontCustomPlatformData(); + + int handle; // for use with QFontDatabase::addApplicationFont/removeApplicationFont + + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode); +}; + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer); + +} // namespace WebCore + +#endif // FontCustomPlatformData_h_ diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h new file mode 100644 index 0000000..e4363be --- /dev/null +++ b/WebCore/platform/graphics/qt/FontPlatformData.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#ifndef FontPlatformData_h +#define FontPlatformData_h + +namespace WebCore { + +class FontPlatformData +{ +public: + // this is only used for custom loaded fonts and represents the id handle passed to + // QFontDatabase::addApplicationFont/removeApplicationFont + int handle; +}; + +} // namespace WebCore + +#endif // FontPlatformData_h diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp new file mode 100644 index 0000000..e2ef605 --- /dev/null +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -0,0 +1,706 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "Font.h" +#include "FontDescription.h" +#include "FontSelector.h" + +#include "GraphicsContext.h" +#include <QTextLayout> +#include <QPainter> +#include <QFontMetrics> +#include <QFontInfo> +#include <qalgorithms.h> +#include <qdebug.h> + +#include <limits.h> +namespace WebCore { + +#if QT_VERSION >= 0x040400 + +Font::Font() + : m_letterSpacing(0) + , m_wordSpacing(0) + , m_font() + , m_scFont() +{ + QFontMetrics metrics(m_font); + m_spaceWidth = metrics.width(QLatin1Char(' ')); +} + +Font::Font(const FontDescription& description, short letterSpacing, short wordSpacing) + : m_fontDescription(description) + , m_letterSpacing(letterSpacing) + , m_wordSpacing(wordSpacing) +{ + const FontFamily* family = &description.family(); + QString familyName; + while (family) { + familyName += family->family(); + family = family->next(); + if (family) + familyName += QLatin1Char(','); + } + + m_font.setFamily(familyName); + m_font.setPixelSize(qRound(description.computedSize())); + m_font.setItalic(description.italic()); + // FIXME: Map all FontWeight values to QFont weights. + if (description.weight() >= FontWeight600) + m_font.setWeight(QFont::Bold); + else + m_font.setWeight(QFont::Normal); + + bool smallCaps = description.smallCaps(); + m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); + + QFontMetrics metrics = QFontMetrics(m_font); + m_spaceWidth = metrics.width(QLatin1Char(' ')); + + if (wordSpacing) + m_font.setWordSpacing(wordSpacing); + if (letterSpacing) + m_font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); +} + +void Font::setWordSpacing(short s) +{ + m_font.setWordSpacing(s); + m_wordSpacing = s; +} +void Font::setLetterSpacing(short s) +{ + m_font.setLetterSpacing(QFont::AbsoluteSpacing, s); + m_letterSpacing = s; +} + + +static QString qstring(const TextRun& run) +{ + QString string((QChar *)run.characters(), run.length()); + QChar *uc = string.data(); + for (int i = 0; i < string.length(); ++i) { + if (Font::treatAsSpace(uc[i].unicode())) + uc[i] = 0x20; + else if (Font::treatAsZeroWidthSpace(uc[i].unicode())) + uc[i] = 0x200c; + } + return string; +} + + +static QTextLine setupLayout(QTextLayout* layout, const TextRun& style) +{ + int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; + if (style.padding()) + flags |= Qt::TextJustificationForced; + layout->setFlags(flags); + layout->beginLayout(); + QTextLine line = layout->createLine(); + line.setLineWidth(INT_MAX/256); + if (style.padding()) + line.setLineWidth(line.naturalTextWidth() + style.padding()); + layout->endLayout(); + return line; +} + +void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + if (to < 0) + to = run.length(); + QPainter *p = ctx->platformContext(); + Color color = ctx->fillColor(); + p->setPen(QColor(color)); + + QString string = qstring(run); + + // text shadow + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + bool hasShadow = ctx->textDrawingMode() == cTextFill && ctx->getShadow(shadowSize, shadowBlur, shadowColor); + + if (from > 0 || to < run.length()) { + QTextLayout layout(string, m_font); + QTextLine line = setupLayout(&layout, run); + float x1 = line.cursorToX(from); + float x2 = line.cursorToX(to); + if (x2 < x1) + qSwap(x1, x2); + + QFontMetrics fm(m_font); + int ascent = fm.ascent(); + QRectF clip(point.x() + x1, point.y() - ascent, x2 - x1, fm.height()); + + if (hasShadow) { + // TODO: when blur support is added, the clip will need to account + // for the blur radius + qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0; + if (shadowSize.width() > 0) + dx2 = shadowSize.width(); + else + dx1 = -shadowSize.width(); + if (shadowSize.height() > 0) + dy2 = shadowSize.height(); + else + dy1 = -shadowSize.height(); + // expand the clip rect to include the text shadow as well + clip.adjust(dx1, dx2, dy1, dy2); + } + p->save(); + p->setClipRect(clip.toRect()); + QPointF pt(point.x(), point.y() - ascent); + if (hasShadow) { + p->save(); + p->setPen(QColor(shadowColor)); + p->translate(shadowSize.width(), shadowSize.height()); + line.draw(p, pt); + p->restore(); + } + line.draw(p, pt); + p->restore(); + return; + } + + p->setFont(m_font); + + QPointF pt(point.x(), point.y()); + int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; + if (hasShadow) { + // TODO: text shadow blur support + p->save(); + p->setPen(QColor(shadowColor)); + p->translate(shadowSize.width(), shadowSize.height()); + p->drawText(pt, string, flags, run.padding()); + p->restore(); + } + p->drawText(pt, string, flags, run.padding()); +} + +int Font::width(const TextRun& run) const +{ + if (!run.length()) + return 0; + QString string = qstring(run); + QTextLayout layout(string, m_font); + QTextLine line = setupLayout(&layout, run); + int w = int(line.naturalTextWidth()); + // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) + if (treatAsSpace(run[0])) + w -= m_wordSpacing; + + return w + run.padding(); +} + +float Font::floatWidth(const TextRun& run) const +{ + return width(run); +} + +float Font::floatWidth(const TextRun& run, int /*extraCharsAvailable*/, int& charsConsumed, String& glyphName) const +{ + charsConsumed = run.length(); + glyphName = ""; + return width(run); +} + +int Font::offsetForPosition(const TextRun& run, int position, bool /*includePartialGlyphs*/) const +{ + QString string = qstring(run); + QTextLayout layout(string, m_font); + QTextLine line = setupLayout(&layout, run); + return line.xToCursor(position); +} + +FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& pt, int h, int from, int to) const +{ + QString string = qstring(run); + QTextLayout layout(string, m_font); + QTextLine line = setupLayout(&layout, run); + + float x1 = line.cursorToX(from); + float x2 = line.cursorToX(to); + if (x2 < x1) + qSwap(x1, x2); + + return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); +} + +#else + + +struct TextRunComponent { + TextRunComponent() : font(0) {} + TextRunComponent(const UChar *start, int length, bool rtl, const QFont *font, int offset, bool sc = false); + TextRunComponent(int spaces, bool rtl, const QFont *font, int offset); + + inline bool isSpace() const { return spaces != 0; } + + QString string; + const QFont *font; + int width; + int offset; + int spaces; +}; + +TextRunComponent::TextRunComponent(const UChar *start, int length, bool rtl, const QFont *f, int o, bool sc) + : string(reinterpret_cast<const QChar*>(start), length) + , font(f) + , offset(o) + , spaces(0) +{ + if (sc) + string = string.toUpper(); + string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); + width = QFontMetrics(*font).width(string); +} + +TextRunComponent::TextRunComponent(int s, bool rtl, const QFont *f, int o) + : string(s, QLatin1Char(' ')) + , font(f) + , offset(o) + , spaces(s) +{ + string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); + width = spaces * QFontMetrics(*font).width(QLatin1Char(' ')); +} + + +Font::Font() + : m_letterSpacing(0) + , m_wordSpacing(0) + , m_font() + , m_scFont() +{ + QFontMetrics metrics(m_font); + m_spaceWidth = metrics.width(QLatin1Char(' ')); + qreal pointsize = m_font.pointSizeF(); + if (pointsize > 0) + m_scFont.setPointSizeF(pointsize*0.7); + else + m_scFont.setPixelSize(qRound(m_font.pixelSize()*.7)); +} + +Font::Font(const FontDescription& description, short letterSpacing, short wordSpacing) + : m_fontDescription(description) + , m_letterSpacing(letterSpacing) + , m_wordSpacing(wordSpacing) +{ + const FontFamily* family = &description.family(); + QString familyName; + while (family) { + familyName += family->family(); + family = family->next(); + if (family) + familyName += QLatin1Char(','); + } + + m_font.setFamily(familyName); + m_font.setPixelSize(qRound(description.computedSize())); + m_font.setItalic(description.italic()); + // FIXME: Map all FontWeight values to QFont weights. + if (description.weight() >= FontWeight600) + m_font.setWeight(QFont::Bold); + else + m_font.setWeight(QFont::Normal); + + QFontMetrics metrics = QFontMetrics(m_font); + m_spaceWidth = metrics.width(QLatin1Char(' ')); + m_scFont = m_font; + m_scFont.setPixelSize(qRound(description.computedSize()*.7)); +} + +void Font::setWordSpacing(short s) +{ + m_wordSpacing = s; +} +void Font::setLetterSpacing(short s) +{ + m_letterSpacing = s; +} + +static int generateComponents(Vector<TextRunComponent, 1024>* components, const Font &font, const TextRun &run) +{ +// qDebug() << "generateComponents" << QString((const QChar *)run.characters(), run.length()); + int letterSpacing = font.letterSpacing(); + int wordSpacing = font.wordSpacing(); + bool smallCaps = font.fontDescription().smallCaps(); + int padding = run.padding(); + int numSpaces = 0; + if (padding) { + for (int i = 0; i < run.length(); i++) + if (Font::treatAsSpace(run[i])) + ++numSpaces; + } + + int offset = 0; + const QFont *f = &font.font(); + if (letterSpacing || smallCaps) { + // need to draw every letter on it's own + int start = 0; + if (Font::treatAsSpace(run[0])) { + int add = 0; + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); + offset += add + letterSpacing + components->last().width; + start = 1; +// qDebug() << "space at 0" << offset; + } else if (smallCaps) { + f = (QChar::category(run[0]) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); + } + for (int i = 1; i < run.length(); ++i) { + uint ch = run[i]; + if (QChar(ch).isHighSurrogate() && QChar(run[i-1]).isLowSurrogate()) + ch = QChar::surrogateToUcs4(ch, run[i-1]); + if (QChar(ch).isLowSurrogate() || QChar::category(ch) == QChar::Mark_NonSpacing) + continue; + if (Font::treatAsSpace(run[i])) { + int add = 0; +// qDebug() << " treatAsSpace:" << i << start; + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run.rtl(), + f, offset, f == &font.scFont())); + offset += components->last().width + letterSpacing; +// qDebug() << " appending(1) " << components->last().string << components->last().width; + } + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); + offset += wordSpacing + add + components->last().width + letterSpacing; + start = i + 1; + continue; + } else if (!letterSpacing) { +// qDebug() << i << char(run[i]) << (QChar::category(ch) == QChar::Letter_Lowercase) << +// QFontInfo(*f).pointSizeF(); + if (QChar::category(ch) == QChar::Letter_Lowercase) { + if (f == &font.scFont()) + continue; + } else { + if (f == &font.font()) + continue; + } + } + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run.rtl(), + f, offset, f == &font.scFont())); + offset += components->last().width + letterSpacing; +// qDebug() << " appending(2) " << components->last().string << components->last().width; + } + if (smallCaps) + f = (QChar::category(ch) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); + start = i; + } + if (run.length() - start > 0) { + components->append(TextRunComponent(run.characters() + start, run.length() - start, + run.rtl(), + f, offset, f == &font.scFont())); + offset += components->last().width; +// qDebug() << " appending(3) " << components->last().string << components->last().width; + } + offset += letterSpacing; + } else { + int start = 0; + for (int i = 0; i < run.length(); ++i) { + if (Font::treatAsSpace(run[i])) { + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run.rtl(), + f, offset)); + offset += components->last().width; + } + int add = 0; + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); + offset += add + components->last().width; + if (i) + offset += wordSpacing; + start = i + 1; + } + } + if (run.length() - start > 0) { + components->append(TextRunComponent(run.characters() + start, run.length() - start, + run.rtl(), + f, offset)); + offset += components->last().width; + } + } + return offset; +} + +void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + if (to < 0) + to = run.length(); + QPainter *p = ctx->platformContext(); + Color color = ctx->fillColor(); + p->setPen(QColor(color)); + + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + + if (from > 0 || to < run.length()) { + FloatRect clip = selectionRectForText(run, + IntPoint(qRound(point.x()), qRound(point.y())), + QFontMetrics(m_font).height(), from, to); + QRectF rect(clip.x(), clip.y() - ascent(), clip.width(), clip.height()); + p->save(); + p->setClipRect(rect.toRect()); + } + + if (run.rtl()) { + for (int i = 0; i < components.size(); ++i) { + if (!components.at(i).isSpace()) { + p->setFont(*components.at(i).font); + QPointF pt(point.x() + w - components.at(i).offset - components.at(i).width, point.y()); + p->drawText(pt, components.at(i).string); + } + } + } else { + for (int i = 0; i < components.size(); ++i) { + if (!components.at(i).isSpace()) { + p->setFont(*components.at(i).font); + QPointF pt(point.x() + components.at(i).offset, point.y()); + p->drawText(pt, components.at(i).string); + } + } + } + if (from > 0 || to < run.length()) + p->restore(); +} + +int Font::width(const TextRun& run) const +{ + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + +// qDebug() << " width=" << w; + return w; +} + +float Font::floatWidth(const TextRun& run) const +{ + return width(run); +} + +float Font::floatWidth(const TextRun& run, int /*extraCharsAvailable*/, int& charsConsumed, String& glyphName) const +{ + charsConsumed = run.length(); + glyphName = ""; + return width(run); +} + +int Font::offsetForPosition(const TextRun& run, int position, bool includePartialGlyphs) const +{ + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + + int offset = 0; + if (run.rtl()) { + for (int i = 0; i < components.size(); ++i) { + int xe = w - components.at(i).offset; + int xs = xe - components.at(i).width; + if (position >= xs) { + QTextLayout layout(components.at(i).string, *components.at(i).font); + layout.beginLayout(); + QTextLine l = layout.createLine(); + if (!l.isValid()) + return offset; + + l.setLineWidth(INT_MAX/256); + layout.endLayout(); + + if (position - xs >= l.width()) + return offset; + int cursor = l.xToCursor(position - xs); + if (cursor > 1) + --cursor; + return offset + cursor; + } else { + offset += components.at(i).string.length() - 1; + } + } + } else { + for (int i = 0; i < components.size(); ++i) { + int xs = components.at(i).offset; + int xe = xs + components.at(i).width; + if (position <= xe) { + QTextLayout layout(components.at(i).string, *components.at(i).font); + layout.beginLayout(); + QTextLine l = layout.createLine(); + if (!l.isValid()) + return offset; + + l.setLineWidth(INT_MAX/256); + layout.endLayout(); + + if (position - xs >= l.width()) + return offset + components.at(i).string.length() - 1; + int cursor = l.xToCursor(position - xs); + if (cursor > 1) + --cursor; + return offset + cursor; + } else { + offset += components.at(i).string.length() - 1; + } + } + } + return run.length(); +} + +static float cursorToX(const Vector<TextRunComponent, 1024>& components, int width, bool rtl, int cursor) +{ + int start = 0; + for (int i = 0; i < components.size(); ++i) { + if (start + components.at(i).string.length() - 1 < cursor) { + start += components.at(i).string.length() - 1; + continue; + } + int xs = components.at(i).offset; + if (rtl) + xs = width - xs - components.at(i).width; + QTextLayout layout(components.at(i).string, *components.at(i).font); + layout.beginLayout(); + QTextLine l = layout.createLine(); + if (!l.isValid()) + return 0; + + l.setLineWidth(INT_MAX/256); + layout.endLayout(); + + return xs + l.cursorToX(cursor - start + 1); + } + return width; +} + +FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& pt, + int h, int from, int to) const +{ + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + + if (from == 0 && to == run.length()) + return FloatRect(pt.x(), pt.y(), w, h); + + float x1 = cursorToX(components, w, run.rtl(), from); + float x2 = cursorToX(components, w, run.rtl(), to); + if (x2 < x1) + qSwap(x1, x2); + + return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); +} +#endif + + +Font::~Font() +{ +} + +Font::Font(const Font& other) + : m_fontDescription(other.m_fontDescription) + , m_letterSpacing(other.m_letterSpacing) + , m_wordSpacing(other.m_wordSpacing) + , m_font(other.m_font) + , m_scFont(other.m_scFont) + , m_spaceWidth(other.m_spaceWidth) +{ +} + +Font& Font::operator=(const Font& other) +{ + m_fontDescription = other.m_fontDescription; + m_letterSpacing = other.m_letterSpacing; + m_wordSpacing = other.m_wordSpacing; + m_font = other.m_font; + m_scFont = other.m_scFont; + m_spaceWidth = other.m_spaceWidth; + return *this; +} + +bool Font::operator==(const Font& other) const +{ + return m_fontDescription == other.m_fontDescription + && m_letterSpacing == other.m_letterSpacing + && m_wordSpacing == other.m_wordSpacing + && m_font == other.m_font + && m_scFont == other.m_scFont + && m_spaceWidth == other.m_spaceWidth; +} + +void Font::update(PassRefPtr<FontSelector>) const +{ + // don't think we need this +} + + +bool Font::isFixedPitch() const +{ + return QFontInfo(m_font).fixedPitch(); +} + +// Metrics that we query the FontFallbackList for. +int Font::ascent() const +{ + return QFontMetrics(m_font).ascent(); +} + +int Font::descent() const +{ + return QFontMetrics(m_font).descent(); +} + +int Font::lineSpacing() const +{ + return QFontMetrics(m_font).lineSpacing(); +} + +int Font::lineGap() const +{ + return QFontMetrics(m_font).leading(); +} + +float Font::xHeight() const +{ + return QFontMetrics(m_font).xHeight(); +} + +unsigned Font::unitsPerEm() const +{ + return 1; // FIXME! +} + +int Font::spaceWidth() const +{ + return m_spaceWidth; +} + +} diff --git a/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp new file mode 100644 index 0000000..d32cc63 --- /dev/null +++ b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp @@ -0,0 +1,31 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#include "config.h" +#include "GlyphPageTreeNode.h" + +namespace WebCore { + +void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData* fontData) +{ +} + +} diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp new file mode 100644 index 0000000..f414efa --- /dev/null +++ b/WebCore/platform/graphics/qt/GradientQt.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * 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 "Gradient.h" + +#include "CSSParser.h" +#include "NotImplemented.h" + +#include <QGradient> + +namespace WebCore { + +void Gradient::platformDestroy() +{ + delete m_gradient; + m_gradient = 0; +} + +QGradient* Gradient::platformGradient() +{ + if (m_gradient) + return m_gradient; + + if (m_radial) + m_gradient = new QRadialGradient(m_p1.x(), m_p1.y(), m_r1, m_p0.x(), m_p0.y()); + else + m_gradient = new QLinearGradient(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y()); + + QColor stopColor; + Vector<ColorStop>::iterator stopIterator = m_stops.begin(); + qreal lastStop; + const qreal lastStopDiff = 0.0000001; + while (stopIterator != m_stops.end()) { + stopColor.setRgbF(stopIterator->red, stopIterator->green, stopIterator->blue, stopIterator->alpha); + if (qFuzzyCompare(lastStop, qreal(stopIterator->stop))) + lastStop = stopIterator->stop + lastStopDiff; + else + 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); + ++stopIterator; + } + + return m_gradient; +} + +void Gradient::fill(GraphicsContext* context, const FloatRect& rect) +{ + notImplemented(); +} + +} //namespace diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp new file mode 100644 index 0000000..600d77c --- /dev/null +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -0,0 +1,1146 @@ +/* + * 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. + */ + +#include "config.h" + +#ifdef Q_WS_WIN +#include <windows.h> +#endif + +#include "AffineTransform.h" +#include "Color.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 <QDebug> +#include <QGradient> +#include <QPainter> +#include <QPaintDevice> +#include <QPaintEngine> +#include <QPainterPath> +#include <QPixmap> +#include <QPolygonF> +#include <QStack> +#include <QVector> + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +namespace WebCore { + +static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op) +{ + switch (op) { + case CompositeClear: + return QPainter::CompositionMode_Clear; + case CompositeCopy: + return QPainter::CompositionMode_Source; + case CompositeSourceOver: + return QPainter::CompositionMode_SourceOver; + case CompositeSourceIn: + return QPainter::CompositionMode_SourceIn; + case CompositeSourceOut: + return QPainter::CompositionMode_SourceOut; + case CompositeSourceAtop: + return QPainter::CompositionMode_SourceAtop; + case CompositeDestinationOver: + return QPainter::CompositionMode_DestinationOver; + case CompositeDestinationIn: + return QPainter::CompositionMode_DestinationIn; + case CompositeDestinationOut: + return QPainter::CompositionMode_DestinationOut; + case CompositeDestinationAtop: + return QPainter::CompositionMode_DestinationAtop; + case CompositeXOR: + return QPainter::CompositionMode_Xor; + case CompositePlusDarker: + return QPainter::CompositionMode_SourceOver; + case CompositeHighlight: + return QPainter::CompositionMode_SourceOver; + case CompositePlusLighter: + return QPainter::CompositionMode_SourceOver; + } + + return QPainter::CompositionMode_SourceOver; +} + +static inline Qt::PenCapStyle toQtLineCap(LineCap lc) +{ + switch (lc) { + case ButtCap: + return Qt::FlatCap; + case RoundCap: + return Qt::RoundCap; + case SquareCap: + return Qt::SquareCap; + } + + return Qt::FlatCap; +} + +static inline Qt::PenJoinStyle toQtLineJoin(LineJoin lj) +{ + switch (lj) { + case MiterJoin: + return Qt::SvgMiterJoin; + case RoundJoin: + return Qt::RoundJoin; + case BevelJoin: + return Qt::BevelJoin; + } + + return Qt::MiterJoin; +} + +static Qt::PenStyle toQPenStyle(StrokeStyle style) +{ + switch (style) { + case NoStroke: + return Qt::NoPen; + break; + case SolidStroke: + return Qt::SolidLine; + break; + case DottedStroke: + return Qt::DotLine; + break; + case DashedStroke: + return Qt::DashLine; + break; + } + qWarning("couldn't recognize the pen 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) + : pixmap(rect.width(), rect.height()) + { + 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()); + painter.setClipPath(p->clipPath()); + } + + TransparencyLayer() + { + } + + QPixmap pixmap; + QPoint offset; + QPainter painter; + qreal opacity; +private: + TransparencyLayer(const TransparencyLayer &) {} + TransparencyLayer & operator=(const TransparencyLayer &) { return *this; } +}; + +class GraphicsContextPlatformPrivate +{ +public: + GraphicsContextPlatformPrivate(QPainter* painter); + ~GraphicsContextPlatformPrivate(); + + inline QPainter* p() + { + if (layers.isEmpty()) { + if (redirect) + return redirect; + + return painter; + } else + return &layers.top()->painter; + } + + bool antiAliasingForRectsAndLines; + + QStack<TransparencyLayer *> layers; + QPainter* redirect; + + QBrush solidColor; + + // Only used by SVG for now. + QPainterPath currentPath; + +private: + QPainter* painter; +}; + + +GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p) +{ + painter = p; + redirect = 0; + + 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() +{ +} + +GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) + : m_common(createGraphicsContextPrivate()) + , m_data(new GraphicsContextPlatformPrivate(context)) +{ + setPaintingDisabled(!context); + if (context) { + // Make sure the context starts in sync with our state. + setPlatformFillColor(fillColor()); + setPlatformStrokeColor(strokeColor()); + } +} + +GraphicsContext::~GraphicsContext() +{ + while(!m_data->layers.isEmpty()) + endTransparencyLayer(); + + destroyGraphicsContextPrivate(m_common); + delete m_data; +} + +PlatformGraphicsContext* GraphicsContext::platformContext() const +{ + return m_data->p(); +} + +AffineTransform GraphicsContext::getCTM() const +{ + return platformContext()->combinedMatrix(); +} + +void GraphicsContext::savePlatformState() +{ + m_data->p()->save(); +} + +void GraphicsContext::restorePlatformState() +{ + m_data->p()->restore(); +} + +/* FIXME: DISABLED WHILE MERGING BACK FROM UNITY +void GraphicsContext::drawTextShadow(const TextRun& run, const IntPoint& point, const FontStyle& style) +{ + if (paintingDisabled()) + return; + + if (m_data->shadow.isNull()) + return; + + TextShadow* shadow = &m_data->shadow; + + if (shadow->blur <= 0) { + Pen p = pen(); + setPen(shadow->color); + font().drawText(this, run, style, IntPoint(point.x() + shadow->x, point.y() + shadow->y)); + setPen(p); + } else { + const int thickness = shadow->blur; + // FIXME: OPTIMIZE: limit the area to only the actually painted area + 2*thickness + const int w = m_data->p()->device()->width(); + const int h = m_data->p()->device()->height(); + const QRgb color = qRgb(255, 255, 255); + const QRgb bgColor = qRgb(0, 0, 0); + QImage image(QSize(w, h), QImage::Format_ARGB32); + image.fill(bgColor); + QPainter p; + + Pen curPen = pen(); + p.begin(&image); + setPen(color); + m_data->redirect = &p; + font().drawText(this, run, style, IntPoint(point.x() + shadow->x, point.y() + shadow->y)); + m_data->redirect = 0; + p.end(); + setPen(curPen); + + int md = thickness * thickness; // max-dist^2 + + // blur map/precalculated shadow-decay + float* bmap = (float*) alloca(sizeof(float) * (md + 1)); + for (int n = 0; n <= md; n++) { + float f; + f = n / (float) (md + 1); + f = 1.0 - f * f; + bmap[n] = f; + } + + float factor = 0.0; // maximal potential opacity-sum + for (int n = -thickness; n <= thickness; n++) { + for (int m = -thickness; m <= thickness; m++) { + int d = n * n + m * m; + if (d <= md) + factor += bmap[d]; + } + } + + // alpha map + float* amap = (float*) alloca(sizeof(float) * (h * w)); + memset(amap, 0, h * w * (sizeof(float))); + + for (int j = thickness; j<h-thickness; j++) { + for (int i = thickness; i<w-thickness; i++) { + QRgb col = image.pixel(i,j); + if (col == bgColor) + continue; + + float g = qAlpha(col); + g = g / 255; + + for (int n = -thickness; n <= thickness; n++) { + for (int m = -thickness; m <= thickness; m++) { + int d = n * n + m * m; + if (d > md) + continue; + + float f = bmap[d]; + amap[(i + m) + (j + n) * w] += (g * f); + } + } + } + } + + QImage res(QSize(w,h),QImage::Format_ARGB32); + int r = shadow->color.red(); + int g = shadow->color.green(); + int b = shadow->color.blue(); + int a1 = shadow->color.alpha(); + + // arbitratry factor adjustment to make shadows more solid. + factor = 1.333 / factor; + + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + int a = (int) (amap[i + j * w] * factor * a1); + if (a > 255) + a = 255; + + res.setPixel(i,j, qRgba(r, g, b, a)); + } + } + + m_data->p()->drawImage(0, 0, res, 0, 0, -1, -1, Qt::DiffuseAlphaDither | Qt::ColorOnly | Qt::PreferDither); + } +} +*/ + +// Draws a filled rectangle with a stroked border. +void GraphicsContext::drawRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + 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. +static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, + const StrokeStyle& penStyle) +{ + // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic + // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., + // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave + // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. + if (penStyle == DottedStroke || penStyle == DashedStroke) { + if (p1.x() == p2.x()) { + p1.setY(p1.y() + strokeWidth); + p2.setY(p2.y() - strokeWidth); + } else { + p1.setX(p1.x() + strokeWidth); + p2.setX(p2.x() - strokeWidth); + } + } + + if (((int) strokeWidth) % 2) { + if (p1.x() == p2.x()) { + // We're a vertical line. Adjust our x. + p1.setX(p1.x() + 0.5); + p2.setX(p2.x() + 0.5); + } else { + // We're a horizontal line. Adjust our y. + p1.setY(p1.y() + 0.5); + p2.setY(p2.y() + 0.5); + } + } +} + +// This is only used to draw borders. +void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) +{ + if (paintingDisabled()) + return; + + 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()); + + 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. +void GraphicsContext::drawEllipse(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + m_data->p()->drawEllipse(rect); +} + +void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) +{ + if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha()) + return; + + 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) +{ + if (paintingDisabled()) + return; + + if (npoints <= 1) + return; + + QPolygonF polygon(npoints); + + for (size_t i = 0; i < npoints; i++) + polygon[i] = points[i]; + + QPainter *p = m_data->p(); + p->save(); + p->setRenderHint(QPainter::Antialiasing, shouldAntialias); + p->drawConvexPolygon(polygon); + p->restore(); +} + +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; + + 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) +{ + if (paintingDisabled()) + return; + + 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) +{ + if (paintingDisabled() || !color.alpha()) + return; + + Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight); + m_data->p()->fillPath(*path.platformPath(), QColor(color)); +} + +void GraphicsContext::beginPath() +{ + m_data->currentPath = QPainterPath(); +} + +void GraphicsContext::addPath(const Path& path) +{ + m_data->currentPath = *(path.platformPath()); +} + +bool GraphicsContext::inTransparencyLayer() const +{ + return !m_data->layers.isEmpty(); +} + +PlatformPath* GraphicsContext::currentPath() +{ + return &m_data->currentPath; +} + +void GraphicsContext::clip(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + if (p->clipRegion().isEmpty()) + p->setClipRect(rect); + else p->setClipRect(rect, Qt::IntersectClip); +} + +/** + * Focus ring handling is not handled here. Qt style in + * RenderTheme handles drawing focus on widgets which + * need it. + */ +Color focusRingColor() { return Color(0, 0, 0); } +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (paintingDisabled()) + return; + + const Vector<IntRect>& rects = focusRingRects(); + unsigned rectCount = rects.size(); + + if (rects.size() == 0) + 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(); + + QPen nPen = p->pen(); + nPen.setColor(color); + p->setBrush(Qt::NoBrush); + nPen.setStyle(Qt::DotLine); + p->setPen(nPen); +#if 0 + // FIXME How do we do a bounding outline with Qt? + QPainterPath path; + for (int i = 0; i < rectCount; ++i) + path.addRect(QRectF(rects[i])); + QPainterPathStroker stroker; + QPainterPath newPath = stroker.createStroke(path); + p->strokePath(newPath, nPen); +#else + for (int i = 0; i < rectCount; ++i) + p->drawRect(QRectF(rects[i])); +#endif + p->setPen(oldPen); + p->setBrush(oldBrush); + + p->setRenderHint(QPainter::Antialiasing, antiAlias); +} + +void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) +{ + if (paintingDisabled()) + return; + + IntPoint endPoint = origin + IntSize(width, 0); + drawLine(origin, endPoint); +} + +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, + int width, bool grammar) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +{ + QRectF rect(frect); + rect = m_data->p()->deviceMatrix().mapRect(rect); + + QRect result = rect.toRect(); //round it + return FloatRect(QRectF(result)); +} + +void GraphicsContext::setPlatformShadow(const IntSize& pos, int blur, const Color &color) +{ + // Qt doesn't support shadows natively, they are drawn manually in the draw* + // functions +} + +void GraphicsContext::clearPlatformShadow() +{ + // Qt doesn't support shadows natively, they are drawn manually in the draw* + // functions +} + +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + if (paintingDisabled()) + return; + + int x, y, w, h; + x = y = 0; + QPainter *p = m_data->p(); + const QPaintDevice *device = p->device(); + w = device->width(); + h = device->height(); + + QRectF clip = p->clipPath().boundingRect(); + 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; + m_data->layers.push(layer); +} + +void GraphicsContext::endTransparencyLayer() +{ + if (paintingDisabled()) + return; + + TransparencyLayer *layer = m_data->layers.pop(); + layer->painter.end(); + + QPainter *p = m_data->p(); + p->save(); + p->resetTransform(); + p->setOpacity(layer->opacity); + p->drawPixmap(layer->offset, layer->pixmap); + p->restore(); + + delete layer; +} + +void GraphicsContext::clearRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QPainter::CompositionMode currentCompositionMode = p->compositionMode(); + if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) + p->setCompositionMode(QPainter::CompositionMode_Source); + p->eraseRect(rect); + if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) + p->setCompositionMode(currentCompositionMode); +} + +void GraphicsContext::strokeRect(const FloatRect& rect, float width) +{ + if (paintingDisabled()) + return; + + QPainterPath path; + path.addRect(rect); + setStrokeThickness(width); + m_data->currentPath = path; + + strokePath(); +} + +void GraphicsContext::setLineCap(LineCap lc) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QPen nPen = p->pen(); + nPen.setCapStyle(toQtLineCap(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()) + return; + + QPainter *p = m_data->p(); + QPen nPen = p->pen(); + nPen.setJoinStyle(toQtLineJoin(lj)); + p->setPen(nPen); +} + +void GraphicsContext::setMiterLimit(float limit) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QPen nPen = p->pen(); + nPen.setMiterLimit(limit); + p->setPen(nPen); +} + +void GraphicsContext::setAlpha(float opacity) +{ + if (paintingDisabled()) + return; + QPainter *p = m_data->p(); + p->setOpacity(opacity); +} + +void GraphicsContext::setCompositeOperation(CompositeOperator op) +{ + if (paintingDisabled()) + return; + + if (m_data->p()->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) + m_data->p()->setCompositionMode(toQtCompositionMode(op)); +} + +void GraphicsContext::clip(const Path& path) +{ + if (paintingDisabled()) + return; + + m_data->p()->setClipPath(*path.platformPath(), Qt::IntersectClip); +} + +void GraphicsContext::clipOut(const Path& path) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QRectF clipBounds = p->clipPath().boundingRect(); + QPainterPath clippedOut = *path.platformPath(); + QPainterPath newClip; + newClip.setFillRule(Qt::OddEvenFill); + newClip.addRect(clipBounds); + newClip.addPath(clippedOut); + + p->setClipPath(newClip, Qt::IntersectClip); +} + +void GraphicsContext::translate(float x, float y) +{ + if (paintingDisabled()) + return; + + m_data->p()->translate(x, y); +} + +IntPoint GraphicsContext::origin() +{ + if (paintingDisabled()) + return IntPoint(); + const QTransform &transform = m_data->p()->transform(); + return IntPoint(qRound(transform.dx()), qRound(transform.dy())); +} + +void GraphicsContext::rotate(float radians) +{ + if (paintingDisabled()) + return; + + m_data->p()->rotate(180/M_PI*radians); +} + +void GraphicsContext::scale(const FloatSize& s) +{ + if (paintingDisabled()) + return; + + m_data->p()->scale(s.width(), s.height()); +} + +void GraphicsContext::clipOut(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QRectF clipBounds = p->clipPath().boundingRect(); + QPainterPath newClip; + newClip.setFillRule(Qt::OddEvenFill); + newClip.addRect(clipBounds); + newClip.addRect(QRect(rect)); + + p->setClipPath(newClip, Qt::IntersectClip); +} + +void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QRectF clipBounds = p->clipPath().boundingRect(); + QPainterPath newClip; + newClip.setFillRule(Qt::OddEvenFill); + newClip.addRect(clipBounds); + newClip.addEllipse(QRect(rect)); + + p->setClipPath(newClip, Qt::IntersectClip); +} + +void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) +{ + notImplemented(); +} + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, + int thickness) +{ + if (paintingDisabled()) + return; + + clip(rect); + QPainterPath path; + + // Add outer ellipse + path.addEllipse(QRectF(rect.x(), rect.y(), rect.width(), rect.height())); + + // Add inner ellipse. + path.addEllipse(QRectF(rect.x() + thickness, rect.y() + thickness, + rect.width() - (thickness * 2), rect.height() - (thickness * 2))); + + path.setFillRule(Qt::OddEvenFill); + m_data->p()->setClipPath(path, Qt::IntersectClip); +} + +void GraphicsContext::concatCTM(const AffineTransform& transform) +{ + if (paintingDisabled()) + return; + + m_data->p()->setMatrix(transform, true); +} + +void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +{ + notImplemented(); +} + +void GraphicsContext::setPlatformFont(const Font& aFont) +{ + if (paintingDisabled()) + return; + m_data->p()->setFont(aFont.font()); +} + +void GraphicsContext::setPlatformStrokeColor(const Color& color) +{ + if (paintingDisabled()) + return; + QPainter *p = m_data->p(); + QPen newPen(p->pen()); + newPen.setColor(color); + p->setPen(newPen); +} + +void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle) +{ + if (paintingDisabled()) + return; + QPainter *p = m_data->p(); + QPen newPen(p->pen()); + newPen.setStyle(toQPenStyle(strokeStyle)); + p->setPen(newPen); +} + +void GraphicsContext::setPlatformStrokeThickness(float thickness) +{ + if (paintingDisabled()) + return; + QPainter *p = m_data->p(); + QPen newPen(p->pen()); + newPen.setWidthF(thickness); + p->setPen(newPen); +} + +void GraphicsContext::setPlatformFillColor(const Color& color) +{ + if (paintingDisabled()) + return; + m_data->p()->setBrush(QBrush(color)); +} + +void GraphicsContext::setUseAntialiasing(bool enable) +{ + if (paintingDisabled()) + return; + 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 diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp new file mode 100644 index 0000000..b04668c --- /dev/null +++ b/WebCore/platform/graphics/qt/IconQt.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Icon.h" + +#include "GraphicsContext.h" +#include "PlatformString.h" +#include "IntRect.h" +#include "NotImplemented.h" + +#include <qpainter.h> +#include <qpixmap.h> +#include <qrect.h> +#include <qglobal.h> + +namespace WebCore { + +Icon::Icon() +{ +} + +Icon::~Icon() +{ +} + +PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +{ + RefPtr<Icon> i = adoptRef(new Icon); + i->m_icon = QIcon(filename); + return i.release(); +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +{ + //FIXME: Implement this + return 0; +} + +void Icon::paint(GraphicsContext* ctx, const IntRect& rect) +{ + QPixmap px = m_icon.pixmap(rect.size()); + QPainter *p = static_cast<QPainter*>(ctx->platformContext()); + if (p && !px.isNull()) { + p->drawPixmap(rect.x(), rect.y(), px); + } +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/ImageBufferData.h b/WebCore/platform/graphics/qt/ImageBufferData.h new file mode 100644 index 0000000..222dabe --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageBufferData.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 Google 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 ImageBufferData_h +#define ImageBufferData_h + +#include <QPainter> +#include <QPixmap> + +#include "OwnPtr.h" + +namespace WebCore { + +class IntSize; + +class ImageBufferData { +public: + ImageBufferData(const IntSize&); + + QPixmap m_pixmap; + OwnPtr<QPainter> m_painter; +}; + +} // namespace WebCore + +#endif // ImageBufferData_h diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp new file mode 100644 index 0000000..d4ab59f --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2008 Holger Hans Peter Freyther + * + * 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 "ImageBuffer.h" + +#include "CString.h" +#include "GraphicsContext.h" +#include "ImageData.h" +#include "MIMETypeRegistry.h" +#include "NotImplemented.h" +#include "StillImageQt.h" + +#include <QBuffer> +#include <QImageWriter> +#include <QPainter> +#include <QPixmap> + +namespace WebCore { + +ImageBufferData::ImageBufferData(const IntSize& size) + : m_pixmap(size) +{ + m_pixmap.fill(QColor(Qt::transparent)); + m_painter.set(new QPainter(&m_pixmap)); +} + +ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success) + : m_data(size) + , m_size(size) +{ + m_context.set(new GraphicsContext(m_data.m_painter.get())); + success = true; +} + +ImageBuffer::~ImageBuffer() +{ +} + +GraphicsContext* ImageBuffer::context() const +{ + ASSERT(m_data.m_painter->isActive()); + + return m_context.get(); +} + +Image* ImageBuffer::image() const +{ + 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); + } + + return m_image.get(); +} + +PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const +{ + notImplemented(); + return 0; +} + +void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&) +{ + notImplemented(); +} + +// We get a mimeType here but QImageWriter does not support mimetypes but +// only formats (png, gif, jpeg..., xpm). So assume we get image/ as image +// mimetypes and then remove the image/ to get the Qt format. +String ImageBuffer::toDataURL(const String& mimeType) const +{ + ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); + + if (!mimeType.startsWith("image/")) + return "data:,"; + + // prepare our target + QByteArray data; + QBuffer buffer(&data); + buffer.open(QBuffer::WriteOnly); + + if (!m_data.m_pixmap.save(&buffer, mimeType.substring(sizeof "image").utf8().data())) + return "data:,"; + + buffer.close(); + return String::format("data:%s;base64,%s", mimeType.utf8().data(), data.toBase64().data()); +} + +} diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp new file mode 100644 index 0000000..e3b00a1 --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com> + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 "ImageDecoderQt.h" + +#include <QtCore/QByteArray> +#include <QtCore/QBuffer> + +#include <QtGui/QImageReader> +#include <qdebug.h> + +namespace { + const QImage::Format DesiredFormat = QImage::Format_ARGB32; + const bool debugImageDecoderQt = false; +} + +namespace WebCore { +ImageDecoderQt::ImageData::ImageData(const QImage& image, ImageState imageState, int duration) : + m_image(image), m_imageState(imageState), m_duration(duration) +{ +} + +// Context, maintains IODevice on a data buffer. +class ImageDecoderQt::ReadContext { +public: + + enum LoadMode { + // Load images incrementally. This is still experimental and + // will cause the image plugins to report errors. + // Also note that as of Qt 4.2.2, the JPEG loader does not return error codes + // on "preliminary end of data". + LoadIncrementally, + // Load images only if all data have been received + LoadComplete }; + + ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target); + + enum ReadResult { ReadEOF, ReadFailed, ReadPartial, ReadComplete }; + + // Append data and read out all images. Returns the result + // of the last read operation, so, even if ReadPartial is returned, + // a few images might have been read. + ReadResult read(bool allDataReceived); + + QImageReader *reader() { return &m_reader; } + +private: + enum IncrementalReadResult { IncrementalReadFailed, IncrementalReadPartial, IncrementalReadComplete }; + // Incrementally read an image + IncrementalReadResult readImageLines(ImageData &); + + const LoadMode m_loadMode; + + QByteArray m_data; + QBuffer m_buffer; + QImageReader m_reader; + + ImageList &m_target; + + // Detected data format of the stream + enum QImage::Format m_dataFormat; + QSize m_size; + +}; + +ImageDecoderQt::ReadContext::ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target) + : m_loadMode(loadMode) + , m_data(data.data(), data.size()) + , m_buffer(&m_data) + , m_reader(&m_buffer) + , m_target(target) + , m_dataFormat(QImage::Format_Invalid) +{ + m_buffer.open(QIODevice::ReadOnly); +} + + +ImageDecoderQt::ReadContext::ReadResult + ImageDecoderQt::ReadContext::read(bool allDataReceived) +{ + // Complete mode: Read only all all data received + if (m_loadMode == LoadComplete && !allDataReceived) + return ReadPartial; + + // Attempt to read out all images + while (true) { + if (m_target.empty() || m_target.back().m_imageState == ImageComplete) { + // Start a new image. + if (!m_reader.canRead()) + return ReadEOF; + + // Attempt to construct an empty image of the matching size and format + // for efficient reading + QImage newImage = m_dataFormat != QImage::Format_Invalid ? + QImage(m_size,m_dataFormat) : QImage(); + m_target.push_back(ImageData(newImage)); + } + + // read chunks + switch (readImageLines(m_target.back())) { + case IncrementalReadFailed: + m_target.pop_back(); + return ReadFailed; + case IncrementalReadPartial: + return ReadPartial; + case IncrementalReadComplete: + m_target.back().m_imageState = ImageComplete; + //store for next + m_dataFormat = m_target.back().m_image.format(); + m_size = m_target.back().m_image.size(); + const bool supportsAnimation = m_reader.supportsAnimation(); + + if (debugImageDecoderQt) + qDebug() << "readImage(): #" << m_target.size() << " complete, " << m_size << " format " << m_dataFormat + << " supportsAnimation=" << supportsAnimation ; + // No point in readinfg further + if (!supportsAnimation) + return ReadComplete; + + break; + } + } + return ReadComplete; +} + + + +ImageDecoderQt::ReadContext::IncrementalReadResult + ImageDecoderQt::ReadContext::readImageLines(ImageData &imageData) +{ + // TODO: Implement incremental reading here, + // set state to reflect complete header, etc. + // For now, we read the whole image. + + const qint64 startPos = m_buffer.pos (); + // Oops, failed. Rewind. + if (!m_reader.read(&imageData.m_image)) { + m_buffer.seek(startPos); + const bool gotHeader = imageData.m_image.size().width(); + + if (debugImageDecoderQt) + qDebug() << "readImageLines(): read() failed: " << m_reader.errorString() + << " got header=" << gotHeader; + // [Experimental] Did we manage to read the header? + if (gotHeader) { + imageData.m_imageState = ImageHeaderValid; + return IncrementalReadPartial; + } + return IncrementalReadFailed; + } + imageData.m_duration = m_reader.nextImageDelay(); + return IncrementalReadComplete; +} + + +// ImageDecoderQt +ImageDecoderQt::ImageDecoderQt( ) +{ +} + +ImageDecoderQt::~ImageDecoderQt() +{ +} + +bool ImageDecoderQt::hasFirstImageHeader() const +{ + return !m_imageList.empty() && m_imageList[0].m_imageState >= ImageHeaderValid; +} + +void ImageDecoderQt::reset() +{ + m_failed = false; + m_imageList.clear(); + m_pixmapCache.clear(); + m_sizeAvailable = false; + m_loopCount = cAnimationNone; + m_size = IntSize(-1, -1); +} + +void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived) +{ + reset(); + ReadContext readContext(data, ReadContext::LoadComplete, m_imageList); + + if (debugImageDecoderQt) + qDebug() << " setData " << data.size() << " image bytes, complete=" << allDataReceived; + + const ReadContext::ReadResult readResult = readContext.read(allDataReceived); + + if (debugImageDecoderQt) + qDebug() << " read returns " << readResult; + + switch ( readResult) { + case ReadContext::ReadFailed: + m_failed = true; + break; + case ReadContext::ReadEOF: + case ReadContext::ReadPartial: + case ReadContext::ReadComplete: + // Did we read anything - try to set the size. + if (hasFirstImageHeader()) { + m_sizeAvailable = true; + m_size = m_imageList[0].m_image.size(); + + if (readContext.reader()->supportsAnimation()) { + if (readContext.reader()->loopCount() != -1) + m_loopCount = readContext.reader()->loopCount(); + else + m_loopCount = 0; //loop forever + } + } + break; + } +} + + +bool ImageDecoderQt::isSizeAvailable() const +{ + if (debugImageDecoderQt) + qDebug() << " ImageDecoderQt::isSizeAvailable() returns" << m_sizeAvailable; + return m_sizeAvailable; +} + +int ImageDecoderQt::frameCount() const +{ + if (debugImageDecoderQt) + qDebug() << " ImageDecoderQt::frameCount() returns" << m_imageList.size(); + return m_imageList.size(); +} + + +int ImageDecoderQt::repetitionCount() const +{ + if (debugImageDecoderQt) + qDebug() << " ImageDecoderQt::repetitionCount() returns" << m_loopCount; + return m_loopCount; +} + + +bool ImageDecoderQt::supportsAlpha() const +{ + return hasFirstImageHeader() && m_imageList[0].m_image.hasAlphaChannel(); +} + +int ImageDecoderQt::duration(size_t index) const +{ + if (index >= m_imageList.size()) + return 0; + return m_imageList[index].m_duration; +} + +RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) +{ + Q_ASSERT("use imageAtIndex instead"); + return 0; +} + +QPixmap* ImageDecoderQt::imageAtIndex(size_t index) const +{ + if (debugImageDecoderQt) + qDebug() << "ImageDecoderQt::imageAtIndex(" << index << ')'; + + if (index >= m_imageList.size()) + return 0; + + if (!m_pixmapCache.contains(index)) { + m_pixmapCache.insert(index, + QPixmap::fromImage(m_imageList[index].m_image)); + } + return &m_pixmapCache[index]; +} + +void ImageDecoderQt::clearFrame(size_t index) +{ + if (m_imageList.size() < (int)index) + m_imageList[index].m_image = QImage(); + m_pixmapCache.take(index); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h new file mode 100644 index 0000000..3573dd0 --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com> + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 ImageDecoderQt_h +#define ImageDecoderQt_h + +#include "ImageDecoder.h" +#include <QtGui/QImage> +#include <QtGui/QPixmap> +#include <QtCore/QList> +#include <QtCore/QHash> + +namespace WebCore { + + +class ImageDecoderQt : public ImageDecoder +{ + ImageDecoderQt(const ImageDecoderQt&); + ImageDecoderQt &operator=(const ImageDecoderQt&); +public: + ImageDecoderQt(); + ~ImageDecoderQt(); + + typedef Vector<char> IncomingData; + + virtual void setData(const IncomingData& data, bool allDataReceived); + + virtual bool isSizeAvailable() const; + + virtual int frameCount() const; + + + virtual int repetitionCount() const; + + + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + + QPixmap* imageAtIndex(size_t index) const; + + virtual bool supportsAlpha() const; + + int duration(size_t index) const; + + void clearFrame(size_t index); +private: + class ReadContext; + void reset(); + bool hasFirstImageHeader() const; + + enum ImageState { + // Started image reading + ImagePartial, + // Header (size / alpha) are known + ImageHeaderValid, + // Image is complete + ImageComplete }; + + struct ImageData { + ImageData(const QImage& image, ImageState imageState = ImagePartial, int duration=0); + QImage m_image; + ImageState m_imageState; + int m_duration; + }; + + typedef QList<ImageData> ImageList; + ImageList m_imageList; + mutable QHash<int, QPixmap> m_pixmapCache; + int m_loopCount; +}; + + + +} + +#endif + diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp new file mode 100644 index 0000000..9234c69 --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org> + * + * 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 "Image.h" + +#include "BitmapImage.h" +#include "FloatRect.h" +#include "PlatformString.h" +#include "GraphicsContext.h" +#include "AffineTransform.h" +#include "NotImplemented.h" +#include "StillImageQt.h" +#include "qwebsettings.h" + +#include <QPixmap> +#include <QPainter> +#include <QImage> +#include <QImageReader> +#if QT_VERSION >= 0x040300 +#include <QTransform> +#endif + +#include <QDebug> + +#include <math.h> + +// This function loads resources into WebKit +static QPixmap loadResourcePixmap(const char *name) +{ + QPixmap pixmap; + if (qstrcmp(name, "missingImage") == 0) + pixmap = QWebSettings::webGraphic(QWebSettings::MissingImageGraphic); + else if (qstrcmp(name, "nullPlugin") == 0) + pixmap = QWebSettings::webGraphic(QWebSettings::MissingPluginGraphic); + else if (qstrcmp(name, "urlIcon") == 0) + pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic); + else if (qstrcmp(name, "textAreaResizeCorner") == 0) + pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic); + + return pixmap; +} + +namespace WebCore { + +void FrameData::clear() +{ + if (m_frame) { + m_frame = 0; + // NOTE: We purposefully don't reset metadata here, so that even if we + // throw away previously-decoded data, animation loops can still access + // properties like frame durations without re-decoding. + } +} + + + +// ================================================ +// Image Class +// ================================================ + +PassRefPtr<Image> Image::loadPlatformResource(const char* name) +{ + return StillImage::create(loadResourcePixmap(name)); +} + + +void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, + const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) +{ + notImplemented(); +} + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +// Drawing Routines +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, + const FloatRect& src, CompositeOperator op) +{ + startAnimation(); + + QPixmap* image = nativeImageForCurrentFrame(); + if (!image) + return; + + if (mayFillWithSolidColor()) { + fillWithSolidColor(ctxt, dst, solidColor(), op); + return; + } + + IntSize selfSize = size(); + + ctxt->save(); + + // Set the compositing operation. + ctxt->setCompositeOperation(op); + + QPainter* painter(ctxt->platformContext()); + + // Test using example site at + // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html + painter->drawPixmap(dst, *image, src); + + ctxt->restore(); +} + +void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, + const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) +{ + QPixmap* framePixmap = nativeImageForCurrentFrame(); + if (!framePixmap) // If it's too early we won't have an image yet. + return; + + QPixmap pixmap = *framePixmap; + QRect tr = QRectF(tileRect).toRect(); + if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) { + pixmap = pixmap.copy(tr); + } + + QBrush b(pixmap); + b.setMatrix(patternTransform); + ctxt->save(); + ctxt->setCompositeOperation(op); + QPainter* p = ctxt->platformContext(); + p->setBrushOrigin(phase); + p->fillRect(destRect, b); + ctxt->restore(); +} + +void BitmapImage::checkForSolidColor() +{ + // FIXME: It's easy to implement this optimization. Just need to check the RGBA32 buffer to see if it is 1x1. + m_isSolidColor = false; +} + +} + + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp new file mode 100644 index 0000000..1d14f9d --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 "ImageSource.h" +#include "ImageDecoderQt.h" +#include "SharedBuffer.h" + +#include <QBuffer> +#include <QImage> +#include <QImageReader> + +namespace WebCore { +static bool canHandleImage(const SharedBuffer& _data) +{ + // We need at least 4 bytes to figure out what kind of image we're dealing with. + if (_data.size() < 4) + return false; + + QByteArray data = QByteArray::fromRawData(_data.data(), _data.size()); + QBuffer buffer(&data); + if (!buffer.open(QBuffer::ReadOnly)) + return false; + + return !QImageReader::imageFormat(&buffer).isEmpty(); +} + +ImageDecoderQt* createDecoder(const SharedBuffer& data) { + if (!canHandleImage(data)) + return 0; + return new ImageDecoderQt(); +} + +ImageSource::ImageSource() + : m_decoder(0) +{ +} + +ImageSource::~ImageSource() +{ + delete m_decoder; +} + +bool ImageSource::initialized() const +{ + return m_decoder; +} + +void ImageSource::setData(SharedBuffer* data, bool allDataReceived) +{ + // Make the decoder by sniffing the bytes. + // This method will examine the data and instantiate an instance of the appropriate decoder plugin. + // If insufficient bytes are available to determine the image type, no decoder plugin will be + // made. + if (!m_decoder) + m_decoder = createDecoder(*data); + + if (!m_decoder) + return; + + m_decoder->setData(data->buffer(), allDataReceived); +} + +bool ImageSource::isSizeAvailable() +{ + if (!m_decoder) + return false; + + return m_decoder->isSizeAvailable(); +} + +IntSize ImageSource::size() const +{ + if (!m_decoder) + return IntSize(); + + return m_decoder->size(); +} + +IntSize ImageSource::frameSizeAtIndex(size_t) const +{ + return size(); +} + +int ImageSource::repetitionCount() +{ + if (!m_decoder) + return cAnimationNone; + + return m_decoder->repetitionCount(); +} + +size_t ImageSource::frameCount() const +{ + if (!m_decoder) + return 0; + + return m_decoder->frameCount(); +} + +NativeImagePtr ImageSource::createFrameAtIndex(size_t index) +{ + if (!m_decoder) + return 0; + + return m_decoder->imageAtIndex(index); +} + +float ImageSource::frameDurationAtIndex(size_t index) +{ + if (!m_decoder) + return 0; + + // Many annoying ads specify a 0 duration to make an image flash as quickly + // as possible. We follow WinIE's behavior and use a duration of 100 ms + // for any frames that specify a duration of <= 50 ms. See + // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for + // more. + const float duration = m_decoder->duration(index) / 1000.0f; + return (duration < 0.051f) ? 0.100f : duration; +} + +bool ImageSource::frameHasAlphaAtIndex(size_t index) +{ + if (!m_decoder || !m_decoder->supportsAlpha()) + return false; + + const QPixmap* source = m_decoder->imageAtIndex( index); + if (!source) + return false; + + return source->hasAlphaChannel(); +} + +bool ImageSource::frameIsCompleteAtIndex(size_t index) +{ + return (m_decoder && m_decoder->imageAtIndex(index) != 0); +} + +void ImageSource::clear() +{ + delete m_decoder; + m_decoder = 0; +} + + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/IntPointQt.cpp b/WebCore/platform/graphics/qt/IntPointQt.cpp new file mode 100644 index 0000000..f9d336a --- /dev/null +++ b/WebCore/platform/graphics/qt/IntPointQt.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * 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 "IntPoint.h" + +#include <QPoint> + +namespace WebCore { + +IntPoint::IntPoint(const QPoint& p) + : m_x(p.x()) + , m_y(p.y()) +{ +} + +IntPoint::operator QPoint() const +{ + return QPoint(m_x, m_y); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/IntRectQt.cpp b/WebCore/platform/graphics/qt/IntRectQt.cpp new file mode 100644 index 0000000..ccc153e --- /dev/null +++ b/WebCore/platform/graphics/qt/IntRectQt.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * 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 "IntRect.h" + +#include <QRect> + +namespace WebCore { + +IntRect::IntRect(const QRect& r) + : m_location(r.topLeft()) + , m_size(r.width(), r.height()) +{ +} + +IntRect::operator QRect() const +{ + return QRect(x(), y(), width(), height()); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/IntSizeQt.cpp b/WebCore/platform/graphics/qt/IntSizeQt.cpp new file mode 100644 index 0000000..4f2bf35 --- /dev/null +++ b/WebCore/platform/graphics/qt/IntSizeQt.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * + * 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 <QSize> + +#include "IntSize.h" + +namespace WebCore { + +IntSize::IntSize(const QSize& r) + : m_width(r.width()) + , m_height(r.height()) +{ +} + +IntSize::operator QSize() const +{ + return QSize(width(), height()); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp new file mode 100644 index 0000000..431e68e --- /dev/null +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -0,0 +1,533 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "MediaPlayerPrivatePhonon.h" + +#include <limits> + +#include "CString.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "Widget.h" +#include <wtf/HashSet.h> + +#include <QDebug> +#include <QPainter> +#include <QWidget> +#include <QMetaEnum> +#include <QUrl> +#include <QEvent> +#include <phonon> + +using namespace Phonon; + +#define LOG_MEDIAOBJECT() (LOG(Media,"%s", debugMediaObject(this, *m_mediaObject).constData())) + +static QByteArray debugMediaObject(WebCore::MediaPlayerPrivate* mediaPlayer, const MediaObject& mediaObject) +{ + QByteArray byteArray; + QTextStream stream(&byteArray); + + const QMetaObject* metaObj = mediaPlayer->metaObject(); + QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState")); + + stream << "debugMediaObject -> Phonon::MediaObject("; + stream << "State: " << phononStates.valueToKey(mediaObject.state()); + stream << " | Current time: " << mediaObject.currentTime(); + stream << " | Remaining time: " << mediaObject.remainingTime(); + stream << " | Total time: " << mediaObject.totalTime(); + stream << " | Meta-data: "; + QMultiMap<QString, QString> map = mediaObject.metaData(); + for (QMap<QString, QString>::const_iterator it = map.constBegin(); + it != map.constEnd(); ++it) { + stream << "(" << it.key() << ", " << it.value() << ")"; + } + stream << " | Has video: " << mediaObject.hasVideo(); + stream << " | Is seekable: " << mediaObject.isSeekable(); + stream << ")"; + + stream.flush(); + + return byteArray; +} + +using namespace WTF; + +namespace WebCore { + +MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) + : m_player(player) + , m_networkState(MediaPlayer::Empty) + , m_readyState(MediaPlayer::DataUnavailable) + , m_mediaObject(new MediaObject()) + , m_videoWidget(new VideoWidget(0)) + , m_audioOutput(new AudioOutput()) + , m_isVisible(false) +{ + // Hint to Phonon to disable overlay painting + m_videoWidget->setAttribute(Qt::WA_DontShowOnScreen); + + createPath(m_mediaObject, m_videoWidget); + createPath(m_mediaObject, m_audioOutput); + + // Make sure we get updates for each frame + m_videoWidget->installEventFilter(this); + foreach(QWidget* widget, qFindChildren<QWidget*>(m_videoWidget)) { + widget->installEventFilter(this); + } + + connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), + this, SLOT(stateChanged(Phonon::State, Phonon::State))); + connect(m_mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64))); + connect(m_mediaObject, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged())); + connect(m_mediaObject, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool))); + connect(m_mediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasVideoChanged(bool))); + connect(m_mediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int))); + connect(m_mediaObject, SIGNAL(finished()), this, SLOT(finished())); + connect(m_mediaObject, SIGNAL(currentSourceChanged(const Phonon::MediaSource&)), + this, SLOT(currentSourceChanged(const Phonon::MediaSource&))); + connect(m_mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish())); + connect(m_mediaObject, SIGNAL(prefinishMarkReached(qint32)), this, SLOT(prefinishMarkReached(qint32))); + connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64))); +} + +MediaPlayerPrivate::~MediaPlayerPrivate() +{ + LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting videowidget"); + m_videoWidget->close(); + delete m_videoWidget; + m_videoWidget = 0; + + LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting audiooutput"); + delete m_audioOutput; + m_audioOutput = 0; + + LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting mediaobject"); + delete m_mediaObject; + m_mediaObject = 0; +} + +void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&) +{ + notImplemented(); +} + +bool MediaPlayerPrivate::hasVideo() const +{ + bool hasVideo = m_mediaObject->hasVideo(); + LOG(Media, "MediaPlayerPrivatePhonon::hasVideo() -> %s", hasVideo ? "true" : "false"); + return hasVideo; +} + +void MediaPlayerPrivate::load(String url) +{ + LOG(Media, "MediaPlayerPrivatePhonon::load(\"%s\")", url.utf8().data()); + + // We are now loading + if (m_networkState != MediaPlayer::Loading) { + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + } + + // And we don't have any data yet + if (m_readyState != MediaPlayer::DataUnavailable) { + m_readyState = MediaPlayer::DataUnavailable; + m_player->readyStateChanged(); + } + + m_mediaObject->setCurrentSource(QUrl(url)); + m_audioOutput->setVolume(m_player->volume()); + setVisible(m_player->visible()); +} + +void MediaPlayerPrivate::cancelLoad() +{ + notImplemented(); +} + + +void MediaPlayerPrivate::play() +{ + LOG(Media, "MediaPlayerPrivatePhonon::play()"); + m_mediaObject->play(); +} + +void MediaPlayerPrivate::pause() +{ + LOG(Media, "MediaPlayerPrivatePhonon::pause()"); + m_mediaObject->pause(); +} + + +bool MediaPlayerPrivate::paused() const +{ + bool paused = m_mediaObject->state() == Phonon::PausedState; + LOG(Media, "MediaPlayerPrivatePhonon::paused() --> %s", paused ? "true" : "false"); + return paused; +} + +void MediaPlayerPrivate::seek(float position) +{ + LOG(Media, "MediaPlayerPrivatePhonon::seek(%f)", position); + + if (!m_mediaObject->isSeekable()) + return; + + if (position > duration()) + position = duration(); + + m_mediaObject->seek(position * 1000.0f); +} + +bool MediaPlayerPrivate::seeking() const +{ + return false; +} + +float MediaPlayerPrivate::duration() const +{ + if (m_networkState < MediaPlayer::LoadedMetaData) + return 0.0f; + + float duration = m_mediaObject->totalTime() / 1000.0f; + + if (duration == 0.0f) // We are streaming + duration = std::numeric_limits<float>::infinity(); + + LOG(Media, "MediaPlayerPrivatePhonon::duration() --> %f", duration); + return duration; +} + +float MediaPlayerPrivate::currentTime() const +{ + float currentTime = m_mediaObject->currentTime() / 1000.0f; + + LOG(Media, "MediaPlayerPrivatePhonon::currentTime() --> %f", currentTime); + return currentTime; +} + +void MediaPlayerPrivate::setEndTime(float endTime) +{ + notImplemented(); +} + +float MediaPlayerPrivate::maxTimeBuffered() const +{ + notImplemented(); + return 0.0f; +} + +float MediaPlayerPrivate::maxTimeSeekable() const +{ + notImplemented(); + return 0.0f; +} + +unsigned MediaPlayerPrivate::bytesLoaded() const +{ + notImplemented(); + return 0; +} + +bool MediaPlayerPrivate::totalBytesKnown() const +{ + //notImplemented(); + return false; +} + +unsigned MediaPlayerPrivate::totalBytes() const +{ + //notImplemented(); + return 0; +} + +void MediaPlayerPrivate::setRate(float) +{ + notImplemented(); +} + +void MediaPlayerPrivate::setVolume(float volume) +{ + LOG(Media, "MediaPlayerPrivatePhonon::setVolume()"); + m_audioOutput->setVolume(volume); +} + +void MediaPlayerPrivate::setMuted(bool muted) +{ + LOG(Media, "MediaPlayerPrivatePhonon::setMuted()"); + m_audioOutput->setMuted(muted); +} + + +int MediaPlayerPrivate::dataRate() const +{ + // This is not used at the moment + return 0; +} + + +MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const +{ + const QMetaObject* metaObj = this->metaObject(); + QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState")); + LOG(Media, "MediaPlayerPrivatePhonon::networkState() --> %s", networkStates.valueToKey(m_networkState)); + return m_networkState; +} + +MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const +{ + const QMetaObject* metaObj = this->metaObject(); + QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState")); + LOG(Media, "MediaPlayerPrivatePhonon::readyState() --> %s", readyStates.valueToKey(m_readyState)); + return m_readyState; +} + +void MediaPlayerPrivate::updateStates() +{ + MediaPlayer::NetworkState oldNetworkState = m_networkState; + MediaPlayer::ReadyState oldReadyState = m_readyState; + + Phonon::State phononState = m_mediaObject->state(); + + if (phononState == Phonon::StoppedState) { + if (oldNetworkState < MediaPlayer::LoadedMetaData) { + m_networkState = MediaPlayer::LoadedMetaData; + m_readyState = MediaPlayer::DataUnavailable; + m_mediaObject->pause(); + } + } else if (phononState == Phonon::PausedState) { + m_networkState = MediaPlayer::LoadedFirstFrame; + m_readyState = MediaPlayer::CanPlayThrough; + } else if (phononState == Phonon::ErrorState) { + if (!m_mediaObject || m_mediaObject->errorType() == Phonon::FatalError) { + m_networkState = MediaPlayer::LoadFailed; + m_readyState = MediaPlayer::DataUnavailable; + cancelLoad(); + } else { + m_mediaObject->pause(); + } + } + + if (seeking()) + m_readyState = MediaPlayer::DataUnavailable; + + if (m_networkState != oldNetworkState) { + const QMetaObject* metaObj = this->metaObject(); + QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState")); + LOG(Media, "Network state changed from '%s' to '%s'", + networkStates.valueToKey(oldNetworkState), + networkStates.valueToKey(m_networkState)); + m_player->networkStateChanged(); + } + + if (m_readyState != oldReadyState) { + const QMetaObject* metaObj = this->metaObject(); + QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState")); + LOG(Media, "Ready state changed from '%s' to '%s'", + readyStates.valueToKey(oldReadyState), + readyStates.valueToKey(m_readyState)); + m_player->readyStateChanged(); + } +} + +void MediaPlayerPrivate::setVisible(bool visible) +{ + m_isVisible = visible; + LOG(Media, "MediaPlayerPrivatePhonon::setVisible(%s)", visible ? "true" : "false"); + + m_videoWidget->setVisible(m_isVisible); +} + +void MediaPlayerPrivate::setRect(const IntRect& newRect) +{ + if (!m_videoWidget) + return; + + LOG(Media, "MediaPlayerPrivatePhonon::setRect(%d,%d %dx%d)", + newRect.x(), newRect.y(), + newRect.width(), newRect.height()); + + QRect currentRect = m_videoWidget->rect(); + + if (newRect.width() != currentRect.width() || newRect.height() != currentRect.height()) + m_videoWidget->resize(newRect.width(), newRect.height()); +} + + +void MediaPlayerPrivate::loadStateChanged() +{ + notImplemented(); +} + +void MediaPlayerPrivate::rateChanged() +{ + notImplemented(); +} + +void MediaPlayerPrivate::sizeChanged() +{ + notImplemented(); +} + +void MediaPlayerPrivate::timeChanged() +{ + notImplemented(); +} + +void MediaPlayerPrivate::volumeChanged() +{ + notImplemented(); +} + +void MediaPlayerPrivate::didEnd() +{ + notImplemented(); +} + +void MediaPlayerPrivate::loadingFailed() +{ + notImplemented(); +} + +IntSize MediaPlayerPrivate::naturalSize() const +{ + if (!hasVideo()) { + LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d", + 0, 0); + return IntSize(); + } + + if (m_networkState < MediaPlayer::LoadedMetaData) { + LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d", + 0, 0); + return IntSize(); + } + + QSize videoSize = m_videoWidget->sizeHint(); + IntSize naturalSize(videoSize.width(), videoSize.height()); + LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d", + naturalSize.width(), naturalSize.height()); + return naturalSize; +} + +bool MediaPlayerPrivate::eventFilter(QObject* obj, QEvent* event) +{ + if (event->type() == QEvent::Paint) + m_player->repaint(); + + return QObject::eventFilter(obj, event); +} + +void MediaPlayerPrivate::repaint() +{ + m_player->repaint(); +} + +void MediaPlayerPrivate::paint(GraphicsContext* graphicsContect, const IntRect& rect) +{ + if (graphicsContect->paintingDisabled()) + return; + + if (!m_isVisible) + return; + + QPainter* painter = graphicsContect->platformContext(); + + painter->fillRect(rect, Qt::black); + + m_videoWidget->render(painter, QPoint(rect.x(), rect.y()), + QRegion(0, 0, rect.width(), rect.height())); +} + +// ====================== Phonon::MediaObject signals ====================== + +void MediaPlayerPrivate::stateChanged(Phonon::State newState, Phonon::State oldState) +{ + const QMetaObject* metaObj = this->metaObject(); + QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState")); + LOG(Media, "MediaPlayerPrivatePhonon::stateChanged(newState=%s, oldState=%s)", + phononStates.valueToKey(newState), phononStates.valueToKey(oldState)); + + updateStates(); +} + +void MediaPlayerPrivate::tick(qint64) +{ + updateStates(); + m_player->timeChanged(); +} + +void MediaPlayerPrivate::metaDataChanged() +{ + LOG(Media, "MediaPlayerPrivatePhonon::metaDataChanged()"); + LOG_MEDIAOBJECT(); +} + +void MediaPlayerPrivate::seekableChanged(bool) +{ + notImplemented(); + LOG_MEDIAOBJECT(); +} + +void MediaPlayerPrivate::hasVideoChanged(bool hasVideo) +{ + LOG(Media, "MediaPlayerPrivatePhonon::hasVideoChanged(%s)", hasVideo ? "true" : "false"); +} + +void MediaPlayerPrivate::bufferStatus(int) +{ + notImplemented(); + LOG_MEDIAOBJECT(); +} + +void MediaPlayerPrivate::finished() +{ + notImplemented(); + LOG_MEDIAOBJECT(); +} + +void MediaPlayerPrivate::currentSourceChanged(const Phonon::MediaSource&) +{ + notImplemented(); + LOG_MEDIAOBJECT(); +} + +void MediaPlayerPrivate::aboutToFinish() +{ + notImplemented(); + LOG_MEDIAOBJECT(); +} + +void MediaPlayerPrivate::prefinishMarkReached(qint32) +{ + notImplemented(); + LOG_MEDIAOBJECT(); +} + +void MediaPlayerPrivate::totalTimeChanged(qint64 totalTime) +{ + LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%d)", totalTime); + LOG_MEDIAOBJECT(); +} + +} // namespace WebCore + +#include "moc_MediaPlayerPrivatePhonon.cpp" diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h new file mode 100644 index 0000000..5eb2a09 --- /dev/null +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h @@ -0,0 +1,159 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MediaPlayerPrivatePhonon_h +#define MediaPlayerPrivatePhonon_h + +#include "MediaPlayer.h" +#include <wtf/Noncopyable.h> + +#include <QObject> +#include <phononnamespace.h> + +QT_BEGIN_NAMESPACE +class QWidget; +class QUrl; + +namespace Phonon { + class MediaObject; + class VideoWidget; + class AudioOutput; + class MediaSource; +} +QT_END_NAMESPACE + +namespace WebCore { + + class MediaPlayerPrivate : public QObject, Noncopyable { + + Q_OBJECT + + public: + MediaPlayerPrivate(MediaPlayer*); + ~MediaPlayerPrivate(); + + // These enums are used for debugging + Q_ENUMS(ReadyState NetworkState PhononState) + + enum ReadyState { + DataUnavailable, + CanShowCurrentFrame, + CanPlay, + CanPlayThrough + }; + + enum NetworkState { + Empty, + LoadFailed, + Loading, + LoadedMetaData, + LoadedFirstFrame, + Loaded + }; + + enum PhononState { + LoadingState, + StoppedState, + PlayingState, + BufferingState, + PausedState, + ErrorState + }; + + IntSize naturalSize() const; + bool hasVideo() const; + + void load(String url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration() const; + float currentTime() const; + void seek(float); + void setEndTime(float); + + void setRate(float); + void setVolume(float); + void setMuted(bool); + + int dataRate() const; + + MediaPlayer::NetworkState networkState() const; + MediaPlayer::ReadyState readyState() const; + + float maxTimeBuffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + bool totalBytesKnown() const; + unsigned totalBytes() const; + + void setVisible(bool); + void setRect(const IntRect&); + + void loadStateChanged(); + void rateChanged(); + void sizeChanged(); + void timeChanged(); + void volumeChanged(); + void didEnd(); + void loadingFailed(); + + void repaint(); + void paint(GraphicsContext*, const IntRect&); + static void getSupportedTypes(HashSet<String>&); + static bool isAvailable() { return true; } + + protected: + bool eventFilter(QObject*, QEvent*); + + private slots: + void stateChanged(Phonon::State, Phonon::State); + void tick(qint64); + void metaDataChanged(); + void seekableChanged(bool); + void hasVideoChanged(bool); + void bufferStatus(int); + void finished(); + void currentSourceChanged(const Phonon::MediaSource&); + void aboutToFinish(); + void prefinishMarkReached(qint32); + void totalTimeChanged(qint64); + + private: + void updateStates(); + + MediaPlayer* m_player; + + MediaPlayer::NetworkState m_networkState; + MediaPlayer::ReadyState m_readyState; + + Phonon::MediaObject* m_mediaObject; + Phonon::VideoWidget* m_videoWidget; + Phonon::AudioOutput* m_audioOutput; + + bool m_isVisible; + }; +} + +#endif // MediaPlayerPrivatePhonon_h diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp new file mode 100644 index 0000000..76f375c --- /dev/null +++ b/WebCore/platform/graphics/qt/PathQt.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * 2006 Rob Buis <buis@kde.org> + * + * 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 "Path.h" + +#include "FloatRect.h" +#include "PlatformString.h" +#include "AffineTransform.h" +#include <QPainterPath> +#include <QMatrix> +#include <QString> + +#define _USE_MATH_DEFINES +#include <math.h> + +namespace WebCore { + +Path::Path() + : m_path(new QPainterPath()) +{ +} + +Path::~Path() +{ + delete m_path; +} + +Path::Path(const Path& other) + : m_path(new QPainterPath(*other.platformPath())) +{ +} + +Path& Path::operator=(const Path& other) +{ + if (&other != this) { + delete m_path; + m_path = new QPainterPath(*other.platformPath()); + } + + return *this; +} + +bool Path::contains(const FloatPoint& point, WindRule rule) const +{ + Qt::FillRule savedRule = m_path->fillRule(); + m_path->setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); + + bool contains = m_path->contains(point); + + m_path->setFillRule(savedRule); + return contains; +} + +void Path::translate(const FloatSize& size) +{ + QMatrix matrix; + matrix.translate(size.width(), size.height()); + *m_path = (*m_path) * matrix; +} + +FloatRect Path::boundingRect() const +{ + return m_path->boundingRect(); +} + +void Path::moveTo(const FloatPoint& point) +{ + m_path->moveTo(point); +} + +void Path::addLineTo(const FloatPoint& p) +{ + m_path->lineTo(p); +} + +void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + m_path->quadTo(cp, p); +} + +void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + m_path->cubicTo(cp1, cp2, p); +} + +void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) +{ + //FIXME: busted + qWarning("arcTo is busted"); + m_path->arcTo(p1.x(), p1.y(), p2.x(), p2.y(), radius, 90); +} + +void Path::closeSubpath() +{ + m_path->closeSubpath(); +} + +#define DEGREES(t) ((t) * 180.0 / M_PI) +void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise) +{ + qreal xc = p.x(); + qreal yc = p.y(); + qreal radius = r; + + + //### HACK + // In Qt we don't switch the coordinate system for degrees + // and still use the 0,0 as bottom left for degrees so we need + // to switch + sar = -sar; + ear = -ear; + anticlockwise = !anticlockwise; + //end hack + + float sa = DEGREES(sar); + float ea = DEGREES(ear); + + double span = 0; + + double xs = xc - radius; + double ys = yc - radius; + double width = radius*2; + double height = radius*2; + + if (!anticlockwise && (ea < sa)) + span += 360; + else if (anticlockwise && (sa < ea)) + span -= 360; + + // this is also due to switched coordinate system + // we would end up with a 0 span instead of 360 + if (!(qFuzzyCompare(span + (ea - sa) + 1, 1.0) && + qFuzzyCompare(qAbs(span), 360.0))) { + span += ea - sa; + } + + m_path->moveTo(QPointF(xc + radius * cos(sar), + yc - radius * sin(sar))); + + m_path->arcTo(xs, ys, width, height, sa, span); +} + +void Path::addRect(const FloatRect& r) +{ + m_path->addRect(r.x(), r.y(), r.width(), r.height()); +} + +void Path::addEllipse(const FloatRect& r) +{ + m_path->addEllipse(r.x(), r.y(), r.width(), r.height()); +} + +void Path::clear() +{ + *m_path = QPainterPath(); +} + +bool Path::isEmpty() const +{ + return m_path->isEmpty(); +} + +String Path::debugString() const +{ + QString ret; + for (int i = 0; i < m_path->elementCount(); ++i) { + const QPainterPath::Element &cur = m_path->elementAt(i); + + switch (cur.type) { + case QPainterPath::MoveToElement: + ret += QString(QLatin1String("M %1 %2")).arg(cur.x).arg(cur.y); + break; + case QPainterPath::LineToElement: + ret += QString(QLatin1String("L %1 %2")).arg(cur.x).arg(cur.y); + break; + case QPainterPath::CurveToElement: + { + const QPainterPath::Element &c1 = m_path->elementAt(i + 1); + const QPainterPath::Element &c2 = m_path->elementAt(i + 2); + + Q_ASSERT(c1.type == QPainterPath::CurveToDataElement); + Q_ASSERT(c2.type == QPainterPath::CurveToDataElement); + + ret += QString(QLatin1String("C %1 %2 %3 %4 %5 %6")).arg(cur.x).arg(cur.y).arg(c1.x).arg(c1.y).arg(c2.x).arg(c2.y); + + i += 2; + break; + } + case QPainterPath::CurveToDataElement: + Q_ASSERT(false); + break; + } + } + + return ret; +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + PathElement pelement; + FloatPoint points[3]; + pelement.points = points; + for (int i = 0; i < m_path->elementCount(); ++i) { + const QPainterPath::Element& cur = m_path->elementAt(i); + + switch (cur.type) { + case QPainterPath::MoveToElement: + pelement.type = PathElementMoveToPoint; + pelement.points[0] = QPointF(cur); + function(info, &pelement); + break; + case QPainterPath::LineToElement: + pelement.type = PathElementAddLineToPoint; + pelement.points[0] = QPointF(cur); + function(info, &pelement); + break; + case QPainterPath::CurveToElement: + { + const QPainterPath::Element& c1 = m_path->elementAt(i + 1); + const QPainterPath::Element& c2 = m_path->elementAt(i + 2); + + Q_ASSERT(c1.type == QPainterPath::CurveToDataElement); + Q_ASSERT(c2.type == QPainterPath::CurveToDataElement); + + pelement.type = PathElementAddCurveToPoint; + pelement.points[0] = QPointF(cur); + pelement.points[1] = QPointF(c1); + pelement.points[2] = QPointF(c2); + function(info, &pelement); + + i += 2; + break; + } + case QPainterPath::CurveToDataElement: + Q_ASSERT(false); + } + } +} + +void Path::transform(const AffineTransform& transform) +{ + if (m_path) { + QMatrix mat = transform; + QPainterPath temp = mat.map(*m_path); + delete m_path; + m_path = new QPainterPath(temp); + } +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/PatternQt.cpp b/WebCore/platform/graphics/qt/PatternQt.cpp new file mode 100644 index 0000000..883a258 --- /dev/null +++ b/WebCore/platform/graphics/qt/PatternQt.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2008 Eric Seidel <eric@webkit.org> + * + * 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 "Pattern.h" + +#include "AffineTransform.h" +#include "GraphicsContext.h" + +namespace WebCore { + +QBrush Pattern::createPlatformPattern(const AffineTransform& transform) const +{ + QPixmap* pixmap = tileImage()->nativeImageForCurrentFrame(); + if (!pixmap) + return QBrush(); + + QBrush brush(*pixmap); + brush.setMatrix(transform); + + return brush; +} + +} diff --git a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp new file mode 100644 index 0000000..1ffce33 --- /dev/null +++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -0,0 +1,55 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#include "config.h" +#include "SimpleFontData.h" + +#include "SVGFontData.h" + +namespace WebCore { + +SimpleFontData::SimpleFontData(const FontPlatformData& font, bool customFont, bool loading, SVGFontData*) + : m_font(font) + , m_isCustomFont(customFont) + , m_isLoading(loading) +{ +} + +SimpleFontData::~SimpleFontData() +{ +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + return true; +} + +const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const +{ + return this; +} + +bool SimpleFontData::isSegmented() const +{ + return false; +} + +} diff --git a/WebCore/platform/graphics/qt/StillImageQt.cpp b/WebCore/platform/graphics/qt/StillImageQt.cpp new file mode 100644 index 0000000..95b3bc8 --- /dev/null +++ b/WebCore/platform/graphics/qt/StillImageQt.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 Holger Hans Peter Freyther + * + * 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 "StillImageQt.h" + +#include "GraphicsContext.h" +#include "IntSize.h" + +#include <QPainter> + +namespace WebCore { + +StillImage::StillImage(const QPixmap& pixmap) + : m_pixmap(pixmap) +{} + +IntSize StillImage::size() const +{ + return IntSize(m_pixmap.width(), m_pixmap.height()); +} + +NativeImagePtr StillImage::nativeImageForCurrentFrame() +{ + return const_cast<NativeImagePtr>(&m_pixmap); +} + +void StillImage::draw(GraphicsContext* ctxt, const FloatRect& dst, + const FloatRect& src, CompositeOperator op) +{ + if (m_pixmap.isNull()) + return; + + ctxt->save(); + ctxt->setCompositeOperation(op); + QPainter* painter(ctxt->platformContext()); + painter->drawPixmap(dst, m_pixmap, src); + ctxt->restore(); +} + +} diff --git a/WebCore/platform/graphics/qt/StillImageQt.h b/WebCore/platform/graphics/qt/StillImageQt.h new file mode 100644 index 0000000..37b8b2c --- /dev/null +++ b/WebCore/platform/graphics/qt/StillImageQt.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008 Holger Hans Peter Freyther + * + * 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 StillImageQt_h +#define StillImageQt_h + +#include "Image.h" + +namespace WebCore { + + class StillImage : public Image { + public: + static PassRefPtr<StillImage> create(const QPixmap& pixmap) + { + return adoptRef(new StillImage(pixmap)); + } + + // FIXME: StillImages are underreporting decoded sizes and will be unable + // to prune because these functions are not implemented yet. + virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) { } + virtual unsigned decodedSize() const { return 0; } + + virtual IntSize size() const; + virtual NativeImagePtr nativeImageForCurrentFrame(); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + + private: + StillImage(const QPixmap& pixmap); + + QPixmap m_pixmap; + }; + +} + +#endif |