diff options
author | Steve Block <steveblock@google.com> | 2011-05-25 08:15:24 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-05-25 08:15:24 -0700 |
commit | fa91a01aee5d4a80ca6c80f722116b850f09996c (patch) | |
tree | f72740e60d3c3d4f0ab144e88c03d1f134944ce3 /Source/WebCore/platform/graphics | |
parent | 96f37d6d1b390f6690858789706ee6ec25bc1677 (diff) | |
parent | feebf8e7a79ad68b04a1a948e2b8078d6e5f0048 (diff) | |
download | external_webkit-fa91a01aee5d4a80ca6c80f722116b850f09996c.zip external_webkit-fa91a01aee5d4a80ca6c80f722116b850f09996c.tar.gz external_webkit-fa91a01aee5d4a80ca6c80f722116b850f09996c.tar.bz2 |
Merge changes I78ff6a85,Ic85c6405,Ibf903baa,I3a0459db,I35140385,I54790419,I6bfe5d24,Ia9f39b83,I5bcecd5a,I1de96683,I543c6810,I8a5b0878,I0ae670bf,Ide4d58dc,I28ebaf3d,I499d6631,Ie5090e0d,I6d3e5f1f
* changes:
Merge WebKit at r78450: Update ThirdPartyProject.prop
Merge WebKit at r78450: Add new Font::canExpandAroundIdeographsInComplexText()
Merge WebKit at r78450: Add new ChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
Merge WebKit at r78450: FrameLoaderClient::didRunInsecureContent() signature changed
Merge WebKit at r78450: HTMLAreaElement::getRect() renamed
Merge WebKit at r78450: FrameLoader::url() removed
Merge WebKit at r78450: HTMLParserQuirks removed
Merge WebKit at r78450: TextRun::padding() renamed
Merge WebKit at r78450: Use new FontMetrics
Merge WebKit at r78450: GraphicsContext current path removed
Merge WebKit at r78450: TransformationMatrix multiply methods renamed and meaning changed
Merge WebKit at r78450: FontCustomPlatformData::fontPlatformData() signature changed
Merge WebKit at r78450: IntRect::bottom()/right() renamed
Merge WebKit at r78450: Fix remaining conflicts
Merge WebKit at r78450: Fix conflicts due to new ENABLE_WEB_ARCHIVE guard
Merge WebKit at r78450: Fix conflicts in media controls
Merge WebKit at r78450: Fix Makefiles
Merge WebKit at r78450: Initial merge by git.
Diffstat (limited to 'Source/WebCore/platform/graphics')
228 files changed, 6325 insertions, 1969 deletions
diff --git a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp index f416b47..9e64904 100644 --- a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp +++ b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "ANGLEWebKitBridge.h" #include <wtf/OwnArrayPtr.h> @@ -93,7 +93,7 @@ bool ANGLEWebKitBridge::validateShaderSource(const char* shaderSource, ANGLEShad int logSize = 0; ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &logSize); if (logSize > 1) { - OwnArrayPtr<char> logBuffer(new char[logSize]); + OwnArrayPtr<char> logBuffer = adoptArrayPtr(new char[logSize]); if (logBuffer) { ShGetInfoLog(compiler, logBuffer.get()); shaderValidationLog = logBuffer.get(); @@ -105,7 +105,7 @@ bool ANGLEWebKitBridge::validateShaderSource(const char* shaderSource, ANGLEShad int translationLength = 0; ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &translationLength); if (translationLength > 1) { - OwnArrayPtr<char> translationBuffer(new char[translationLength]); + OwnArrayPtr<char> translationBuffer = adoptArrayPtr(new char[translationLength]); if (!translationBuffer) return false; ShGetObjectCode(compiler, translationBuffer.get()); @@ -117,4 +117,4 @@ bool ANGLEWebKitBridge::validateShaderSource(const char* shaderSource, ANGLEShad } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/ContextShadow.h b/Source/WebCore/platform/graphics/ContextShadow.h index a1fba5c..c0571f0 100644 --- a/Source/WebCore/platform/graphics/ContextShadow.h +++ b/Source/WebCore/platform/graphics/ContextShadow.h @@ -68,6 +68,8 @@ typedef void* PlatformContext; // This class should be copyable since GraphicsContextQt keeps a stack of // the shadow state for savePlatformState and restorePlatformState. +// This class is Deprecated. Platforms should migrate to ShadowBlur. + class ContextShadow { public: enum { diff --git a/Source/WebCore/platform/graphics/Extensions3D.h b/Source/WebCore/platform/graphics/Extensions3D.h index 1a2b7a1..6d6efe5 100644 --- a/Source/WebCore/platform/graphics/Extensions3D.h +++ b/Source/WebCore/platform/graphics/Extensions3D.h @@ -52,6 +52,7 @@ public: // GL_ANGLE_framebuffer_blit / GL_ANGLE_framebuffer_multisample // GL_OES_texture_float // GL_OES_standard_derivatives + // GL_OES_rgb8_rgba8 // Takes full name of extension; for example, // "GL_EXT_texture_format_BGRA8888". @@ -87,6 +88,10 @@ public: // GL_OES_standard_derivatives names FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B, + + // GL_OES_rgb8_rgba8 names + RGB8_OES = 0x8051, + RGBA8_OES = 0x8058, }; // GL_ARB_robustness diff --git a/Source/WebCore/platform/graphics/FloatQuad.h b/Source/WebCore/platform/graphics/FloatQuad.h index 6cd86f6..e913723 100644 --- a/Source/WebCore/platform/graphics/FloatQuad.h +++ b/Source/WebCore/platform/graphics/FloatQuad.h @@ -54,9 +54,9 @@ public: FloatQuad(const FloatRect& inRect) : m_p1(inRect.location()) - , m_p2(inRect.right(), inRect.y()) - , m_p3(inRect.right(), inRect.bottom()) - , m_p4(inRect.x(), inRect.bottom()) + , m_p2(inRect.maxX(), inRect.y()) + , m_p3(inRect.maxX(), inRect.maxY()) + , m_p4(inRect.x(), inRect.maxY()) { } diff --git a/Source/WebCore/platform/graphics/FloatRect.cpp b/Source/WebCore/platform/graphics/FloatRect.cpp index 0d8a24e..36f3d3a 100644 --- a/Source/WebCore/platform/graphics/FloatRect.cpp +++ b/Source/WebCore/platform/graphics/FloatRect.cpp @@ -51,22 +51,22 @@ bool FloatRect::intersects(const FloatRect& other) const { // Checking emptiness handles negative widths as well as zero. return !isEmpty() && !other.isEmpty() - && x() < other.right() && other.x() < right() - && y() < other.bottom() && other.y() < bottom(); + && x() < other.maxX() && other.x() < maxX() + && y() < other.maxY() && other.y() < maxY(); } bool FloatRect::contains(const FloatRect& other) const { - return x() <= other.x() && right() >= other.right() - && y() <= other.y() && bottom() >= other.bottom(); + return x() <= other.x() && maxX() >= other.maxX() + && y() <= other.y() && maxY() >= other.maxY(); } void FloatRect::intersect(const FloatRect& other) { float l = max(x(), other.x()); float t = max(y(), other.y()); - float r = min(right(), other.right()); - float b = min(bottom(), other.bottom()); + float r = min(maxX(), other.maxX()); + float b = min(maxY(), other.maxY()); // Return a clean empty rectangle for non-intersecting cases. if (l >= r || t >= b) { @@ -91,8 +91,8 @@ void FloatRect::unite(const FloatRect& other) float l = min(x(), other.x()); float t = min(y(), other.y()); - float r = max(right(), other.right()); - float b = max(bottom(), other.bottom()); + float r = max(maxX(), other.maxX()); + float b = max(maxY(), other.maxY()); setLocationAndSizeFromEdges(l, t, r, b); } @@ -180,8 +180,8 @@ IntRect enclosingIntRect(const FloatRect& rect) { float left = floorf(rect.x()); float top = floorf(rect.y()); - float width = ceilf(rect.right()) - left; - float height = ceilf(rect.bottom()) - top; + float width = ceilf(rect.maxX()) - left; + float height = ceilf(rect.maxY()) - top; return IntRect(safeFloatToInt(left), safeFloatToInt(top), safeFloatToInt(width), safeFloatToInt(height)); } diff --git a/Source/WebCore/platform/graphics/FloatRect.h b/Source/WebCore/platform/graphics/FloatRect.h index 10ad838..733f7cc 100644 --- a/Source/WebCore/platform/graphics/FloatRect.h +++ b/Source/WebCore/platform/graphics/FloatRect.h @@ -90,6 +90,8 @@ public: float x() const { return m_location.x(); } float y() const { return m_location.y(); } + float maxX() const { return x() + width(); } + float maxY() const { return y() + height(); } float width() const { return m_size.width(); } float height() const { return m_size.height(); } @@ -100,11 +102,6 @@ public: bool isEmpty() const { return m_size.isEmpty(); } - float left() const { return x(); } - float right() const { return x() + width(); } - float top() const { return y(); } - float bottom() const { return y() + height(); } - FloatPoint center() const { return FloatPoint(x() + width() / 2, y() + height() / 2); } void move(const FloatSize& delta) { m_location += delta; } @@ -119,10 +116,9 @@ public: // Note, this doesn't match what IntRect::contains(IntPoint&) does; the int version // is really checking for containment of 1x1 rect, but that doesn't make sense with floats. bool contains(float px, float py) const - { return px >= x() && px <= right() && py >= y() && py <= bottom(); } + { return px >= x() && px <= maxX() && py >= y() && py <= maxY(); } bool contains(const FloatPoint& point) const { return contains(point.x(), point.y()); } - void inflateX(float dx) { m_location.setX(m_location.x() - dx); m_size.setWidth(m_size.width() + dx + dx); diff --git a/Source/WebCore/platform/graphics/Font.cpp b/Source/WebCore/platform/graphics/Font.cpp index 394de35..6bdddfc 100644 --- a/Source/WebCore/platform/graphics/Font.cpp +++ b/Source/WebCore/platform/graphics/Font.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -247,21 +247,15 @@ bool Font::isSVGFont() const } #endif -String Font::normalizeSpaces(const String& string) +String Font::normalizeSpaces(const UChar* characters, unsigned length) { - const UChar* characters = string.characters(); - unsigned length = string.length(); - Vector<UChar, 256> buffer(length); - bool didReplacement = false; - - for (unsigned i = 0; i < length; ++i) { - UChar originalCharacter = characters[i]; - buffer[i] = normalizeSpaces(originalCharacter); - if (buffer[i] != originalCharacter) - didReplacement = true; - } + UChar* buffer; + String normalized = String::createUninitialized(length, buffer); + + for (unsigned i = 0; i < length; ++i) + buffer[i] = normalizeSpaces(characters[i]); - return didReplacement ? String(buffer.data(), length) : string; + return normalized; } static bool shouldUseFontSmoothing = true; @@ -293,7 +287,7 @@ Font::CodePath Font::codePath(const TextRun& run) const return s_codePath; #if PLATFORM(QT) - if (run.padding() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing()) + if (run.expansion() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing()) return Complex; #endif @@ -458,6 +452,56 @@ bool Font::isCJKIdeographOrSymbol(UChar32 c) return isCJKIdeograph(c); } +unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion) +{ + static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText(); + unsigned count = 0; + if (direction == LTR) { + for (size_t i = 0; i < length; ++i) { + UChar32 character = characters[i]; + if (treatAsSpace(character)) { + count++; + isAfterExpansion = true; + continue; + } + if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) { + character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]); + i++; + } + if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { + if (!isAfterExpansion) + count++; + count++; + isAfterExpansion = true; + continue; + } + isAfterExpansion = false; + } + } else { + for (size_t i = length; i > 0; --i) { + UChar32 character = characters[i - 1]; + if (treatAsSpace(character)) { + count++; + isAfterExpansion = true; + continue; + } + if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) { + character = U16_GET_SUPPLEMENTARY(characters[i - 2], character); + i--; + } + if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { + if (!isAfterExpansion) + count++; + count++; + isAfterExpansion = true; + continue; + } + isAfterExpansion = false; + } + } + return count; +} + bool Font::canReceiveTextEmphasis(UChar32 c) { CharCategory category = Unicode::category(c); diff --git a/Source/WebCore/platform/graphics/Font.h b/Source/WebCore/platform/graphics/Font.h index 2957c0a..258240b 100644 --- a/Source/WebCore/platform/graphics/Font.h +++ b/Source/WebCore/platform/graphics/Font.h @@ -2,7 +2,7 @@ * Copyright (C) 2000 Lars Knoll (knoll@kde.org) * (C) 2000 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006, 2007, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2007, 2010, 2011 Apple Inc. All rights reserved. * Copyright (C) 2008 Holger Hans Peter Freyther * * This library is free software; you can redistribute it and/or @@ -25,14 +25,15 @@ #ifndef Font_h #define Font_h -#include "CharacterNames.h" #include "FontDescription.h" #include "FontFallbackList.h" #include "SimpleFontData.h" +#include "TextDirection.h" #include "TypesettingFeatures.h" #include <wtf/HashMap.h> #include <wtf/HashSet.h> #include <wtf/MathExtras.h> +#include <wtf/unicode/CharacterNames.h> #if PLATFORM(QT) #include <QFont> @@ -43,7 +44,7 @@ namespace WebCore { class FloatPoint; class FloatRect; class FontData; -class FontFallbackList; +class FontMetrics; class FontPlatformData; class FontSelector; class GlyphBuffer; @@ -54,8 +55,6 @@ class TextRun; struct GlyphData; -const unsigned defaultUnitsPerEm = 1000; - struct GlyphOverflow { GlyphOverflow() : left(0) @@ -124,17 +123,12 @@ public: bool italic() const { return m_fontDescription.italic(); } FontWeight weight() const { return m_fontDescription.weight(); } + FontWidthVariant widthVariant() const { return m_fontDescription.widthVariant(); } bool isPlatformFont() const { return m_isPlatformFont; } // Metrics that we query the FontFallbackList for. - int ascent(FontBaseline baselineType = AlphabeticBaseline) const { return primaryFont()->ascent(baselineType); } - int descent(FontBaseline baselineType = AlphabeticBaseline) const { return primaryFont()->descent(baselineType); } - int height() const { return ascent() + descent(); } - int lineSpacing() const { return primaryFont()->lineSpacing(); } - int lineGap() const { return primaryFont()->lineGap(); } - float xHeight() const { return primaryFont()->xHeight(); } - unsigned unitsPerEm() const { return primaryFont()->unitsPerEm(); } + const FontMetrics& fontMetrics() const { return primaryFont()->fontMetrics(); } int spaceWidth() const { return (int)ceilf(primaryFont()->adjustedSpaceWidth() + m_letterSpacing); } float tabWidth(const SimpleFontData& fontData) const { return 8 * ceilf(fontData.adjustedSpaceWidth() + letterSpacing()); } int emphasisMarkAscent(const AtomicString&) const; @@ -150,7 +144,9 @@ public: static bool isCJKIdeograph(UChar32); static bool isCJKIdeographOrSymbol(UChar32); - + + static unsigned expansionOpportunityCount(const UChar*, size_t length, TextDirection, bool& isAfterExpansion); + #if PLATFORM(QT) QFont font() const; #endif @@ -185,6 +181,7 @@ private: bool getEmphasisMarkGlyphData(const AtomicString&, GlyphData&) const; static bool canReturnFallbackFontsForComplexText(); + static bool canExpandAroundIdeographsInComplexText(); CodePath codePath(const TextRun&) const; @@ -226,7 +223,7 @@ public: return character; } - static String normalizeSpaces(const String&); + static String normalizeSpaces(const UChar*, unsigned length); #if ENABLE(SVG_FONTS) bool isSVGFont() const; diff --git a/Source/WebCore/platform/graphics/FontCache.cpp b/Source/WebCore/platform/graphics/FontCache.cpp index cfca980..ca82ebd 100644 --- a/Source/WebCore/platform/graphics/FontCache.cpp +++ b/Source/WebCore/platform/graphics/FontCache.cpp @@ -57,7 +57,7 @@ struct FontPlatformDataCacheKey { WTF_MAKE_FAST_ALLOCATED; public: FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, unsigned weight = 0, bool italic = false, - bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode, FontOrientation orientation = Horizontal) + bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode, FontOrientation orientation = Horizontal, FontWidthVariant widthVariant = RegularWidth) : m_size(size) , m_weight(weight) , m_family(family) @@ -65,6 +65,7 @@ public: , m_printerFont(isPrinterFont) , m_renderingMode(renderingMode) , m_orientation(orientation) + , m_widthVariant(widthVariant) { } @@ -75,7 +76,7 @@ public: { return equalIgnoringCase(m_family, other.m_family) && m_size == other.m_size && m_weight == other.m_weight && m_italic == other.m_italic && m_printerFont == other.m_printerFont && - m_renderingMode == other.m_renderingMode && m_orientation == other.m_orientation; + m_renderingMode == other.m_renderingMode && m_orientation == other.m_orientation && m_widthVariant == other.m_widthVariant; } unsigned m_size; @@ -85,6 +86,7 @@ public: bool m_printerFont; FontRenderingMode m_renderingMode; FontOrientation m_orientation; + FontWidthVariant m_widthVariant; private: static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; } @@ -92,10 +94,11 @@ private: inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey) { - unsigned hashCodes[4] = { + unsigned hashCodes[5] = { CaseFoldingHash::hash(fontKey.m_family), fontKey.m_size, fontKey.m_weight, + fontKey.m_widthVariant, static_cast<unsigned>(fontKey.m_orientation) << 3 | static_cast<unsigned>(fontKey.m_italic) << 2 | static_cast<unsigned>(fontKey.m_printerFont) << 1 | static_cast<unsigned>(fontKey.m_renderingMode) }; return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes); @@ -195,7 +198,7 @@ FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fo } FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.weight(), fontDescription.italic(), - fontDescription.usePrinterFont(), fontDescription.renderingMode(), fontDescription.orientation()); + fontDescription.usePrinterFont(), fontDescription.renderingMode(), fontDescription.orientation(), fontDescription.widthVariant()); FontPlatformData* result = 0; bool foundResult; FontPlatformDataCache::iterator it = gFontPlatformDataCache->find(key); diff --git a/Source/WebCore/platform/graphics/FontDescription.h b/Source/WebCore/platform/graphics/FontDescription.h index 12900bf..283d297 100644 --- a/Source/WebCore/platform/graphics/FontDescription.h +++ b/Source/WebCore/platform/graphics/FontDescription.h @@ -30,6 +30,7 @@ #include "FontRenderingMode.h" #include "FontSmoothingMode.h" #include "FontTraitsMask.h" +#include "FontWidthVariant.h" #include "TextRenderingMode.h" namespace WebCore { @@ -57,6 +58,7 @@ public: : m_specifiedSize(0) , m_computedSize(0) , m_orientation(Horizontal) + , m_widthVariant(RegularWidth) , m_italic(false) , m_smallCaps(false) , m_isAbsoluteSize(false) @@ -97,6 +99,7 @@ public: FontTraitsMask traitsMask() const; bool isSpecifiedFont() const { return m_isSpecifiedFont; } FontOrientation orientation() const { return m_orientation; } + FontWidthVariant widthVariant() const { return m_widthVariant; } void setFamily(const FontFamily& family) { m_familyList = family; } void setComputedSize(float s) { m_computedSize = s; } @@ -117,6 +120,7 @@ public: void setTextRenderingMode(TextRenderingMode rendering) { m_textRendering = rendering; } void setIsSpecifiedFont(bool isSpecifiedFont) { m_isSpecifiedFont = isSpecifiedFont; } void setOrientation(FontOrientation orientation) { m_orientation = orientation; } + void setWidthVariant(FontWidthVariant widthVariant) { m_widthVariant = widthVariant; } private: FontFamily m_familyList; // The list of font families to be used. @@ -126,6 +130,8 @@ private: float m_computedSize; // Computed size adjusted for the minimum font size and the zoom factor. FontOrientation m_orientation; + + FontWidthVariant m_widthVariant; bool m_italic : 1; bool m_smallCaps : 1; @@ -162,7 +168,8 @@ inline bool FontDescription::operator==(const FontDescription& other) const && m_fontSmoothing == other.m_fontSmoothing && m_textRendering == other.m_textRendering && m_isSpecifiedFont == other.m_isSpecifiedFont - && m_orientation == other.m_orientation; + && m_orientation == other.m_orientation + && m_widthVariant == other.m_widthVariant; } } diff --git a/Source/WebCore/platform/graphics/FontFastPath.cpp b/Source/WebCore/platform/graphics/FontFastPath.cpp index f927c13..034ac22 100644 --- a/Source/WebCore/platform/graphics/FontFastPath.cpp +++ b/Source/WebCore/platform/graphics/FontFastPath.cpp @@ -23,7 +23,6 @@ #include "config.h" #include "Font.h" -#include "CharacterNames.h" #include "FloatRect.h" #include "FontCache.h" #include "FontFallbackList.h" @@ -32,8 +31,8 @@ #include "SimpleFontData.h" #include "TextRun.h" #include "WidthIterator.h" - #include <wtf/MathExtras.h> +#include <wtf/unicode/CharacterNames.h> #include <wtf/unicode/Unicode.h> using namespace WTF; @@ -252,7 +251,7 @@ int Font::emphasisMarkAscent(const AtomicString& mark) const if (!markFontData) return 0; - return markFontData->ascent(); + return markFontData->fontMetrics().ascent(); } int Font::emphasisMarkDescent(const AtomicString& mark) const @@ -266,7 +265,7 @@ int Font::emphasisMarkDescent(const AtomicString& mark) const if (!markFontData) return 0; - return markFontData->descent(); + return markFontData->fontMetrics().descent(); } int Font::emphasisMarkHeight(const AtomicString& mark) const @@ -280,7 +279,7 @@ int Font::emphasisMarkHeight(const AtomicString& mark) const if (!markFontData) return 0; - return markFontData->height(); + return markFontData->fontMetrics().height(); } float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const @@ -414,8 +413,8 @@ float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer it.advance(run.length(), glyphBuffer); if (glyphOverflow) { - glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - ascent()); - glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - descent()); + glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - fontMetrics().ascent()); + glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - fontMetrics().descent()); glyphOverflow->left = ceilf(it.firstGlyphOverflow()); glyphOverflow->right = ceilf(it.lastGlyphOverflow()); } diff --git a/Source/WebCore/platform/graphics/FontMetrics.h b/Source/WebCore/platform/graphics/FontMetrics.h new file mode 100644 index 0000000..89c5545 --- /dev/null +++ b/Source/WebCore/platform/graphics/FontMetrics.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved. + * + * 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 FontMetrics_h +#define FontMetrics_h + +#include <wtf/MathExtras.h> + +namespace WebCore { + +const unsigned gDefaultUnitsPerEm = 1000; + +class FontMetrics { +public: + FontMetrics() + : m_unitsPerEm(gDefaultUnitsPerEm) + , m_ascent(0) + , m_descent(0) + , m_lineGap(0) + , m_lineSpacing(0) + , m_xHeight(0) + { + } + + unsigned unitsPerEm() const { return m_unitsPerEm; } + void setUnitsPerEm(unsigned unitsPerEm) { m_unitsPerEm = unitsPerEm; } + + float floatAscent(FontBaseline baselineType = AlphabeticBaseline) const + { + if (baselineType == AlphabeticBaseline) + return m_ascent; + return floatHeight() / 2; + } + + void setAscent(float ascent) { m_ascent = ascent; } + + float floatDescent(FontBaseline baselineType = AlphabeticBaseline) const + { + if (baselineType == AlphabeticBaseline) + return m_descent; + return floatHeight() / 2; + } + + void setDescent(float descent) { m_descent = descent; } + + float floatHeight(FontBaseline baselineType = AlphabeticBaseline) const + { + return floatAscent(baselineType) + floatDescent(baselineType); + } + + float floatLineGap() const { return m_lineGap; } + void setLineGap(float lineGap) { m_lineGap = lineGap; } + + float floatLineSpacing() const { return m_lineSpacing; } + void setLineSpacing(float lineSpacing) { m_lineSpacing = lineSpacing; } + + float xHeight() const { return m_xHeight; } + void setXHeight(float xHeight) { m_xHeight = xHeight; } + + // Integer variants of certain metrics, used for HTML rendering. + int ascent(FontBaseline baselineType = AlphabeticBaseline) const + { + if (baselineType == AlphabeticBaseline) + return lroundf(m_ascent); + return height() - height() / 2; + } + + int descent(FontBaseline baselineType = AlphabeticBaseline) const + { + if (baselineType == AlphabeticBaseline) + return lroundf(m_descent); + return height() / 2; + } + + int height(FontBaseline baselineType = AlphabeticBaseline) const + { + return ascent(baselineType) + descent(baselineType); + } + + int lineGap() const { return lroundf(m_lineGap); } + int lineSpacing() const { return lroundf(m_lineSpacing); } + +private: + friend class SimpleFontData; + + void reset() + { + m_unitsPerEm = gDefaultUnitsPerEm; + m_ascent = 0; + m_descent = 0; + m_lineGap = 0; + m_lineSpacing = 0; + m_xHeight = 0; + } + + unsigned m_unitsPerEm; + float m_ascent; + float m_descent; + float m_lineGap; + float m_lineSpacing; + float m_xHeight; +}; + +} // namespace WebCore + +#endif // FontMetrics_h diff --git a/Source/WebCore/platform/graphics/FontWidthVariant.h b/Source/WebCore/platform/graphics/FontWidthVariant.h new file mode 100644 index 0000000..bbc98ee --- /dev/null +++ b/Source/WebCore/platform/graphics/FontWidthVariant.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 Apple 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 FontWidthVariant_h +#define FontWidthVariant_h + +namespace WebCore { + +enum FontWidthVariant { RegularWidth, HalfWidth, ThirdWidth, QuarterWidth }; + +} // namespace WebCore + +#endif // FontWidthVariant_h diff --git a/Source/WebCore/platform/graphics/GlyphBuffer.h b/Source/WebCore/platform/graphics/GlyphBuffer.h index 6f1fe7b..7aac1e3 100644 --- a/Source/WebCore/platform/graphics/GlyphBuffer.h +++ b/Source/WebCore/platform/graphics/GlyphBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2009, 2011 Apple Inc. All rights reserved. * Copyright (C) 2007-2008 Torch Mobile Inc. * * Redistribution and use in source and binary forms, with or without @@ -187,7 +187,20 @@ public: m_advances.append(advance); } #endif - + + void expandLastAdvance(float width) + { + ASSERT(!isEmpty()); + GlyphBufferAdvance& lastAdvance = m_advances.last(); +#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) + lastAdvance.width += width; +#elif OS(WINCE) + lastAdvance += width; +#else + lastAdvance += FloatSize(width, 0); +#endif + } + private: Vector<const SimpleFontData*, 2048> m_fontData; Vector<GlyphBufferGlyph, 2048> m_glyphs; diff --git a/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp index 3df14b9..e7ed193 100644 --- a/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp +++ b/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp @@ -29,12 +29,12 @@ #include "config.h" #include "GlyphPageTreeNode.h" -#include "CharacterNames.h" #include "PlatformString.h" #include "SegmentedFontData.h" #include "SimpleFontData.h" #include <stdio.h> #include <wtf/text/CString.h> +#include <wtf/unicode/CharacterNames.h> #include <wtf/unicode/Unicode.h> namespace WebCore { diff --git a/Source/WebCore/platform/graphics/GraphicsContext.cpp b/Source/WebCore/platform/graphics/GraphicsContext.cpp index 9f94ac9..a0a7ea9 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext.cpp +++ b/Source/WebCore/platform/graphics/GraphicsContext.cpp @@ -142,6 +142,18 @@ void GraphicsContext::setShadow(const FloatSize& offset, float blur, const Color setPlatformShadow(offset, blur, color, colorSpace); } +void GraphicsContext::setLegacyShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace) +{ + m_state.shadowOffset = offset; + m_state.shadowBlur = blur; + m_state.shadowColor = color; + m_state.shadowColorSpace = colorSpace; +#if PLATFORM(CG) + m_state.shadowsUseLegacyRadius = true; +#endif + setPlatformShadow(offset, blur, color, colorSpace); +} + void GraphicsContext::clearShadow() { m_state.shadowOffset = FloatSize(); @@ -532,10 +544,10 @@ void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorS InterpolationQuality previousInterpolationQuality = imageInterpolationQuality(); // FIXME: Should be InterpolationLow setImageInterpolationQuality(InterpolationNone); - image->draw(this, styleColorSpace, dest, src, op, useLowQualityScale); + image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale); setImageInterpolationQuality(previousInterpolationQuality); } else - image->draw(this, styleColorSpace, dest, src, op, useLowQualityScale); + image->draw(this, styleColorSpace, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op, useLowQualityScale); } void GraphicsContext::addRoundedRectClip(const RoundedIntRect& rect) @@ -565,6 +577,14 @@ void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& re buffer->clip(this, rect); } +#if !PLATFORM(CG) +IntRect GraphicsContext::clipBounds() const +{ + ASSERT_NOT_REACHED(); + return IntRect(); +} +#endif + TextDrawingModeFlags GraphicsContext::textDrawingMode() const { return m_state.textDrawingMode; @@ -590,6 +610,34 @@ void GraphicsContext::fillRoundedRect(const RoundedIntRect& rect, const Color& c fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color, colorSpace); } +#if !PLATFORM(CG) +void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedIntRect& roundedHoleRect, const Color& color, ColorSpace colorSpace) +{ + if (paintingDisabled()) + return; + + Path path; + path.addRect(rect); + + if (!roundedHoleRect.radii().isZero()) + path.addRoundedRect(roundedHoleRect.rect(), roundedHoleRect.radii().topLeft(), roundedHoleRect.radii().topRight(), roundedHoleRect.radii().bottomLeft(), roundedHoleRect.radii().bottomRight()); + else + path.addRect(roundedHoleRect.rect()); + + WindRule oldFillRule = fillRule(); + Color oldFillColor = fillColor(); + ColorSpace oldFillColorSpace = fillColorSpace(); + + setFillRule(RULE_EVENODD); + setFillColor(color, colorSpace); + + fillPath(path); + + setFillRule(oldFillRule); + setFillColor(oldFillColor, oldFillColorSpace); +} +#endif + void GraphicsContext::setCompositeOperation(CompositeOperator compositeOperation) { m_state.compositeOperator = compositeOperation; diff --git a/Source/WebCore/platform/graphics/GraphicsContext.h b/Source/WebCore/platform/graphics/GraphicsContext.h index 77321e2..21a9067 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext.h +++ b/Source/WebCore/platform/graphics/GraphicsContext.h @@ -176,6 +176,11 @@ namespace WebCore { , shouldSmoothFonts(true) , paintingDisabled(false) , shadowsIgnoreTransforms(false) +#if PLATFORM(CG) + // Core Graphics incorrectly renders shadows with radius > 8px (<rdar://problem/8103442>), + // but we need to preserve this buggy behavior for canvas and -webkit-box-shadow. + , shadowsUseLegacyRadius(false) +#endif { } @@ -212,6 +217,9 @@ namespace WebCore { bool shouldSmoothFonts : 1; bool paintingDisabled : 1; bool shadowsIgnoreTransforms : 1; +#if PLATFORM(CG) + bool shadowsUseLegacyRadius : 1; +#endif }; class GraphicsContext { @@ -320,6 +328,7 @@ namespace WebCore { void fillRect(const FloatRect&, Generator&); void fillRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color&, ColorSpace); void fillRoundedRect(const RoundedIntRect&, const Color&, ColorSpace); + void fillRectWithRoundedHole(const IntRect&, const RoundedIntRect& roundedHoleRect, const Color&, ColorSpace); void clearRect(const FloatRect&); @@ -355,6 +364,8 @@ namespace WebCore { void clipPath(const Path&, WindRule); void clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias = true); void clipToImageBuffer(ImageBuffer*, const FloatRect&); + + IntRect clipBounds() const; TextDrawingModeFlags textDrawingMode() const; void setTextDrawingMode(TextDrawingModeFlags); @@ -385,6 +396,10 @@ namespace WebCore { bool hasShadow() const; void setShadow(const FloatSize&, float blur, const Color&, ColorSpace); + // Legacy shadow blur radius is used for canvas, and -webkit-box-shadow. + // It has different treatment of radii > 8px. + void setLegacyShadow(const FloatSize&, float blur, const Color&, ColorSpace); + bool getShadow(FloatSize&, float&, Color&, ColorSpace&) const; void clearShadow(); @@ -404,16 +419,11 @@ namespace WebCore { void setCompositeOperation(CompositeOperator); CompositeOperator compositeOperation() const; -#if PLATFORM(SKIA) - void beginPath(); - void addPath(const Path&); -#endif - void clip(const Path&); // This clip function is used only by <canvas> code. It allows // implementations to handle clipping on the canvas differently since - // the disipline is different. + // the discipline is different. void canvasClip(const Path&); void clipOut(const Path&); @@ -500,7 +510,6 @@ namespace WebCore { bool inTransparencyLayer() const; void pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask); void takeOwnershipOfPlatformContext(); - static QPainter::CompositionMode toQtCompositionMode(CompositeOperator op); #endif #if PLATFORM(QT) || PLATFORM(CAIRO) diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.cpp b/Source/WebCore/platform/graphics/GraphicsContext3D.cpp index f7c5a66..324fed8 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext3D.cpp +++ b/Source/WebCore/platform/graphics/GraphicsContext3D.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "GraphicsContext3D.h" @@ -1437,4 +1437,4 @@ bool GraphicsContext3D::packPixels(const uint8_t* sourceData, } // namespace WebCore -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.h b/Source/WebCore/platform/graphics/GraphicsContext3D.h index 24827e5..d6c1cec 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext3D.h +++ b/Source/WebCore/platform/graphics/GraphicsContext3D.h @@ -47,7 +47,9 @@ typedef unsigned int GC3Denum; typedef unsigned char GC3Dboolean; typedef unsigned int GC3Dbitfield; +typedef signed char GC3Dbyte; typedef unsigned char GC3Dubyte; +typedef short GC3Dshort; typedef unsigned short GC3Dushort; typedef int GC3Dint; typedef int GC3Dsizei; @@ -117,7 +119,7 @@ class GraphicsContext3DInternal; class GraphicsContext3D : public RefCounted<GraphicsContext3D> { public: - enum WebGLEnumType { + enum { DEPTH_BUFFER_BIT = 0x00000100, STENCIL_BUFFER_BIT = 0x00000400, COLOR_BUFFER_BIT = 0x00004000, @@ -452,6 +454,14 @@ public: RenderDirectlyToHostWindow }; + class ContextLostCallback { + public: + virtual void onContextLost() = 0; + virtual ~ContextLostCallback() {} + }; + + void setContextLostCallback(PassOwnPtr<ContextLostCallback>); + static PassRefPtr<GraphicsContext3D> create(Attributes, HostWindow*, RenderStyle = RenderOffscreen); ~GraphicsContext3D(); @@ -487,10 +497,6 @@ public: void prepareTexture(); #endif - // Helper to return the size in bytes of OpenGL data types - // like GL_FLOAT, GL_INT, etc. - unsigned int sizeInBytes(GC3Denum type); - // Helper to texImage2D with pixel==0 case: pixels are initialized to 0. // Return true if no GL error is synthesized. // By default, alignment is 4, the OpenGL default setting. diff --git a/Source/WebCore/platform/graphics/Icon.h b/Source/WebCore/platform/graphics/Icon.h index c83685f..2797133 100644 --- a/Source/WebCore/platform/graphics/Icon.h +++ b/Source/WebCore/platform/graphics/Icon.h @@ -42,6 +42,7 @@ typedef struct _GdkPixbuf GdkPixbuf; #elif PLATFORM(EFL) typedef struct _Evas_Object Evas_Object; #elif PLATFORM(CHROMIUM) +#include "Image.h" #include "PlatformIcon.h" #endif @@ -60,6 +61,8 @@ public: #if PLATFORM(WIN) static PassRefPtr<Icon> create(HICON hIcon) { return adoptRef(new Icon(hIcon)); } +#elif PLATFORM(CHROMIUM) + static PassRefPtr<Icon> create(PassRefPtr<PlatformIcon> icon) { return adoptRef(new Icon(icon)); } #endif private: @@ -79,8 +82,8 @@ private: Icon(); Evas_Object* m_icon; #elif PLATFORM(CHROMIUM) - Icon(const PlatformIcon&); - PlatformIcon m_icon; + Icon(PassRefPtr<PlatformIcon>); + RefPtr<PlatformIcon> m_icon; #endif }; diff --git a/Source/WebCore/platform/graphics/IntRect.cpp b/Source/WebCore/platform/graphics/IntRect.cpp index 188b5f9..7591c41 100644 --- a/Source/WebCore/platform/graphics/IntRect.cpp +++ b/Source/WebCore/platform/graphics/IntRect.cpp @@ -44,22 +44,22 @@ bool IntRect::intersects(const IntRect& other) const { // Checking emptiness handles negative widths as well as zero. return !isEmpty() && !other.isEmpty() - && x() < other.right() && other.x() < right() - && y() < other.bottom() && other.y() < bottom(); + && x() < other.maxX() && other.x() < maxX() + && y() < other.maxY() && other.y() < maxY(); } bool IntRect::contains(const IntRect& other) const { - return x() <= other.x() && right() >= other.right() - && y() <= other.y() && bottom() >= other.bottom(); + return x() <= other.x() && maxX() >= other.maxX() + && y() <= other.y() && maxY() >= other.maxY(); } void IntRect::intersect(const IntRect& other) { int l = max(x(), other.x()); int t = max(y(), other.y()); - int r = min(right(), other.right()); - int b = min(bottom(), other.bottom()); + int r = min(maxX(), other.maxX()); + int b = min(maxY(), other.maxY()); // Return a clean empty rectangle for non-intersecting cases. if (l >= r || t >= b) { @@ -87,8 +87,8 @@ void IntRect::unite(const IntRect& other) int l = min(x(), other.x()); int t = min(y(), other.y()); - int r = max(right(), other.right()); - int b = max(bottom(), other.bottom()); + int r = max(maxX(), other.maxX()); + int b = max(maxY(), other.maxY()); m_location.setX(l); m_location.setY(t); diff --git a/Source/WebCore/platform/graphics/IntRect.h b/Source/WebCore/platform/graphics/IntRect.h index 638db75..3a2433d 100644 --- a/Source/WebCore/platform/graphics/IntRect.h +++ b/Source/WebCore/platform/graphics/IntRect.h @@ -91,6 +91,8 @@ public: int x() const { return m_location.x(); } int y() const { return m_location.y(); } + int maxX() const { return x() + width(); } + int maxY() const { return y() + height(); } int width() const { return m_size.width(); } int height() const { return m_size.height(); } @@ -99,18 +101,8 @@ public: void setWidth(int width) { m_size.setWidth(width); } void setHeight(int height) { m_size.setHeight(height); } - // Be careful with these functions. The point is considered to be to the right and below. These are not - // substitutes for right() and bottom(). - IntPoint topLeft() const { return m_location; } - IntPoint topRight() const { return IntPoint(right() - 1, y()); } - IntPoint bottomLeft() const { return IntPoint(x(), bottom() - 1); } - IntPoint bottomRight() const { return IntPoint(right() - 1, bottom() - 1); } - bool isEmpty() const { return m_size.isEmpty(); } - int right() const { return x() + width(); } - int bottom() const { return y() + height(); } - // NOTE: The result is rounded to integer values, and thus may be not the exact // center point. IntPoint center() const { return IntPoint(x() + width() / 2, y() + height() / 2); } @@ -118,26 +110,26 @@ public: void move(const IntSize& s) { m_location += s; } void move(int dx, int dy) { m_location.move(dx, dy); } - void shiftLeftEdgeTo(int edge) + void shiftXEdgeTo(int edge) { int delta = edge - x(); setX(edge); setWidth(std::max(0, width() - delta)); } - void shiftRightEdgeTo(int edge) + void shiftMaxXEdgeTo(int edge) { - int delta = edge - right(); + int delta = edge - maxX(); setWidth(std::max(0, width() + delta)); } - void shiftTopEdgeTo(int edge) + void shiftYEdgeTo(int edge) { int delta = edge - y(); setY(edge); setHeight(std::max(0, height() - delta)); } - void shiftBottomEdgeTo(int edge) + void shiftMaxYEdgeTo(int edge) { - int delta = edge - bottom(); + int delta = edge - maxY(); setHeight(std::max(0, height() + delta)); } @@ -147,7 +139,7 @@ public: // This checks to see if the rect contains x,y in the traditional sense. // Equivalent to checking if the rect contains a 1x1 rect below and to the right of (px,py). bool contains(int px, int py) const - { return px >= x() && px < right() && py >= y() && py < bottom(); } + { return px >= x() && px < maxX() && py >= y() && py < maxY(); } bool contains(const IntPoint& point) const { return contains(point.x(), point.y()); } void intersect(const IntRect&); diff --git a/Source/WebCore/platform/graphics/IntRectHash.h b/Source/WebCore/platform/graphics/IntRectHash.h new file mode 100644 index 0000000..7138f33 --- /dev/null +++ b/Source/WebCore/platform/graphics/IntRectHash.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 Apple 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 INC. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 IntRectHash_h +#define IntRectHash_h + +#include "IntPointHash.h" +#include "IntRect.h" +#include "IntSizeHash.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> + +namespace WTF { + +template<> struct IntHash<WebCore::IntRect> { + static unsigned hash(const WebCore::IntRect& key) + { + return intHash(static_cast<uint64_t>(DefaultHash<WebCore::IntPoint>::Hash::hash(key.location())) << 32 | DefaultHash<WebCore::IntSize>::Hash::hash(key.size())); + } + static bool equal(const WebCore::IntRect& a, const WebCore::IntRect& b) + { + return DefaultHash<WebCore::IntPoint>::Hash::equal(a.location(), b.location()) && DefaultHash<WebCore::IntSize>::Hash::equal(a.size(), b.size()); + } + static const bool safeToCompareToEmptyOrDeleted = true; +}; +template<> struct DefaultHash<WebCore::IntRect> { typedef IntHash<WebCore::IntRect> Hash; }; + +template<> struct HashTraits<WebCore::IntRect> : GenericHashTraits<WebCore::IntRect> { + static const bool emptyValueIsZero = true; + static const bool needsDestruction = false; + static void constructDeletedValue(WebCore::IntRect& slot) { new (&slot) WebCore::IntRect(-1, -1, -1, -1); } + static bool isDeletedValue(const WebCore::IntRect& value) { return value.x() == -1 && value.y() == -1 && value.width() == -1 && value.height() == -1; } +}; + +} + +#endif diff --git a/Source/WebCore/platform/graphics/IntSizeHash.h b/Source/WebCore/platform/graphics/IntSizeHash.h index ad6eac3..0cca000 100644 --- a/Source/WebCore/platform/graphics/IntSizeHash.h +++ b/Source/WebCore/platform/graphics/IntSizeHash.h @@ -24,22 +24,20 @@ #include <wtf/HashMap.h> #include <wtf/HashSet.h> -using WebCore::IntSize; - namespace WTF { - template<> struct IntHash<IntSize> { - static unsigned hash(const IntSize& key) { return intHash((static_cast<uint64_t>(key.width()) << 32 | key.height())); } - static bool equal(const IntSize& a, const IntSize& b) { return a == b; } + template<> struct IntHash<WebCore::IntSize> { + static unsigned hash(const WebCore::IntSize& key) { return intHash((static_cast<uint64_t>(key.width()) << 32 | key.height())); } + static bool equal(const WebCore::IntSize& a, const WebCore::IntSize& b) { return a == b; } static const bool safeToCompareToEmptyOrDeleted = true; }; - template<> struct DefaultHash<IntSize> { typedef IntHash<IntSize> Hash; }; + template<> struct DefaultHash<WebCore::IntSize> { typedef IntHash<WebCore::IntSize> Hash; }; - template<> struct HashTraits<IntSize> : GenericHashTraits<IntSize> { + template<> struct HashTraits<WebCore::IntSize> : GenericHashTraits<WebCore::IntSize> { static const bool emptyValueIsZero = true; static const bool needsDestruction = false; - static void constructDeletedValue(IntSize& slot) { new (&slot) IntSize(-1, -1); } - static bool isDeletedValue(const IntSize& value) { return value.width() == -1 && value.height() == -1; } + static void constructDeletedValue(WebCore::IntSize& slot) { new (&slot) WebCore::IntSize(-1, -1); } + static bool isDeletedValue(const WebCore::IntSize& value) { return value.width() == -1 && value.height() == -1; } }; } // namespace WTF diff --git a/Source/WebCore/platform/graphics/MediaPlayer.cpp b/Source/WebCore/platform/graphics/MediaPlayer.cpp index 60f55a5..8eed0d2 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.cpp +++ b/Source/WebCore/platform/graphics/MediaPlayer.cpp @@ -698,6 +698,26 @@ double MediaPlayer::maximumDurationToCacheMediaTime() const return m_private->maximumDurationToCacheMediaTime(); } +unsigned long MediaPlayer::decodedFrames() const +{ + return m_private->decodedFrames(); +} + +unsigned long MediaPlayer::droppedFrames() const +{ + return m_private->droppedFrames(); +} + +unsigned long MediaPlayer::audioBytesDecoded() const +{ + return m_private->audioBytesDecoded(); +} + +unsigned long MediaPlayer::videoBytesDecoded() const +{ + return m_private->videoBytesDecoded(); +} + void MediaPlayer::reloadTimerFired(Timer<MediaPlayer>*) { m_private->cancelLoad(); diff --git a/Source/WebCore/platform/graphics/MediaPlayer.h b/Source/WebCore/platform/graphics/MediaPlayer.h index ef0b3eb..1112148 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.h +++ b/Source/WebCore/platform/graphics/MediaPlayer.h @@ -287,6 +287,11 @@ public: double maximumDurationToCacheMediaTime() const; + unsigned long decodedFrames() const; + unsigned long droppedFrames() const; + unsigned long audioBytesDecoded() const; + unsigned long videoBytesDecoded() const; + private: MediaPlayer(MediaPlayerClient*); void loadWithNextMediaEngine(MediaPlayerFactory*); diff --git a/Source/WebCore/platform/graphics/MediaPlayerPrivate.h b/Source/WebCore/platform/graphics/MediaPlayerPrivate.h index 6abe258..04b2612 100644 --- a/Source/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/Source/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -136,6 +136,10 @@ public: // it is OK to calculate movie time before refreshing the cached time. virtual double maximumDurationToCacheMediaTime() const { return 0; } + virtual unsigned long decodedFrames() const { return 0; } + virtual unsigned long droppedFrames() const { return 0; } + virtual unsigned long audioBytesDecoded() const { return 0; } + virtual unsigned long videoBytesDecoded() const { return 0; } }; } diff --git a/Source/WebCore/platform/graphics/ShadowBlur.cpp b/Source/WebCore/platform/graphics/ShadowBlur.cpp new file mode 100644 index 0000000..f61ecff --- /dev/null +++ b/Source/WebCore/platform/graphics/ShadowBlur.cpp @@ -0,0 +1,733 @@ +/* + * Copyright (C) 2011 Apple Inc. + * Copyright (C) 2010 Sencha, Inc. + * Copyright (C) 2010 Igalia S.L. + * 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 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 "ShadowBlur.h" + +#include "AffineTransform.h" +#include "FloatQuad.h" +#include "GraphicsContext.h" +#include "ImageBuffer.h" +#include "Timer.h" +#include <wtf/MathExtras.h> +#include <wtf/Noncopyable.h> +#include <wtf/UnusedParam.h> + +using namespace std; + +namespace WebCore { + +static inline int roundUpToMultipleOf32(int d) +{ + return (1 + (d >> 5)) << 5; +} + +// ShadowBlur needs a scratch image as the buffer for the blur filter. +// Instead of creating and destroying the buffer for every operation, +// we create a buffer which will be automatically purged via a timer. +class ScratchBuffer { +public: + ScratchBuffer() + : m_purgeTimer(this, &ScratchBuffer::timerFired) +#if !ASSERT_DISABLED + , m_bufferInUse(false) +#endif + { + } + + ImageBuffer* getScratchBuffer(const IntSize& size) + { + ASSERT(!m_bufferInUse); +#if !ASSERT_DISABLED + m_bufferInUse = true; +#endif + // We do not need to recreate the buffer if the current buffer is large enough. + if (m_imageBuffer && m_imageBuffer->width() >= size.width() && m_imageBuffer->height() >= size.height()) + return m_imageBuffer.get(); + + // Round to the nearest 32 pixels so we do not grow the buffer for similar sized requests. + IntSize roundedSize(roundUpToMultipleOf32(size.width()), roundUpToMultipleOf32(size.height())); + + m_imageBuffer = ImageBuffer::create(roundedSize); + return m_imageBuffer.get(); + } + + void scheduleScratchBufferPurge() + { +#if !ASSERT_DISABLED + m_bufferInUse = false; +#endif + if (m_purgeTimer.isActive()) + m_purgeTimer.stop(); + + const double scratchBufferPurgeInterval = 2; + m_purgeTimer.startOneShot(scratchBufferPurgeInterval); + } + + static ScratchBuffer& shared(); + +private: + void timerFired(Timer<ScratchBuffer>*) + { + clearScratchBuffer(); + } + + void clearScratchBuffer() + { + m_imageBuffer = 0; + } + + OwnPtr<ImageBuffer> m_imageBuffer; + Timer<ScratchBuffer> m_purgeTimer; +#if !ASSERT_DISABLED + bool m_bufferInUse; +#endif +}; + +ScratchBuffer& ScratchBuffer::shared() +{ + DEFINE_STATIC_LOCAL(ScratchBuffer, scratchBuffer, ()); + return scratchBuffer; +} + +static const int templateSideLength = 1; + +ShadowBlur::ShadowBlur(float radius, const FloatSize& offset, const Color& color, ColorSpace colorSpace) + : m_color(color) + , m_colorSpace(colorSpace) + , m_blurRadius(radius) + , m_offset(offset) + , m_layerImage(0) + , m_shadowsIgnoreTransforms(false) +{ + // Limit blur radius to 128 to avoid lots of very expensive blurring. + m_blurRadius = min<float>(m_blurRadius, 128); + + // The type of shadow is decided by the blur radius, shadow offset, and shadow color. + if (!m_color.isValid() || !color.alpha()) { + // Can't paint the shadow with invalid or invisible color. + m_type = NoShadow; + } else if (m_blurRadius > 0) { + // Shadow is always blurred, even the offset is zero. + m_type = BlurShadow; + } else if (!m_offset.width() && !m_offset.height()) { + // Without blur and zero offset means the shadow is fully hidden. + m_type = NoShadow; + } else + m_type = SolidShadow; +} + +// Instead of integer division, we use 17.15 for fixed-point division. +static const int blurSumShift = 15; +static const float gaussianKernelFactor = 3 / 4.f * sqrtf(2 * piFloat); + +void ShadowBlur::blurLayerImage(unsigned char* imageData, const IntSize& size, int rowStride) +{ + const int channels[4] = +#if CPU(BIG_ENDIAN) + { 0, 3, 2, 0 }; +#elif CPU(MIDDLE_ENDIAN) + { 1, 2, 3, 1 }; +#else + { 3, 0, 1, 3 }; +#endif + + int diameter; + if (m_shadowsIgnoreTransforms) + diameter = max(2, static_cast<int>(floorf((2 / 3.f) * m_blurRadius))); // Canvas shadow. FIXME: we should adjust the blur radius higher up. + else { + // http://dev.w3.org/csswg/css3-background/#box-shadow + // Approximate a Gaussian blur with a standard deviation equal to half the blur radius, + // which http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement tell us how to do. + // However, shadows rendered according to that spec will extend a little further than m_blurRadius, + // so we apply a fudge factor to bring the radius down slightly. + float stdDev = m_blurRadius / 2; + const float fudgeFactor = 0.88f; + diameter = max(2, static_cast<int>(floorf(stdDev * gaussianKernelFactor * fudgeFactor + 0.5f))); + } + + enum { + leftLobe = 0, + rightLobe = 1 + }; + + int lobes[3][2]; // indexed by pass, and left/right lobe + + if (diameter & 1) { + // if d is odd, use three box-blurs of size 'd', centered on the output pixel. + int lobeSize = (diameter - 1) / 2; + lobes[0][leftLobe] = lobeSize; + lobes[0][rightLobe] = lobeSize; + lobes[1][leftLobe] = lobeSize; + lobes[1][rightLobe] = lobeSize; + lobes[2][leftLobe] = lobeSize; + lobes[2][rightLobe] = lobeSize; + } else { + // if d is even, two box-blurs of size 'd' (the first one centered on the pixel boundary + // between the output pixel and the one to the left, the second one centered on the pixel + // boundary between the output pixel and the one to the right) and one box blur of size 'd+1' centered on the output pixel + int lobeSize = diameter / 2; + lobes[0][leftLobe] = lobeSize; + lobes[0][rightLobe] = lobeSize - 1; + lobes[1][leftLobe] = lobeSize - 1; + lobes[1][rightLobe] = lobeSize; + lobes[2][leftLobe] = lobeSize; + lobes[2][rightLobe] = lobeSize; + } + + // First pass is horizontal. + int stride = 4; + int delta = rowStride; + int final = size.height(); + int dim = size.width(); + + // Two stages: horizontal and vertical + for (int pass = 0; pass < 2; ++pass) { + unsigned char* pixels = imageData; + + for (int j = 0; j < final; ++j, pixels += delta) { + // For each step, we blur the alpha in a channel and store the result + // in another channel for the subsequent step. + // We use sliding window algorithm to accumulate the alpha values. + // This is much more efficient than computing the sum of each pixels + // covered by the box kernel size for each x. + for (int step = 0; step < 3; ++step) { + int side1 = lobes[step][leftLobe]; + int side2 = lobes[step][rightLobe]; + int pixelCount = side1 + 1 + side2; + int invCount = ((1 << blurSumShift) + pixelCount - 1) / pixelCount; + int ofs = 1 + side2; + int alpha1 = pixels[channels[step]]; + int alpha2 = pixels[(dim - 1) * stride + channels[step]]; + + unsigned char* ptr = pixels + channels[step + 1]; + unsigned char* prev = pixels + stride + channels[step]; + unsigned char* next = pixels + ofs * stride + channels[step]; + + int i; + int sum = side1 * alpha1 + alpha1; + int limit = (dim < side2 + 1) ? dim : side2 + 1; + + for (i = 1; i < limit; ++i, prev += stride) + sum += *prev; + + if (limit <= side2) + sum += (side2 - limit + 1) * alpha2; + + limit = (side1 < dim) ? side1 : dim; + for (i = 0; i < limit; ptr += stride, next += stride, ++i, ++ofs) { + *ptr = (sum * invCount) >> blurSumShift; + sum += ((ofs < dim) ? *next : alpha2) - alpha1; + } + + prev = pixels + channels[step]; + for (; ofs < dim; ptr += stride, prev += stride, next += stride, ++i, ++ofs) { + *ptr = (sum * invCount) >> blurSumShift; + sum += (*next) - (*prev); + } + + for (; i < dim; ptr += stride, prev += stride, ++i) { + *ptr = (sum * invCount) >> blurSumShift; + sum += alpha2 - (*prev); + } + } + } + + // Last pass is vertical. + stride = rowStride; + delta = 4; + final = size.width(); + dim = size.height(); + } +} + +void ShadowBlur::adjustBlurRadius(GraphicsContext* context) +{ + if (!m_shadowsIgnoreTransforms) + return; + + const AffineTransform transform = context->getCTM(); + + // Adjust blur if we're scaling, since the radius must not be affected by transformations. + // FIXME: use AffineTransform::isIdentityOrTranslationOrFlipped()? + if (transform.isIdentity()) + return; + + // Calculate transformed unit vectors. + const FloatQuad unitQuad(FloatPoint(0, 0), FloatPoint(1, 0), + FloatPoint(0, 1), FloatPoint(1, 1)); + const FloatQuad transformedUnitQuad = transform.mapQuad(unitQuad); + + // Calculate X axis scale factor. + const FloatSize xUnitChange = transformedUnitQuad.p2() - transformedUnitQuad.p1(); + const float xAxisScale = sqrtf(xUnitChange.width() * xUnitChange.width() + + xUnitChange.height() * xUnitChange.height()); + + // Calculate Y axis scale factor. + const FloatSize yUnitChange = transformedUnitQuad.p3() - transformedUnitQuad.p1(); + const float yAxisScale = sqrtf(yUnitChange.width() * yUnitChange.width() + + yUnitChange.height() * yUnitChange.height()); + + // blurLayerImage() does not support per-axis blurring, so calculate a balanced scaling. + // FIXME: does AffineTransform.xScale()/yScale() help? + const float scale = sqrtf(xAxisScale * yAxisScale); + m_blurRadius = roundf(m_blurRadius / scale); +} + +IntRect ShadowBlur::calculateLayerBoundingRect(GraphicsContext* context, const FloatRect& shadowedRect, const IntRect& clipRect) +{ + const float roundedRadius = ceilf(m_blurRadius); + + // Calculate the destination of the blurred and/or transformed layer. + FloatRect layerRect; + float inflation = 0; + + const AffineTransform transform = context->getCTM(); + if (m_shadowsIgnoreTransforms && !transform.isIdentity()) { + FloatQuad transformedPolygon = transform.mapQuad(FloatQuad(shadowedRect)); + transformedPolygon.move(m_offset); + layerRect = transform.inverse().mapQuad(transformedPolygon).boundingBox(); + } else { + layerRect = shadowedRect; + layerRect.move(m_offset); + } + + // We expand the area by the blur radius to give extra space for the blur transition. + if (m_type == BlurShadow) { + layerRect.inflate(roundedRadius); + inflation = roundedRadius; + } + + FloatRect unclippedLayerRect = layerRect; + + if (!clipRect.contains(enclosingIntRect(layerRect))) { + // If we are totally outside the clip region, we aren't painting at all. + if (intersection(layerRect, clipRect).isEmpty()) + return IntRect(); + + IntRect inflatedClip = clipRect; + // Pixels at the edges can be affected by pixels outside the buffer, + // so intersect with the clip inflated by the blur. + if (m_type == BlurShadow) + inflatedClip.inflate(roundedRadius); + + layerRect.intersect(inflatedClip); + } + + const float frameSize = inflation * 2; + m_sourceRect = FloatRect(0, 0, shadowedRect.width() + frameSize, shadowedRect.height() + frameSize); + m_layerOrigin = FloatPoint(layerRect.x(), layerRect.y()); + m_layerSize = layerRect.size(); + + const FloatPoint unclippedLayerOrigin = FloatPoint(unclippedLayerRect.x(), unclippedLayerRect.y()); + const FloatSize clippedOut = unclippedLayerOrigin - m_layerOrigin; + + // Set the origin as the top left corner of the scratch image, or, in case there's a clipped + // out region, set the origin accordingly to the full bounding rect's top-left corner. + float translationX = -shadowedRect.x() + inflation - fabsf(clippedOut.width()); + float translationY = -shadowedRect.y() + inflation - fabsf(clippedOut.height()); + m_layerContextTranslation = FloatSize(translationX, translationY); + + return enclosingIntRect(layerRect); +} + +GraphicsContext* ShadowBlur::beginShadowLayer(GraphicsContext* graphicsContext, const IntRect& layerRect) +{ + adjustBlurRadius(graphicsContext); + + // Don't paint if we are totally outside the clip region. + if (layerRect.isEmpty()) + return 0; + + m_layerImage = ScratchBuffer::shared().getScratchBuffer(layerRect.size()); + GraphicsContext* layerContext = m_layerImage->context(); + + layerContext->save(); // Balanced by restore() in endShadowLayer(). + + // Always clear the surface first. FIXME: we could avoid the clear on first allocation. + // Add a pixel to avoid later edge aliasing when rotated. + layerContext->clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1)); + layerContext->translate(m_layerContextTranslation); + + return layerContext; +} + +void ShadowBlur::endShadowLayer(GraphicsContext* graphicsContext) +{ + if (!m_layerImage) + return; + + m_layerImage->context()->restore(); + + if (m_type == BlurShadow) { + IntRect blurRect = enclosingIntRect(FloatRect(FloatPoint(), m_layerSize)); + RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect); + blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4); + m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint()); + } + + graphicsContext->save(); + + IntSize bufferSize = m_layerImage->size(); + if (bufferSize != m_layerSize) { + // The rect passed to clipToImageBuffer() has to be the size of the entire buffer, + // but we may not have cleared it all, so clip to the filled part first. + graphicsContext->clip(FloatRect(m_layerOrigin, m_layerSize)); + } + graphicsContext->clipToImageBuffer(m_layerImage, FloatRect(m_layerOrigin, bufferSize)); + graphicsContext->setFillColor(m_color, m_colorSpace); + + graphicsContext->clearShadow(); + graphicsContext->fillRect(FloatRect(m_layerOrigin, m_sourceRect.size())); + + graphicsContext->restore(); + + m_layerImage = 0; + + // Schedule a purge of the scratch buffer. We do not need to destroy the surface. + ScratchBuffer::shared().scheduleScratchBufferPurge(); +} + +static void computeSliceSizesFromRadii(int twiceRadius, const RoundedIntRect::Radii& radii, int& leftSlice, int& rightSlice, int& topSlice, int& bottomSlice) +{ + leftSlice = twiceRadius + max(radii.topLeft().width(), radii.bottomLeft().width()); + rightSlice = twiceRadius + max(radii.topRight().width(), radii.bottomRight().width()); + + topSlice = twiceRadius + max(radii.topLeft().height(), radii.topRight().height()); + bottomSlice = twiceRadius + max(radii.bottomLeft().height(), radii.bottomRight().height()); +} + +IntSize ShadowBlur::templateSize(const RoundedIntRect::Radii& radii) const +{ + const int templateSideLength = 1; + + int leftSlice; + int rightSlice; + int topSlice; + int bottomSlice; + computeSliceSizesFromRadii(2 * ceilf(m_blurRadius), radii, leftSlice, rightSlice, topSlice, bottomSlice); + + return IntSize(templateSideLength + leftSlice + rightSlice, + templateSideLength + topSlice + bottomSlice); +} + +void ShadowBlur::drawRectShadow(GraphicsContext* graphicsContext, const FloatRect& shadowedRect, const RoundedIntRect::Radii& radii) +{ + IntRect layerRect = calculateLayerBoundingRect(graphicsContext, shadowedRect, graphicsContext->clipBounds()); + if (layerRect.isEmpty()) + return; + + // drawRectShadowWithTiling does not work with rotations. + // https://bugs.webkit.org/show_bug.cgi?id=45042 + if (!graphicsContext->getCTM().isIdentityOrTranslationOrFlipped() || m_type != BlurShadow) { + drawRectShadowWithoutTiling(graphicsContext, shadowedRect, radii, layerRect); + return; + } + + IntSize templateSize = this->templateSize(radii); + + if (templateSize.width() > shadowedRect.width() || templateSize.height() > shadowedRect.height() + || (templateSize.width() * templateSize.height() > m_sourceRect.width() * m_sourceRect.height())) { + drawRectShadowWithoutTiling(graphicsContext, shadowedRect, radii, layerRect); + return; + } + + drawRectShadowWithTiling(graphicsContext, shadowedRect, radii, templateSize); +} + +void ShadowBlur::drawInsetShadow(GraphicsContext* graphicsContext, const FloatRect& rect, const FloatRect& holeRect, const RoundedIntRect::Radii& holeRadii) +{ + IntRect layerRect = calculateLayerBoundingRect(graphicsContext, rect, graphicsContext->clipBounds()); + if (layerRect.isEmpty()) + return; + + // drawInsetShadowWithTiling does not work with rotations. + // https://bugs.webkit.org/show_bug.cgi?id=45042 + if (!graphicsContext->getCTM().isIdentityOrTranslationOrFlipped() || m_type != BlurShadow) { + drawInsetShadowWithoutTiling(graphicsContext, rect, holeRect, holeRadii, layerRect); + return; + } + + IntSize templateSize = this->templateSize(holeRadii); + + if (templateSize.width() > holeRect.width() || templateSize.height() > holeRect.height() + || (templateSize.width() * templateSize.height() > holeRect.width() * holeRect.height())) { + drawInsetShadowWithoutTiling(graphicsContext, rect, holeRect, holeRadii, layerRect); + return; + } + + drawInsetShadowWithTiling(graphicsContext, rect, holeRect, holeRadii, templateSize); +} + +void ShadowBlur::drawRectShadowWithoutTiling(GraphicsContext* graphicsContext, const FloatRect& shadowedRect, const RoundedIntRect::Radii& radii, const IntRect& layerRect) +{ + GraphicsContext* shadowContext = beginShadowLayer(graphicsContext, layerRect); + if (!shadowContext) + return; + + Path path; + path.addRoundedRect(shadowedRect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + shadowContext->fillPath(path); + + endShadowLayer(graphicsContext); +} + +void ShadowBlur::drawInsetShadowWithoutTiling(GraphicsContext* graphicsContext, const FloatRect& rect, const FloatRect& holeRect, const RoundedIntRect::Radii& holeRadii, const IntRect& layerRect) +{ + GraphicsContext* shadowContext = beginShadowLayer(graphicsContext, layerRect); + if (!shadowContext) + return; + + Path path; + path.addRect(rect); + path.addRoundedRect(holeRect, holeRadii.topLeft(), holeRadii.topRight(), holeRadii.bottomLeft(), holeRadii.bottomRight()); + + shadowContext->setFillRule(RULE_EVENODD); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + shadowContext->fillPath(path); + + endShadowLayer(graphicsContext); +} + +/* + These functions use tiling to improve the performance of the shadow + drawing of rounded rectangles. The code basically does the following + steps: + + 1. Calculate the size of the shadow template, a rectangle that + contains all the necessary tiles to draw the complete shadow. + + 2. If that size is smaller than the real rectangle render the new + template rectangle and its shadow in a new surface, in other case + render the shadow of the real rectangle in the destination + surface. + + 3. Calculate the sizes and positions of the tiles and their + destinations and use drawPattern to render the final shadow. The + code divides the rendering in 8 tiles: + + 1 | 2 | 3 + ----------- + 4 | | 5 + ----------- + 6 | 7 | 8 + + The corners are directly copied from the template rectangle to the + real one and the side tiles are 1 pixel width, we use them as + tiles to cover the destination side. The corner tiles are bigger + than just the side of the rounded corner, we need to increase it + because the modifications caused by the corner over the blur + effect. We fill the central or outer part with solid color to complete + the shadow. + */ + +void ShadowBlur::drawInsetShadowWithTiling(GraphicsContext* graphicsContext, const FloatRect& rect, const FloatRect& holeRect, const RoundedIntRect::Radii& radii, const IntSize& templateSize) +{ + graphicsContext->save(); + graphicsContext->clearShadow(); + + const float roundedRadius = ceilf(m_blurRadius); + const float twiceRadius = roundedRadius * 2; + + m_layerImage = ScratchBuffer::shared().getScratchBuffer(templateSize); + + // Draw the rectangle with hole. + FloatRect templateBounds(0, 0, templateSize.width(), templateSize.height()); + FloatRect templateHole = FloatRect(roundedRadius, roundedRadius, templateSize.width() - twiceRadius, templateSize.height() - twiceRadius); + Path path; + path.addRect(templateBounds); + path.addRoundedRect(templateHole, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + + // Draw shadow into a new ImageBuffer. + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->save(); + shadowContext->clearRect(templateBounds); + shadowContext->setFillRule(RULE_EVENODD); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + shadowContext->fillPath(path); + blurAndColorShadowBuffer(templateSize); + shadowContext->restore(); + + FloatRect boundingRect = rect; + boundingRect.move(m_offset); + + FloatRect destHoleRect = holeRect; + destHoleRect.move(m_offset); + FloatRect destHoleBounds = destHoleRect; + destHoleBounds.inflate(roundedRadius); + + // Fill the external part of the shadow (which may be visible because of offset). + Path exteriorPath; + exteriorPath.addRect(boundingRect); + exteriorPath.addRect(destHoleBounds); + + graphicsContext->save(); + graphicsContext->setFillRule(RULE_EVENODD); + graphicsContext->setFillColor(m_color, m_colorSpace); + graphicsContext->fillPath(exteriorPath); + graphicsContext->restore(); + + drawLayerPieces(graphicsContext, destHoleBounds, radii, roundedRadius, templateSize, InnerShadow); + + graphicsContext->restore(); + + m_layerImage = 0; + // Schedule a purge of the scratch buffer. + ScratchBuffer::shared().scheduleScratchBufferPurge(); +} + +void ShadowBlur::drawRectShadowWithTiling(GraphicsContext* graphicsContext, const FloatRect& shadowedRect, const RoundedIntRect::Radii& radii, const IntSize& templateSize) +{ + graphicsContext->save(); + graphicsContext->clearShadow(); + + const float roundedRadius = ceilf(m_blurRadius); + const float twiceRadius = roundedRadius * 2; + + m_layerImage = ScratchBuffer::shared().getScratchBuffer(templateSize); + + // Draw the rectangle. + FloatRect templateShadow = FloatRect(roundedRadius, roundedRadius, templateSize.width() - twiceRadius, templateSize.height() - twiceRadius); + Path path; + path.addRoundedRect(templateShadow, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + + // Draw shadow into the ImageBuffer. + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->save(); + shadowContext->clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height())); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + shadowContext->fillPath(path); + blurAndColorShadowBuffer(templateSize); + shadowContext->restore(); + + FloatRect shadowBounds = shadowedRect; + shadowBounds.move(m_offset.width(), m_offset.height()); + shadowBounds.inflate(roundedRadius); + + drawLayerPieces(graphicsContext, shadowBounds, radii, roundedRadius, templateSize, OuterShadow); + + graphicsContext->restore(); + + m_layerImage = 0; + // Schedule a purge of the scratch buffer. + ScratchBuffer::shared().scheduleScratchBufferPurge(); +} + +void ShadowBlur::drawLayerPieces(GraphicsContext* graphicsContext, const FloatRect& shadowBounds, const RoundedIntRect::Radii& radii, float roundedRadius, const IntSize& templateSize, ShadowDirection direction) +{ + const float twiceRadius = roundedRadius * 2; + + int leftSlice; + int rightSlice; + int topSlice; + int bottomSlice; + computeSliceSizesFromRadii(twiceRadius, radii, leftSlice, rightSlice, topSlice, bottomSlice); + + int centerWidth = shadowBounds.width() - leftSlice - rightSlice; + int centerHeight = shadowBounds.height() - topSlice - bottomSlice; + + if (direction == OuterShadow) { + FloatRect shadowInterior(shadowBounds.x() + leftSlice, shadowBounds.y() + topSlice, centerWidth, centerHeight); + if (!shadowInterior.isEmpty()) { + graphicsContext->save(); + + graphicsContext->setFillColor(m_color, m_colorSpace); + graphicsContext->fillRect(shadowInterior); + + graphicsContext->restore(); + } + } + + // Note that drawing the ImageBuffer is faster than creating a Image and drawing that, + // because ImageBuffer::draw() knows that it doesn't have to copy the image bits. + + // Top side. + FloatRect tileRect = FloatRect(leftSlice, 0, templateSideLength, topSlice); + FloatRect destRect = FloatRect(shadowBounds.x() + leftSlice, shadowBounds.y(), centerWidth, topSlice); + graphicsContext->drawImageBuffer(m_layerImage, ColorSpaceDeviceRGB, destRect, tileRect); + + // Draw the bottom side. + tileRect.setY(templateSize.height() - bottomSlice); + tileRect.setHeight(bottomSlice); + destRect.setY(shadowBounds.maxY() - bottomSlice); + destRect.setHeight(bottomSlice); + graphicsContext->drawImageBuffer(m_layerImage, ColorSpaceDeviceRGB, destRect, tileRect); + + // Left side. + tileRect = FloatRect(0, topSlice, leftSlice, templateSideLength); + destRect = FloatRect(shadowBounds.x(), shadowBounds.y() + topSlice, leftSlice, centerHeight); + graphicsContext->drawImageBuffer(m_layerImage, ColorSpaceDeviceRGB, destRect, tileRect); + + // Right side. + tileRect.setX(templateSize.width() - rightSlice); + tileRect.setWidth(rightSlice); + destRect.setX(shadowBounds.maxX() - rightSlice); + destRect.setWidth(rightSlice); + graphicsContext->drawImageBuffer(m_layerImage, ColorSpaceDeviceRGB, destRect, tileRect); + + // Top left corner. + tileRect = FloatRect(0, 0, leftSlice, topSlice); + destRect = FloatRect(shadowBounds.x(), shadowBounds.y(), leftSlice, topSlice); + graphicsContext->drawImageBuffer(m_layerImage, ColorSpaceDeviceRGB, destRect, tileRect); + + // Top right corner. + tileRect = FloatRect(templateSize.width() - rightSlice, 0, rightSlice, topSlice); + destRect = FloatRect(shadowBounds.maxX() - rightSlice, shadowBounds.y(), rightSlice, topSlice); + graphicsContext->drawImageBuffer(m_layerImage, ColorSpaceDeviceRGB, destRect, tileRect); + + // Bottom right corner. + tileRect = FloatRect(templateSize.width() - rightSlice, templateSize.height() - bottomSlice, rightSlice, bottomSlice); + destRect = FloatRect(shadowBounds.maxX() - rightSlice, shadowBounds.maxY() - bottomSlice, rightSlice, bottomSlice); + graphicsContext->drawImageBuffer(m_layerImage, ColorSpaceDeviceRGB, destRect, tileRect); + + // Bottom left corner. + tileRect = FloatRect(0, templateSize.height() - bottomSlice, leftSlice, bottomSlice); + destRect = FloatRect(shadowBounds.x(), shadowBounds.maxY() - bottomSlice, leftSlice, bottomSlice); + graphicsContext->drawImageBuffer(m_layerImage, ColorSpaceDeviceRGB, destRect, tileRect); +} + + +void ShadowBlur::blurAndColorShadowBuffer(const IntSize& templateSize) +{ + { + IntRect blurRect(IntPoint(), templateSize); + RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect); + blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4); + m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint()); + } + + // Mask the image with the shadow color. + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->setCompositeOperation(CompositeSourceIn); + shadowContext->setFillColor(m_color, m_colorSpace); + shadowContext->fillRect(FloatRect(0, 0, templateSize.width(), templateSize.height())); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/ShadowBlur.h b/Source/WebCore/platform/graphics/ShadowBlur.h new file mode 100644 index 0000000..e52d6dc --- /dev/null +++ b/Source/WebCore/platform/graphics/ShadowBlur.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2011 Apple Inc. + * Copyright (C) 2010 Sencha, Inc. + * Copyright (C) 2010 Igalia S.L. + * 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 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 ShadowBlur_h +#define ShadowBlur_h + +#include "Color.h" +#include "ColorSpace.h" +#include "FloatRect.h" +#include "RoundedIntRect.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class AffineTransform; +class GraphicsContext; +class ImageBuffer; + +class ShadowBlur { + WTF_MAKE_NONCOPYABLE(ShadowBlur); +public: + ShadowBlur(float radius, const FloatSize& offset, const Color&, ColorSpace); + + void setShadowsIgnoreTransforms(bool ignoreTransforms) { m_shadowsIgnoreTransforms = ignoreTransforms; } + bool shadowsIgnoreTransforms() const { return m_shadowsIgnoreTransforms; } + + void drawRectShadow(GraphicsContext*, const FloatRect&, const RoundedIntRect::Radii&); + void drawInsetShadow(GraphicsContext*, const FloatRect&, const FloatRect& holeRect, const RoundedIntRect::Radii& holeRadii); + +private: + GraphicsContext* beginShadowLayer(GraphicsContext*, const IntRect& layerRect); + void endShadowLayer(GraphicsContext*); + + void adjustBlurRadius(GraphicsContext*); + void blurLayerImage(unsigned char*, const IntSize&, int stride); + + enum ShadowDirection { + OuterShadow, + InnerShadow + }; + + IntRect calculateLayerBoundingRect(GraphicsContext*, const FloatRect& layerArea, const IntRect& clipRect); + IntSize templateSize(const RoundedIntRect::Radii&) const; + + void drawRectShadowWithoutTiling(GraphicsContext*, const FloatRect&, const RoundedIntRect::Radii&, const IntRect& layerRect); + void drawRectShadowWithTiling(GraphicsContext*, const FloatRect&, const RoundedIntRect::Radii&, const IntSize& shadowTemplateSize); + + void drawInsetShadowWithoutTiling(GraphicsContext*, const FloatRect&, const FloatRect& holeRect, const RoundedIntRect::Radii&, const IntRect& layerRect); + void drawInsetShadowWithTiling(GraphicsContext*, const FloatRect&, const FloatRect& holeRect, const RoundedIntRect::Radii&, const IntSize& shadowTemplateSize); + + void drawLayerPieces(GraphicsContext*, const FloatRect& shadowBounds, const RoundedIntRect::Radii&, float roundedRadius, const IntSize& templateSize, ShadowDirection); + + void blurAndColorShadowBuffer(const IntSize& templateSize); + + enum ShadowType { + NoShadow, + SolidShadow, + BlurShadow + }; + + ShadowType m_type; + + Color m_color; + ColorSpace m_colorSpace; + float m_blurRadius; + FloatSize m_offset; + + ImageBuffer* m_layerImage; // Buffer to where the temporary shadow will be drawn to. + + FloatRect m_sourceRect; // Sub-rect of m_layerImage that contains the shadow pixels. + FloatPoint m_layerOrigin; // Top-left corner of the (possibly clipped) bounding rect to draw the shadow to. + FloatSize m_layerSize; // Size of m_layerImage pixels that need blurring. + FloatSize m_layerContextTranslation; // Translation to apply to m_layerContext for the shadow to be correctly clipped. + + bool m_shadowsIgnoreTransforms; +}; + +} // namespace WebCore + +#endif // ShadowBlur_h diff --git a/Source/WebCore/platform/graphics/SimpleFontData.cpp b/Source/WebCore/platform/graphics/SimpleFontData.cpp index e773880..2693609 100644 --- a/Source/WebCore/platform/graphics/SimpleFontData.cpp +++ b/Source/WebCore/platform/graphics/SimpleFontData.cpp @@ -50,7 +50,6 @@ namespace WebCore { SimpleFontData::SimpleFontData(const FontPlatformData& platformData, bool isCustomFont, bool isLoading) : m_maxCharWidth(-1) , m_avgCharWidth(-1) - , m_unitsPerEm(defaultUnitsPerEm) , m_orientation(platformData.orientation()) , m_platformData(platformData) , m_treatAsFixedPitch(false) @@ -74,31 +73,36 @@ SimpleFontData::SimpleFontData(PassOwnPtr<SVGFontData> svgFontData, int size, bo , m_isBrokenIdeographFont(false) { SVGFontFaceElement* svgFontFaceElement = m_svgFontData->svgFontFaceElement(); - m_unitsPerEm = svgFontFaceElement->unitsPerEm(); - - double scale = size; - if (m_unitsPerEm) - scale /= m_unitsPerEm; - - m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale); - m_descent = static_cast<int>(svgFontFaceElement->descent() * scale); - m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale); - m_lineGap = 0.1f * size; - m_lineSpacing = m_ascent + m_descent + m_lineGap; + unsigned unitsPerEm = svgFontFaceElement->unitsPerEm(); + + float scale = size; + if (unitsPerEm) + scale /= unitsPerEm; + + float xHeight = svgFontFaceElement->xHeight() * scale; + float ascent = svgFontFaceElement->ascent() * scale; + float descent = svgFontFaceElement->descent() * scale; + float lineGap = 0.1f * size; + m_fontMetrics.setUnitsPerEm(unitsPerEm); + m_fontMetrics.setAscent(ascent); + m_fontMetrics.setDescent(descent); + m_fontMetrics.setLineGap(lineGap); + m_fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap)); + m_fontMetrics.setXHeight(xHeight); SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); Vector<SVGGlyphIdentifier> spaceGlyphs; associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs); - m_spaceWidth = spaceGlyphs.isEmpty() ? m_xHeight : static_cast<float>(spaceGlyphs.first().horizontalAdvanceX * scale); + m_spaceWidth = spaceGlyphs.isEmpty() ? xHeight : spaceGlyphs.first().horizontalAdvanceX * scale; Vector<SVGGlyphIdentifier> numeralZeroGlyphs; associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs); - m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : static_cast<float>(numeralZeroGlyphs.first().horizontalAdvanceX * scale); + m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : numeralZeroGlyphs.first().horizontalAdvanceX * scale; Vector<SVGGlyphIdentifier> letterWGlyphs; associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs); - m_maxCharWidth = letterWGlyphs.isEmpty() ? m_ascent : static_cast<float>(letterWGlyphs.first().horizontalAdvanceX * scale); + m_maxCharWidth = letterWGlyphs.isEmpty() ? ascent : letterWGlyphs.first().horizontalAdvanceX * scale; // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above? m_spaceGlyph = 0; @@ -126,10 +130,10 @@ void SimpleFontData::initCharWidths() // If we can't retrieve the width of a '0', fall back to the x height. if (m_avgCharWidth <= 0.f) - m_avgCharWidth = m_xHeight; + m_avgCharWidth = m_fontMetrics.xHeight(); if (m_maxCharWidth <= 0.f) - m_maxCharWidth = max<float>(m_avgCharWidth, m_ascent); + m_maxCharWidth = max(m_avgCharWidth, m_fontMetrics.floatAscent()); } void SimpleFontData::platformGlyphInit() diff --git a/Source/WebCore/platform/graphics/SimpleFontData.h b/Source/WebCore/platform/graphics/SimpleFontData.h index 90713af..07c2bd1 100644 --- a/Source/WebCore/platform/graphics/SimpleFontData.h +++ b/Source/WebCore/platform/graphics/SimpleFontData.h @@ -26,6 +26,7 @@ #include "FontBaseline.h" #include "FontData.h" +#include "FontMetrics.h" #include "FontPlatformData.h" #include "FloatRect.h" #include "GlyphMetricsMap.h" @@ -101,15 +102,9 @@ public: // FIXME: Use the actual metrics for fonts with vertical tables instead of just hard-coding. If the font is horizontally oriented or // a broken ideographic font, then just hard-code to split ascent/descent down the middle. Otherwise we should actually use the metrics // from the font itself. - int ascent(FontBaseline baselineType = AlphabeticBaseline) const { return baselineType == AlphabeticBaseline ? m_ascent : height() - height() / 2; } - int descent(FontBaseline baselineType = AlphabeticBaseline) const { return baselineType == AlphabeticBaseline ? m_descent : height() / 2; } - int height() const { return m_ascent + m_descent; } - int lineSpacing() const { return m_lineSpacing; } - int lineGap() const { return m_lineGap; } + const FontMetrics& fontMetrics() const { return m_fontMetrics; } float maxCharWidth() const { return m_maxCharWidth; } float avgCharWidth() const { return m_avgCharWidth; } - float xHeight() const { return m_xHeight; } - unsigned unitsPerEm() const { return m_unitsPerEm; } FloatRect boundsForGlyph(Glyph) const; float widthForGlyph(Glyph glyph) const; @@ -211,14 +206,9 @@ private: float widthForGDIGlyph(Glyph glyph) const; #endif - int m_ascent; - int m_descent; - int m_lineSpacing; - int m_lineGap; + FontMetrics m_fontMetrics; float m_maxCharWidth; float m_avgCharWidth; - float m_xHeight; - unsigned m_unitsPerEm; FontOrientation m_orientation; // This is our supported orientation according to the tables in the font. FontPlatformData will just always have the desired orientation. // This value represents what we actually support. diff --git a/Source/WebCore/platform/graphics/StringTruncator.cpp b/Source/WebCore/platform/graphics/StringTruncator.cpp index 65325f0..8468188 100644 --- a/Source/WebCore/platform/graphics/StringTruncator.cpp +++ b/Source/WebCore/platform/graphics/StringTruncator.cpp @@ -29,12 +29,12 @@ #include "config.h" #include "StringTruncator.h" -#include "CharacterNames.h" #include "Font.h" #include "TextBreakIterator.h" #include "TextRun.h" #include <wtf/Assertions.h> #include <wtf/Vector.h> +#include <wtf/unicode/CharacterNames.h> namespace WebCore { diff --git a/Source/WebCore/platform/graphics/TextRun.h b/Source/WebCore/platform/graphics/TextRun.h index dce5535..ef434bd 100644 --- a/Source/WebCore/platform/graphics/TextRun.h +++ b/Source/WebCore/platform/graphics/TextRun.h @@ -2,7 +2,7 @@ * Copyright (C) 2000 Lars Knoll (knoll@kde.org) * (C) 2000 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006, 2007 Apple Computer, Inc. + * Copyright (C) 2003, 2006, 2007, 2011 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -33,12 +33,18 @@ class RenderSVGResource; class TextRun { public: - TextRun(const UChar* c, int len, bool allowTabs = false, int xpos = 0, int padding = 0, bool rtl = false, bool directionalOverride = false, + enum TrailingExpansionBehavior { + AllowTrailingExpansion, + ForbidTrailingExpansion + }; + + TextRun(const UChar* c, int len, bool allowTabs = false, int xpos = 0, int expansion = 0, TrailingExpansionBehavior trailingExpansionBehavior = AllowTrailingExpansion, bool rtl = false, bool directionalOverride = false, bool applyRunRounding = true, bool applyWordRounding = true) : m_characters(c) , m_len(len) , m_xpos(xpos) - , m_padding(padding) + , m_expansion(expansion) + , m_trailingExpansionBehavior(trailingExpansionBehavior) #if ENABLE(SVG) , m_horizontalGlyphStretch(1) #endif @@ -55,12 +61,13 @@ public: { } - TextRun(const String& s, bool allowTabs = false, int xpos = 0, int padding = 0, bool rtl = false, bool directionalOverride = false, + TextRun(const String& s, bool allowTabs = false, int xpos = 0, int expansion = 0, TrailingExpansionBehavior trailingExpansionBehavior = AllowTrailingExpansion, bool rtl = false, bool directionalOverride = false, bool applyRunRounding = true, bool applyWordRounding = true) : m_characters(s.characters()) , m_len(s.length()) , m_xpos(xpos) - , m_padding(padding) + , m_expansion(expansion) + , m_trailingExpansionBehavior(trailingExpansionBehavior) #if ENABLE(SVG) , m_horizontalGlyphStretch(1) #endif @@ -92,7 +99,8 @@ public: bool allowTabs() const { return m_allowTabs; } int xPos() const { return m_xpos; } - int padding() const { return m_padding; } + int expansion() const { return m_expansion; } + bool allowsTrailingExpansion() const { return m_trailingExpansionBehavior == AllowTrailingExpansion; } bool rtl() const { return m_rtl; } bool ltr() const { return !m_rtl; } bool directionalOverride() const { return m_directionalOverride; } @@ -121,7 +129,8 @@ private: // start of the containing block. In the case of right alignment or center alignment, left start of // the text line is not the same as left start of the containing block. int m_xpos; - int m_padding; + int m_expansion; + TrailingExpansionBehavior m_trailingExpansionBehavior; #if ENABLE(SVG) float m_horizontalGlyphStretch; #endif diff --git a/Source/WebCore/platform/graphics/TiledBackingStore.cpp b/Source/WebCore/platform/graphics/TiledBackingStore.cpp index 1d6f237..f6921ef 100644 --- a/Source/WebCore/platform/graphics/TiledBackingStore.cpp +++ b/Source/WebCore/platform/graphics/TiledBackingStore.cpp @@ -73,8 +73,8 @@ void TiledBackingStore::invalidate(const IntRect& contentsDirtyRect) { IntRect dirtyRect(mapFromContents(contentsDirtyRect)); - Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.topLeft()); - Tile::Coordinate bottomRight = tileCoordinateForPoint(dirtyRect.bottomRight()); + Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.location()); + Tile::Coordinate bottomRight = tileCoordinateForPoint(IntPoint(dirtyRect.maxX(), dirtyRect.maxY())); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { @@ -93,6 +93,8 @@ void TiledBackingStore::updateTileBuffers() if (m_contentsFrozen) return; + m_client->tiledBackingStorePaintBegin(); + Vector<IntRect> paintedArea; Vector<RefPtr<Tile> > dirtyTiles; TileMap::iterator end = m_tiles.end(); @@ -104,10 +106,10 @@ void TiledBackingStore::updateTileBuffers() paintedArea.append(mapToContents(it->second->rect())); } - if (dirtyTiles.isEmpty()) + if (dirtyTiles.isEmpty()) { + m_client->tiledBackingStorePaintEnd(paintedArea); return; - - m_client->tiledBackingStorePaintBegin(); + } // FIXME: In single threaded case, tile back buffers could be updated asynchronously // one by one and then swapped to front in one go. This would minimize the time spent @@ -132,8 +134,8 @@ void TiledBackingStore::paint(GraphicsContext* context, const IntRect& rect) IntRect dirtyRect = mapFromContents(rect); - Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.topLeft()); - Tile::Coordinate bottomRight = tileCoordinateForPoint(dirtyRect.bottomRight()); + Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.location()); + Tile::Coordinate bottomRight = tileCoordinateForPoint(IntPoint(dirtyRect.maxX(), dirtyRect.maxY())); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { @@ -227,8 +229,8 @@ void TiledBackingStore::createTiles() double shortestDistance = std::numeric_limits<double>::infinity(); Vector<Tile::Coordinate> tilesToCreate; unsigned requiredTileCount = 0; - Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.topLeft()); - Tile::Coordinate bottomRight = tileCoordinateForPoint(coverRect.bottomRight()); + Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.location()); + Tile::Coordinate bottomRight = tileCoordinateForPoint(IntPoint(coverRect.maxX(), coverRect.maxY())); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); diff --git a/Source/WebCore/platform/graphics/WidthIterator.cpp b/Source/WebCore/platform/graphics/WidthIterator.cpp index 412c86e..a1a88da 100644 --- a/Source/WebCore/platform/graphics/WidthIterator.cpp +++ b/Source/WebCore/platform/graphics/WidthIterator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. * Copyright (C) 2008 Holger Hans Peter Freyther * * This library is free software; you can redistribute it and/or @@ -47,6 +47,7 @@ WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const , m_end(run.length()) , m_currentCharacter(0) , m_runWidthSoFar(0) + , m_isAfterExpansion(true) , m_finalRoundingWidth(0) , m_fallbackFonts(fallbackFonts) , m_accountForGlyphBounds(accountForGlyphBounds) @@ -58,20 +59,19 @@ WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const { // If the padding is non-zero, count the number of spaces in the run // and divide that by the padding for per space addition. - m_padding = m_run.padding(); - if (!m_padding) - m_padPerSpace = 0; + m_expansion = m_run.expansion(); + if (!m_expansion) + m_expansionPerOpportunity = 0; else { - int numSpaces = 0; - for (int i = 0; i < run.length(); i++) { - if (Font::treatAsSpace(m_run[i])) - numSpaces++; - } + bool isAfterExpansion = true; + unsigned expansionOpportunityCount = Font::expansionOpportunityCount(m_run.characters(), m_end, m_run.ltr() ? LTR : RTL, isAfterExpansion); + if (isAfterExpansion && !m_run.allowsTrailingExpansion()) + expansionOpportunityCount--; - if (!numSpaces) - m_padPerSpace = 0; + if (!expansionOpportunityCount) + m_expansionPerOpportunity = 0; else - m_padPerSpace = m_padding / numSpaces; + m_expansionPerOpportunity = m_expansion / expansionOpportunityCount; } } @@ -84,7 +84,7 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) const UChar* cp = m_run.data(currentCharacter); bool rtl = m_run.rtl(); - bool hasExtraSpacing = (m_font->letterSpacing() || m_font->wordSpacing() || m_padding) && !m_run.spacingDisabled(); + bool hasExtraSpacing = (m_font->letterSpacing() || m_font->wordSpacing() || m_expansion) && !m_run.spacingDisabled(); float widthSinceLastRounding = m_runWidthSoFar; m_runWidthSoFar = floorf(m_runWidthSoFar); @@ -173,26 +173,34 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) if (width && m_font->letterSpacing()) width += m_font->letterSpacing(); - if (Font::treatAsSpace(c)) { - // Account for padding. WebCore uses space padding to justify text. - // We distribute the specified padding over the available spaces in the run. - if (m_padding) { - // Use left over padding if not evenly divisible by number of spaces. - if (m_padding < m_padPerSpace) { - width += m_padding; - m_padding = 0; - } else { - float previousPadding = m_padding; - m_padding -= m_padPerSpace; - width += roundf(previousPadding) - roundf(m_padding); + static bool expandAroundIdeographs = Font::canExpandAroundIdeographsInComplexText(); + bool treatAsSpace = Font::treatAsSpace(c); + if (treatAsSpace || (expandAroundIdeographs && Font::isCJKIdeographOrSymbol(c))) { + // Distribute the run's total expansion evenly over all expansion opportunities in the run. + if (m_expansion && (m_run.allowsTrailingExpansion() || (m_run.ltr() && currentCharacter + clusterLength < static_cast<size_t>(m_run.length())) + || (m_run.rtl() && currentCharacter))) { + float previousExpansion = m_expansion; + if (!treatAsSpace && !m_isAfterExpansion) { + // Take the expansion opportunity before this ideograph. + m_expansion -= m_expansionPerOpportunity; + int expansion = roundf(previousExpansion) - roundf(m_expansion); + m_runWidthSoFar += expansion; + if (glyphBuffer) + glyphBuffer->expandLastAdvance(expansion); + previousExpansion = m_expansion; } - } + m_expansion -= m_expansionPerOpportunity; + width += roundf(previousExpansion) - roundf(m_expansion); + m_isAfterExpansion = true; + } else + m_isAfterExpansion = false; // Account for word spacing. // We apply additional space between "words" by adding width to the space character. - if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) + if (treatAsSpace && currentCharacter && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) width += m_font->wordSpacing(); - } + } else + m_isAfterExpansion = false; } if (m_accountForGlyphBounds) { @@ -247,9 +255,9 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) lastRoundingWidth = width - oldWidth; if (m_accountForGlyphBounds) { - m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, bounds.bottom()); + m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, bounds.maxY()); m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, bounds.y()); - m_lastGlyphOverflow = max<float>(0, bounds.right() - width); + m_lastGlyphOverflow = max<float>(0, bounds.maxX() - width); } } @@ -260,13 +268,13 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer) { - glyphBuffer->clear(); + int oldSize = glyphBuffer->size(); advance(m_currentCharacter + 1, glyphBuffer); float w = 0; - for (int i = 0; i < glyphBuffer->size(); ++i) + for (int i = oldSize; i < glyphBuffer->size(); ++i) w += glyphBuffer->advanceAt(i); width = w; - return !glyphBuffer->isEmpty(); + return glyphBuffer->size() > oldSize; } UChar32 WidthIterator::normalizeVoicingMarks(int currentCharacter) diff --git a/Source/WebCore/platform/graphics/WidthIterator.h b/Source/WebCore/platform/graphics/WidthIterator.h index 8b3c067..2b4f051 100644 --- a/Source/WebCore/platform/graphics/WidthIterator.h +++ b/Source/WebCore/platform/graphics/WidthIterator.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2008, 2011 Apple Inc. All rights reserved. * Copyright (C) 2008 Holger Hans Peter Freyther * * This library is free software; you can redistribute it and/or @@ -50,8 +50,9 @@ struct WidthIterator { unsigned m_currentCharacter; float m_runWidthSoFar; - float m_padding; - float m_padPerSpace; + float m_expansion; + float m_expansionPerOpportunity; + bool m_isAfterExpansion; float m_finalRoundingWidth; private: diff --git a/Source/WebCore/platform/graphics/android/FontAndroid.cpp b/Source/WebCore/platform/graphics/android/FontAndroid.cpp index 7fcad73..af2edc7 100644 --- a/Source/WebCore/platform/graphics/android/FontAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/FontAndroid.cpp @@ -161,6 +161,11 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } +bool Font::canExpandAroundIdeographsInComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const @@ -918,7 +923,7 @@ void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, bool haveMultipleLayers = isCanvasMultiLayered(canvas); TextRunWalker walker(run, point.x(), this); walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing()); - walker.setPadding(run.padding()); + walker.setPadding(run.expansion()); while (walker.nextScriptRun()) { if (fill) { diff --git a/Source/WebCore/platform/graphics/android/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/android/FontCustomPlatformData.cpp index 4795d9e..7190f32 100644 --- a/Source/WebCore/platform/graphics/android/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/android/FontCustomPlatformData.cpp @@ -46,7 +46,7 @@ FontCustomPlatformData::~FontCustomPlatformData() } FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, - FontOrientation, FontRenderingMode) + FontOrientation, FontWidthVariant, FontRenderingMode) { // turn bold/italic into fakeBold/fakeItalic if (m_typeface != NULL) { diff --git a/Source/WebCore/platform/graphics/android/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/android/FontCustomPlatformData.h index b03afa9..f74abc5 100644 --- a/Source/WebCore/platform/graphics/android/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/android/FontCustomPlatformData.h @@ -28,6 +28,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" +#include "FontWidthVariant.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -46,7 +47,7 @@ public: SkTypeface* typeface() const { return m_typeface; } - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode); static bool supportsFormat(const String&); private: diff --git a/Source/WebCore/platform/graphics/android/FontDataAndroid.cpp b/Source/WebCore/platform/graphics/android/FontDataAndroid.cpp index 545dcf7..1f19b6d 100644 --- a/Source/WebCore/platform/graphics/android/FontDataAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/FontDataAndroid.cpp @@ -43,22 +43,20 @@ namespace WebCore { void SimpleFontData::platformInit() { SkPaint paint; - SkPaint::FontMetrics metrics; + SkPaint::FontMetrics skiaFontMetrics; m_platformData.setupPaint(&paint); - (void)paint.getFontMetrics(&metrics); - - // use ceil instead of round to favor descent, given a lot of accidental - // clipping of descenders (e.g. 14pt 'g') in textedit fields - int d = SkScalarCeil(metrics.fDescent); - int s = SkScalarRound(metrics.fDescent - metrics.fAscent); - int a = s - d; - - m_ascent = a; - m_descent = d; - m_xHeight = SkScalarToFloat(-metrics.fAscent) * 0.56f; // hack I stole from the window's port - m_lineSpacing = a + d; - m_lineGap = SkScalarRound(metrics.fLeading); + paint.getFontMetrics(&skiaFontMetrics); + + float d = SkScalarToFloat(skiaFontMetrics.fDescent); + float s = SkScalarToFloat(skiaFontMetrics.fDescent - skiaFontMetrics.fAscent); + float a = s - d; + + m_fontMetrics.setAscent(a); + m_fontMetrics.setDescent(d); + m_fontMetrics.setXHeight(SkScalarToFloat(-skiaFontMetrics.fAscent) * 0.56f); // hack I stole from the window's port + m_fontMetrics.setLineSpacing(a + d); + m_fontMetrics.setLineGap(SkScalarToFloat(skiaFontMetrics.fLeading)); } void SimpleFontData::platformCharWidthInit() diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index f46d335..966670d 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -229,7 +229,7 @@ void GLWebViewState::inval(const IntRect& rect) rect.x(), rect.y(), rect.right(), rect.bottom()); } } else { - m_invalidateRegion.op(rect.x(), rect.y(), rect.right(), rect.bottom(), SkRegion::kUnion_Op); + m_invalidateRegion.op(rect.x(), rect.y(), rect.maxX(), rect.maxY(), SkRegion::kUnion_Op); } } diff --git a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp index 888be5b..012c1a8 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp @@ -115,7 +115,6 @@ struct ShadowRec { class GraphicsContextPlatformPrivate { public: struct State { - SkPath* path; SkPathEffect* pathEffect; float miterLimit; float alpha; @@ -133,8 +132,7 @@ public: WTF::Vector<SkPath> antiAliasClipPaths; State() - : path(0) // Lazily allocated - , pathEffect(0) + : pathEffect(0) , miterLimit(4) , alpha(1) , strokeThickness(0) // Same as default in GraphicsContextPrivate.h @@ -162,13 +160,11 @@ public: , strokeColor(other.strokeColor) , useAA(other.useAA) { - path = deepCopyPtr<SkPath>(other.path); SkSafeRef(pathEffect); } ~State() { - delete path; SkSafeUnref(pathEffect); } @@ -273,26 +269,6 @@ public: m_state->strokeThickness = f; } - void beginPath() - { - if (m_state->path) - m_state->path->reset(); - } - - void addPath(const SkPath& other) - { - if (!m_state->path) - m_state->path = new SkPath(other); - else - m_state->path->addPath(other); - } - - // May return null - SkPath* getPath() const - { - return m_state->path; - } - void setupPaintCommon(SkPaint* paint) const { paint->setAntiAlias(m_state->useAA); @@ -538,11 +514,6 @@ bool GraphicsContext::willStroke() const return m_data->getState()->strokeColor; } -const SkPath* GraphicsContext::getCurrPath() const -{ - return m_data->getState()->path; -} - // Draws a filled rectangle with a stroked border. void GraphicsContext::drawRect(const IntRect& rect) { @@ -909,12 +880,7 @@ void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule) if (paintingDisabled()) return; - // FIXME: Be smarter about this. - beginPath(); - addPath(pathToClip); - - const SkPath* oldPath = m_data->getPath(); - SkPath path(*oldPath); + SkPath path = *pathToClip.platformPath(); path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); GC2CANVAS(this)->clipPath(path); } @@ -1231,23 +1197,9 @@ AffineTransform GraphicsContext::getCTM() const /////////////////////////////////////////////////////////////////////////////// -void GraphicsContext::beginPath() -{ - m_data->beginPath(); -} - -void GraphicsContext::addPath(const Path& p) -{ - m_data->addPath(*p.platformPath()); -} - void GraphicsContext::fillPath(const Path& pathToFill) { - // FIXME: Be smarter about this. - beginPath(); - addPath(pathToFill); - - SkPath* path = m_data->getPath(); + SkPath* path = pathToFill.platformPath(); if (paintingDisabled() || !path) return; @@ -1272,11 +1224,7 @@ void GraphicsContext::fillPath(const Path& pathToFill) void GraphicsContext::strokePath(const Path& pathToStroke) { - // FIXME: Be smarter about this. - beginPath(); - addPath(pathToStroke); - - const SkPath* path = m_data->getPath(); + const SkPath* path = pathToStroke.platformPath(); if (paintingDisabled() || !path) return; diff --git a/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp b/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp index 0a36051..5807f87 100644 --- a/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp @@ -120,7 +120,7 @@ PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); unsigned char* data = result->data(); - if (rect.x() < 0 || rect.y() < 0 || rect.right() > m_size.width() || rect.bottom() > m_size.height()) + if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > m_size.width() || rect.maxY() > m_size.height()) memset(data, 0, result->length()); int originx = rect.x(); @@ -189,7 +189,7 @@ void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sou ASSERT(originx >= 0); ASSERT(originx <= sourceRect.right()); - int endx = destPoint.x() + sourceRect.right(); + int endx = destPoint.x() + sourceRect.maxX(); ASSERT(endx <= m_size.width()); int numColumns = endx - destx; @@ -201,7 +201,7 @@ void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sou ASSERT(originy >= 0); ASSERT(originy <= sourceRect.bottom()); - int endy = destPoint.y() + sourceRect.bottom(); + int endy = destPoint.y() + sourceRect.maxY(); ASSERT(endy <= m_size.height()); int numRows = endy - desty; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index c0fbf61..34c02e9 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -600,7 +600,7 @@ void LayerAndroid::updateGLPositions(const TransformationMatrix& parentMatrix, localMatrix.translate3d(originX + position.x(), originY + position.y(), anchorPointZ()); - localMatrix.multLeft(m_transform); + localMatrix.multiply(m_transform); localMatrix.translate3d(-originX, -originY, -anchorPointZ()); @@ -648,7 +648,7 @@ void LayerAndroid::updateGLPositions(const TransformationMatrix& parentMatrix, if (!m_childrenTransform.isIdentity()) { localMatrix.translate(getSize().width() * 0.5f, getSize().height() * 0.5f); - localMatrix.multLeft(m_childrenTransform); + localMatrix.multiply(m_childrenTransform); localMatrix.translate(-getSize().width() * 0.5f, -getSize().height() * 0.5f); } for (int i = 0; i < count; i++) diff --git a/Source/WebCore/platform/graphics/android/PathAndroid.cpp b/Source/WebCore/platform/graphics/android/PathAndroid.cpp index e0d7171..ad345bb 100644 --- a/Source/WebCore/platform/graphics/android/PathAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/PathAndroid.cpp @@ -285,35 +285,20 @@ void Path::transform(const AffineTransform& xform) /////////////////////////////////////////////////////////////////////////////// -// Computes the bounding box for the stroke and style currently selected into -// the given bounding box. This also takes into account the stroke width. -static FloatRect boundingBoxForCurrentStroke(GraphicsContext* context) -{ - const SkPath* path = context->getCurrPath(); - if (NULL == path) { - return FloatRect(); - } - - SkPaint paint; - context->setupStrokePaint(&paint); - SkPath fillPath; - paint.getFillPath(*path, &fillPath); - const SkRect& r = fillPath.getBounds(); - return FloatRect(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop), - SkScalarToFloat(r.width()), SkScalarToFloat(r.height())); -} - FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) { GraphicsContext* scratch = scratchContext(); scratch->save(); - scratch->beginPath(); - scratch->addPath(*this); - + if (applier) applier->strokeStyle(scratch); - - FloatRect r = boundingBoxForCurrentStroke(scratch); + + SkPaint paint; + scratch->setupStrokePaint(&paint); + SkPath boundingPath; + paint.getFillPath(*platformPath(), &boundingPath); + + FloatRect r = boundingPath.getBounds(); scratch->restore(); return r; } diff --git a/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h b/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h index 0ce86d2..98fcc49 100644 --- a/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h +++ b/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h @@ -118,7 +118,7 @@ public: state == WebCore::RenderSkinAndroid::kFocused) return; m_state = state; - SkCanvas* canvas = m_picture->beginRecording(m_rect.right(), m_rect.bottom()); + SkCanvas* canvas = m_picture->beginRecording(m_rect.maxX(), m_rect.maxY()); buttonSkin->draw(canvas, m_rect, state); m_picture->endRecording(); } diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp index 0117bc0..f2b2dc8 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp @@ -224,9 +224,7 @@ void ShaderProgram::setProjectionMatrix(SkRect& geometry) TransformationMatrix scale; scale.scale3d(geometry.width(), geometry.height(), 1.0); - TransformationMatrix total = m_projectionMatrix; - total.multLeft(translate); - total.multLeft(scale); + TransformationMatrix total = m_projectionMatrix * translate * scale; GLfloat projectionMatrix[16]; GLUtils::toGLMatrix(projectionMatrix, total); @@ -264,14 +262,10 @@ void ShaderProgram::setViewRect(const IntRect& viewRect) TransformationMatrix scale; scale.scale3d(m_viewRect.width() * 0.5f, m_viewRect.height() * 0.5f, 1); - m_documentToScreenMatrix = m_projectionMatrix; - m_documentToScreenMatrix.multiply(translate); - m_documentToScreenMatrix.multiply(scale); + m_documentToScreenMatrix = scale * translate * m_projectionMatrix; - m_documentToInvScreenMatrix = m_projectionMatrix; translate.scale3d(1, -1, 1); - m_documentToInvScreenMatrix.multiply(translate); - m_documentToInvScreenMatrix.multiply(scale); + m_documentToInvScreenMatrix = scale * translate * m_projectionMatrix; } // This function transform a clip rect extracted from the current layer @@ -279,8 +273,7 @@ void ShaderProgram::setViewRect(const IntRect& viewRect) FloatRect ShaderProgram::rectInScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size) { FloatRect srect(0, 0, size.width(), size.height()); - TransformationMatrix renderMatrix = drawMatrix; - renderMatrix.multiply(m_documentToScreenMatrix); + TransformationMatrix renderMatrix = m_documentToScreenMatrix * drawMatrix; return renderMatrix.mapRect(srect); } @@ -288,8 +281,7 @@ FloatRect ShaderProgram::rectInScreenCoord(const TransformationMatrix& drawMatri FloatRect ShaderProgram::rectInInvScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size) { FloatRect srect(0, 0, size.width(), size.height()); - TransformationMatrix renderMatrix = drawMatrix; - renderMatrix.multiply(m_documentToInvScreenMatrix); + TransformationMatrix renderMatrix = m_documentToInvScreenMatrix * drawMatrix; return renderMatrix.mapRect(srect); } @@ -372,9 +364,9 @@ IntRect ShaderProgram::clippedRectWithViewport(const IntRect& rect, int margin) float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, float h) { - TransformationMatrix renderMatrix = drawMatrix; - renderMatrix.scale3d(w, h, 1); - renderMatrix.multiply(m_projectionMatrix); + TransformationMatrix modifiedDrawMatrix = drawMatrix; + modifiedDrawMatrix.scale3d(w, h, 1); + TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix; FloatPoint3D point(0.5, 0.5, 0.0); FloatPoint3D result = renderMatrix.mapPoint(point); return result.z(); @@ -385,11 +377,11 @@ void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix, bool forceBlending) { - TransformationMatrix renderMatrix = drawMatrix; + TransformationMatrix modifiedDrawMatrix = drawMatrix; // move the drawing depending on where the texture is on the layer - renderMatrix.translate(geometry.fLeft, geometry.fTop); - renderMatrix.scale3d(geometry.width(), geometry.height(), 1); - renderMatrix.multiply(m_projectionMatrix); + modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop); + modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1); + TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix; GLfloat projectionMatrix[16]; GLUtils::toGLMatrix(projectionMatrix, renderMatrix); @@ -414,10 +406,10 @@ void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix, // switch to our custom yuv video rendering program glUseProgram(m_videoProgram); - TransformationMatrix renderMatrix = drawMatrix; - renderMatrix.translate(geometry.fLeft, geometry.fTop); - renderMatrix.scale3d(geometry.width(), geometry.height(), 1); - renderMatrix.multiply(m_projectionMatrix); + TransformationMatrix modifiedDrawMatrix = drawMatrix; + modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop); + modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1); + TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix; GLfloat projectionMatrix[16]; GLUtils::toGLMatrix(projectionMatrix, renderMatrix); diff --git a/Source/WebCore/platform/graphics/android/TiledPage.cpp b/Source/WebCore/platform/graphics/android/TiledPage.cpp index 5212871..0e1e947 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.cpp +++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp @@ -122,14 +122,14 @@ void TiledPage::invalidateRect(const IntRect& inval, const unsigned int pictureC const int firstDirtyTileX = static_cast<int>(floorf(inval.x() * invTileContentWidth)); const int firstDirtyTileY = static_cast<int>(floorf(inval.y() * invTileContentHeight)); - const int lastDirtyTileX = static_cast<int>(ceilf(inval.right() * invTileContentWidth)); - const int lastDirtyTileY = static_cast<int>(ceilf(inval.bottom() * invTileContentHeight)); + const int lastDirtyTileX = static_cast<int>(ceilf(inval.maxX() * invTileContentWidth)); + const int lastDirtyTileY = static_cast<int>(ceilf(inval.maxY() * invTileContentHeight)); XLOG("Marking X %d-%d and Y %d-%d dirty", firstDirtyTileX, lastDirtyTileX, firstDirtyTileY, lastDirtyTileY); // We defer marking the tile as dirty until the next time we need to prepare // to draw. m_invalRegion.op(firstDirtyTileX, firstDirtyTileY, lastDirtyTileX, lastDirtyTileY, SkRegion::kUnion_Op); - m_invalTilesRegion.op(inval.x(), inval.y(), inval.right(), inval.bottom(), SkRegion::kUnion_Op); + m_invalTilesRegion.op(inval.x(), inval.y(), inval.maxX(), inval.maxY(), SkRegion::kUnion_Op); m_latestPictureInval = pictureCount; } diff --git a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp index 01e25e9..2b4a39e 100644 --- a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp +++ b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp @@ -1507,7 +1507,7 @@ void GraphicsLayerCA::pauseCAAnimationOnLayer(AnimatedPropertyID property, const return; // Animations on the layer are immutable, so we have to clone and modify. - RefPtr<PlatformCAAnimation> newAnim = PlatformCAAnimation::create(curAnim.get()); + RefPtr<PlatformCAAnimation> newAnim = curAnim->copy(); newAnim->setSpeed(0); newAnim->setTimeOffset(timeOffset); @@ -1646,7 +1646,7 @@ void GraphicsLayerCA::setupAnimation(PlatformCAAnimation* propertyAnim, const An float repeatCount = anim->iterationCount(); if (repeatCount == Animation::IterationCountInfinite) - repeatCount = FLT_MAX; + repeatCount = numeric_limits<float>::max(); else if (anim->direction() == Animation::AnimationDirectionAlternate) repeatCount /= 2; diff --git a/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h b/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h index 4bfce63..a8528fd 100644 --- a/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h +++ b/Source/WebCore/platform/graphics/ca/PlatformCAAnimation.h @@ -63,13 +63,14 @@ public: enum ValueFunctionType { NoValueFunction, RotateX, RotateY, RotateZ, ScaleX, ScaleY, ScaleZ, Scale, TranslateX, TranslateY, TranslateZ, Translate }; static PassRefPtr<PlatformCAAnimation> create(AnimationType, const String& keyPath); - static PassRefPtr<PlatformCAAnimation> create(PlatformAnimationRef animation); - static PassRefPtr<PlatformCAAnimation> create(const PlatformCAAnimation* animation); + static PassRefPtr<PlatformCAAnimation> create(PlatformAnimationRef); ~PlatformCAAnimation(); static bool supportsValueFunction(); + PassRefPtr<PlatformCAAnimation> copy() const; + PlatformAnimationRef platformAnimation() const; AnimationType animationType() const { return m_type; } @@ -136,8 +137,7 @@ public: protected: PlatformCAAnimation(AnimationType, const String& keyPath); - PlatformCAAnimation(PlatformAnimationRef animation); - PlatformCAAnimation(const PlatformCAAnimation* animation); + PlatformCAAnimation(PlatformAnimationRef); private: AnimationType m_type; diff --git a/Source/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm b/Source/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm index 2a00857..506bd40 100644 --- a/Source/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm +++ b/Source/WebCore/platform/graphics/ca/mac/PlatformCAAnimationMac.mm @@ -159,11 +159,6 @@ PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(PlatformAnimationRef return adoptRef(new PlatformCAAnimation(animation)); } -PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(const PlatformCAAnimation* animation) -{ - return adoptRef(new PlatformCAAnimation(animation)); -} - PlatformCAAnimation::PlatformCAAnimation(AnimationType type, const String& keyPath) : m_type(type) { @@ -187,38 +182,36 @@ PlatformCAAnimation::PlatformCAAnimation(PlatformAnimationRef animation) m_animation = static_cast<CAPropertyAnimation*>(animation); } -PlatformCAAnimation::PlatformCAAnimation(const PlatformCAAnimation* animation) +PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::copy() const { - PlatformCAAnimation* newAnimation = new PlatformCAAnimation(animation->animationType(), animation->keyPath()); - - newAnimation->setBeginTime(animation->beginTime()); - newAnimation->setDuration(animation->duration()); - newAnimation->setSpeed(animation->speed()); - newAnimation->setTimeOffset(animation->timeOffset()); - newAnimation->setRepeatCount(animation->repeatCount()); - newAnimation->setAutoreverses(animation->autoreverses()); - newAnimation->setFillMode(animation->fillMode()); - newAnimation->setRemovedOnCompletion(animation->isRemovedOnCompletion()); - newAnimation->setAdditive(animation->isAdditive()); - newAnimation->copyTimingFunctionFrom(animation); - -#if HAVE_MODERN_QUARTZCORE - newAnimation->setValueFunction(animation->valueFunction()); -#endif - - setNonZeroBeginTimeFlag(newAnimation, hasNonZeroBeginTimeFlag(animation)); + RefPtr<PlatformCAAnimation> animation = create(animationType(), keyPath()); + + animation->setBeginTime(beginTime()); + animation->setDuration(duration()); + animation->setSpeed(speed()); + animation->setTimeOffset(timeOffset()); + animation->setRepeatCount(repeatCount()); + animation->setAutoreverses(autoreverses()); + animation->setFillMode(fillMode()); + animation->setRemovedOnCompletion(isRemovedOnCompletion()); + animation->setAdditive(isAdditive()); + animation->copyTimingFunctionFrom(this); + animation->setValueFunction(valueFunction()); + + setNonZeroBeginTimeFlag(animation.get(), hasNonZeroBeginTimeFlag(this)); // Copy the specific Basic or Keyframe values - if (animation->animationType() == Keyframe) { - newAnimation->copyValuesFrom(animation); - newAnimation->copyKeyTimesFrom(animation); - newAnimation->copyTimingFunctionsFrom(animation); + if (animationType() == Keyframe) { + animation->copyValuesFrom(this); + animation->copyKeyTimesFrom(this); + animation->copyTimingFunctionsFrom(this); } else { - newAnimation->copyFromValueFrom(animation); - newAnimation->copyToValueFrom(animation); + animation->copyFromValueFrom(this); + animation->copyToValueFrom(this); } + + return animation; } - PlatformCAAnimation::~PlatformCAAnimation() { } diff --git a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.cpp b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.cpp index 1d27608..9dc30ea 100644 --- a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.cpp +++ b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.cpp @@ -28,49 +28,22 @@ #if USE(ACCELERATED_COMPOSITING) +#include "CACFLayerTreeHostClient.h" #include "LayerChangesFlusher.h" +#include "LegacyCACFLayerTreeHost.h" #include "PlatformCALayer.h" +#include "WKCACFViewLayerTreeHost.h" #include "WebCoreInstanceHandle.h" -#include <WebKitSystemInterface/WebKitSystemInterface.h> #include <limits.h> #include <wtf/CurrentTime.h> -#include <wtf/HashMap.h> #include <wtf/OwnArrayPtr.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> -#include <wtf/StdLibExtras.h> -#ifndef NDEBUG -#define D3D_DEBUG_INFO -#endif - -#include <d3d9.h> -#include <d3dx9.h> - -using namespace std; - -#pragma comment(lib, "d3d9") -#pragma comment(lib, "d3dx9") #ifdef DEBUG_ALL #pragma comment(lib, "QuartzCore_debug") #else #pragma comment(lib, "QuartzCore") #endif -static IDirect3D9* s_d3d = 0; -static IDirect3D9* d3d() -{ - if (s_d3d) - return s_d3d; - - if (!LoadLibrary(TEXT("d3d9.dll"))) - return 0; - - s_d3d = Direct3DCreate9(D3D_SDK_VERSION); - - return s_d3d; -} - inline static CGRect winRectToCGRect(RECT rc) { return CGRectMake(rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top)); @@ -83,40 +56,6 @@ inline static CGRect winRectToCGRect(RECT rc, RECT relativeToRect) namespace WebCore { -static D3DPRESENT_PARAMETERS initialPresentationParameters() -{ - D3DPRESENT_PARAMETERS parameters = {0}; - parameters.Windowed = TRUE; - parameters.SwapEffect = D3DSWAPEFFECT_COPY; - parameters.BackBufferCount = 1; - parameters.BackBufferFormat = D3DFMT_A8R8G8B8; - parameters.MultiSampleType = D3DMULTISAMPLE_NONE; - - return parameters; -} - -// FIXME: <rdar://6507851> Share this code with CoreAnimation. -static bool hardwareCapabilitiesIndicateCoreAnimationSupport(const D3DCAPS9& caps) -{ - // CoreAnimation needs two or more texture units. - if (caps.MaxTextureBlendStages < 2) - return false; - - // CoreAnimation needs non-power-of-two textures. - if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && !(caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)) - return false; - - // CoreAnimation needs vertex shader 2.0 or greater. - if (D3DSHADER_VERSION_MAJOR(caps.VertexShaderVersion) < 2) - return false; - - // CoreAnimation needs pixel shader 2.0 or greater. - if (D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion) < 2) - return false; - - return true; -} - bool CACFLayerTreeHost::acceleratedCompositingAvailable() { static bool available; @@ -158,7 +97,7 @@ bool CACFLayerTreeHost::acceleratedCompositingAvailable() wcex.hInstance = WebCore::instanceHandle(); wcex.lpszClassName = L"CoreAnimationTesterWindowClass"; ::RegisterClassEx(&wcex); - HWND testWindow = ::CreateWindow(L"CoreAnimationTesterWindowClass", L"CoreAnimationTesterWindow", WS_POPUP, -500, -500, 0, 0, 0, 0, 0, 0); + HWND testWindow = ::CreateWindow(L"CoreAnimationTesterWindowClass", L"CoreAnimationTesterWindow", WS_POPUP, -500, -500, 20, 20, 0, 0, 0, 0); if (!testWindow) { available = false; @@ -168,6 +107,7 @@ bool CACFLayerTreeHost::acceleratedCompositingAvailable() RefPtr<CACFLayerTreeHost> host = CACFLayerTreeHost::create(); host->setWindow(testWindow); available = host->createRenderer(); + host->setWindow(0); ::DestroyWindow(testWindow); return available; @@ -177,22 +117,29 @@ PassRefPtr<CACFLayerTreeHost> CACFLayerTreeHost::create() { if (!acceleratedCompositingAvailable()) return 0; - return adoptRef(new CACFLayerTreeHost()); + RefPtr<CACFLayerTreeHost> host = WKCACFViewLayerTreeHost::create(); + if (!host) + host = LegacyCACFLayerTreeHost::create(); + host->initialize(); + return host.release(); } CACFLayerTreeHost::CACFLayerTreeHost() : m_client(0) - , m_mightBeAbleToCreateDeviceLater(true) , m_rootLayer(PlatformCALayer::create(PlatformCALayer::LayerTypeRootLayer, 0)) - , m_context(wkCACFContextCreate()) , m_window(0) - , m_renderTimer(this, &CACFLayerTreeHost::renderTimerFired) - , m_mustResetLostDeviceBeforeRendering(false) , m_shouldFlushPendingGraphicsLayerChanges(false) , m_isFlushingLayerChanges(false) +#if !ASSERT_DISABLED + , m_state(WindowNotSet) +#endif +{ +} + +void CACFLayerTreeHost::initialize() { // Point the CACFContext to this - wkCACFContextSetUserData(m_context, this); + initializeContext(this, m_rootLayer.get()); // Under the root layer, we have a clipping layer to clip the content, // that contains a scroll layer that we use for scrolling the content. @@ -212,20 +159,11 @@ CACFLayerTreeHost::CACFLayerTreeHost() m_rootLayer->setBackgroundColor(debugColor); CGColorRelease(debugColor); #endif - - if (m_context) - wkCACFContextSetLayer(m_context, m_rootLayer->platformLayer()); - -#ifndef NDEBUG - char* printTreeFlag = getenv("CA_PRINT_TREE"); - m_printTree = printTreeFlag && atoi(printTreeFlag); -#endif } CACFLayerTreeHost::~CACFLayerTreeHost() { - setWindow(0); - wkCACFContextDestroy(m_context); + ASSERT_WITH_MESSAGE(m_state != WindowSet, "Must call setWindow(0) before destroying CACFLayerTreeHost"); } void CACFLayerTreeHost::setWindow(HWND window) @@ -233,13 +171,28 @@ void CACFLayerTreeHost::setWindow(HWND window) if (window == m_window) return; +#if !ASSERT_DISABLED + switch (m_state) { + case WindowNotSet: + ASSERT_ARG(window, window); + ASSERT(!m_window); + m_state = WindowSet; + break; + case WindowSet: + ASSERT_ARG(window, !window); + ASSERT(m_window); + m_state = WindowCleared; + break; + case WindowCleared: + ASSERT_NOT_REACHED(); + break; + } +#endif + if (m_window) destroyRenderer(); m_window = window; - - if (m_window) - createRenderer(); } PlatformCALayer* CACFLayerTreeHost::rootLayer() const @@ -275,109 +228,11 @@ void CACFLayerTreeHost::layerTreeDidChange() LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this); } -bool CACFLayerTreeHost::createRenderer() -{ - if (m_d3dDevice || !m_mightBeAbleToCreateDeviceLater) - return m_d3dDevice; - - m_mightBeAbleToCreateDeviceLater = false; - D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); - - if (!d3d() || !::IsWindow(m_window)) - return false; - - // D3D doesn't like to make back buffers for 0 size windows. We skirt this problem if we make the - // passed backbuffer width and height non-zero. The window will necessarily get set to a non-zero - // size eventually, and then the backbuffer size will get reset. - RECT rect; - GetClientRect(m_window, &rect); - - if (rect.left-rect.right == 0 || rect.bottom-rect.top == 0) { - parameters.BackBufferWidth = 1; - parameters.BackBufferHeight = 1; - } - - D3DCAPS9 d3dCaps; - if (FAILED(d3d()->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps))) - return false; - - DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE; - if ((d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) && d3dCaps.VertexProcessingCaps) - behaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; - else - behaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; - - COMPtr<IDirect3DDevice9> device; - if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_window, behaviorFlags, ¶meters, &device))) { - // In certain situations (e.g., shortly after waking from sleep), Direct3DCreate9() will - // return an IDirect3D9 for which IDirect3D9::CreateDevice will always fail. In case we - // have one of these bad IDirect3D9s, get rid of it so we'll fetch a new one the next time - // we want to call CreateDevice. - s_d3d->Release(); - s_d3d = 0; - - // Even if we don't have a bad IDirect3D9, in certain situations (e.g., shortly after - // waking from sleep), CreateDevice will fail, but will later succeed if called again. - m_mightBeAbleToCreateDeviceLater = true; - - return false; - } - - // Now that we've created the IDirect3DDevice9 based on the capabilities we - // got from the IDirect3D9 global object, we requery the device for its - // actual capabilities. The capabilities returned by the device can - // sometimes be more complete, for example when using software vertex - // processing. - D3DCAPS9 deviceCaps; - if (FAILED(device->GetDeviceCaps(&deviceCaps))) - return false; - - if (!hardwareCapabilitiesIndicateCoreAnimationSupport(deviceCaps)) - return false; - - m_d3dDevice = device; - - initD3DGeometry(); - - wkCACFContextSetD3DDevice(m_context, m_d3dDevice.get()); - - if (IsWindow(m_window)) - m_rootLayer->setBounds(bounds()); - - return true; -} - void CACFLayerTreeHost::destroyRenderer() { - LayerChangesFlusher::shared().cancelPendingFlush(this); - - wkCACFContextSetLayer(m_context, 0); - - wkCACFContextSetD3DDevice(m_context, 0); - m_d3dDevice = 0; - if (s_d3d) - s_d3d->Release(); - - s_d3d = 0; m_rootLayer = 0; m_rootChildLayer = 0; - - m_mightBeAbleToCreateDeviceLater = true; -} - -void CACFLayerTreeHost::resize() -{ - if (!m_d3dDevice) - return; - - // Resetting the device might fail here. But that's OK, because if it does it we will attempt to - // reset the device the next time we try to render. - resetDevice(ChangedWindowSize); - - if (m_rootLayer) { - m_rootLayer->setBounds(bounds()); - wkCACFContextFlush(m_context); - } + LayerChangesFlusher::shared().cancelPendingFlush(this); } static void getDirtyRects(HWND window, Vector<CGRect>& outRects) @@ -398,7 +253,7 @@ static void getDirtyRects(HWND window, Vector<CGRect>& outRects) } DWORD dataSize = GetRegionData(region.get(), 0, 0); - OwnArrayPtr<unsigned char> regionDataBuffer(new unsigned char[dataSize]); + OwnArrayPtr<unsigned char> regionDataBuffer = adoptArrayPtr(new unsigned char[dataSize]); RGNDATA* regionData = reinterpret_cast<RGNDATA*>(regionDataBuffer.get()); if (!GetRegionData(region.get(), dataSize, regionData)) return; @@ -410,120 +265,13 @@ static void getDirtyRects(HWND window, Vector<CGRect>& outRects) outRects[i] = winRectToCGRect(*rect, clientRect); } -void CACFLayerTreeHost::renderTimerFired(Timer<CACFLayerTreeHost>*) -{ - paint(); -} - void CACFLayerTreeHost::paint() { - createRenderer(); - if (!m_d3dDevice) { - if (m_mightBeAbleToCreateDeviceLater) - renderSoon(); - return; - } - Vector<CGRect> dirtyRects; getDirtyRects(m_window, dirtyRects); render(dirtyRects); } -void CACFLayerTreeHost::render(const Vector<CGRect>& windowDirtyRects) -{ - ASSERT(m_d3dDevice); - - if (m_mustResetLostDeviceBeforeRendering && !resetDevice(LostDevice)) { - // We can't reset the device right now. Try again soon. - renderSoon(); - return; - } - - // All pending animations will have been started with the flush. Fire the animationStarted calls - double currentTime = WTF::currentTime(); - double currentMediaTime = CACurrentMediaTime(); - double t = currentTime + wkCACFContextGetLastCommitTime(m_context) - currentMediaTime; - ASSERT(t <= currentTime); - - HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end(); - for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it) { - PlatformCALayerClient* owner = (*it)->owner(); - owner->platformCALayerAnimationStarted(t); - } - - m_pendingAnimatedLayers.clear(); - - CGRect bounds = this->bounds(); - - // Give the renderer some space to use. This needs to be valid until the - // wkCACFContextFinishUpdate() call below. - char space[4096]; - if (!wkCACFContextBeginUpdate(m_context, space, sizeof(space), currentMediaTime, bounds, windowDirtyRects.data(), windowDirtyRects.size())) - return; - - HRESULT err = S_OK; - CFTimeInterval timeToNextRender = numeric_limits<CFTimeInterval>::infinity(); - - do { - // FIXME: don't need to clear dirty region if layer tree is opaque. - - WKCACFUpdateRectEnumerator* e = wkCACFContextCopyUpdateRectEnumerator(m_context); - if (!e) - break; - - Vector<D3DRECT, 64> rects; - for (const CGRect* r = wkCACFUpdateRectEnumeratorNextRect(e); r; r = wkCACFUpdateRectEnumeratorNextRect(e)) { - D3DRECT rect; - rect.x1 = r->origin.x; - rect.x2 = rect.x1 + r->size.width; - rect.y1 = bounds.origin.y + bounds.size.height - (r->origin.y + r->size.height); - rect.y2 = rect.y1 + r->size.height; - - rects.append(rect); - } - wkCACFUpdateRectEnumeratorRelease(e); - - timeToNextRender = wkCACFContextGetNextUpdateTime(m_context); - - if (rects.isEmpty()) - break; - - m_d3dDevice->Clear(rects.size(), rects.data(), D3DCLEAR_TARGET, 0, 1.0f, 0); - - m_d3dDevice->BeginScene(); - wkCACFContextRenderUpdate(m_context); - m_d3dDevice->EndScene(); - - err = m_d3dDevice->Present(0, 0, 0, 0); - - if (err == D3DERR_DEVICELOST) { - wkCACFContextAddUpdateRect(m_context, bounds); - if (!resetDevice(LostDevice)) { - // We can't reset the device right now. Try again soon. - renderSoon(); - return; - } - } - } while (err == D3DERR_DEVICELOST); - - wkCACFContextFinishUpdate(m_context); - -#ifndef NDEBUG - if (m_printTree) - m_rootLayer->printTree(); -#endif - - // If timeToNextRender is not infinity, it means animations are running, so queue up to render again - if (timeToNextRender != numeric_limits<CFTimeInterval>::infinity()) - renderSoon(); -} - -void CACFLayerTreeHost::renderSoon() -{ - if (!m_renderTimer.isActive()) - m_renderTimer.startOneShot(0); -} - void CACFLayerTreeHost::flushPendingGraphicsLayerChangesSoon() { m_shouldFlushPendingGraphicsLayerChanges = true; @@ -545,75 +293,36 @@ void CACFLayerTreeHost::flushPendingLayerChangesNow() } // Flush changes stored up in PlatformCALayers to the context so they will be rendered. - wkCACFContextFlush(m_context); - - renderSoon(); + flushContext(); m_isFlushingLayerChanges = false; } -CGRect CACFLayerTreeHost::bounds() const +void CACFLayerTreeHost::contextDidChange() { - RECT clientRect; - GetClientRect(m_window, &clientRect); - - return winRectToCGRect(clientRect); + // All pending animations will have been started with the flush. Fire the animationStarted calls. + notifyAnimationsStarted(); } -void CACFLayerTreeHost::initD3DGeometry() +void CACFLayerTreeHost::notifyAnimationsStarted() { - ASSERT(m_d3dDevice); - - CGRect bounds = this->bounds(); - - float x0 = bounds.origin.x; - float y0 = bounds.origin.y; - float x1 = x0 + bounds.size.width; - float y1 = y0 + bounds.size.height; + double currentTime = WTF::currentTime(); + double time = currentTime + lastCommitTime() - CACurrentMediaTime(); + ASSERT(time <= currentTime); - D3DXMATRIXA16 projection; - D3DXMatrixOrthoOffCenterRH(&projection, x0, x1, y0, y1, -1.0f, 1.0f); + HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end(); + for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it) + (*it)->animationStarted(time); - m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); + m_pendingAnimatedLayers.clear(); } -bool CACFLayerTreeHost::resetDevice(ResetReason reason) +CGRect CACFLayerTreeHost::bounds() const { - ASSERT(m_d3dDevice); - ASSERT(m_context); - - HRESULT hr = m_d3dDevice->TestCooperativeLevel(); - - if (hr == D3DERR_DEVICELOST || hr == D3DERR_DRIVERINTERNALERROR) { - // The device cannot be reset at this time. Try again soon. - m_mustResetLostDeviceBeforeRendering = true; - return false; - } - - m_mustResetLostDeviceBeforeRendering = false; - - if (reason == LostDevice && hr == D3D_OK) { - // The device wasn't lost after all. - return true; - } - - // We can reset the device. - - // We have to release the context's D3D resrouces whenever we reset the IDirect3DDevice9 in order to - // destroy any D3DPOOL_DEFAULT resources that Core Animation has allocated (e.g., textures used - // for mask layers). See <http://msdn.microsoft.com/en-us/library/bb174425(v=VS.85).aspx>. - wkCACFContextReleaseD3DResources(m_context); - - D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); - hr = m_d3dDevice->Reset(¶meters); - - // TestCooperativeLevel told us the device may be reset now, so we should - // not be told here that the device is lost. - ASSERT(hr != D3DERR_DEVICELOST); - - initD3DGeometry(); + RECT clientRect; + GetClientRect(m_window, &clientRect); - return true; + return winRectToCGRect(clientRect); } } diff --git a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h index fc61f39..6d91a73 100644 --- a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h +++ b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h @@ -47,75 +47,59 @@ typedef struct CGImage* CGImageRef; namespace WebCore { +class CACFLayerTreeHostClient; class PlatformCALayer; -class CACFLayerTreeHostClient { -public: - virtual ~CACFLayerTreeHostClient() { } - virtual void flushPendingGraphicsLayerChanges() { } -}; - -// FIXME: Currently there is a CACFLayerTreeHost for each WebView and each -// has its own CARenderOGLContext and Direct3DDevice9, which is inefficient. -// (https://bugs.webkit.org/show_bug.cgi?id=31855) class CACFLayerTreeHost : public RefCounted<CACFLayerTreeHost> { friend PlatformCALayer; public: static PassRefPtr<CACFLayerTreeHost> create(); - ~CACFLayerTreeHost(); + virtual ~CACFLayerTreeHost(); static bool acceleratedCompositingAvailable(); void setClient(CACFLayerTreeHostClient* client) { m_client = client; } void setRootChildLayer(PlatformCALayer*); - void layerTreeDidChange(); void setWindow(HWND); - void paint(); - void resize(); + virtual void paint(); + virtual void resize() = 0; void flushPendingGraphicsLayerChangesSoon(); void flushPendingLayerChangesNow(); protected: - PlatformCALayer* rootLayer() const; - void addPendingAnimatedLayer(PassRefPtr<PlatformCALayer>); - -private: CACFLayerTreeHost(); - bool createRenderer(); - void destroyRenderer(); - void renderSoon(); - void renderTimerFired(Timer<CACFLayerTreeHost>*); - CGRect bounds() const; + PlatformCALayer* rootLayer() const; + HWND window() const { return m_window; } + void notifyAnimationsStarted(); - void initD3DGeometry(); + virtual bool createRenderer() = 0; + virtual void destroyRenderer(); + virtual void contextDidChange(); - // Call this when the device window has changed size or when IDirect3DDevice9::Present returns - // D3DERR_DEVICELOST. Returns true if the device was recovered, false if rendering must be - // aborted and reattempted soon. - enum ResetReason { ChangedWindowSize, LostDevice }; - bool resetDevice(ResetReason); +private: + void initialize(); + void addPendingAnimatedLayer(PassRefPtr<PlatformCALayer>); + void layerTreeDidChange(); - void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>()); + virtual void flushContext() = 0; + virtual CFTimeInterval lastCommitTime() const = 0; + virtual void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>()) = 0; + virtual void initializeContext(void* userData, PlatformCALayer*) = 0; CACFLayerTreeHostClient* m_client; - bool m_mightBeAbleToCreateDeviceLater; - COMPtr<IDirect3DDevice9> m_d3dDevice; RefPtr<PlatformCALayer> m_rootLayer; RefPtr<PlatformCALayer> m_rootChildLayer; - WKCACFContext* m_context; + HashSet<RefPtr<PlatformCALayer> > m_pendingAnimatedLayers; HWND m_window; - Timer<CACFLayerTreeHost> m_renderTimer; - bool m_mustResetLostDeviceBeforeRendering; bool m_shouldFlushPendingGraphicsLayerChanges; bool m_isFlushingLayerChanges; - HashSet<RefPtr<PlatformCALayer> > m_pendingAnimatedLayers; -#ifndef NDEBUG - bool m_printTree; +#if !ASSERT_DISABLED + enum { WindowNotSet, WindowSet, WindowCleared } m_state; #endif }; diff --git a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHostClient.h b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHostClient.h new file mode 100644 index 0000000..845f934 --- /dev/null +++ b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHostClient.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 Apple 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 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 CACFLayerTreeHostClient_h +#define CACFLayerTreeHostClient_h + +#if USE(ACCELERATED_COMPOSITING) + +namespace WebCore { + +class CACFLayerTreeHostClient { +public: + virtual ~CACFLayerTreeHostClient() { } + virtual void flushPendingGraphicsLayerChanges() { } +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // CACFLayerTreeHostClient_h diff --git a/Source/WebCore/platform/graphics/ca/win/LegacyCACFLayerTreeHost.cpp b/Source/WebCore/platform/graphics/ca/win/LegacyCACFLayerTreeHost.cpp new file mode 100644 index 0000000..772244b --- /dev/null +++ b/Source/WebCore/platform/graphics/ca/win/LegacyCACFLayerTreeHost.cpp @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2011 Apple 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 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 "LegacyCACFLayerTreeHost.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "PlatformCALayer.h" +#include <WebKitSystemInterface/WebKitSystemInterface.h> + +#ifndef NDEBUG +#define D3D_DEBUG_INFO +#endif + +#include <d3d9.h> +#include <d3dx9.h> + +#pragma comment(lib, "d3d9") +#pragma comment(lib, "d3dx9") + +using namespace std; + +namespace WebCore { + +static IDirect3D9* s_d3d = 0; +static IDirect3D9* d3d() +{ + if (s_d3d) + return s_d3d; + + if (!LoadLibrary(TEXT("d3d9.dll"))) + return 0; + + s_d3d = Direct3DCreate9(D3D_SDK_VERSION); + + return s_d3d; +} + +static D3DPRESENT_PARAMETERS initialPresentationParameters() +{ + D3DPRESENT_PARAMETERS parameters = {0}; + parameters.Windowed = TRUE; + parameters.SwapEffect = D3DSWAPEFFECT_COPY; + parameters.BackBufferCount = 1; + parameters.BackBufferFormat = D3DFMT_A8R8G8B8; + parameters.MultiSampleType = D3DMULTISAMPLE_NONE; + + return parameters; +} + +// FIXME: <rdar://6507851> Share this code with CoreAnimation. +static bool hardwareCapabilitiesIndicateCoreAnimationSupport(const D3DCAPS9& caps) +{ + // CoreAnimation needs two or more texture units. + if (caps.MaxTextureBlendStages < 2) + return false; + + // CoreAnimation needs non-power-of-two textures. + if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && !(caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)) + return false; + + // CoreAnimation needs vertex shader 2.0 or greater. + if (D3DSHADER_VERSION_MAJOR(caps.VertexShaderVersion) < 2) + return false; + + // CoreAnimation needs pixel shader 2.0 or greater. + if (D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion) < 2) + return false; + + return true; +} + +PassRefPtr<LegacyCACFLayerTreeHost> LegacyCACFLayerTreeHost::create() +{ + return adoptRef(new LegacyCACFLayerTreeHost); +} + +LegacyCACFLayerTreeHost::LegacyCACFLayerTreeHost() + : m_renderTimer(this, &LegacyCACFLayerTreeHost::renderTimerFired) + , m_context(wkCACFContextCreate()) + , m_mightBeAbleToCreateDeviceLater(true) + , m_mustResetLostDeviceBeforeRendering(false) +{ +#ifndef NDEBUG + char* printTreeFlag = getenv("CA_PRINT_TREE"); + m_printTree = printTreeFlag && atoi(printTreeFlag); +#endif +} + +LegacyCACFLayerTreeHost::~LegacyCACFLayerTreeHost() +{ + wkCACFContextDestroy(m_context); +} + +void LegacyCACFLayerTreeHost::initializeContext(void* userData, PlatformCALayer* layer) +{ + wkCACFContextSetUserData(m_context, userData); + wkCACFContextSetLayer(m_context, layer->platformLayer()); +} + +bool LegacyCACFLayerTreeHost::createRenderer() +{ + if (m_d3dDevice || !m_mightBeAbleToCreateDeviceLater) + return m_d3dDevice; + + m_mightBeAbleToCreateDeviceLater = false; + D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); + + if (!d3d() || !::IsWindow(window())) + return false; + + // D3D doesn't like to make back buffers for 0 size windows. We skirt this problem if we make the + // passed backbuffer width and height non-zero. The window will necessarily get set to a non-zero + // size eventually, and then the backbuffer size will get reset. + RECT rect; + GetClientRect(window(), &rect); + + if (rect.left-rect.right == 0 || rect.bottom-rect.top == 0) { + parameters.BackBufferWidth = 1; + parameters.BackBufferHeight = 1; + } + + D3DCAPS9 d3dCaps; + if (FAILED(d3d()->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps))) + return false; + + DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE; + if ((d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) && d3dCaps.VertexProcessingCaps) + behaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; + else + behaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; + + COMPtr<IDirect3DDevice9> device; + if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window(), behaviorFlags, ¶meters, &device))) { + // In certain situations (e.g., shortly after waking from sleep), Direct3DCreate9() will + // return an IDirect3D9 for which IDirect3D9::CreateDevice will always fail. In case we + // have one of these bad IDirect3D9s, get rid of it so we'll fetch a new one the next time + // we want to call CreateDevice. + s_d3d->Release(); + s_d3d = 0; + + // Even if we don't have a bad IDirect3D9, in certain situations (e.g., shortly after + // waking from sleep), CreateDevice will fail, but will later succeed if called again. + m_mightBeAbleToCreateDeviceLater = true; + + return false; + } + + // Now that we've created the IDirect3DDevice9 based on the capabilities we + // got from the IDirect3D9 global object, we requery the device for its + // actual capabilities. The capabilities returned by the device can + // sometimes be more complete, for example when using software vertex + // processing. + D3DCAPS9 deviceCaps; + if (FAILED(device->GetDeviceCaps(&deviceCaps))) + return false; + + if (!hardwareCapabilitiesIndicateCoreAnimationSupport(deviceCaps)) + return false; + + m_d3dDevice = device; + + initD3DGeometry(); + + wkCACFContextSetD3DDevice(m_context, m_d3dDevice.get()); + + if (IsWindow(window())) { + rootLayer()->setBounds(bounds()); + flushContext(); + } + + return true; +} + +void LegacyCACFLayerTreeHost::destroyRenderer() +{ + wkCACFContextSetLayer(m_context, 0); + + wkCACFContextSetD3DDevice(m_context, 0); + m_d3dDevice = 0; + if (s_d3d) + s_d3d->Release(); + + s_d3d = 0; + m_mightBeAbleToCreateDeviceLater = true; + + CACFLayerTreeHost::destroyRenderer(); +} + +void LegacyCACFLayerTreeHost::resize() +{ + if (!m_d3dDevice) + return; + + // Resetting the device might fail here. But that's OK, because if it does it we will attempt to + // reset the device the next time we try to render. + resetDevice(ChangedWindowSize); + + if (rootLayer()) { + rootLayer()->setBounds(bounds()); + flushContext(); + } +} + +void LegacyCACFLayerTreeHost::renderTimerFired(Timer<LegacyCACFLayerTreeHost>*) +{ + paint(); +} + +void LegacyCACFLayerTreeHost::paint() +{ + createRenderer(); + if (!m_d3dDevice) { + if (m_mightBeAbleToCreateDeviceLater) + renderSoon(); + return; + } + + CACFLayerTreeHost::paint(); +} + +void LegacyCACFLayerTreeHost::render(const Vector<CGRect>& windowDirtyRects) +{ + ASSERT(m_d3dDevice); + + if (m_mustResetLostDeviceBeforeRendering && !resetDevice(LostDevice)) { + // We can't reset the device right now. Try again soon. + renderSoon(); + return; + } + + CGRect bounds = this->bounds(); + + // Give the renderer some space to use. This needs to be valid until the + // wkCACFContextFinishUpdate() call below. + char space[4096]; + if (!wkCACFContextBeginUpdate(m_context, space, sizeof(space), CACurrentMediaTime(), bounds, windowDirtyRects.data(), windowDirtyRects.size())) + return; + + HRESULT err = S_OK; + CFTimeInterval timeToNextRender = numeric_limits<CFTimeInterval>::infinity(); + + do { + // FIXME: don't need to clear dirty region if layer tree is opaque. + + WKCACFUpdateRectEnumerator* e = wkCACFContextCopyUpdateRectEnumerator(m_context); + if (!e) + break; + + Vector<D3DRECT, 64> rects; + for (const CGRect* r = wkCACFUpdateRectEnumeratorNextRect(e); r; r = wkCACFUpdateRectEnumeratorNextRect(e)) { + D3DRECT rect; + rect.x1 = r->origin.x; + rect.x2 = rect.x1 + r->size.width; + rect.y1 = bounds.origin.y + bounds.size.height - (r->origin.y + r->size.height); + rect.y2 = rect.y1 + r->size.height; + + rects.append(rect); + } + wkCACFUpdateRectEnumeratorRelease(e); + + timeToNextRender = wkCACFContextGetNextUpdateTime(m_context); + + if (rects.isEmpty()) + break; + + m_d3dDevice->Clear(rects.size(), rects.data(), D3DCLEAR_TARGET, 0, 1.0f, 0); + + m_d3dDevice->BeginScene(); + wkCACFContextRenderUpdate(m_context); + m_d3dDevice->EndScene(); + + err = m_d3dDevice->Present(0, 0, 0, 0); + + if (err == D3DERR_DEVICELOST) { + wkCACFContextAddUpdateRect(m_context, bounds); + if (!resetDevice(LostDevice)) { + // We can't reset the device right now. Try again soon. + renderSoon(); + return; + } + } + } while (err == D3DERR_DEVICELOST); + + wkCACFContextFinishUpdate(m_context); + +#ifndef NDEBUG + if (m_printTree) + rootLayer()->printTree(); +#endif + + // If timeToNextRender is not infinity, it means animations are running, so queue up to render again + if (timeToNextRender != numeric_limits<CFTimeInterval>::infinity()) + renderSoon(); +} + +void LegacyCACFLayerTreeHost::renderSoon() +{ + if (!m_renderTimer.isActive()) + m_renderTimer.startOneShot(0); +} + +void LegacyCACFLayerTreeHost::flushContext() +{ + wkCACFContextFlush(m_context); + contextDidChange(); +} + +void LegacyCACFLayerTreeHost::contextDidChange() +{ + renderSoon(); + CACFLayerTreeHost::contextDidChange(); +} + +CFTimeInterval LegacyCACFLayerTreeHost::lastCommitTime() const +{ + return wkCACFContextGetLastCommitTime(m_context); +} + +void LegacyCACFLayerTreeHost::initD3DGeometry() +{ + ASSERT(m_d3dDevice); + + CGRect bounds = this->bounds(); + + float x0 = bounds.origin.x; + float y0 = bounds.origin.y; + float x1 = x0 + bounds.size.width; + float y1 = y0 + bounds.size.height; + + D3DXMATRIXA16 projection; + D3DXMatrixOrthoOffCenterRH(&projection, x0, x1, y0, y1, -1.0f, 1.0f); + + m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); +} + +bool LegacyCACFLayerTreeHost::resetDevice(ResetReason reason) +{ + ASSERT(m_d3dDevice); + ASSERT(m_context); + + HRESULT hr = m_d3dDevice->TestCooperativeLevel(); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_DRIVERINTERNALERROR) { + // The device cannot be reset at this time. Try again soon. + m_mustResetLostDeviceBeforeRendering = true; + return false; + } + + m_mustResetLostDeviceBeforeRendering = false; + + if (reason == LostDevice && hr == D3D_OK) { + // The device wasn't lost after all. + return true; + } + + // We can reset the device. + + // We have to release the context's D3D resrouces whenever we reset the IDirect3DDevice9 in order to + // destroy any D3DPOOL_DEFAULT resources that Core Animation has allocated (e.g., textures used + // for mask layers). See <http://msdn.microsoft.com/en-us/library/bb174425(v=VS.85).aspx>. + wkCACFContextReleaseD3DResources(m_context); + + D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); + hr = m_d3dDevice->Reset(¶meters); + + // TestCooperativeLevel told us the device may be reset now, so we should + // not be told here that the device is lost. + ASSERT(hr != D3DERR_DEVICELOST); + + initD3DGeometry(); + + return true; +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/ca/win/LegacyCACFLayerTreeHost.h b/Source/WebCore/platform/graphics/ca/win/LegacyCACFLayerTreeHost.h new file mode 100644 index 0000000..bfa530b --- /dev/null +++ b/Source/WebCore/platform/graphics/ca/win/LegacyCACFLayerTreeHost.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 Apple 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 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 LegacyCACFLayerTreeHost_h +#define LegacyCACFLayerTreeHost_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "CACFLayerTreeHost.h" + +namespace WebCore { + +// FIXME: Currently there is a LegacyCACFLayerTreeHost for each WebView and each +// has its own WKCACFContext and Direct3DDevice9, which is inefficient. +// (https://bugs.webkit.org/show_bug.cgi?id=31855) +class LegacyCACFLayerTreeHost : public CACFLayerTreeHost { +public: + static PassRefPtr<LegacyCACFLayerTreeHost> create(); + virtual ~LegacyCACFLayerTreeHost(); + +private: + LegacyCACFLayerTreeHost(); + + void initD3DGeometry(); + + // Call this when the device window has changed size or when IDirect3DDevice9::Present returns + // D3DERR_DEVICELOST. Returns true if the device was recovered, false if rendering must be + // aborted and reattempted soon. + enum ResetReason { ChangedWindowSize, LostDevice }; + bool resetDevice(ResetReason); + + void renderSoon(); + void renderTimerFired(Timer<LegacyCACFLayerTreeHost>*); + + virtual void initializeContext(void* userData, PlatformCALayer*); + virtual void resize(); + virtual bool createRenderer(); + virtual void destroyRenderer(); + virtual CFTimeInterval lastCommitTime() const; + virtual void flushContext(); + virtual void contextDidChange(); + virtual void paint(); + virtual void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>()); + + Timer<LegacyCACFLayerTreeHost> m_renderTimer; + COMPtr<IDirect3DDevice9> m_d3dDevice; + WKCACFContext* m_context; + bool m_mightBeAbleToCreateDeviceLater; + bool m_mustResetLostDeviceBeforeRendering; + +#ifndef NDEBUG + bool m_printTree; +#endif +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // LegacyCACFLayerTreeHost_h diff --git a/Source/WebCore/platform/graphics/ca/win/PlatformCAAnimationWin.cpp b/Source/WebCore/platform/graphics/ca/win/PlatformCAAnimationWin.cpp index 228bb01..6e3011b 100644 --- a/Source/WebCore/platform/graphics/ca/win/PlatformCAAnimationWin.cpp +++ b/Source/WebCore/platform/graphics/ca/win/PlatformCAAnimationWin.cpp @@ -145,11 +145,6 @@ PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(PlatformAnimationRef return adoptRef(new PlatformCAAnimation(animation)); } -PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(const PlatformCAAnimation* animation) -{ - return adoptRef(new PlatformCAAnimation(animation)); -} - PlatformCAAnimation::PlatformCAAnimation(AnimationType type, const String& keyPath) : m_type(type) { @@ -176,33 +171,33 @@ PlatformCAAnimation::PlatformCAAnimation(PlatformAnimationRef animation) m_animation = animation; } -PlatformCAAnimation::PlatformCAAnimation(const PlatformCAAnimation* animation) +PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::copy() const { - m_animation.adoptCF(CACFAnimationCreate((animation->animationType() == Basic) ? kCACFBasicAnimation : kCACFKeyframeAnimation)); - RetainPtr<CFStringRef> keyPath(AdoptCF, animation->keyPath().createCFString()); - CACFAnimationSetKeyPath(m_animation.get(), keyPath.get()); - - setBeginTime(animation->beginTime()); - setDuration(animation->duration()); - setSpeed(animation->speed()); - setTimeOffset(animation->timeOffset()); - setRepeatCount(animation->repeatCount()); - setAutoreverses(animation->autoreverses()); - setFillMode(animation->fillMode()); - setRemovedOnCompletion(animation->isRemovedOnCompletion()); - setAdditive(animation->isAdditive()); - copyTimingFunctionFrom(animation); - setValueFunction(animation->valueFunction()); - + RefPtr<PlatformCAAnimation> animation = create(animationType(), keyPath()); + + animation->setBeginTime(beginTime()); + animation->setDuration(duration()); + animation->setSpeed(speed()); + animation->setTimeOffset(timeOffset()); + animation->setRepeatCount(repeatCount()); + animation->setAutoreverses(autoreverses()); + animation->setFillMode(fillMode()); + animation->setRemovedOnCompletion(isRemovedOnCompletion()); + animation->setAdditive(isAdditive()); + animation->copyTimingFunctionFrom(this); + animation->setValueFunction(valueFunction()); + // Copy the specific Basic or Keyframe values - if (animation->animationType() == Keyframe) { - copyValuesFrom(animation); - copyKeyTimesFrom(animation); - copyTimingFunctionsFrom(animation); + if (animationType() == Keyframe) { + animation->copyValuesFrom(this); + animation->copyKeyTimesFrom(this); + animation->copyTimingFunctionsFrom(this); } else { - copyFromValueFrom(animation); - copyToValueFrom(animation); + animation->copyFromValueFrom(this); + animation->copyToValueFrom(this); } + + return animation; } PlatformCAAnimation::~PlatformCAAnimation() diff --git a/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp b/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp new file mode 100644 index 0000000..e672c2d --- /dev/null +++ b/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2011 Apple 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 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 "WKCACFViewLayerTreeHost.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "PlatformCALayer.h" +#include "SoftLinking.h" +#include <wtf/CurrentTime.h> + +typedef struct _CACFLayer* CACFLayerRef; + +namespace WebCore { + +#ifdef DEBUG_ALL +SOFT_LINK_DEBUG_LIBRARY(WebKitQuartzCoreAdditions) +#else +SOFT_LINK_LIBRARY(WebKitQuartzCoreAdditions) +#endif + +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewCreate, WKCACFViewRef, __cdecl, (), ()) +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewSetLayer, void, __cdecl, (WKCACFViewRef view, CACFLayerRef layer), (view, layer)) +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewUpdate, void, __cdecl, (WKCACFViewRef view, HWND window, const CGRect* bounds), (view, window, bounds)) +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewCanDraw, bool, __cdecl, (WKCACFViewRef view), (view)) +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewDraw, void, __cdecl, (WKCACFViewRef view), (view)) +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewFlushContext, void, __cdecl, (WKCACFViewRef view), (view)) +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewInvalidateRects, void, __cdecl, (WKCACFViewRef view, const CGRect rects[], size_t count), (view, rects, count)) +typedef void (*WKCACFViewContextDidChangeCallback)(WKCACFViewRef view, void* info); +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewSetContextDidChangeCallback, void, __cdecl, (WKCACFViewRef view, WKCACFViewContextDidChangeCallback callback, void* info), (view, callback, info)) +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewGetLastCommitTime, CFTimeInterval, __cdecl, (WKCACFViewRef view), (view)) +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewSetContextUserData, void, __cdecl, (WKCACFViewRef view, void* userData), (view, userData)) + +PassRefPtr<WKCACFViewLayerTreeHost> WKCACFViewLayerTreeHost::create() +{ + if (!WebKitQuartzCoreAdditionsLibrary()) + return 0; + + return adoptRef(new WKCACFViewLayerTreeHost); +} + +WKCACFViewLayerTreeHost::WKCACFViewLayerTreeHost() + : m_view(AdoptCF, WKCACFViewCreate()) + , m_viewNeedsUpdate(true) +{ +} + +void WKCACFViewLayerTreeHost::updateViewIfNeeded() +{ + if (!m_viewNeedsUpdate) + return; + m_viewNeedsUpdate = false; + + CGRect layerBounds = rootLayer()->bounds(); + + CGRect bounds = this->bounds(); + WKCACFViewUpdate(m_view.get(), window(), &bounds); + + if (CGRectEqualToRect(layerBounds, rootLayer()->bounds())) + return; + + // Flush the context so the layer's rendered bounds will match our bounds. + flushContext(); +} + +void WKCACFViewLayerTreeHost::contextDidChangeCallback(WKCACFViewRef view, void* info) +{ + ASSERT_ARG(view, view); + ASSERT_ARG(info, info); + + WKCACFViewLayerTreeHost* host = static_cast<WKCACFViewLayerTreeHost*>(info); + ASSERT_ARG(view, view == host->m_view); + host->contextDidChange(); +} + +void WKCACFViewLayerTreeHost::contextDidChange() +{ + // Tell the WKCACFView to start rendering now that we have some contents to render. + updateViewIfNeeded(); + + CACFLayerTreeHost::contextDidChange(); +} + +void WKCACFViewLayerTreeHost::initializeContext(void* userData, PlatformCALayer* layer) +{ + WKCACFViewSetContextUserData(m_view.get(), userData); + WKCACFViewSetLayer(m_view.get(), layer->platformLayer()); + WKCACFViewSetContextDidChangeCallback(m_view.get(), contextDidChangeCallback, this); +} + +void WKCACFViewLayerTreeHost::resize() +{ + m_viewNeedsUpdate = true; +} + +bool WKCACFViewLayerTreeHost::createRenderer() +{ + updateViewIfNeeded(); + return WKCACFViewCanDraw(m_view.get()); +} + +void WKCACFViewLayerTreeHost::destroyRenderer() +{ + m_viewNeedsUpdate = true; + WKCACFViewUpdate(m_view.get(), 0, 0); + WKCACFViewSetContextUserData(m_view.get(), 0); + WKCACFViewSetLayer(m_view.get(), 0); + WKCACFViewSetContextDidChangeCallback(m_view.get(), 0, 0); + + CACFLayerTreeHost::destroyRenderer(); +} + +CFTimeInterval WKCACFViewLayerTreeHost::lastCommitTime() const +{ + return WKCACFViewGetLastCommitTime(m_view.get()); +} + +void WKCACFViewLayerTreeHost::flushContext() +{ + WKCACFViewFlushContext(m_view.get()); +} + +void WKCACFViewLayerTreeHost::paint() +{ + updateViewIfNeeded(); + CACFLayerTreeHost::paint(); +} + +void WKCACFViewLayerTreeHost::render(const Vector<CGRect>& dirtyRects) +{ + WKCACFViewInvalidateRects(m_view.get(), dirtyRects.data(), dirtyRects.size()); + WKCACFViewDraw(m_view.get()); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.h b/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.h new file mode 100644 index 0000000..af09f76 --- /dev/null +++ b/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011 Apple 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 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 WKCACFViewLayerTreeHost_h +#define WKCACFViewLayerTreeHost_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "CACFLayerTreeHost.h" + +typedef struct _WKCACFView* WKCACFViewRef; + +namespace WebCore { + +class WKCACFViewLayerTreeHost : public CACFLayerTreeHost { +public: + static PassRefPtr<WKCACFViewLayerTreeHost> create(); + +private: + WKCACFViewLayerTreeHost(); + + void updateViewIfNeeded(); + static void contextDidChangeCallback(WKCACFViewRef, void* info); + + virtual void initializeContext(void* userData, PlatformCALayer*); + virtual void resize(); + virtual bool createRenderer(); + virtual void destroyRenderer(); + virtual void flushContext(); + virtual void contextDidChange(); + virtual void paint(); + virtual void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>()); + virtual CFTimeInterval lastCommitTime() const; + + RetainPtr<WKCACFViewRef> m_view; + bool m_viewNeedsUpdate; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WKCACFViewLayerTreeHost_h diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp index 013a4af..ee159a1 100644 --- a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp +++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp @@ -106,7 +106,11 @@ cairo_operator_t toCairoOperator(CompositeOperator op) case CompositeXOR: return CAIRO_OPERATOR_XOR; case CompositePlusDarker: +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0) + return CAIRO_OPERATOR_DARKEN; +#else return CAIRO_OPERATOR_SATURATE; +#endif case CompositeHighlight: // There is no Cairo equivalent for CompositeHighlight. return CAIRO_OPERATOR_OVER; diff --git a/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h index 50ea00f..5807102 100644 --- a/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/cairo/FontCustomPlatformData.h @@ -24,6 +24,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" +#include "FontWidthVariant.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -40,7 +41,7 @@ struct FontCustomPlatformData { public: FontCustomPlatformData(FT_Face, SharedBuffer*); ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); private: diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 51b5ee6..f7d6040 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -173,7 +173,7 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& d destx = -originx; originx = 0; } - int endx = rect.right(); + int endx = rect.maxX(); if (endx > size.width()) endx = size.width(); int numColumns = endx - originx; @@ -184,7 +184,7 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& d desty = -originy; originy = 0; } - int endy = rect.bottom(); + int endy = rect.maxY(); if (endy > size.height()) endy = size.height(); int numRows = endy - originy; @@ -239,9 +239,9 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& ASSERT(destx >= 0); ASSERT(destx < size.width()); ASSERT(originx >= 0); - ASSERT(originx <= sourceRect.right()); + ASSERT(originx <= sourceRect.maxX()); - int endx = destPoint.x() + sourceRect.right(); + int endx = destPoint.x() + sourceRect.maxX(); ASSERT(endx <= size.width()); int numColumns = endx - destx; @@ -251,9 +251,9 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& ASSERT(desty >= 0); ASSERT(desty < size.height()); ASSERT(originy >= 0); - ASSERT(originy <= sourceRect.bottom()); + ASSERT(originy <= sourceRect.maxY()); - int endy = destPoint.y() + sourceRect.bottom(); + int endy = destPoint.y() + sourceRect.maxY(); ASSERT(endy <= size.height()); int numRows = endy - desty; diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp index c19bd72..187d296 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "GraphicsContext3D.h" #include "GraphicsContextCG.h" @@ -105,7 +105,7 @@ bool GraphicsContext3D::getImageData(Image* image, decoder.setData(image->data(), true); if (!decoder.frameCount()) return false; - decodedImage = decoder.createFrameAtIndex(0); + decodedImage.adoptCF(decoder.createFrameAtIndex(0)); cgImage = decodedImage.get(); } else cgImage = image->nativeImageForCurrentFrame(); @@ -116,6 +116,34 @@ bool GraphicsContext3D::getImageData(Image* image, size_t height = CGImageGetHeight(cgImage); if (!width || !height) return false; + + // See whether the image is using an indexed color space, and if + // so, re-render it into an RGB color space. The image re-packing + // code requires color data, not color table indices, for the + // image data. + CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage); + CGColorSpaceModel model = CGColorSpaceGetModel(colorSpace); + if (model == kCGColorSpaceModelIndexed) { + RetainPtr<CGContextRef> bitmapContext; + // FIXME: we should probably manually convert the image by indexing into + // the color table, which would allow us to avoid premultiplying the + // alpha channel. Creation of a bitmap context with an alpha channel + // doesn't seem to work unless it's premultiplied. + bitmapContext.adoptCF(CGBitmapContextCreate(0, width, height, 8, width * 4, + deviceRGBColorSpaceRef(), + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + if (!bitmapContext) + return false; + + CGContextSetBlendMode(bitmapContext.get(), kCGBlendModeCopy); + CGContextSetInterpolationQuality(bitmapContext.get(), kCGInterpolationNone); + CGContextDrawImage(bitmapContext.get(), CGRectMake(0, 0, width, height), cgImage); + + // Now discard the original CG image and replace it with a copy from the bitmap context. + decodedImage.adoptCF(CGBitmapContextCreateImage(bitmapContext.get())); + cgImage = decodedImage.get(); + } + size_t bitsPerComponent = CGImageGetBitsPerComponent(cgImage); size_t bitsPerPixel = CGImageGetBitsPerPixel(cgImage); if (bitsPerComponent != 8 && bitsPerComponent != 16) @@ -168,10 +196,11 @@ bool GraphicsContext3D::getImageData(Image* image, AlphaFormat alphaFormat = AlphaFormatNone; switch (CGImageGetAlphaInfo(cgImage)) { case kCGImageAlphaPremultipliedFirst: - // This path is only accessible for MacOS earlier than 10.6.4. // This is a special case for texImage2D with HTMLCanvasElement input, - // in which case image->data() should be null. - ASSERT(!image->data()); + // in which case image->data() should be null, or indexed color models, + // where we need premultiplied alpha to create the bitmap context + // successfully. + ASSERT(!image->data() || model == kCGColorSpaceModelIndexed); if (!premultiplyAlpha) neededAlphaOp = AlphaDoUnmultiply; alphaFormat = AlphaFormatFirst; @@ -254,4 +283,4 @@ void GraphicsContext3D::paintToCanvas(const unsigned char* imagePixels, int imag } // namespace WebCore -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index bcfc37b..3591479 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -35,6 +35,7 @@ #include "KURL.h" #include "Path.h" #include "Pattern.h" +#include "ShadowBlur.h" #include <CoreGraphics/CoreGraphics.h> #include <wtf/MathExtras.h> @@ -165,9 +166,9 @@ void GraphicsContext::drawRect(const IntRect& rect) setCGFillColor(context, strokeColor(), strokeColorSpace()); CGRect rects[4] = { FloatRect(rect.x(), rect.y(), rect.width(), 1), - FloatRect(rect.x(), rect.bottom() - 1, rect.width(), 1), + FloatRect(rect.x(), rect.maxY() - 1, rect.width(), 1), FloatRect(rect.x(), rect.y() + 1, 1, rect.height() - 2), - FloatRect(rect.right() - 1, rect.y() + 1, 1, rect.height() - 2) + FloatRect(rect.maxX() - 1, rect.y() + 1, 1, rect.height() - 2) }; CGContextFillRects(context, rects, 4); if (oldFillColor != strokeColor()) @@ -563,7 +564,7 @@ void GraphicsContext::fillPath(const Path& path) CGContextClip(layerContext); m_state.fillGradient->paint(layerContext); - CGContextDrawLayerAtPoint(context, CGPointMake(rect.left(), rect.top()), layer); + CGContextDrawLayerAtPoint(context, CGPointMake(rect.x(), rect.y()), layer); CGLayerRelease(layer); } else { CGContextBeginPath(context); @@ -616,6 +617,16 @@ void GraphicsContext::strokePath(const Path& path) CGContextStrokePath(context); } +static float radiusToLegacyRadius(float radius) +{ + return radius > 8 ? 8 + 4 * sqrt((radius - 8) / 2) : radius; +} + +static bool hasBlurredShadow(const GraphicsContextState& state) +{ + return state.shadowColor.isValid() && state.shadowColor.alpha() && state.shadowBlur; +} + void GraphicsContext::fillRect(const FloatRect& rect) { if (paintingDisabled()) @@ -626,11 +637,16 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (m_state.fillGradient) { CGContextSaveGState(context); if (hasShadow()) { - CGContextConcatCTM(context, m_state.fillGradient->gradientSpaceTransform()); CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(rect.width(), rect.height()), 0); CGContextRef layerContext = CGLayerGetContext(layer); + + CGContextTranslateCTM(layerContext, -rect.x(), -rect.y()); + CGContextAddRect(layerContext, rect); + CGContextClip(layerContext); + + CGContextConcatCTM(layerContext, m_state.fillGradient->gradientSpaceTransform()); m_state.fillGradient->paint(layerContext); - CGContextDrawLayerAtPoint(context, CGPointMake(rect.left(), rect.top()), layer); + CGContextDrawLayerAtPoint(context, CGPointMake(rect.x(), rect.y()), layer); CGLayerRelease(layer); } else { CGContextClipToRect(context, rect); @@ -643,7 +659,22 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (m_state.fillPattern) applyFillPattern(); + + bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. + if (drawOwnShadow) { + float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; + // Turn off CG shadows. + CGContextSaveGState(context); + CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0); + + ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace); + contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii()); + } + CGContextFillRect(context, rect); + + if (drawOwnShadow) + CGContextRestoreGState(context); } void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) @@ -658,7 +689,21 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, color, colorSpace); + bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. + if (drawOwnShadow) { + float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; + // Turn off CG shadows. + CGContextSaveGState(context); + CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0); + + ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace); + contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii()); + } + CGContextFillRect(context, rect); + + if (drawOwnShadow) + CGContextRestoreGState(context); if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, oldFillColor, oldColorSpace); @@ -678,12 +723,72 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef Path path; path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); + + bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. + if (drawOwnShadow) { + float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; + + // Turn off CG shadows. + CGContextSaveGState(context); + CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0); + + ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace); + contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii(topLeft, topRight, bottomLeft, bottomRight)); + } + fillPath(path); + if (drawOwnShadow) + CGContextRestoreGState(context); + if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, oldFillColor, oldColorSpace); } +void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedIntRect& roundedHoleRect, const Color& color, ColorSpace colorSpace) +{ + if (paintingDisabled()) + return; + + CGContextRef context = platformContext(); + + Path path; + path.addRect(rect); + + if (!roundedHoleRect.radii().isZero()) + path.addRoundedRect(roundedHoleRect.rect(), roundedHoleRect.radii().topLeft(), roundedHoleRect.radii().topRight(), roundedHoleRect.radii().bottomLeft(), roundedHoleRect.radii().bottomRight()); + else + path.addRect(roundedHoleRect.rect()); + + WindRule oldFillRule = fillRule(); + Color oldFillColor = fillColor(); + ColorSpace oldFillColorSpace = fillColorSpace(); + + setFillRule(RULE_EVENODD); + setFillColor(color, colorSpace); + + // fillRectWithRoundedHole() assumes that the edges of rect are clipped out, so we only care about shadows cast around inside the hole. + bool drawOwnShadow = hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; + if (drawOwnShadow) { + float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; + + // Turn off CG shadows. + CGContextSaveGState(context); + CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0); + + ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace); + contextShadow.drawInsetShadow(this, rect, roundedHoleRect.rect(), roundedHoleRect.radii()); + } + + fillPath(path); + + if (drawOwnShadow) + CGContextRestoreGState(context); + + setFillRule(oldFillRule); + setFillColor(oldFillColor, oldFillColorSpace); +} + void GraphicsContext::clip(const FloatRect& rect) { if (paintingDisabled()) @@ -722,6 +827,11 @@ void GraphicsContext::clipPath(const Path& path, WindRule clipRule) CGContextClip(context); } +IntRect GraphicsContext::clipBounds() const +{ + return enclosingIntRect(CGContextGetClipBoundingBox(platformContext())); +} + void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) { if (paintingDisabled()) @@ -766,6 +876,9 @@ void GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, con { if (paintingDisabled()) return; + + // FIXME: we could avoid the shadow setup cost when we know we'll render the shadow ourselves. + CGFloat xOffset = offset.width(); CGFloat yOffset = offset.height(); CGFloat blurRadius = blur; diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 295f632..ab5907e 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -267,7 +267,7 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& i RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); unsigned char* data = result->data(); - if (rect.x() < 0 || rect.y() < 0 || rect.right() > size.width() || rect.bottom() > size.height()) + if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) memset(data, 0, result->length()); int originx = rect.x(); @@ -276,7 +276,7 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& i destx = -originx; originx = 0; } - int endx = rect.right(); + int endx = rect.maxX(); if (endx > size.width()) endx = size.width(); int numColumns = endx - originx; @@ -287,7 +287,7 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& i desty = -originy; originy = 0; } - int endy = rect.bottom(); + int endy = rect.maxY(); if (endy > size.height()) endy = size.height(); int numRows = endy - originy; @@ -377,9 +377,9 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& ASSERT(destx >= 0); ASSERT(destx < size.width()); ASSERT(originx >= 0); - ASSERT(originx <= sourceRect.right()); + ASSERT(originx <= sourceRect.maxX()); - int endx = destPoint.x() + sourceRect.right(); + int endx = destPoint.x() + sourceRect.maxX(); ASSERT(endx <= size.width()); int numColumns = endx - destx; @@ -389,9 +389,9 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& ASSERT(desty >= 0); ASSERT(desty < size.height()); ASSERT(originy >= 0); - ASSERT(originy <= sourceRect.bottom()); + ASSERT(originy <= sourceRect.maxY()); - int endy = destPoint.y() + sourceRect.bottom(); + int endy = destPoint.y() + sourceRect.maxY(); ASSERT(endy <= size.height()); int numRows = endy - desty; diff --git a/Source/WebCore/platform/graphics/cg/ImageCG.cpp b/Source/WebCore/platform/graphics/cg/ImageCG.cpp index dfee96a..08f65bd 100644 --- a/Source/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageCG.cpp @@ -204,7 +204,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F adjustedDestRect.setHeight(subimageRect.height() / yScale); image.adoptCF(CGImageCreateWithImageInRect(image.get(), subimageRect)); - if (currHeight < srcRect.bottom()) { + if (currHeight < srcRect.maxY()) { ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y); adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale); } @@ -224,7 +224,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F // Flip the coords. CGContextScaleCTM(context, 1, -1); - adjustedDestRect.setY(-adjustedDestRect.bottom()); + adjustedDestRect.setY(-adjustedDestRect.maxY()); // Adjust the color space. image = imageWithColorSpace(image.get(), styleColorSpace); diff --git a/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.cpp b/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.cpp index 92861fc..4598602 100644 --- a/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.cpp @@ -146,7 +146,10 @@ void ComplexTextController::reset(unsigned offset) // TextRun has been reached. bool ComplexTextController::nextScriptRun() { - if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun)) + // Ensure we're not pointing at the small caps buffer. + m_item.string = m_run.characters(); + + if (!hb_utf16_script_run_next(0, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun)) return false; // It is actually wrong to consider script runs at all in this code. @@ -184,11 +187,33 @@ float ComplexTextController::widthOfFullRun() void ComplexTextController::setupFontForScriptRun() { - const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false).fontData; + FontDataVariant fontDataVariant = AutoVariant; + // Determine if this script run needs to be converted to small caps. + // nextScriptRun() will always send us a run of the same case, because a + // case change while in small-caps mode always results in different + // FontData, so we only need to check the first character's case. + if (m_font->isSmallCaps() && u_islower(m_item.string[m_item.item.pos])) { + m_smallCapsString = String(m_run.data(m_item.item.pos), m_item.item.length); + m_smallCapsString.makeUpper(); + m_item.string = m_smallCapsString.characters(); + m_item.item.pos = 0; + fontDataVariant = SmallCapsVariant; + } + const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, fontDataVariant).fontData; const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData(); m_item.face = platformData.harfbuzzFace(); void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData); m_item.font->userData = opaquePlatformData; + + int size = platformData.size(); + m_item.font->x_ppem = size; + m_item.font->y_ppem = size; + // x_ and y_scale are the conversion factors from font design space (fEmSize) to 1/64th of device pixels in 16.16 format. + const int devicePixelFraction = 64; + const int multiplyFor16Dot16 = 1 << 16; + int scale = devicePixelFraction * size * multiplyFor16Dot16 / platformData.emSizeInFontUnits(); + m_item.font->x_scale = scale; + m_item.font->y_scale = scale; } HB_FontRec* ComplexTextController::allocHarfbuzzFont() @@ -197,13 +222,6 @@ HB_FontRec* ComplexTextController::allocHarfbuzzFont() memset(font, 0, sizeof(HB_FontRec)); font->klass = &harfbuzzSkiaClass; font->userData = 0; - // The values which harfbuzzSkiaClass returns are already scaled to - // pixel units, so we just set all these to one to disable further - // scaling. - font->x_ppem = 1; - font->y_ppem = 1; - font->x_scale = 1; - font->y_scale = 1; return font; } @@ -369,7 +387,7 @@ const TextRun& ComplexTextController::getNormalizedTextRun(const TextRun& origin sourceText = normalizedString.getBuffer(); } - normalizedBuffer.set(new UChar[normalizedBufferLength + 1]); + normalizedBuffer = adoptArrayPtr(new UChar[normalizedBufferLength + 1]); normalizeSpacesAndMirrorChars(sourceText, originalRun.rtl(), normalizedBuffer.get(), normalizedBufferLength); diff --git a/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.h b/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.h index a2aea60..6a93878 100644 --- a/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.h +++ b/Source/WebCore/platform/graphics/chromium/ComplexTextControllerLinux.h @@ -111,7 +111,7 @@ public: const unsigned short* logClusters() const { return m_item.log_clusters; } // return the number of code points in the current script run - const unsigned numCodePoints() const { return m_numCodePoints; } + const unsigned numCodePoints() const { return m_item.item.length; } // Return the current pixel position of the controller. const unsigned offsetX() const { return m_offsetX; } @@ -141,7 +141,6 @@ private: ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|. unsigned m_offsetX; // Offset in pixels to the start of the next script run. unsigned m_pixelWidth; // Width (in px) of the current script run. - unsigned m_numCodePoints; // Code points in current script run. unsigned m_glyphsArrayCapacity; // Current size of all the Harfbuzz arrays. OwnPtr<TextRun> m_normalizedRun; @@ -155,6 +154,7 @@ private: // each word break we accumulate error. This is the // number of pixels that we are behind so far. int m_letterSpacing; // pixels to be added after each glyph. + String m_smallCapsString; // substring of m_run converted to small caps. }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp index d00faf8..a38f6bd 100644 --- a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp @@ -343,7 +343,7 @@ void ContentLayerChromium::draw() ASSERT(sv && sv->initialized()); GraphicsContext3D* context = layerRendererContext(); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); - m_contentsTexture->bindTexture(); + bindContentsTexture(); layerRenderer()->useShader(sv->contentShaderProgram()); GLC(context, context->uniform1i(sv->shaderSamplerLocation(), 0)); @@ -361,8 +361,21 @@ void ContentLayerChromium::draw() drawOpacity(), sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); } - m_contentsTexture->unreserve(); + unreserveContentsTexture(); +} + +void ContentLayerChromium::unreserveContentsTexture() +{ + if (m_contentsTexture) + m_contentsTexture->unreserve(); } +void ContentLayerChromium::bindContentsTexture() +{ + if (m_contentsTexture) + m_contentsTexture->bindTexture(); +} + + } #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h index dc1630b..3363518 100644 --- a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h @@ -50,6 +50,9 @@ public: virtual ~ContentLayerChromium(); virtual void updateContentsIfDirty(); + virtual void unreserveContentsTexture(); + virtual void bindContentsTexture(); + virtual void draw(); virtual bool drawsContent() { return m_owner && m_owner->drawsContent(); } diff --git a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp index 2d4ca41..d956841 100644 --- a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp @@ -36,12 +36,20 @@ #include "GraphicsContext3D.h" #include "SharedGraphicsContext3D.h" +#if ENABLE(SKIA_GPU) +#include "GrContext.h" +#endif + #if USE(ACCELERATED_COMPOSITING) #include "Canvas2DLayerChromium.h" #endif namespace WebCore { +#if ENABLE(SKIA_GPU) +extern GrContext* GetGlobalGrContext(); +#endif + struct DrawingBufferInternal { unsigned offscreenColorTexture; #if USE(ACCELERATED_COMPOSITING) @@ -72,7 +80,7 @@ DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, bool multisampleExtensionSupported, bool packedDepthStencilExtensionSupported) : m_context(context) - , m_size(-1, -1) + , m_size(size) , m_multisampleExtensionSupported(multisampleExtensionSupported) , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported) , m_fbo(0) @@ -119,6 +127,8 @@ void DrawingBuffer::publishToPlatformLayer() if (m_callback) m_callback->willPublish(); + if (multisample()) + commit(); unsigned parentTexture = m_internal->platformLayer->textureId(); // FIXME: We do the copy in the canvas' (child) context so that it executes in the correct order relative to // other commands in the child context. This ensures that the parent texture always contains a complete @@ -126,6 +136,9 @@ void DrawingBuffer::publishToPlatformLayer() // happens before the compositor draws. This means we might draw stale frames sometimes. Ideally this // would insert a fence into the child command stream that the compositor could wait for. m_context->makeContextCurrent(); +#if ENABLE(SKIA_GPU) + GetGlobalGrContext()->flush(false); +#endif static_cast<Extensions3DChromium*>(m_context->getExtensions())->copyTextureToParentTextureCHROMIUM(m_colorBuffer, parentTexture); m_context->flush(); } diff --git a/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h b/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h index d120424..92fb7b3 100644 --- a/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h +++ b/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h @@ -44,8 +44,8 @@ public: virtual bool supports(const String&); virtual void ensureEnabled(const String&); virtual int getGraphicsResetStatusARB(); - virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter) { } - virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height) { } + virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter); + virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height); enum { // GL_CHROMIUM_map_sub (enums inherited from GL_ARB_vertex_buffer_object) diff --git a/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp index f4c0dee..33ebc59 100644 --- a/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp @@ -399,6 +399,28 @@ static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMET return 1; } +struct GetLastResortFallbackFontProcData { + GetLastResortFallbackFontProcData(FontCache* fontCache, const FontDescription* fontDescription, wchar_t* fontName) + : m_fontCache(fontCache) + , m_fontDescription(fontDescription) + , m_fontName(fontName) + , m_fontData(0) + { + } + + FontCache* m_fontCache; + const FontDescription* m_fontDescription; + wchar_t* m_fontName; + SimpleFontData* m_fontData; +}; + +static int CALLBACK getLastResortFallbackFontProc(const LOGFONT* logFont, const TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) +{ + GetLastResortFallbackFontProcData* procData = reinterpret_cast<GetLastResortFallbackFontProcData*>(lParam); + procData->m_fontData = fontDataFromDescriptionAndLogFont(procData->m_fontCache, *procData->m_fontDescription, *logFont, procData->m_fontName); + return !procData->m_fontData; +} + void FontCache::platformInit() { // Not needed on Windows. @@ -548,6 +570,21 @@ SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& desc return simpleFont; } + // Fall back to all the fonts installed in this PC. When a font has a + // localized name according to the system locale as well as an English name, + // both GetTextFace() and EnumFontFamilies() return the localized name. So, + // FontCache::createFontPlatformData() does not filter out the fonts + // returned by this EnumFontFamilies() call. + HDC dc = GetDC(0); + if (dc) { + GetLastResortFallbackFontProcData procData(this, &description, fallbackFontName); + EnumFontFamilies(dc, 0, getLastResortFallbackFontProc, reinterpret_cast<LPARAM>(&procData)); + ReleaseDC(0, dc); + + if (procData.m_fontData) + return procData.m_fontData; + } + ASSERT_NOT_REACHED(); return 0; } diff --git a/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 5da4d5a..e57a84c 100644 --- a/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -246,10 +246,11 @@ IntRect TransparencyAwareGlyphPainter::estimateTextBounds() for (int i = 0; i < m_numGlyphs; i++) totalWidth += lroundf(m_glyphBuffer.advanceAt(m_from + i)); - return IntRect(m_point.x() - (m_font->ascent() + m_font->descent()) / 2, - m_point.y() - m_font->ascent() - m_font->lineGap(), - totalWidth + m_font->ascent() + m_font->descent(), - m_font->lineSpacing()); + const FontMetrics& fontMetrics = m_font->fontMetrics(); + return IntRect(m_point.x() - (fontMetrics.ascent() + fontMetrics.descent()) / 2, + m_point.y() - fontMetrics.ascent() - fontMetrics.lineGap(), + totalWidth + fontMetrics.ascent() + fontMetrics.descent(), + fontMetrics.lineSpacing()); } bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs, @@ -270,7 +271,7 @@ bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs, // Windows' origin is the top-left of the bounding box, so we have // to subtract off the font ascent to get it. int x = lroundf(m_point.x() + startAdvance); - int y = lroundf(m_point.y() - m_font->ascent()); + int y = lroundf(m_point.y() - m_font->fontMetrics().ascent()); // If there is a non-blur shadow and both the fill color and shadow color // are opaque, handle without skia. @@ -354,10 +355,11 @@ IntRect TransparencyAwareUniscribePainter::estimateTextBounds() // This algorithm for estimating how much extra space we need (the text may // go outside the selection rect) is based roughly on // TransparencyAwareGlyphPainter::estimateTextBounds above. - return IntRect(left - (m_font->ascent() + m_font->descent()) / 2, - m_point.y() - m_font->ascent() - m_font->lineGap(), - (right - left) + m_font->ascent() + m_font->descent(), - m_font->lineSpacing()); + const FontMetrics& fontMetrics = m_font->fontMetrics(); + return IntRect(left - (fontMetrics.ascent() + fontMetrics.descent()) / 2, + m_point.y() - fontMetrics.ascent() - fontMetrics.lineGap(), + (right - left) + fontMetrics.ascent() + fontMetrics.descent(), + fontMetrics.lineSpacing()); } } // namespace @@ -367,6 +369,11 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } +bool Font::canExpandAroundIdeographsInComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, @@ -496,14 +503,14 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, COLORREF savedTextColor = GetTextColor(hdc); SetTextColor(hdc, textColor); state.draw(graphicsContext, hdc, static_cast<int>(point.x()) + shadowOffset.width(), - static_cast<int>(point.y() - ascent()) + shadowOffset.height(), from, to); + static_cast<int>(point.y() - fontMetrics().ascent()) + shadowOffset.height(), from, to); SetTextColor(hdc, savedTextColor); } // Uniscribe counts the coordinates from the upper left, while WebKit uses // the baseline, so we have to subtract off the ascent. state.draw(graphicsContext, hdc, static_cast<int>(point.x()), - static_cast<int>(point.y() - ascent()), from, to); + static_cast<int>(point.y() - fontMetrics().ascent()), from, to); context->canvas()->endPlatformPaint(); } diff --git a/Source/WebCore/platform/graphics/chromium/FontLinux.cpp b/Source/WebCore/platform/graphics/chromium/FontLinux.cpp index 822bbbb..823dbc9 100644 --- a/Source/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -55,6 +55,11 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } +bool Font::canExpandAroundIdeographsInComplexText() +{ + return false; +} + static bool isCanvasMultiLayered(SkCanvas* canvas) { SkCanvas::LayerIter layerIterator(canvas, false); @@ -204,7 +209,7 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRun& run, ComplexTextController controller(run, point.x(), this); controller.setWordSpacingAdjustment(wordSpacing()); controller.setLetterSpacingAdjustment(letterSpacing()); - controller.setPadding(run.padding()); + controller.setPadding(run.expansion()); if (run.rtl()) { // FIXME: this causes us to shape the text twice -- once to compute the width and then again @@ -213,7 +218,7 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRun& run, controller.reset(point.x() + controller.widthOfFullRun()); // We need to set the padding again because ComplexTextController layout consumed the value. // Fixing the above problem would help here too. - controller.setPadding(run.padding()); + controller.setPadding(run.expansion()); } while (controller.nextScriptRun()) { @@ -241,7 +246,7 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon ComplexTextController controller(run, 0, this); controller.setWordSpacingAdjustment(wordSpacing()); controller.setLetterSpacingAdjustment(letterSpacing()); - controller.setPadding(run.padding()); + controller.setPadding(run.expansion()); return controller.widthOfFullRun(); } @@ -275,11 +280,11 @@ int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, ComplexTextController controller(run, 0, this); controller.setWordSpacingAdjustment(wordSpacing()); controller.setLetterSpacingAdjustment(letterSpacing()); - controller.setPadding(run.padding()); + controller.setPadding(run.expansion()); if (run.rtl()) { // See FIXME in drawComplexText. controller.reset(controller.widthOfFullRun()); - controller.setPadding(run.padding()); + controller.setPadding(run.expansion()); } unsigned basePosition = 0; @@ -326,11 +331,11 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, ComplexTextController controller(run, 0, this); controller.setWordSpacingAdjustment(wordSpacing()); controller.setLetterSpacingAdjustment(letterSpacing()); - controller.setPadding(run.padding()); + controller.setPadding(run.expansion()); if (run.rtl()) { // See FIXME in drawComplexText. controller.reset(controller.widthOfFullRun()); - controller.setPadding(run.padding()); + controller.setPadding(run.expansion()); } // Iterate through the script runs in logical order, searching for the run covering the positions of interest. diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp index a1ea012..6f9009f 100644 --- a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -36,6 +36,7 @@ #include "PlatformBridge.h" #include "PlatformString.h" +#include "SkAdvancedTypefaceMetrics.h" #include "SkPaint.h" #include "SkTypeface.h" @@ -71,6 +72,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src) : m_typeface(src.m_typeface) , m_family(src.m_family) , m_textSize(src.m_textSize) + , m_emSizeInFontUnits(src.m_emSizeInFontUnits) , m_fakeBold(src.m_fakeBold) , m_fakeItalic(src.m_fakeItalic) , m_orientation(src.m_orientation) @@ -84,6 +86,7 @@ FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float tex : m_typeface(tf) , m_family(family) , m_textSize(textSize) + , m_emSizeInFontUnits(0) , m_fakeBold(fakeBold) , m_fakeItalic(fakeItalic) , m_orientation(orientation) @@ -96,6 +99,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) : m_typeface(src.m_typeface) , m_family(src.m_family) , m_textSize(textSize) + , m_emSizeInFontUnits(src.m_emSizeInFontUnits) , m_fakeBold(src.m_fakeBold) , m_fakeItalic(src.m_fakeItalic) , m_harfbuzzFace(src.m_harfbuzzFace) @@ -109,6 +113,17 @@ FontPlatformData::~FontPlatformData() SkSafeUnref(m_typeface); } +int FontPlatformData::emSizeInFontUnits() const +{ + if (m_emSizeInFontUnits) + return m_emSizeInFontUnits; + + SkAdvancedTypefaceMetrics* metrics = m_typeface->getAdvancedTypefaceMetrics(false); + m_emSizeInFontUnits = metrics->fEmSize; + metrics->unref(); + return m_emSizeInFontUnits; +} + FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) { SkRefCnt_SafeAssign(m_typeface, src.m_typeface); @@ -120,6 +135,7 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) m_harfbuzzFace = src.m_harfbuzzFace; m_orientation = src.m_orientation; m_style = src.m_style; + m_emSizeInFontUnits = src.m_emSizeInFontUnits; return *this; } diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h index 43771d7..d9ebb61 100644 --- a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h +++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h @@ -63,6 +63,7 @@ public: FontPlatformData(WTF::HashTableDeletedValueType) : m_typeface(hashTableDeletedFontValue()) , m_textSize(0) + , m_emSizeInFontUnits(0) , m_fakeBold(false) , m_fakeItalic(false) { } @@ -70,6 +71,7 @@ public: FontPlatformData() : m_typeface(0) , m_textSize(0) + , m_emSizeInFontUnits(0) , m_fakeBold(false) , m_fakeItalic(false) , m_orientation(Horizontal) @@ -78,6 +80,7 @@ public: FontPlatformData(float textSize, bool fakeBold, bool fakeItalic) : m_typeface(0) , m_textSize(textSize) + , m_emSizeInFontUnits(0) , m_fakeBold(fakeBold) , m_fakeItalic(fakeItalic) , m_orientation(Horizontal) @@ -107,6 +110,7 @@ public: unsigned hash() const; float size() const { return m_textSize; } + int emSizeInFontUnits() const; FontOrientation orientation() const { return m_orientation; } @@ -153,6 +157,7 @@ private: SkTypeface* m_typeface; CString m_family; float m_textSize; + mutable int m_emSizeInFontUnits; bool m_fakeBold; bool m_fakeItalic; FontOrientation m_orientation; diff --git a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp index 4393f97..953ee2f 100644 --- a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp +++ b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp @@ -83,6 +83,22 @@ struct GLES2Canvas::State { AffineTransform m_ctm; WTF::Vector<Path> m_clippingPaths; bool m_clippingEnabled; + + // Helper function for applying the state's alpha value to the given input + // color to produce a new output color. The logic is the same as + // PlatformContextSkia::State::applyAlpha(), but the type is different. + Color applyAlpha(const Color& c) + { + int s = roundf(m_alpha * 256); + if (s >= 256) + return c; + if (s < 0) + return Color(); + + int a = (c.alpha() * s) >> 8; + return Color(c.red(), c.green(), c.blue(), a); + } + }; static inline FloatPoint operator*(const FloatPoint& f, float scale) @@ -192,7 +208,7 @@ void GLES2Canvas::fillPath(const Path& path) { m_context->applyCompositeOperator(m_state->m_compositeOp); applyClipping(m_state->m_clippingEnabled); - fillPath(path, m_state->m_fillColor); + fillPath(path, m_state->applyAlpha(m_state->m_fillColor)); } void GLES2Canvas::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) @@ -214,7 +230,7 @@ void GLES2Canvas::fillRect(const FloatRect& rect, const Color& color, ColorSpace void GLES2Canvas::fillRect(const FloatRect& rect) { - fillRect(rect, m_state->m_fillColor, ColorSpaceDeviceRGB); + fillRect(rect, m_state->applyAlpha(m_state->m_fillColor), ColorSpaceDeviceRGB); } void GLES2Canvas::setFillColor(const Color& color, ColorSpace colorSpace) @@ -322,8 +338,8 @@ void GLES2Canvas::drawTexturedRect(Texture* texture, const FloatRect& srcRect, c m_context->useQuadVertices(); m_context->setActiveTexture(GraphicsContext3D::TEXTURE0); - for (int y = tileIdxRect.y(); y <= tileIdxRect.bottom(); y++) { - for (int x = tileIdxRect.x(); x <= tileIdxRect.right(); x++) + for (int y = tileIdxRect.y(); y <= tileIdxRect.maxY(); y++) { + for (int x = tileIdxRect.x(); x <= tileIdxRect.maxX(); x++) drawTexturedRectTile(texture, tiles.tileIndex(x, y), srcRect, dstRect, transform, alpha); } } diff --git a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp index 5e8d148..488230c 100644 --- a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp @@ -263,6 +263,17 @@ void GraphicsLayerChromium::setContentsOpaque(bool opaque) updateContentsOpaque(); } +void GraphicsLayerChromium::setMaskLayer(GraphicsLayer* maskLayer) +{ + if (maskLayer == m_maskLayer) + return; + + GraphicsLayer::setMaskLayer(maskLayer); + + LayerChromium* maskLayerChromium = m_maskLayer ? m_maskLayer->platformLayer() : 0; + m_layer->setMaskLayer(maskLayerChromium); +} + void GraphicsLayerChromium::setBackfaceVisibility(bool visible) { if (m_backfaceVisibility == visible) @@ -283,6 +294,15 @@ void GraphicsLayerChromium::setOpacity(float opacity) primaryLayer()->setOpacity(opacity); } +void GraphicsLayerChromium::setReplicatedByLayer(GraphicsLayer* layer) +{ + GraphicsLayerChromium* layerChromium = static_cast<GraphicsLayerChromium*>(layer); + GraphicsLayer::setReplicatedByLayer(layer); + LayerChromium* replicaLayer = layerChromium ? layerChromium->primaryLayer() : 0; + primaryLayer()->setReplicaLayer(replicaLayer); +} + + void GraphicsLayerChromium::setContentsNeedsDisplay() { if (m_contentsLayer) @@ -494,6 +514,7 @@ void GraphicsLayerChromium::updateAnchorPoint() { primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())); primaryLayer()->setAnchorPointZ(m_anchorPoint.z()); + updateLayerPosition(); } diff --git a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h index 130c25c..92c61fe 100644 --- a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h @@ -67,6 +67,7 @@ public: virtual void setPreserves3D(bool); virtual void setMasksToBounds(bool); virtual void setDrawsContent(bool); + virtual void setMaskLayer(GraphicsLayer*); virtual void setBackgroundColor(const Color&); virtual void clearBackgroundColor(); @@ -74,6 +75,8 @@ public: virtual void setContentsOpaque(bool); virtual void setBackfaceVisibility(bool); + virtual void setReplicatedByLayer(GraphicsLayer*); + virtual void setOpacity(float); virtual void setNeedsDisplay(); diff --git a/Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp b/Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp index 056d8eb..26ca64e 100644 --- a/Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp +++ b/Source/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp @@ -94,7 +94,7 @@ static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 n font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - OwnArrayPtr<uint16_t> glyphs16(new uint16_t[numGlyphs]); + OwnArrayPtr<uint16_t> glyphs16 = adoptArrayPtr(new uint16_t[numGlyphs]); if (!glyphs16.get()) return; for (unsigned i = 0; i < numGlyphs; ++i) @@ -120,7 +120,7 @@ static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); - OwnArrayPtr<uint16_t> glyphs16(new uint16_t[length]); + OwnArrayPtr<uint16_t> glyphs16 = adoptArrayPtr(new uint16_t[length]); if (!glyphs16.get()) return 0; int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16.get()); diff --git a/Source/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp b/Source/WebCore/platform/graphics/chromium/IconChromium.cpp index 16f55e2..398cc3b 100644 --- a/Source/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/IconChromium.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2008, 2009 Google Inc. All rights reserved. - * + * Copyright (c) 2011, 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: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -32,12 +32,11 @@ #include "Icon.h" #include "GraphicsContext.h" -#include "NotImplemented.h" #include "PlatformString.h" namespace WebCore { -Icon::Icon(const PlatformIcon& icon) +Icon::Icon(PassRefPtr<PlatformIcon> icon) : m_icon(icon) { } @@ -46,9 +45,14 @@ Icon::~Icon() { } -void Icon::paint(GraphicsContext*, const IntRect&) +void Icon::paint(GraphicsContext* context, const IntRect& rect) { - notImplemented(); + if (context->paintingDisabled()) + return; + + // An Icon doesn't know the color space of the file upload control. + // So use ColorSpaceDeviceRGB. + context->drawImage(m_icon.get(), ColorSpaceDeviceRGB, rect); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/IconChromiumMac.cpp b/Source/WebCore/platform/graphics/chromium/IconChromiumMac.cpp deleted file mode 100644 index a24afb2..0000000 --- a/Source/WebCore/platform/graphics/chromium/IconChromiumMac.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 THE COPYRIGHT - * OWNER 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 "Icon.h" - -#include "PassRefPtr.h" - -// FIXME: These are temporary stubs, we need real implementations which -// may come in the form of IconChromium.cpp. The Windows Chromium -// implementation is currently in IconWin.cpp. - -namespace WebCore { - -Icon::~Icon() -{ -} - -void Icon::paint(GraphicsContext*, const IntRect&) -{ -} - -} diff --git a/Source/WebCore/platform/graphics/chromium/IconChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/IconChromiumWin.cpp deleted file mode 100644 index e958d4a..0000000 --- a/Source/WebCore/platform/graphics/chromium/IconChromiumWin.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 THE COPYRIGHT - * OWNER 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 "Icon.h" - -#include <windows.h> -#include <shellapi.h> - -#include "GraphicsContext.h" -#include "PlatformContextSkia.h" -#include "PlatformString.h" -#include "SkiaUtils.h" - -namespace WebCore { - -Icon::Icon(const PlatformIcon& icon) - : m_icon(icon) -{ -} - -Icon::~Icon() -{ - if (m_icon) - DestroyIcon(m_icon); -} - -void Icon::paint(GraphicsContext* context, const IntRect& rect) -{ - if (context->paintingDisabled()) - return; - - HDC hdc = context->platformContext()->canvas()->beginPlatformPaint(); - DrawIconEx(hdc, rect.x(), rect.y(), m_icon, rect.width(), rect.height(), 0, 0, DI_NORMAL); - context->platformContext()->canvas()->endPlatformPaint(); -} - -} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp index b7ab098..8d01d9b 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -143,6 +143,7 @@ PassRefPtr<LayerChromium> LayerChromium::create(GraphicsLayerChromium* owner) LayerChromium::LayerChromium(GraphicsLayerChromium* owner) : m_owner(owner) , m_contentsDirty(false) + , m_maskLayer(0) , m_targetRenderSurface(0) , m_superlayer(0) , m_anchorPoint(0.5, 0.5) @@ -162,6 +163,7 @@ LayerChromium::LayerChromium(GraphicsLayerChromium* owner) , m_drawDepth(0) , m_layerRenderer(0) , m_renderSurface(0) + , m_replicaLayer(0) { } @@ -433,9 +435,7 @@ void LayerChromium::drawTexturedQuad(GraphicsContext3D* context, const Transform renderMatrix.scale3d(width, height, 1); // Apply the projection matrix before sending the transform over to the shader. - renderMatrix.multiply(projectionMatrix); - - toGLMatrix(&glMatrix[0], renderMatrix); + toGLMatrix(&glMatrix[0], projectionMatrix * renderMatrix); GLC(context, context->uniformMatrix4fv(matrixLocation, false, &glMatrix[0], 1)); @@ -457,8 +457,7 @@ void LayerChromium::drawDebugBorder() layerRenderer()->useShader(sv->borderShaderProgram()); TransformationMatrix renderMatrix = drawTransform(); renderMatrix.scale3d(bounds().width(), bounds().height(), 1); - renderMatrix.multiply(layerRenderer()->projectionMatrix()); - toGLMatrix(&glMatrix[0], renderMatrix); + toGLMatrix(&glMatrix[0], layerRenderer()->projectionMatrix() * renderMatrix); GraphicsContext3D* context = layerRendererContext(); GLC(context, context->uniformMatrix4fv(sv->borderShaderMatrixLocation(), false, &glMatrix[0], 1)); diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.h b/Source/WebCore/platform/graphics/chromium/LayerChromium.h index a0a690f..5c7e2b1 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.h @@ -112,6 +112,9 @@ public: void setName(const String& name) { m_name = name; } String name() const { return m_name; } + void setMaskLayer(LayerChromium* maskLayer) { m_maskLayer = maskLayer; } + LayerChromium* maskLayer() const { return m_maskLayer.get(); } + void setNeedsDisplay(const FloatRect& dirtyRect); void setNeedsDisplay(); const FloatRect& dirtyRect() const { return m_dirtyRect; } @@ -152,12 +155,17 @@ public: void setOwner(GraphicsLayerChromium* owner) { m_owner = owner; } + void setReplicaLayer(LayerChromium* layer) { m_replicaLayer = layer; } + LayerChromium* replicaLayer() { return m_replicaLayer; } + // Returns the rect containtaining this layer in the current view's coordinate system. const IntRect getDrawRect() const; // These methods typically need to be overwritten by derived classes. virtual bool drawsContent() { return false; } virtual void updateContentsIfDirty() { } + virtual void unreserveContentsTexture() { } + virtual void bindContentsTexture() { } virtual void draw() { } void drawDebugBorder(); @@ -222,6 +230,8 @@ protected: FloatRect m_dirtyRect; bool m_contentsDirty; + RefPtr<LayerChromium> m_maskLayer; + // Render surface this layer draws into. This is a surface that can belong // either to this layer (if m_targetRenderSurface == m_renderSurface) or // to an ancestor of this layer. The target render surface determines the @@ -298,6 +308,9 @@ private: // Hierarchical bounding rect containing the layer and its descendants. IntRect m_drawableContentRect; + // Replica layer used for reflections. + LayerChromium* m_replicaLayer; + String m_name; }; diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp index 90eac74..f5548c9 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -143,20 +143,19 @@ void LayerRendererChromium::useShader(unsigned programId) IntRect LayerRendererChromium::verticalScrollbarRect(const IntRect& visibleRect, const IntRect& contentRect) { - IntRect verticalScrollbar(IntPoint(contentRect.right(), contentRect.y()), IntSize(visibleRect.width() - contentRect.width(), visibleRect.height())); + IntRect verticalScrollbar(IntPoint(contentRect.maxX(), contentRect.y()), IntSize(visibleRect.width() - contentRect.width(), visibleRect.height())); return verticalScrollbar; } IntRect LayerRendererChromium::horizontalScrollbarRect(const IntRect& visibleRect, const IntRect& contentRect) { - IntRect horizontalScrollbar(IntPoint(contentRect.x(), contentRect.bottom()), IntSize(visibleRect.width(), visibleRect.height() - contentRect.height())); + IntRect horizontalScrollbar(IntPoint(contentRect.x(), contentRect.maxY()), IntSize(visibleRect.width(), visibleRect.height() - contentRect.height())); return horizontalScrollbar; } void LayerRendererChromium::invalidateRootLayerRect(const IntRect& dirtyRect, const IntRect& visibleRect, const IntRect& contentRect) { - if (contentRect.intersects(dirtyRect)) - m_rootLayerTiler->invalidateRect(dirtyRect); + m_rootLayerTiler->invalidateRect(dirtyRect); if (m_horizontalScrollbarTiler) { IntRect scrollbar = horizontalScrollbarRect(visibleRect, contentRect); if (dirtyRect.intersects(scrollbar)) { @@ -266,6 +265,11 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect // Re-enable color writes to layers, which may be partially transparent. m_context->colorMask(true, true, true, true); + // Recheck that we still have a root layer. This may become null if + // compositing gets turned off during a paint operation. + if (!m_rootLayer) + return; + // Set the root visible/content rects --- used by subsequent drawLayers calls. m_rootVisibleRect = visibleRect; m_rootContentRect = contentRect; @@ -346,8 +350,8 @@ void LayerRendererChromium::setRootLayer(PassRefPtr<LayerChromium> layer) void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& rect) { - ASSERT(rect.right() <= rootLayerTextureSize().width() - && rect.bottom() <= rootLayerTextureSize().height()); + ASSERT(rect.maxX() <= rootLayerTextureSize().width() + && rect.maxY() <= rootLayerTextureSize().height()); if (!pixels) return; @@ -388,7 +392,7 @@ bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const Transform // bounds into clip space. TransformationMatrix renderMatrix = matrix; renderMatrix.scale3d(layer->bounds().width(), layer->bounds().height(), 1); - renderMatrix.multiply(m_projectionMatrix); + renderMatrix = m_projectionMatrix * renderMatrix; FloatRect layerRect(-0.5, -0.5, 1, 1); FloatRect mappedRect = renderMatrix.mapRect(layerRect); @@ -434,12 +438,12 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr // LT = Tr[l] layerLocalTransform.translate3d(position.x(), position.y(), layer->anchorPointZ()); // LT = Tr[l] * M[l] - layerLocalTransform.multLeft(layer->transform()); + layerLocalTransform.multiply(layer->transform()); // LT = Tr[l] * M[l] * Tr[c] layerLocalTransform.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ()); TransformationMatrix combinedTransform = parentMatrix; - combinedTransform = combinedTransform.multLeft(layerLocalTransform); + combinedTransform = combinedTransform.multiply(layerLocalTransform); FloatRect layerRect(-0.5 * layer->bounds().width(), -0.5 * layer->bounds().height(), layer->bounds().width(), layer->bounds().height()); IntRect transformedLayerRect; @@ -448,12 +452,17 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr // these conditions hold: // 1. The layer clips its descendants and its transform is not a simple translation. // 2. If the layer has opacity != 1 and does not have a preserves-3d transform style. + // 3. The layer uses a mask + // 4. The layer has a replica (used for reflections) // If a layer preserves-3d then we don't create a RenderSurface for it to avoid flattening // out its children. The opacity value of the children layers is multiplied by the opacity // of their parent. bool useSurfaceForClipping = layer->masksToBounds() && !isScaleOrTranslation(combinedTransform); bool useSurfaceForOpacity = layer->opacity() != 1 && !layer->preserves3D(); - if ((useSurfaceForClipping || useSurfaceForOpacity) && layer->descendantsDrawContent()) { + bool useSurfaceForMasking = layer->maskLayer(); + bool useSurfaceForReflection = layer->replicaLayer(); + if (((useSurfaceForClipping || useSurfaceForOpacity) && layer->descendantsDrawContent()) + || useSurfaceForMasking || useSurfaceForReflection) { RenderSurfaceChromium* renderSurface = layer->m_renderSurface.get(); if (!renderSurface) renderSurface = layer->createRenderSurface(); @@ -487,6 +496,18 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr renderSurface->m_layerList.clear(); + if (layer->maskLayer()) { + renderSurface->m_maskLayer = layer->maskLayer(); + layer->maskLayer()->setLayerRenderer(this); + layer->maskLayer()->m_targetRenderSurface = renderSurface; + } else + renderSurface->m_maskLayer = 0; + + if (layer->replicaLayer() && layer->replicaLayer()->maskLayer()) { + layer->replicaLayer()->maskLayer()->setLayerRenderer(this); + layer->replicaLayer()->maskLayer()->m_targetRenderSurface = renderSurface; + } + renderSurfaceLayerList.append(layer); } else { // DT = M[p] * LT @@ -540,7 +561,7 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr } // Apply the sublayer transform at the center of the layer. - sublayerMatrix.multLeft(layer->sublayerTransform()); + sublayerMatrix.multiply(layer->sublayerTransform()); // The origin of the sublayers is the top left corner of the layer, not the // center. The matrix passed down to the sublayers is therefore: @@ -558,16 +579,13 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr if (sublayer->m_renderSurface) { RenderSurfaceChromium* sublayerRenderSurface = sublayer->m_renderSurface.get(); - const IntRect& contentRect = sublayerRenderSurface->contentRect(); - FloatRect sublayerRect(-0.5 * contentRect.width(), -0.5 * contentRect.height(), - contentRect.width(), contentRect.height()); - layer->m_drawableContentRect.unite(enclosingIntRect(sublayerRenderSurface->m_drawTransform.mapRect(sublayerRect))); + layer->m_drawableContentRect.unite(enclosingIntRect(sublayerRenderSurface->drawableContentRect())); descendants.append(sublayer); } else layer->m_drawableContentRect.unite(sublayer->m_drawableContentRect); } - if (layer->masksToBounds()) + if (layer->masksToBounds() || useSurfaceForMasking) layer->m_drawableContentRect.intersect(transformedLayerRect); if (layer->m_renderSurface && layer != m_rootLayer) { @@ -577,9 +595,13 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr // Restrict the RenderSurface size to the portion that's visible. FloatSize centerOffsetDueToClipping; - renderSurface->m_contentRect.intersect(layer->m_scissorRect); - FloatPoint clippedSurfaceCenter = renderSurface->contentRectCenter(); - centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter; + // Don't clip if the layer is reflected as the reflection shouldn't be + // clipped. + if (!layer->replicaLayer()) { + renderSurface->m_contentRect.intersect(layer->m_scissorRect); + FloatPoint clippedSurfaceCenter = renderSurface->contentRectCenter(); + centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter; + } // The RenderSurface backing texture cannot exceed the maximum supported // texture size. @@ -596,6 +618,15 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr // Adjust the origin of the transform to be the center of the render surface. renderSurface->m_drawTransform = renderSurface->m_originTransform; renderSurface->m_drawTransform.translate3d(surfaceCenter.x() + centerOffsetDueToClipping.width(), surfaceCenter.y() + centerOffsetDueToClipping.height(), 0); + + // Compute the transformation matrix used to draw the replica of the render + // surface. + if (layer->replicaLayer()) { + renderSurface->m_replicaDrawTransform = renderSurface->m_originTransform; + renderSurface->m_replicaDrawTransform.translate3d(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y(), 0); + renderSurface->m_replicaDrawTransform.multiply(layer->replicaLayer()->transform()); + renderSurface->m_replicaDrawTransform.translate3d(surfaceCenter.x() - anchorPoint.x() * bounds.width(), surfaceCenter.y() - anchorPoint.y() * bounds.height(), 0); + } } // Compute the depth value of the center of the layer which will be used when @@ -682,10 +713,10 @@ void LayerRendererChromium::drawLayer(LayerChromium* layer, RenderSurfaceChromiu if (!isLayerVisible) return; - // FIXME: Need to take into account the transform of the containing - // RenderSurface here, otherwise single-sided layers that draw on - // transformed surfaces won't always be culled properly. - if (!layer->doubleSided() && layer->m_drawTransform.m33() < 0) + // FIXME: Need to take into account the commulative render surface transforms all the way from + // the default render surface in order to determine visibility. + TransformationMatrix combinedDrawMatrix = (layer->m_renderSurface ? layer->m_renderSurface->drawTransform().multiply(layer->m_drawTransform) : layer->m_drawTransform); + if (!layer->doubleSided() && combinedDrawMatrix.m33() < 0) return; if (layer->drawsContent()) { @@ -711,7 +742,7 @@ void LayerRendererChromium::setScissorToRect(const IntRect& scissorRect) // But, if rendering to offscreen texture, we reverse our sense of 'upside down'. int scissorY; if (m_currentRenderSurface == m_defaultRenderSurface && !m_compositeOffscreen) - scissorY = m_currentRenderSurface->m_contentRect.height() - (scissorRect.bottom() - m_currentRenderSurface->m_contentRect.y()); + scissorY = m_currentRenderSurface->m_contentRect.height() - (scissorRect.maxY() - m_currentRenderSurface->m_contentRect.y()); else scissorY = scissorRect.y() - m_currentRenderSurface->m_contentRect.y(); GLC(m_context.get(), m_context->scissor(scissorX, scissorY, scissorRect.width(), scissorRect.height())); @@ -737,9 +768,9 @@ bool LayerRendererChromium::checkTextureSize(const IntSize& textureSize) void LayerRendererChromium::setDrawViewportRect(const IntRect& drawRect, bool flipY) { if (flipY) - m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.right(), drawRect.bottom(), drawRect.y()); + m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.maxX(), drawRect.maxY(), drawRect.y()); else - m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.right(), drawRect.y(), drawRect.bottom()); + m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.maxX(), drawRect.y(), drawRect.maxY()); GLC(m_context.get(), m_context->viewport(0, 0, drawRect.width(), drawRect.height())); } diff --git a/Source/WebCore/platform/graphics/chromium/LayerTexture.cpp b/Source/WebCore/platform/graphics/chromium/LayerTexture.cpp index 32bfa0b..23cb4b3 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerTexture.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerTexture.cpp @@ -79,6 +79,7 @@ void LayerTexture::unreserve() void LayerTexture::bindTexture() { + ASSERT(m_textureManager->hasTexture(m_token)); m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId); } diff --git a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp index 6b65e66..e28c084 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp @@ -145,8 +145,8 @@ void LayerTilerChromium::contentRectToTileIndices(const IntRect& contentRect, in left = layerRect.x() / m_tileSize.width(); top = layerRect.y() / m_tileSize.height(); - right = (layerRect.right() - 1) / m_tileSize.width(); - bottom = (layerRect.bottom() - 1) / m_tileSize.height(); + right = (layerRect.maxX() - 1) / m_tileSize.width(); + bottom = (layerRect.maxY() - 1) / m_tileSize.height(); } IntRect LayerTilerChromium::contentRectToLayerRect(const IntRect& contentRect) const @@ -272,7 +272,11 @@ void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& cont // Get the contents of the updated rect. const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); ASSERT(bitmap.width() == paintRect.width() && bitmap.height() == paintRect.height()); + if (bitmap.width() != paintRect.width() || bitmap.height() != paintRect.height()) + CRASH(); uint8_t* paintPixels = static_cast<uint8_t*>(bitmap.getPixels()); + if (!paintPixels) + CRASH(); #elif PLATFORM(CG) Vector<uint8_t> canvasPixels; int rowBytes = 4 * paintRect.width(); @@ -299,9 +303,15 @@ void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& cont #error "Need to implement for your platform." #endif + // Painting could cause compositing to get turned off, which may cause the tiler to become invalidated mid-update. + if (!m_tiles.size()) + return; + for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { Tile* tile = m_tiles[tileIndex(i, j)].get(); + if (!tile) + CRASH(); if (!tile->dirty()) continue; @@ -320,13 +330,21 @@ void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& cont // Calculate tile-space rectangle to upload into. IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y()), sourceRect.size()); - ASSERT(destRect.x() >= 0); - ASSERT(destRect.y() >= 0); + if (destRect.x() < 0) + CRASH(); + if (destRect.y() < 0) + CRASH(); // Offset from paint rectangle to this tile's dirty rectangle. IntPoint paintOffset(sourceRect.x() - paintRect.x(), sourceRect.y() - paintRect.y()); - ASSERT(paintOffset.x() >= 0); - ASSERT(paintOffset.y() >= 0); + if (paintOffset.x() < 0) + CRASH(); + if (paintOffset.y() < 0) + CRASH(); + if (paintOffset.x() + destRect.width() > paintRect.width()) + CRASH(); + if (paintOffset.y() + destRect.height() > paintRect.height()) + CRASH(); uint8_t* pixelSource; if (paintRect.width() == sourceRect.width() && !paintOffset.x()) @@ -357,7 +375,7 @@ void LayerTilerChromium::setLayerPosition(const IntPoint& layerPosition) void LayerTilerChromium::draw(const IntRect& contentRect) { - if (m_skipsDraw) + if (m_skipsDraw || !m_tiles.size()) return; // We reuse the shader program used by ContentLayerChromium. @@ -394,6 +412,9 @@ void LayerTilerChromium::resizeLayer(const IntSize& size) int width = (size.width() + m_tileSize.width() - 1) / m_tileSize.width(); int height = (size.height() + m_tileSize.height() - 1) / m_tileSize.height(); + if (height && (width > INT_MAX / height)) + CRASH(); + Vector<OwnPtr<Tile> > newTiles; newTiles.resize(width * height); for (int j = 0; j < m_layerTileSize.height(); ++j) @@ -409,7 +430,7 @@ void LayerTilerChromium::growLayerToContain(const IntRect& contentRect) { // Grow the tile array to contain this content rect. IntRect layerRect = contentRectToLayerRect(contentRect); - IntSize layerSize = IntSize(layerRect.right(), layerRect.bottom()); + IntSize layerSize = IntSize(layerRect.maxX(), layerRect.maxY()); IntSize newSize = layerSize.expandedTo(m_layerSize); resizeLayer(newSize); diff --git a/Source/WebCore/platform/graphics/chromium/PlatformIcon.h b/Source/WebCore/platform/graphics/chromium/PlatformIcon.h index 51613b8..b485917 100644 --- a/Source/WebCore/platform/graphics/chromium/PlatformIcon.h +++ b/Source/WebCore/platform/graphics/chromium/PlatformIcon.h @@ -31,11 +31,11 @@ #ifndef PlatformIcon_h #define PlatformIcon_h -typedef struct HICON__* HICON; - namespace WebCore { -typedef HICON PlatformIcon; +class Image; + +typedef Image PlatformIcon; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp index 696828f..b3ce9d7 100644 --- a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp @@ -38,15 +38,17 @@ namespace WebCore { RenderSurfaceChromium::SharedValues::SharedValues(GraphicsContext3D* context) : m_context(context) , m_shaderProgram(0) + , m_maskShaderProgram(0) , m_shaderSamplerLocation(-1) , m_shaderMatrixLocation(-1) , m_shaderAlphaLocation(-1) + , m_maskShaderSamplerLocation(-1) + , m_maskShaderMaskSamplerLocation(-1) + , m_maskShaderMatrixLocation(-1) + , m_maskShaderAlphaLocation(-1) , m_initialized(false) { - // The following program composites layers whose contents are the results of a previous - // render operation and therefore doesn't perform any color swizzling. It is used - // in scrolling and for compositing offscreen textures. - char renderSurfaceVertexShaderString[] = + char vertexShaderString[] = "attribute vec4 a_position; \n" "attribute vec2 a_texCoord; \n" "uniform mat4 matrix; \n" @@ -56,7 +58,7 @@ RenderSurfaceChromium::SharedValues::SharedValues(GraphicsContext3D* context) " gl_Position = matrix * a_position; \n" " v_texCoord = a_texCoord; \n" "} \n"; - char renderSurfaceFragmentShaderString[] = + char fragmentShaderString[] = "precision mediump float; \n" "varying vec2 v_texCoord; \n" "uniform sampler2D s_texture; \n" @@ -66,9 +68,22 @@ RenderSurfaceChromium::SharedValues::SharedValues(GraphicsContext3D* context) " vec4 texColor = texture2D(s_texture, v_texCoord); \n" " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n" "} \n"; + char fragmentShaderWithMaskString[] = + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D s_texture; \n" + "uniform sampler2D s_mask; \n" + "uniform float alpha; \n" + "void main() \n" + "{ \n" + " vec4 texColor = texture2D(s_texture, v_texCoord); \n" + " vec4 maskColor = texture2D(s_mask, v_texCoord); \n" + " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha * maskColor.w; \n" + "} \n"; - m_shaderProgram = LayerChromium::createShaderProgram(m_context, renderSurfaceVertexShaderString, renderSurfaceFragmentShaderString); - if (!m_shaderProgram) { + m_shaderProgram = LayerChromium::createShaderProgram(m_context, vertexShaderString, fragmentShaderString); + m_maskShaderProgram = LayerChromium::createShaderProgram(m_context, vertexShaderString, fragmentShaderWithMaskString); + if (!m_shaderProgram || !m_maskShaderProgram) { LOG_ERROR("RenderSurfaceChromium: Failed to create shader program"); return; } @@ -76,10 +91,24 @@ RenderSurfaceChromium::SharedValues::SharedValues(GraphicsContext3D* context) GLC(m_context, m_shaderSamplerLocation = m_context->getUniformLocation(m_shaderProgram, "s_texture")); GLC(m_context, m_shaderMatrixLocation = m_context->getUniformLocation(m_shaderProgram, "matrix")); GLC(m_context, m_shaderAlphaLocation = m_context->getUniformLocation(m_shaderProgram, "alpha")); - if (m_shaderSamplerLocation == -1 || m_shaderMatrixLocation == -1 || m_shaderAlphaLocation == -1) { - LOG_ERROR("Failed to initialize texture layer shader."); + + GLC(m_context, m_maskShaderSamplerLocation = m_context->getUniformLocation(m_maskShaderProgram, "s_texture")); + GLC(m_context, m_maskShaderMaskSamplerLocation = m_context->getUniformLocation(m_maskShaderProgram, "s_mask")); + GLC(m_context, m_maskShaderMatrixLocation = m_context->getUniformLocation(m_maskShaderProgram, "matrix")); + GLC(m_context, m_maskShaderAlphaLocation = m_context->getUniformLocation(m_maskShaderProgram, "alpha")); + + if (m_shaderSamplerLocation == -1 || m_shaderMatrixLocation == -1 || m_shaderAlphaLocation == -1 + || m_maskShaderSamplerLocation == -1 || m_maskShaderMaskSamplerLocation == -1 || m_maskShaderMatrixLocation == -1 || m_maskShaderAlphaLocation == -1) { + LOG_ERROR("Failed to initialize render surface shaders."); return; } + + GLC(m_context, m_context->useProgram(m_shaderProgram)); + GLC(m_context, m_context->uniform1i(m_shaderSamplerLocation, 0)); + GLC(m_context, m_context->useProgram(m_maskShaderProgram)); + GLC(m_context, m_context->uniform1i(m_maskShaderSamplerLocation, 0)); + GLC(m_context, m_context->uniform1i(m_maskShaderMaskSamplerLocation, 1)); + GLC(m_context, m_context->useProgram(0)); m_initialized = true; } @@ -87,10 +116,13 @@ RenderSurfaceChromium::SharedValues::~SharedValues() { if (m_shaderProgram) GLC(m_context, m_context->deleteProgram(m_shaderProgram)); + if (m_maskShaderProgram) + GLC(m_context, m_context->deleteProgram(m_maskShaderProgram)); } RenderSurfaceChromium::RenderSurfaceChromium(LayerChromium* owningLayer) : m_owningLayer(owningLayer) + , m_maskLayer(0) , m_skipsDraw(false) { } @@ -116,6 +148,17 @@ LayerRendererChromium* RenderSurfaceChromium::layerRenderer() return m_owningLayer->layerRenderer(); } +FloatRect RenderSurfaceChromium::drawableContentRect() const +{ + FloatRect localContentRect(-0.5 * m_contentRect.width(), -0.5 * m_contentRect.height(), + m_contentRect.width(), m_contentRect.height()); + FloatRect drawableContentRect = m_drawTransform.mapRect(localContentRect); + if (m_owningLayer->replicaLayer()) + drawableContentRect.unite(m_replicaDrawTransform.mapRect(localContentRect)); + + return drawableContentRect; +} + bool RenderSurfaceChromium::prepareContentsTexture() { IntSize requiredSize(m_contentRect.size()); @@ -136,24 +179,69 @@ bool RenderSurfaceChromium::prepareContentsTexture() return true; } -void RenderSurfaceChromium::draw() +void RenderSurfaceChromium::drawSurface(LayerChromium* maskLayer, const TransformationMatrix& drawTransform) { - if (m_skipsDraw || !m_contentsTexture) - return; - - m_contentsTexture->bindTexture(); + GraphicsContext3D* context3D = layerRenderer()->context(); + int shaderMatrixLocation = -1; + int shaderAlphaLocation = -1; const RenderSurfaceChromium::SharedValues* sv = layerRenderer()->renderSurfaceSharedValues(); ASSERT(sv && sv->initialized()); + bool useMask = false; + if (maskLayer && maskLayer->drawsContent()) { + maskLayer->updateContentsIfDirty(); + if (!maskLayer->bounds().isEmpty()) { + context3D->makeContextCurrent(); + layerRenderer()->useShader(sv->maskShaderProgram()); + GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0)); + m_contentsTexture->bindTexture(); + GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE1)); + maskLayer->bindContentsTexture(); + GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0)); + shaderMatrixLocation = sv->maskShaderMatrixLocation(); + shaderAlphaLocation = sv->maskShaderAlphaLocation(); + useMask = true; + } + } + + if (!useMask) { + layerRenderer()->useShader(sv->shaderProgram()); + m_contentsTexture->bindTexture(); + shaderMatrixLocation = sv->shaderMatrixLocation(); + shaderAlphaLocation = sv->shaderAlphaLocation(); + } + + LayerChromium::drawTexturedQuad(layerRenderer()->context(), layerRenderer()->projectionMatrix(), drawTransform, + m_contentRect.width(), m_contentRect.height(), m_drawOpacity, + shaderMatrixLocation, shaderAlphaLocation); + + m_contentsTexture->unreserve(); + + if (maskLayer) + maskLayer->unreserveContentsTexture(); +} + +void RenderSurfaceChromium::draw() +{ + if (m_skipsDraw || !m_contentsTexture) + return; + // FIXME: By using the same RenderSurface for both the content and its reflection, + // it's currently not possible to apply a separate mask to the reflection layer + // or correctly handle opacity in reflections (opacity must be applied after drawing + // both the layer and its reflection). The solution is to introduce yet another RenderSurface + // to draw the layer and its reflection in. For now we only apply a separate reflection + // mask if the contents don't have a mask of their own. + LayerChromium* replicaMaskLayer = m_maskLayer; + if (!m_maskLayer && m_owningLayer->replicaLayer()) + replicaMaskLayer = m_owningLayer->replicaLayer()->maskLayer(); - layerRenderer()->useShader(sv->shaderProgram()); layerRenderer()->setScissorToRect(m_scissorRect); - LayerChromium::drawTexturedQuad(layerRenderer()->context(), layerRenderer()->projectionMatrix(), m_drawTransform, - m_contentRect.width(), m_contentRect.height(), m_drawOpacity, - sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); + // Reflection draws before the layer. + if (m_owningLayer->replicaLayer()) + drawSurface(replicaMaskLayer, m_replicaDrawTransform); - m_contentsTexture->unreserve(); + drawSurface(m_maskLayer, m_drawTransform); } } diff --git a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h index 689a6eb..b1f6a5c 100644 --- a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h +++ b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h @@ -55,6 +55,11 @@ public: FloatPoint contentRectCenter() const { return FloatRect(m_contentRect).center(); } IntRect contentRect() const { return m_contentRect; } + // Returns the rect that encloses the RenderSurface including any reflection. + FloatRect drawableContentRect() const; + + TransformationMatrix drawTransform() const { return m_drawTransform; } + // Stores values that are shared between instances of this class that are // associated with the same LayerRendererChromium (and hence the same GL // context). @@ -64,30 +69,44 @@ public: ~SharedValues(); unsigned shaderProgram() const { return m_shaderProgram; } + unsigned maskShaderProgram() const { return m_maskShaderProgram; } int shaderSamplerLocation() const { return m_shaderSamplerLocation; } int shaderMatrixLocation() const { return m_shaderMatrixLocation; } int shaderAlphaLocation() const { return m_shaderAlphaLocation; } + int maskShaderSamplerLocation() const { return m_maskShaderSamplerLocation; } + int maskShaderMaskSamplerLocation() const { return m_maskShaderMaskSamplerLocation; } + int maskShaderMatrixLocation() const { return m_maskShaderMatrixLocation; } + int maskShaderAlphaLocation() const { return m_maskShaderAlphaLocation; } bool initialized() const { return m_initialized; } private: GraphicsContext3D* m_context; unsigned m_shaderProgram; + unsigned m_maskShaderProgram; int m_shaderSamplerLocation; int m_shaderMatrixLocation; int m_shaderAlphaLocation; + int m_maskShaderSamplerLocation; + int m_maskShaderMaskSamplerLocation; + int m_maskShaderMatrixLocation; + int m_maskShaderAlphaLocation; bool m_initialized; }; private: LayerRendererChromium* layerRenderer(); + void drawSurface(LayerChromium* maskLayer, const TransformationMatrix& drawTransform); LayerChromium* m_owningLayer; + LayerChromium* m_maskLayer; + IntRect m_contentRect; bool m_skipsDraw; OwnPtr<LayerTexture> m_contentsTexture; float m_drawOpacity; TransformationMatrix m_drawTransform; + TransformationMatrix m_replicaDrawTransform; TransformationMatrix m_originTransform; IntRect m_scissorRect; Vector<LayerChromium*> m_layerList; diff --git a/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp index c23c586..1450c5a 100644 --- a/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp @@ -54,14 +54,9 @@ static inline float scaleEmToUnits(float x, int unitsPerEm) void SimpleFontData::platformInit() { if (!m_platformData.size()) { - m_ascent = 0; - m_descent = 0; - m_lineGap = 0; - m_lineSpacing = 0; + m_fontMetrics.reset(); m_avgCharWidth = 0; m_maxCharWidth = 0; - m_xHeight = 0; - m_unitsPerEm = 0; return; } @@ -82,10 +77,11 @@ void SimpleFontData::platformInit() m_avgCharWidth = textMetric.tmAveCharWidth; m_maxCharWidth = textMetric.tmMaxCharWidth; - m_ascent = textMetric.tmAscent; - m_descent = textMetric.tmDescent; - m_lineGap = textMetric.tmExternalLeading; - m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. + // FIXME: Access ascent/descent/lineGap with floating point precision. + float ascent = textMetric.tmAscent; + float descent = textMetric.tmDescent; + float lineGap = textMetric.tmExternalLeading; + float xHeight = ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. OUTLINETEXTMETRIC outlineTextMetric; if (GetOutlineTextMetrics(dc, sizeof(outlineTextMetric), &outlineTextMetric) > 0) { @@ -94,10 +90,14 @@ void SimpleFontData::platformInit() MAT2 identityMatrix = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; DWORD len = GetGlyphOutlineW(dc, 'x', GGO_METRICS, &glyphMetrics, 0, 0, &identityMatrix); if (len != GDI_ERROR && glyphMetrics.gmBlackBoxY > 0) - m_xHeight = static_cast<float>(glyphMetrics.gmBlackBoxY); + xHeight = static_cast<float>(glyphMetrics.gmBlackBoxY); } - m_lineSpacing = m_ascent + m_descent + m_lineGap; + m_fontMetrics.setAscent(ascent); + m_fontMetrics.setDescent(descent); + m_fontMetrics.setLineGap(lineGap); + m_fontMetrics.setXHeight(xHeight); + m_fontMetrics.setLineSpacing(ascent + descent + lineGap); SelectObject(dc, oldFont); ReleaseDC(0, dc); diff --git a/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp b/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp index 355d837..9423d1e 100644 --- a/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp @@ -55,14 +55,9 @@ static const size_t maxVDMXTableSize = 1024 * 1024; // 1 MB void SimpleFontData::platformInit() { if (!m_platformData.size()) { - m_ascent = 0; - m_descent = 0; - m_lineGap = 0; - m_lineSpacing = 0; + m_fontMetrics.reset(); m_avgCharWidth = 0; m_maxCharWidth = 0; - m_xHeight = 0; - m_unitsPerEm = 0; return; } @@ -88,26 +83,35 @@ void SimpleFontData::platformInit() fastFree(vdmxTable); } + float ascent; + float descent; + // Beware those who step here: This code is designed to match Win32 font // metrics *exactly*. if (isVDMXValid) { - m_ascent = vdmxAscent; - m_descent = -vdmxDescent; + ascent = vdmxAscent; + descent = -vdmxDescent; } else { SkScalar height = -metrics.fAscent + metrics.fDescent + metrics.fLeading; - m_ascent = SkScalarRound(-metrics.fAscent); - m_descent = SkScalarRound(height) - m_ascent; + ascent = SkScalarRound(-metrics.fAscent); + descent = SkScalarRound(height) - ascent; } + m_fontMetrics.setAscent(ascent); + m_fontMetrics.setDescent(descent); + + float xHeight; if (metrics.fXHeight) - m_xHeight = metrics.fXHeight; + xHeight = metrics.fXHeight; else { // hack taken from the Windows port - m_xHeight = static_cast<float>(m_ascent) * 0.56; + xHeight = ascent * 0.56f; } - m_lineGap = SkScalarRound(metrics.fLeading); - m_lineSpacing = m_ascent + m_descent + m_lineGap; + float lineGap = SkScalarToFloat(metrics.fLeading); + m_fontMetrics.setLineGap(lineGap); + m_fontMetrics.setXHeight(xHeight); + m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); if (m_orientation == Vertical) { static const uint32_t vheaTag = SkSetFourByteTag('v', 'h', 'e', 'a'); @@ -128,7 +132,7 @@ void SimpleFontData::platformInit() if (metrics.fAvgCharWidth) m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth); else { - m_avgCharWidth = m_xHeight; + m_avgCharWidth = xHeight; GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); diff --git a/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp index ba66eae..193271d 100644 --- a/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp @@ -446,9 +446,9 @@ void TransparencyWin::compositeOpaqueComposite() identity.reset(); destCanvas->setMatrix(identity); - destRect.set(m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom()); + destRect.set(m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.maxX(), m_transformedSourceRect.maxY()); } else - destRect.set(m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.right(), m_sourceRect.bottom()); + destRect.set(m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.maxX(), m_sourceRect.maxY()); SkPaint paint; paint.setFilterBitmap(true); @@ -487,7 +487,7 @@ void TransparencyWin::compositeTextComposite() SkMatrix identity; identity.reset(); destCanvas->setMatrix(identity); - SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom() }; + SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.maxX(), m_transformedSourceRect.maxY() }; // Note that we need to specify the source layer subset, since the bitmap // may have been cached and it could be larger than what we're using. diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp b/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp index aa18b4a..c060b43 100644 --- a/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp +++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp @@ -51,14 +51,14 @@ UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run, setLetterSpacing(font.letterSpacing()); setSpaceWidth(font.spaceWidth()); setWordSpacing(font.wordSpacing()); - setAscent(font.primaryFont()->ascent()); + setAscent(font.fontMetrics().ascent()); init(); - // Padding is the amount to add to make justification happen. This + // Expansion is the amount to add to make justification happen. This // should be done after Init() so all the runs are already measured. - if (run.padding() > 0) - justify(run.padding()); + if (run.expansion() > 0) + justify(run.expansion()); } UniscribeHelperTextRun::UniscribeHelperTextRun( @@ -121,7 +121,7 @@ bool UniscribeHelperTextRun::nextWinFontData( m_hfonts.append(simpleFontData->platformData().hfont()); m_scriptCaches.append(simpleFontData->platformData().scriptCache()); m_fontProperties.append(simpleFontData->platformData().scriptFontProperties()); - m_ascents.append(simpleFontData->ascent()); + m_ascents.append(simpleFontData->fontMetrics().ascent()); } *hfont = m_hfonts[m_fontIndex - 1]; diff --git a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp index 776b83f..41cd180 100644 --- a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp @@ -60,6 +60,7 @@ VideoLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context) , m_rgbaShaderMatrixLocation(0) , m_rgbaWidthScaleFactorLocation(0) , m_ccMatrixLocation(0) + , m_signAdjLocation(0) , m_yTextureLocation(0) , m_uTextureLocation(0) , m_vTextureLocation(0) @@ -96,14 +97,15 @@ VideoLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context) "uniform sampler2D u_texture; \n" "uniform sampler2D v_texture; \n" "uniform float alpha; \n" + "uniform float adj; \n" "uniform mat3 cc_matrix; \n" "void main() \n" "{ \n" " float y = texture2D(y_texture, v_texCoord).x; \n" - " float u = texture2D(u_texture, v_texCoord).r - .5; \n" - " float v = texture2D(v_texture, v_texCoord).r - .5; \n" + " float u = texture2D(u_texture, v_texCoord).x - adj; \n" + " float v = texture2D(v_texture, v_texCoord).x - adj; \n" " vec3 rgb = cc_matrix * vec3(y, u, v); \n" - " gl_FragColor = vec4(rgb.x, rgb.y, rgb.z, 1.0) * alpha; \n" + " gl_FragColor = vec4(rgb, float(1)) * alpha; \n" "} \n"; char rgbaFragmentShaderString[] = @@ -113,7 +115,7 @@ VideoLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context) "uniform float alpha; \n" "void main() \n" "{ \n" - " vec4 texColor = texture2D(rgba_texture, vec2(v_texCoord.x, 1.0 - v_texCoord.y)); \n" + " vec4 texColor = texture2D(rgba_texture, vec2(v_texCoord.x, float(1) - v_texCoord.y)); \n" " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n" "} \n"; @@ -135,6 +137,7 @@ VideoLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context) m_uTextureLocation = m_context->getUniformLocation(m_yuvShaderProgram, "u_texture"); m_vTextureLocation = m_context->getUniformLocation(m_yuvShaderProgram, "v_texture"); m_ccMatrixLocation = m_context->getUniformLocation(m_yuvShaderProgram, "cc_matrix"); + m_signAdjLocation = m_context->getUniformLocation(m_yuvShaderProgram, "adj"); m_yuvAlphaLocation = m_context->getUniformLocation(m_yuvShaderProgram, "alpha"); ASSERT(m_yuvShaderMatrixLocation != -1); @@ -143,6 +146,7 @@ VideoLayerChromium::SharedValues::SharedValues(GraphicsContext3D* context) ASSERT(m_uTextureLocation != -1); ASSERT(m_vTextureLocation != -1); ASSERT(m_ccMatrixLocation != -1); + ASSERT(m_signAdjLocation != -1); ASSERT(m_yuvAlphaLocation != -1); m_rgbaShaderMatrixLocation = m_context->getUniformLocation(m_rgbaShaderProgram, "matrix"); @@ -375,6 +379,12 @@ void VideoLayerChromium::drawYUV(const SharedValues* sv) GLC(context, context->uniform1i(sv->uTextureLocation(), 2)); GLC(context, context->uniform1i(sv->vTextureLocation(), 3)); + // This value of 0.5 maps to 128. It is used in the YUV to RGB conversion + // formula to turn unsigned u and v values to signed u and v values. + // This is loaded as a uniform because certain drivers have problems + // reading literal float values. + GLC(context, context->uniform1f(sv->signAdjLocation(), 0.5)); + GLC(context, context->uniformMatrix3fv(sv->ccMatrixLocation(), 0, const_cast<float*>(yuv2RGB), 1)); drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), diff --git a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h index 0992ab7..ac3bca9 100644 --- a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.h @@ -70,6 +70,7 @@ public: int rgbaAlphaLocation() const { return m_rgbaAlphaLocation; } int rgbaTextureLocation() const { return m_rgbaTextureLocation; } int ccMatrixLocation() const { return m_ccMatrixLocation; } + int signAdjLocation() const { return m_signAdjLocation; } bool initialized() const { return m_initialized; } private: GraphicsContext3D* m_context; @@ -80,6 +81,7 @@ public: int m_rgbaShaderMatrixLocation; int m_rgbaWidthScaleFactorLocation; int m_ccMatrixLocation; + int m_signAdjLocation; int m_yTextureLocation; int m_uTextureLocation; int m_vTextureLocation; diff --git a/Source/WebCore/platform/graphics/cocoa/FontPlatformData.h b/Source/WebCore/platform/graphics/cocoa/FontPlatformData.h index 8cf08fb..ca38029 100644 --- a/Source/WebCore/platform/graphics/cocoa/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/cocoa/FontPlatformData.h @@ -25,6 +25,7 @@ #define FontPlatformData_h #include "FontOrientation.h" +#include "FontWidthVariant.h" #include <wtf/text/StringImpl.h> #ifdef __OBJC__ @@ -59,11 +60,12 @@ inline CTFontRef toCTFontRef(NSFont *nsFont) { return reinterpret_cast<CTFontRef class FontPlatformData { public: - FontPlatformData(float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation = Horizontal) + FontPlatformData(float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation = Horizontal, FontWidthVariant widthVariant = RegularWidth) : m_syntheticBold(syntheticBold) , m_syntheticOblique(syntheticOblique) , m_orientation(orientation) , m_size(size) + , m_widthVariant(widthVariant) , m_font(0) #ifdef BUILDING_ON_TIGER , m_cgFont(0) @@ -72,13 +74,14 @@ class FontPlatformData { { } - FontPlatformData(NSFont *nsFont, float size, bool syntheticBold = false, bool syntheticOblique = false, FontOrientation = Horizontal); + FontPlatformData(NSFont*, float size, bool syntheticBold = false, bool syntheticOblique = false, FontOrientation = Horizontal, FontWidthVariant = RegularWidth); - FontPlatformData(CGFontRef cgFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation) + FontPlatformData(CGFontRef cgFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, FontWidthVariant widthVariant) : m_syntheticBold(syntheticBold) , m_syntheticOblique(syntheticOblique) , m_orientation(orientation) , m_size(size) + , m_widthVariant(widthVariant) , m_font(0) , m_cgFont(cgFont) , m_isColorBitmapFont(false) @@ -96,17 +99,20 @@ class FontPlatformData { bool syntheticBold() const { return m_syntheticBold; } bool syntheticOblique() const { return m_syntheticOblique; } FontOrientation orientation() const { return m_orientation; } + FontWidthVariant widthVariant() const { return m_widthVariant; } bool m_syntheticBold; bool m_syntheticOblique; FontOrientation m_orientation; float m_size; + + FontWidthVariant m_widthVariant; unsigned hash() const { ASSERT(m_font != 0 || m_cgFont == 0); - uintptr_t hashCodes[2] = { (uintptr_t)m_font, m_orientation << 2 | m_syntheticBold << 1 | m_syntheticOblique }; + uintptr_t hashCodes[3] = { (uintptr_t)m_font, m_widthVariant, m_orientation << 2 | m_syntheticBold << 1 | m_syntheticOblique }; return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes); } @@ -115,7 +121,7 @@ class FontPlatformData { bool operator==(const FontPlatformData& other) const { return m_font == other.m_font && m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique && - m_cgFont == other.m_cgFont && m_size == other.m_size && m_orientation == other.m_orientation; + m_cgFont == other.m_cgFont && m_size == other.m_size && m_orientation == other.m_orientation && m_widthVariant == other.m_widthVariant; } NSFont *font() const { return m_font; } diff --git a/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm b/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm index 8dacbe3..b40f698 100644 --- a/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm +++ b/Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm @@ -30,6 +30,9 @@ namespace WebCore { +// These CoreText Text Spacing feature selectors are not defined in CoreText. +enum TextSpacingCTFeatureSelector { TextSpacingProportional, TextSpacingFullWidth, TextSpacingHalfWidth, TextSpacingThirdWidth, TextSpacingQuarterWidth }; + #if PLATFORM(MAC) void FontPlatformData::loadFont(NSFont* nsFont, float, NSFont*& outNSFont, CGFontRef& cgFont) { @@ -42,10 +45,11 @@ void FontPlatformData::loadFont(NSFont* nsFont, float, NSFont*& outNSFont, CGFon } #endif // PLATFORM(MAC) -FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation) +FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, FontWidthVariant widthVariant) : m_syntheticBold(syntheticBold) , m_syntheticOblique(syntheticOblique) , m_size(size) + , m_widthVariant(widthVariant) , m_font(nsFont) #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) // FIXME: Chromium: The following code isn't correct for the Chromium port since the sandbox might @@ -79,6 +83,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& f) m_syntheticBold = f.m_syntheticBold; m_syntheticOblique = f.m_syntheticOblique; m_size = f.m_size; + m_widthVariant = f.m_widthVariant; m_cgFont = f.m_cgFont; m_isColorBitmapFont = f.m_isColorBitmapFont; m_orientation = f.m_orientation; @@ -99,6 +104,7 @@ const FontPlatformData& FontPlatformData::operator=(const FontPlatformData& f) m_syntheticBold = f.m_syntheticBold; m_syntheticOblique = f.m_syntheticOblique; m_size = f.m_size; + m_widthVariant = f.m_widthVariant; m_cgFont = f.m_cgFont; if (m_font == f.m_font) return *this; @@ -165,12 +171,48 @@ bool FontPlatformData::allowsLigatures() const return ![[m_font coveredCharacterSet] characterIsMember:'a']; } +inline int mapFontWidthVariantToCTFeatureSelector(FontWidthVariant variant) +{ + switch(variant) { + case RegularWidth: + return TextSpacingProportional; + + case HalfWidth: + return TextSpacingHalfWidth; + + case ThirdWidth: + return TextSpacingThirdWidth; + + case QuarterWidth: + return TextSpacingQuarterWidth; + } + + ASSERT_NOT_REACHED(); + return TextSpacingProportional; +} + CTFontRef FontPlatformData::ctFont() const { - if (m_font) - return toCTFontRef(m_font); - if (!m_CTFont) - m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_size, 0, 0)); + if (m_widthVariant == RegularWidth) { + if (m_font) + return toCTFontRef(m_font); + if (!m_CTFont) + m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_size, 0, 0)); + return m_CTFont.get(); + } + + if (!m_CTFont) { + int featureTypeValue = kTextSpacingType; + int featureSelectorValue = mapFontWidthVariantToCTFeatureSelector(m_widthVariant); + RetainPtr<CTFontRef> sourceFont(AdoptCF, CTFontCreateWithGraphicsFont(m_cgFont.get(), m_size, 0, 0)); + RetainPtr<CTFontDescriptorRef> sourceDescriptor(AdoptCF, CTFontCopyFontDescriptor(sourceFont.get())); + RetainPtr<CFNumberRef> featureType(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeValue)); + RetainPtr<CFNumberRef> featureSelector(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorValue)); + RetainPtr<CTFontDescriptorRef> newDescriptor(AdoptCF, CTFontDescriptorCreateCopyWithFeature(sourceDescriptor.get(), featureType.get(), featureSelector.get())); + RetainPtr<CTFontRef> newFont(AdoptCF, CTFontCreateWithFontDescriptor(newDescriptor.get(), m_size, 0)); + + m_CTFont = newFont.get() ? newFont : sourceFont; + } return m_CTFont.get(); } diff --git a/Source/WebCore/platform/graphics/efl/FontEfl.cpp b/Source/WebCore/platform/graphics/efl/FontEfl.cpp index d3ca183..83cc7ff 100644 --- a/Source/WebCore/platform/graphics/efl/FontEfl.cpp +++ b/Source/WebCore/platform/graphics/efl/FontEfl.cpp @@ -50,6 +50,11 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } +bool Font::canExpandAroundIdeographsInComplexText() +{ + return false; +} + float Font::floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>*, GlyphOverflow*) const { notImplemented(); diff --git a/Source/WebCore/platform/graphics/filters/DistantLightSource.cpp b/Source/WebCore/platform/graphics/filters/DistantLightSource.cpp new file mode 100644 index 0000000..4c3b49b --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/DistantLightSource.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Renata Hodovan <reni@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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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" + +#if ENABLE(FILTERS) +#include "DistantLightSource.h" + +#include "RenderTreeAsText.h" + +namespace WebCore { + +void DistantLightSource::initPaintingData(PaintingData& paintingData) +{ + float azimuth = deg2rad(m_azimuth); + float elevation = deg2rad(m_elevation); + paintingData.lightVector.setX(cosf(azimuth) * cosf(elevation)); + paintingData.lightVector.setY(sinf(azimuth) * cosf(elevation)); + paintingData.lightVector.setZ(sinf(elevation)); + paintingData.lightVectorLength = 1; +} + +void DistantLightSource::updatePaintingData(PaintingData&, int, int, float) +{ +} + +bool DistantLightSource::setAzimuth(float azimuth) +{ + if (m_azimuth == azimuth) + return false; + m_azimuth = azimuth; + return true; +} + +bool DistantLightSource::setElevation(float elevation) +{ + if (m_elevation == elevation) + return false; + m_elevation = elevation; + return true; +} + +TextStream& DistantLightSource::externalRepresentation(TextStream& ts) const +{ + ts << "[type=DISTANT-LIGHT] "; + ts << "[azimuth=\"" << azimuth() << "\"]"; + ts << "[elevation=\"" << elevation() << "\"]"; + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/DistantLightSource.h b/Source/WebCore/platform/graphics/filters/DistantLightSource.h index d5d474f..1e19c62 100644 --- a/Source/WebCore/platform/graphics/filters/DistantLightSource.h +++ b/Source/WebCore/platform/graphics/filters/DistantLightSource.h @@ -36,7 +36,9 @@ public: } float azimuth() const { return m_azimuth; } + bool setAzimuth(float); float elevation() const { return m_elevation; } + bool setElevation(float); virtual void initPaintingData(PaintingData&); virtual void updatePaintingData(PaintingData&, int x, int y, float z); diff --git a/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp index a8a825a..5f9d049 100644 --- a/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp +++ b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp @@ -52,9 +52,12 @@ Color FEDiffuseLighting::lightingColor() const return m_lightingColor; } -void FEDiffuseLighting::setLightingColor(const Color& lightingColor) +bool FEDiffuseLighting::setLightingColor(const Color& lightingColor) { + if (m_lightingColor == lightingColor) + return false; m_lightingColor = lightingColor; + return true; } float FEDiffuseLighting::surfaceScale() const @@ -62,9 +65,12 @@ float FEDiffuseLighting::surfaceScale() const return m_surfaceScale; } -void FEDiffuseLighting::setSurfaceScale(float surfaceScale) +bool FEDiffuseLighting::setSurfaceScale(float surfaceScale) { + if (m_surfaceScale == surfaceScale) + return false; m_surfaceScale = surfaceScale; + return true; } float FEDiffuseLighting::diffuseConstant() const @@ -72,9 +78,12 @@ float FEDiffuseLighting::diffuseConstant() const return m_diffuseConstant; } -void FEDiffuseLighting::setDiffuseConstant(float diffuseConstant) +bool FEDiffuseLighting::setDiffuseConstant(float diffuseConstant) { + if (m_diffuseConstant == diffuseConstant) + return false; m_diffuseConstant = diffuseConstant; + return true; } float FEDiffuseLighting::kernelUnitLengthX() const @@ -82,9 +91,12 @@ float FEDiffuseLighting::kernelUnitLengthX() const return m_kernelUnitLengthX; } -void FEDiffuseLighting::setKernelUnitLengthX(float kernelUnitLengthX) +bool FEDiffuseLighting::setKernelUnitLengthX(float kernelUnitLengthX) { + if (m_kernelUnitLengthX == kernelUnitLengthX) + return false; m_kernelUnitLengthX = kernelUnitLengthX; + return true; } float FEDiffuseLighting::kernelUnitLengthY() const @@ -92,9 +104,12 @@ float FEDiffuseLighting::kernelUnitLengthY() const return m_kernelUnitLengthY; } -void FEDiffuseLighting::setKernelUnitLengthY(float kernelUnitLengthY) +bool FEDiffuseLighting::setKernelUnitLengthY(float kernelUnitLengthY) { + if (m_kernelUnitLengthY == kernelUnitLengthY) + return false; m_kernelUnitLengthY = kernelUnitLengthY; + return true; } const LightSource* FEDiffuseLighting::lightSource() const diff --git a/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h index b58b47a..5f20651 100644 --- a/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h +++ b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h @@ -36,19 +36,19 @@ public: virtual ~FEDiffuseLighting(); Color lightingColor() const; - void setLightingColor(const Color&); + bool setLightingColor(const Color&); float surfaceScale() const; - void setSurfaceScale(float); + bool setSurfaceScale(float); float diffuseConstant() const; - void setDiffuseConstant(float); + bool setDiffuseConstant(float); float kernelUnitLengthX() const; - void setKernelUnitLengthX(float); + bool setKernelUnitLengthX(float); float kernelUnitLengthY() const; - void setKernelUnitLengthY(float); + bool setKernelUnitLengthY(float); const LightSource* lightSource() const; void setLightSource(PassRefPtr<LightSource>); diff --git a/Source/WebCore/platform/graphics/filters/FilterEffect.cpp b/Source/WebCore/platform/graphics/filters/FilterEffect.cpp index 85154b5..f07d00c 100644 --- a/Source/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/Source/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -77,6 +77,16 @@ FilterEffect* FilterEffect::inputEffect(unsigned number) const return m_inputEffects.at(number).get(); } +void FilterEffect::clearResult() +{ + if (m_imageBufferResult) + m_imageBufferResult.clear(); + if (m_unmultipliedImageResult) + m_unmultipliedImageResult.clear(); + if (m_premultipliedImageResult) + m_premultipliedImageResult.clear(); +} + ImageBuffer* FilterEffect::asImageBuffer() { if (!hasResult()) @@ -109,7 +119,7 @@ PassRefPtr<ByteArray> FilterEffect::asPremultipliedImage(const IntRect& rect) inline void FilterEffect::copyImageBytes(ByteArray* source, ByteArray* destination, const IntRect& rect) { // Copy the necessary lines. - if (rect.x() < 0 || rect.y() < 0 || rect.bottom() > m_absolutePaintRect.width() || rect.bottom() > m_absolutePaintRect.height()) + if (rect.x() < 0 || rect.y() < 0 || rect.maxY() > m_absolutePaintRect.width() || rect.maxY() > m_absolutePaintRect.height()) memset(destination->data(), 0, destination->length()); int xOrigin = rect.x(); @@ -118,7 +128,7 @@ inline void FilterEffect::copyImageBytes(ByteArray* source, ByteArray* destinati xDest = -xOrigin; xOrigin = 0; } - int xEnd = rect.right(); + int xEnd = rect.maxX(); if (xEnd > m_absolutePaintRect.width()) xEnd = m_absolutePaintRect.width(); @@ -128,7 +138,7 @@ inline void FilterEffect::copyImageBytes(ByteArray* source, ByteArray* destinati yDest = -yOrigin; yOrigin = 0; } - int yEnd = rect.bottom(); + int yEnd = rect.maxY(); if (yEnd > m_absolutePaintRect.height()) yEnd = m_absolutePaintRect.height(); diff --git a/Source/WebCore/platform/graphics/filters/FilterEffect.h b/Source/WebCore/platform/graphics/filters/FilterEffect.h index 062dd1b..2de8ac5 100644 --- a/Source/WebCore/platform/graphics/filters/FilterEffect.h +++ b/Source/WebCore/platform/graphics/filters/FilterEffect.h @@ -53,6 +53,7 @@ public: virtual ~FilterEffect(); bool hasResult() const { return m_imageBufferResult || m_unmultipliedImageResult || m_premultipliedImageResult; } + void clearResult(); ImageBuffer* asImageBuffer(); PassRefPtr<ByteArray> asUnmultipliedImage(const IntRect&); PassRefPtr<ByteArray> asPremultipliedImage(const IntRect&); diff --git a/Source/WebCore/platform/graphics/filters/LightSource.cpp b/Source/WebCore/platform/graphics/filters/LightSource.cpp index de0691e..cf262e8 100644 --- a/Source/WebCore/platform/graphics/filters/LightSource.cpp +++ b/Source/WebCore/platform/graphics/filters/LightSource.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> * Copyright (C) 2005 Eric Seidel <eric@webkit.org> * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * Copyright (C) 2011 Renata Hodovan <reni@webkit.org>, University of Szeged. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -33,136 +34,80 @@ namespace WebCore { -void PointLightSource::initPaintingData(PaintingData&) +bool LightSource::setAzimuth(float azimuth) { + if (m_type == LS_DISTANT) + return static_cast<DistantLightSource*>(this)->setAzimuth(azimuth); + return false; } -void PointLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) +bool LightSource::setElevation(float elevation) { - paintingData.lightVector.setX(m_position.x() - x); - paintingData.lightVector.setY(m_position.y() - y); - paintingData.lightVector.setZ(m_position.z() - z); - paintingData.lightVectorLength = paintingData.lightVector.length(); + if (m_type == LS_DISTANT) + return static_cast<DistantLightSource*>(this)->setElevation(elevation); + return false; } -// spot-light edge darkening depends on an absolute treshold -// according to the SVG 1.1 SE light regression tests -static const float antiAliasTreshold = 0.016f; - -void SpotLightSource::initPaintingData(PaintingData& paintingData) +bool LightSource::setX(float x) { - paintingData.privateColorVector = paintingData.colorVector; - paintingData.directionVector.setX(m_direction.x() - m_position.x()); - paintingData.directionVector.setY(m_direction.y() - m_position.y()); - paintingData.directionVector.setZ(m_direction.z() - m_position.z()); - paintingData.directionVector.normalize(); - - if (!m_limitingConeAngle) { - paintingData.coneCutOffLimit = 0.0f; - paintingData.coneFullLight = -antiAliasTreshold; - } else { - float limitingConeAngle = m_limitingConeAngle; - if (limitingConeAngle < 0.0f) - limitingConeAngle = -limitingConeAngle; - if (limitingConeAngle > 90.0f) - limitingConeAngle = 90.0f; - paintingData.coneCutOffLimit = cosf(deg2rad(180.0f - limitingConeAngle)); - paintingData.coneFullLight = paintingData.coneCutOffLimit - antiAliasTreshold; - } - - // Optimization for common specularExponent values - if (!m_specularExponent) - paintingData.specularExponent = 0; - else if (m_specularExponent == 1.0f) - paintingData.specularExponent = 1; - else // It is neither 0.0f nor 1.0f - paintingData.specularExponent = 2; + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setX(x); + if (m_type == LS_POINT) + return static_cast<PointLightSource*>(this)->setX(x); + return false; } -void SpotLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) +bool LightSource::setY(float y) { - paintingData.lightVector.setX(m_position.x() - x); - paintingData.lightVector.setY(m_position.y() - y); - paintingData.lightVector.setZ(m_position.z() - z); - paintingData.lightVectorLength = paintingData.lightVector.length(); - - float cosineOfAngle = (paintingData.lightVector * paintingData.directionVector) / paintingData.lightVectorLength; - if (cosineOfAngle > paintingData.coneCutOffLimit) { - // No light is produced, scanlines are not updated - paintingData.colorVector.setX(0.0f); - paintingData.colorVector.setY(0.0f); - paintingData.colorVector.setZ(0.0f); - return; - } - - // Set the color of the pixel - float lightStrength; - switch (paintingData.specularExponent) { - case 0: - lightStrength = 1.0f; // -cosineOfAngle ^ 0 == 1 - break; - case 1: - lightStrength = -cosineOfAngle; // -cosineOfAngle ^ 1 == -cosineOfAngle - break; - default: - lightStrength = powf(-cosineOfAngle, m_specularExponent); - break; - } - - if (cosineOfAngle > paintingData.coneFullLight) - lightStrength *= (paintingData.coneCutOffLimit - cosineOfAngle) / (paintingData.coneCutOffLimit - paintingData.coneFullLight); - - if (lightStrength > 1.0f) - lightStrength = 1.0f; - - paintingData.colorVector.setX(paintingData.privateColorVector.x() * lightStrength); - paintingData.colorVector.setY(paintingData.privateColorVector.y() * lightStrength); - paintingData.colorVector.setZ(paintingData.privateColorVector.z() * lightStrength); + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setY(y); + if (m_type == LS_POINT) + return static_cast<PointLightSource*>(this)->setY(y); + return false; } -void DistantLightSource::initPaintingData(PaintingData& paintingData) +bool LightSource::setZ(float z) { - float azimuth = deg2rad(m_azimuth); - float elevation = deg2rad(m_elevation); - paintingData.lightVector.setX(cosf(azimuth) * cosf(elevation)); - paintingData.lightVector.setY(sinf(azimuth) * cosf(elevation)); - paintingData.lightVector.setZ(sinf(elevation)); - paintingData.lightVectorLength = 1; + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setZ(z); + if (m_type == LS_POINT) + return static_cast<PointLightSource*>(this)->setZ(z); + return false; } -void DistantLightSource::updatePaintingData(PaintingData&, int, int, float) +bool LightSource::setPointsAtX(float pointsAtX) { + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setPointsAtX(pointsAtX); + return false; } -static TextStream& operator<<(TextStream& ts, const FloatPoint3D& p) +bool LightSource::setPointsAtY(float pointsAtY) { - ts << "x=" << p.x() << " y=" << p.y() << " z=" << p.z(); - return ts; + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setPointsAtY(pointsAtY); + return false; } -TextStream& PointLightSource::externalRepresentation(TextStream& ts) const +bool LightSource::setPointsAtZ(float pointsAtZ) { - ts << "[type=POINT-LIGHT] "; - ts << "[position=\"" << position() << "\"]"; - return ts; + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setPointsAtZ(pointsAtZ); + return false; } -TextStream& SpotLightSource::externalRepresentation(TextStream& ts) const +bool LightSource::setSpecularExponent(float specularExponent) { - ts << "[type=SPOT-LIGHT] "; - ts << "[position=\"" << position() << "\"]"; - ts << "[direction=\"" << direction() << "\"]"; - ts << "[specularExponent=\"" << specularExponent() << "\"]"; - ts << "[limitingConeAngle=\"" << limitingConeAngle() << "\"]"; - return ts; + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setSpecularExponent(specularExponent); + return false; } -TextStream& DistantLightSource::externalRepresentation(TextStream& ts) const +bool LightSource::setLimitingConeAngle(float limitingConeAngle) { - ts << "[type=DISTANT-LIGHT] "; - ts << "[azimuth=\"" << azimuth() << "\"]"; - ts << "[elevation=\"" << elevation() << "\"]"; - return ts; + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setLimitingConeAngle(limitingConeAngle); + return false; } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/filters/LightSource.h b/Source/WebCore/platform/graphics/filters/LightSource.h index 013e910..24c319a 100644 --- a/Source/WebCore/platform/graphics/filters/LightSource.h +++ b/Source/WebCore/platform/graphics/filters/LightSource.h @@ -74,6 +74,17 @@ public: // specified "surfaceScale" constant, which type is <number> in the SVG standard virtual void updatePaintingData(PaintingData&, int x, int y, float z) = 0; + bool setAzimuth(float); + bool setElevation(float); + bool setX(float); + bool setY(float); + bool setZ(float); + bool setPointsAtX(float); + bool setPointsAtY(float); + bool setPointsAtZ(float); + bool setSpecularExponent(float); + bool setLimitingConeAngle(float); + private: LightType m_type; }; diff --git a/Source/WebCore/platform/graphics/filters/PointLightSource.cpp b/Source/WebCore/platform/graphics/filters/PointLightSource.cpp new file mode 100644 index 0000000..207ed8e --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/PointLightSource.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Renata Hodovan <reni@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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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" + +#if ENABLE(FILTERS) +#include "PointLightSource.h" + +#include "TextStream.h" + +namespace WebCore { + +void PointLightSource::initPaintingData(PaintingData&) +{ +} + +void PointLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) +{ + paintingData.lightVector.setX(m_position.x() - x); + paintingData.lightVector.setY(m_position.y() - y); + paintingData.lightVector.setZ(m_position.z() - z); + paintingData.lightVectorLength = paintingData.lightVector.length(); +} + +bool PointLightSource::setX(float x) +{ + if (m_position.x() == x) + return false; + m_position.setX(x); + return true; +} + +bool PointLightSource::setY(float y) +{ + if (m_position.y() == y) + return false; + m_position.setY(y); + return true; +} + +bool PointLightSource::setZ(float z) +{ + if (m_position.z() == z) + return false; + m_position.setZ(z); + return true; +} + +static TextStream& operator<<(TextStream& ts, const FloatPoint3D& p) +{ + ts << "x=" << p.x() << " y=" << p.y() << " z=" << p.z(); + return ts; +} + +TextStream& PointLightSource::externalRepresentation(TextStream& ts) const +{ + ts << "[type=POINT-LIGHT] "; + ts << "[position=\"" << position() << "\"]"; + return ts; +} + +}; // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/PointLightSource.h b/Source/WebCore/platform/graphics/filters/PointLightSource.h index 163c829..a93bf2c 100644 --- a/Source/WebCore/platform/graphics/filters/PointLightSource.h +++ b/Source/WebCore/platform/graphics/filters/PointLightSource.h @@ -36,6 +36,9 @@ public: } const FloatPoint3D& position() const { return m_position; } + bool setX(float); + bool setY(float); + bool setZ(float); virtual void initPaintingData(PaintingData&); virtual void updatePaintingData(PaintingData&, int x, int y, float z); diff --git a/Source/WebCore/platform/graphics/filters/SpotLightSource.cpp b/Source/WebCore/platform/graphics/filters/SpotLightSource.cpp new file mode 100644 index 0000000..648fcae --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/SpotLightSource.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Renata Hodovan <reni@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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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" + +#if ENABLE(FILTERS) +#include "SpotLightSource.h" + +#include "TextStream.h" + +namespace WebCore { + +// spot-light edge darkening depends on an absolute treshold +// according to the SVG 1.1 SE light regression tests +static const float antiAliasTreshold = 0.016f; + +void SpotLightSource::initPaintingData(PaintingData& paintingData) +{ + paintingData.privateColorVector = paintingData.colorVector; + paintingData.directionVector.setX(m_direction.x() - m_position.x()); + paintingData.directionVector.setY(m_direction.y() - m_position.y()); + paintingData.directionVector.setZ(m_direction.z() - m_position.z()); + paintingData.directionVector.normalize(); + + if (!m_limitingConeAngle) { + paintingData.coneCutOffLimit = 0.0f; + paintingData.coneFullLight = -antiAliasTreshold; + } else { + float limitingConeAngle = m_limitingConeAngle; + if (limitingConeAngle < 0.0f) + limitingConeAngle = -limitingConeAngle; + if (limitingConeAngle > 90.0f) + limitingConeAngle = 90.0f; + paintingData.coneCutOffLimit = cosf(deg2rad(180.0f - limitingConeAngle)); + paintingData.coneFullLight = paintingData.coneCutOffLimit - antiAliasTreshold; + } + + // Optimization for common specularExponent values + if (!m_specularExponent) + paintingData.specularExponent = 0; + else if (m_specularExponent == 1.0f) + paintingData.specularExponent = 1; + else // It is neither 0.0f nor 1.0f + paintingData.specularExponent = 2; +} + +void SpotLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) +{ + paintingData.lightVector.setX(m_position.x() - x); + paintingData.lightVector.setY(m_position.y() - y); + paintingData.lightVector.setZ(m_position.z() - z); + paintingData.lightVectorLength = paintingData.lightVector.length(); + + float cosineOfAngle = (paintingData.lightVector * paintingData.directionVector) / paintingData.lightVectorLength; + if (cosineOfAngle > paintingData.coneCutOffLimit) { + // No light is produced, scanlines are not updated + paintingData.colorVector.setX(0.0f); + paintingData.colorVector.setY(0.0f); + paintingData.colorVector.setZ(0.0f); + return; + } + + // Set the color of the pixel + float lightStrength; + switch (paintingData.specularExponent) { + case 0: + lightStrength = 1.0f; // -cosineOfAngle ^ 0 == 1 + break; + case 1: + lightStrength = -cosineOfAngle; // -cosineOfAngle ^ 1 == -cosineOfAngle + break; + default: + lightStrength = powf(-cosineOfAngle, m_specularExponent); + break; + } + + if (cosineOfAngle > paintingData.coneFullLight) + lightStrength *= (paintingData.coneCutOffLimit - cosineOfAngle) / (paintingData.coneCutOffLimit - paintingData.coneFullLight); + + if (lightStrength > 1.0f) + lightStrength = 1.0f; + + paintingData.colorVector.setX(paintingData.privateColorVector.x() * lightStrength); + paintingData.colorVector.setY(paintingData.privateColorVector.y() * lightStrength); + paintingData.colorVector.setZ(paintingData.privateColorVector.z() * lightStrength); +} + +bool SpotLightSource::setX(float x) +{ + if (m_position.x() == x) + return false; + m_position.setX(x); + return true; +} + +bool SpotLightSource::setY(float y) +{ + if (m_position.y() == y) + return false; + m_position.setY(y); + return true; +} + +bool SpotLightSource::setZ(float z) +{ + if (m_position.z() == z) + return false; + m_position.setZ(z); + return true; +} + +bool SpotLightSource::setPointsAtX(float pointsAtX) +{ + if (m_direction.x() == pointsAtX) + return false; + m_direction.setX(pointsAtX); + return true; +} + +bool SpotLightSource::setPointsAtY(float pointsAtY) +{ + if (m_direction.y() == pointsAtY) + return false; + m_direction.setY(pointsAtY); + return true; +} + +bool SpotLightSource::setPointsAtZ(float pointsAtZ) +{ + if (m_direction.z() == pointsAtZ) + return false; + m_direction.setZ(pointsAtZ); + return true; +} + +bool SpotLightSource::setSpecularExponent(float specularExponent) +{ + if (m_specularExponent == specularExponent) + return false; + m_specularExponent = specularExponent; + return true; +} + +bool SpotLightSource::setLimitingConeAngle(float limitingConeAngle) +{ + if (m_limitingConeAngle == limitingConeAngle) + return false; + m_limitingConeAngle = limitingConeAngle; + return true; +} + +static TextStream& operator<<(TextStream& ts, const FloatPoint3D& p) +{ + ts << "x=" << p.x() << " y=" << p.y() << " z=" << p.z(); + return ts; +} + +TextStream& SpotLightSource::externalRepresentation(TextStream& ts) const +{ + ts << "[type=SPOT-LIGHT] "; + ts << "[position=\"" << position() << "\"]"; + ts << "[direction=\"" << direction() << "\"]"; + ts << "[specularExponent=\"" << specularExponent() << "\"]"; + ts << "[limitingConeAngle=\"" << limitingConeAngle() << "\"]"; + return ts; +} + +}; // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/SpotLightSource.h b/Source/WebCore/platform/graphics/filters/SpotLightSource.h index cd6a614..b4f1b61 100644 --- a/Source/WebCore/platform/graphics/filters/SpotLightSource.h +++ b/Source/WebCore/platform/graphics/filters/SpotLightSource.h @@ -37,10 +37,18 @@ public: } const FloatPoint3D& position() const { return m_position; } + bool setX(float); + bool setY(float); + bool setZ(float); const FloatPoint3D& direction() const { return m_direction; } + bool setPointsAtX(float); + bool setPointsAtY(float); + bool setPointsAtZ(float); float specularExponent() const { return m_specularExponent; } + bool setSpecularExponent(float); float limitingConeAngle() const { return m_limitingConeAngle; } + bool setLimitingConeAngle(float); virtual void initPaintingData(PaintingData&); virtual void updatePaintingData(PaintingData&, int x, int y, float z); diff --git a/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp b/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp index c547224..841c8a3 100644 --- a/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp +++ b/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp @@ -59,7 +59,7 @@ FontCustomPlatformData::~FontCustomPlatformData() cairo_font_face_destroy(m_fontFace); } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode) { return FontPlatformData(m_fontFace, size, bold, italic); } diff --git a/Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp b/Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp index 97fd81a..6290eeb 100644 --- a/Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp +++ b/Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp @@ -50,21 +50,28 @@ void SimpleFontData::platformInit() cairo_font_extents_t font_extents; cairo_text_extents_t text_extents; cairo_scaled_font_extents(m_platformData.scaledFont(), &font_extents); - m_ascent = static_cast<int>(lroundf(font_extents.ascent)); - m_descent = static_cast<int>(lroundf(font_extents.descent)); - m_lineSpacing = static_cast<int>(lroundf(font_extents.height)); + + m_fontMetrics.setAscent(font_extents.ascent); + m_fontMetrics.setDescent(font_extents.descent); + // There seems to be some rounding error in cairo (or in how we // use cairo) with some fonts, like DejaVu Sans Mono, which makes // cairo report a height smaller than ascent + descent, which is // wrong and confuses WebCore's layout system. Workaround this // while we figure out what's going on. - if (m_lineSpacing < m_ascent + m_descent) - m_lineSpacing = m_ascent + m_descent; + float lineSpacing = font_extents.height; + if (lineSpacing < font_extents.ascent + font_extents.descent) + lineSpacing = font_extents.ascent + font_extents.descent; + + m_fontMetrics.setLineSpacing(lroundf(lineSpacing)); + m_fontMetrics.setLineGap(lineSpacing - font_extents.ascent - font_extents.descent); + cairo_scaled_font_text_extents(m_platformData.scaledFont(), "x", &text_extents); - m_xHeight = text_extents.height; + m_fontMetrics.setXHeight(text_extents.height); + cairo_scaled_font_text_extents(m_platformData.scaledFont(), " ", &text_extents); m_spaceWidth = static_cast<float>(text_extents.x_advance); - m_lineGap = m_lineSpacing - m_ascent - m_descent; + m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; } diff --git a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp index dae83a2..2a83fcf 100644 --- a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp +++ b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp @@ -30,7 +30,7 @@ #include "config.h" -#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(3D_CANVAS) +#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(WEBGL) #include "DrawingBuffer.h" @@ -41,10 +41,11 @@ namespace WebCore { PassRefPtr<DrawingBuffer> DrawingBuffer::create(GraphicsContext3D* context, const IntSize& size) { Extensions3D* extensions = context->getExtensions(); - bool multisampleSupported = extensions->supports("GL_ANGLE_framebuffer_blit") && extensions->supports("GL_ANGLE_framebuffer_multisample"); + bool multisampleSupported = extensions->supports("GL_ANGLE_framebuffer_blit") && extensions->supports("GL_ANGLE_framebuffer_multisample") && extensions->supports("GL_OES_rgb8_rgba8"); if (multisampleSupported) { extensions->ensureEnabled("GL_ANGLE_framebuffer_blit"); extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample"); + extensions->ensureEnabled("GL_OES_rgb8_rgba8"); } bool packedDepthStencilSupported = extensions->supports("GL_OES_packed_depth_stencil"); if (packedDepthStencilSupported) @@ -145,8 +146,6 @@ void DrawingBuffer::resizeDepthStencil(int sampleCount) void DrawingBuffer::reset(const IntSize& newSize) { - if (m_size == newSize) - return; m_size = newSize; if (!m_context) @@ -155,13 +154,15 @@ void DrawingBuffer::reset(const IntSize& newSize) m_context->makeContextCurrent(); const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes(); - unsigned long internalColorFormat, colorFormat; + unsigned long internalColorFormat, colorFormat, internalRenderbufferFormat; if (attributes.alpha) { internalColorFormat = GraphicsContext3D::RGBA; colorFormat = GraphicsContext3D::RGBA; + internalRenderbufferFormat = Extensions3D::RGBA8_OES; } else { internalColorFormat = GraphicsContext3D::RGB; colorFormat = GraphicsContext3D::RGB; + internalRenderbufferFormat = Extensions3D::RGB8_OES; } @@ -175,7 +176,7 @@ void DrawingBuffer::reset(const IntSize& newSize) m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); - m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, internalColorFormat, m_size.width(), m_size.height()); + m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, internalRenderbufferFormat, m_size.width(), m_size.height()); m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); resizeDepthStencil(sampleCount); if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { @@ -192,7 +193,8 @@ void DrawingBuffer::reset(const IntSize& newSize) m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE); m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0); m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); - resizeDepthStencil(0); + if (!multisample()) + resizeDepthStencil(0); if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { // Cleanup clear(); diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnPathCache.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnPathCache.cpp new file mode 100644 index 0000000..35f15e5 --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnPathCache.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 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 AND ITS CONTRIBUTORS "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 OR ITS 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 "LoopBlinnPathCache.h" + +namespace WebCore { + +LoopBlinnPathCache::LoopBlinnPathCache() +{ +} + +LoopBlinnPathCache::~LoopBlinnPathCache() +{ +} + +void LoopBlinnPathCache::addVertex(float x, float y, + float k, float l, float m) +{ + m_vertices.append(x); + m_vertices.append(y); + m_texcoords.append(k); + m_texcoords.append(l); + m_texcoords.append(m); +} + +void LoopBlinnPathCache::clear() +{ + m_vertices.clear(); + m_texcoords.clear(); + m_interiorVertices.clear(); +#ifdef LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES + m_interiorEdgeVertices.clear(); +#endif // LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES +} + +void LoopBlinnPathCache::addInteriorVertex(float x, float y) +{ + m_interiorVertices.append(x); + m_interiorVertices.append(y); +} + +#ifdef LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES +unsigned LoopBlinnPathCache::numberOfInteriorEdgeVertices() const +{ + return m_interiorEdgeVertices.size() / 2; +} + +const float* LoopBlinnPathCache::interiorEdgeVertices() const +{ + if (!numberOfInteriorEdgeVertices()) + return 0; + return m_interiorEdgeVertices.data(); +} + +void LoopBlinnPathCache::addInteriorEdgeVertex(float x, float y) +{ + m_interiorEdgeVertices.append(x); + m_interiorEdgeVertices.append(y); +} +#endif // LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnPathCache.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnPathCache.h new file mode 100644 index 0000000..d21d246 --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnPathCache.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2011 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 AND ITS CONTRIBUTORS "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 OR ITS 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 LoopBlinnPathCache_h +#define LoopBlinnPathCache_h + +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> + +namespace WebCore { + +// A cache of the processed triangle mesh for a given path. Because these +// might be expensive to allocate (using malloc/free internally), it is +// recommended to try to reuse them when possible. + +// Uncomment the following to obtain debugging information for the edges +// facing the interior region of the mesh. +// #define LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES + +class LoopBlinnPathCache { + WTF_MAKE_NONCOPYABLE(LoopBlinnPathCache); +public: + LoopBlinnPathCache(); + ~LoopBlinnPathCache(); + + unsigned numberOfVertices() const { return m_vertices.size() / 2; } + + // Get the base pointer to the vertex information. There are two + // coordinates per vertex. This pointer is valid until the cache is + // cleared or another vertex is added. Returns 0 if there are no + // vertices in the mesh. + const float* vertices() const + { + if (!numberOfVertices()) + return 0; + return m_vertices.data(); + } + + // Get the base pointer to the texture coordinate information. There + // are three coordinates per vertex. This pointer is valid until the + // cache is cleared or another vertex is added. Returns 0 if + // there are no vertices in the mesh. + const float* texcoords() const + { + if (!numberOfVertices()) + return 0; + return m_texcoords.data(); + } + + // Adds a vertex's information to the cache. The first two arguments + // are the x and y coordinates of the vertex on the plane; the last + // three arguments are the cubic texture coordinates associated with + // this vertex. + void addVertex(float x, float y, + float /*k*/, float /*l*/, float /*m*/); + + unsigned numberOfInteriorVertices() const { return m_interiorVertices.size() / 2; } + + // Base pointer to the interior vertices; two coordinates per + // vertex, which can be drawn as GL_TRIANGLES. Returns 0 if there + // are no interior vertices in the mesh. + const float* interiorVertices() const + { + if (!numberOfInteriorVertices()) + return 0; + return m_interiorVertices.data(); + } + + void addInteriorVertex(float x, float y); + + // Clears all of the stored vertex information in this cache. + void clear(); + +#ifdef LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES + // The number of interior edge vertices + unsigned numberOfInteriorEdgeVertices() const; + // Base pointer to the interior vertices; two coordinates per + // vertex, which can be drawn as GL_LINES. Returns 0 if there are + // no interior edge vertices in the mesh. + const float* interiorEdgeVertices() const; + void addInteriorEdgeVertex(float x, float y); +#endif // LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES + +private: + // The two-dimensional vertices of the triangle mesh. + Vector<float> m_vertices; + + // The three-dimensional cubic texture coordinates. + Vector<float> m_texcoords; + + Vector<float> m_interiorVertices; + +#ifdef LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES + // The following is only for debugging + Vector<float> m_interiorEdgeVertices; +#endif // LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES +}; + +} // namespace WebCore + +#endif // LoopBlinnPathCache_h diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnPathProcessor.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnPathProcessor.cpp new file mode 100644 index 0000000..e84ddbf --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnPathProcessor.cpp @@ -0,0 +1,1228 @@ +/* + * Copyright (C) 2011 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 AND ITS CONTRIBUTORS "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 OR ITS 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 "LoopBlinnPathProcessor.h" + +#include "FloatPoint.h" +#include "FloatRect.h" +#include "LoopBlinnClassifier.h" +#include "LoopBlinnConstants.h" +#include "LoopBlinnLocalTriangulator.h" +#include "LoopBlinnMathUtils.h" +#include "LoopBlinnPathCache.h" +#include "LoopBlinnTextureCoords.h" +#include "PODArena.h" +#include "PODIntervalTree.h" +#include "Path.h" +#include "internal_glu.h" +#include <algorithm> +#include <wtf/Assertions.h> +#include <wtf/FastMalloc.h> + +#if PLATFORM(SKIA) +#include "SkGeometry.h" +#include "SkPath.h" +#include "SkScalar.h" +#else +// Must port to your platform. +#endif + +namespace WebCore { + +using LoopBlinnMathUtils::XRay; +using LoopBlinnMathUtils::chopCubicAt; +using LoopBlinnMathUtils::numXRayCrossingsForCubic; +using LoopBlinnMathUtils::trianglesOverlap; +using LoopBlinnMathUtils::xRayCrossesLine; +using LoopBlinnPathProcessorImplementation::Contour; +using LoopBlinnPathProcessorImplementation::Segment; + +namespace { + +#ifndef NDEBUG +String valueToString(const FloatRect& arg) +{ + StringBuilder builder; + builder.append("[FloatRect x="); + builder.append(String::number(arg.x())); + builder.append(" y="); + builder.append(String::number(arg.y())); + builder.append(" maxX="); + builder.append(String::number(arg.maxX())); + builder.append(" maxY="); + builder.append(String::number(arg.maxY())); + builder.append("]"); + return builder.toString(); +} +#endif + +struct SweepData; + +} // anonymous namespace + +namespace LoopBlinnPathProcessorImplementation { +class Segment; +} + +#ifndef NDEBUG +// Routines needed to print the types of IntervalNodes we instantiate +// in this file. +template <> +struct ValueToString<float> { + static String string(const float& value) + { + return String::number(value); + } +}; + +template <> +struct ValueToString<SweepData*> { + static String string(SweepData* const& value) + { + return String::format("0x%p", value); + } +}; + +template <> +struct ValueToString<LoopBlinnPathProcessorImplementation::Segment*> { + static String string(LoopBlinnPathProcessorImplementation::Segment* const& value) + { + return String::format("0x%p", value); + } +}; +#endif + +namespace LoopBlinnPathProcessorImplementation { + +//---------------------------------------------------------------------- +// Segment +// + +// Describes a segment of the path: either a cubic or a line segment. +// These are stored in a doubly linked list to speed up curve +// subdivision, which occurs due to either rendering artifacts in the +// loop case or due to overlapping triangles. +class Segment { + WTF_MAKE_NONCOPYABLE(Segment); +public: + enum Kind { + Cubic, + Line + }; + + // No-argument constructor allows construction by the PODArena class. + Segment() + : m_arena(0) + , m_kind(Cubic) + , m_prev(0) + , m_next(0) + , m_contour(0) + , m_triangulator(0) + , m_markedForSubdivision(false) + { + } + + // Initializer for cubic curve segments. + void setup(PODArena* arena, + Contour* contour, + FloatPoint cp0, + FloatPoint cp1, + FloatPoint cp2, + FloatPoint cp3) + { + m_arena = arena; + m_contour = contour; + m_kind = Cubic; + m_points[0] = cp0; + m_points[1] = cp1; + m_points[2] = cp2; + m_points[3] = cp3; + computeBoundingBox(); + } + + // Initializer for line segments. + void setup(PODArena* arena, + Contour* contour, + FloatPoint p0, + FloatPoint p1) + { + m_arena = arena; + m_contour = contour; + m_kind = Line; + m_points[0] = p0; + m_points[1] = p1; + computeBoundingBox(); + } + + Kind kind() const { return m_kind; } + + // Returns the i'th control point, 0 <= i < 4. + const FloatPoint& getPoint(int i) + { + ASSERT(i >= 0 && i < 4); + return m_points[i]; + } + + Segment* next() const { return m_next; } + Segment* prev() const { return m_prev; } + + void setNext(Segment* next) { m_next = next; } + void setPrev(Segment* prev) { m_prev = prev; } + + // The contour this segment belongs to. + Contour* contour() const { return m_contour; } + + // Subdivides the current segment at the given parameter value (0 <= + // t <= 1) and replaces it with the two newly created Segments in + // the linked list, if possible. Returns a pointer to the leftmost + // Segment. + Segment* subdivide(float param) + { + FloatPoint dst[7]; + chopCubicAt(m_points, dst, param); + Segment* left = m_arena->allocateObject<Segment>(); + Segment* right = m_arena->allocateObject<Segment>(); + left->setup(m_arena, m_contour, dst[0], dst[1], dst[2], dst[3]); + right->setup(m_arena, m_contour, dst[3], dst[4], dst[5], dst[6]); + left->setNext(right); + right->setPrev(left); + // Try to set up a link between "this->prev()" and "left". + if (prev()) { + left->setPrev(prev()); + prev()->setNext(left); + } + // Try to set up a link between "this->next()" and "right". + Segment* n = next(); + if (n) { + right->setNext(n); + n->setPrev(right); + } + // Set up a link between "this" and "left"; this is only to + // provide a certain amount of continuity during forward iteration. + setNext(left); + return left; + } + + // Subdivides the current segment at the halfway point and replaces + // it with the two newly created Segments in the linked list, if + // possible. Returns a pointer to the leftmost Segment. + Segment* subdivide() { return subdivide(0.5f); } + + const FloatRect& boundingBox() const { return m_boundingBox; } + + // Computes the number of times a query line starting at the given + // point and extending to x=+infinity crosses this segment. Outgoing + // "ambiguous" argument indicates whether the query intersected an + // endpoint or tangent point of the segment, indicating that another + // query point is preferred. + int numCrossingsForXRay(const XRay& xRay, bool& ambiguous) const + { + if (m_kind == Cubic) + // Should consider caching the monotonic cubics. + return numXRayCrossingsForCubic(xRay, m_points, ambiguous); + + return xRayCrossesLine(xRay, m_points, ambiguous) ? 1 : 0; + } + + // Performs a local triangulation of the control points in this + // segment. This operation only makes sense for cubic type segments. + // texCoords may be null when the klm coordinates have not been + // computed yet. + void triangulate(LoopBlinnLocalTriangulator::InsideEdgeComputation computeInsideEdges, + const LoopBlinnTextureCoords::Result* texCoords); + + // Returns the number of control point triangles associated with + // this segment. + int numberOfTriangles() const + { + if (!m_triangulator) + return 0; + return m_triangulator->numberOfTriangles(); + } + + // Fetches the given control point triangle for this segment. + LoopBlinnLocalTriangulator::Triangle* getTriangle(int index) + { + ASSERT(m_triangulator); + return m_triangulator->getTriangle(index); + } + + // Number of vertices along the inside edge of this segment. This + // can be called either for line or cubic type segments. + int numberOfInteriorVertices() const + { + if (m_kind == Cubic) { + if (m_triangulator) + return m_triangulator->numberOfInteriorVertices(); + + return 0; + } + + return 2; + } + + // Returns the given interior vertex, 0 <= index < numberOfInteriorVertices(). + FloatPoint getInteriorVertex(int index) const + { + ASSERT(index >= 0 && index < numberOfInteriorVertices()); + if (m_kind == Cubic) { + FloatPoint res; + if (m_triangulator) { + LoopBlinnLocalTriangulator::Vertex* vertex = m_triangulator->getInteriorVertex(index); + if (vertex) + res.set(vertex->xyCoordinates().x(), vertex->xyCoordinates().y()); + } + return res; + } + + return m_points[index]; + } + + // State to assist with curve subdivision. + bool markedForSubdivision() const { return m_markedForSubdivision; } + void setMarkedForSubdivision(bool markedForSubdivision) { m_markedForSubdivision = markedForSubdivision; } + +#ifndef NDEBUG + // Suppport for printing Segments. + String toString() const + { + StringBuilder builder; + builder.append("[Segment kind="); + builder.append(kind() == Line ? "line" : "cubic"); + builder.append(" boundingBox="); + builder.append(valueToString(boundingBox())); + builder.append(" contour=0x"); + builder.append(String::format("%p", contour())); + builder.append(" markedForSubdivision="); + builder.append(markedForSubdivision() ? "true" : "false"); + builder.append("]"); + return builder.toString(); + } +#endif + + private: + // Computes the bounding box of this Segment. + void computeBoundingBox() + { + switch (m_kind) { + case Cubic: + m_boundingBox.fitToPoints(m_points[0], m_points[1], m_points[2], m_points[3]); + break; + + case Line: + m_boundingBox.fitToPoints(m_points[0], m_points[1]); + break; + } + } + + PODArena* m_arena; + Kind m_kind; + FloatPoint m_points[4]; + Segment* m_prev; + Segment* m_next; + Contour* m_contour; + FloatRect m_boundingBox; + LoopBlinnLocalTriangulator* m_triangulator; + bool m_markedForSubdivision; +}; + +//---------------------------------------------------------------------- +// Contour +// + +// Describes a closed contour of the path. +class Contour { + WTF_MAKE_NONCOPYABLE(Contour); +public: + Contour() + { + m_first = &m_sentinel; + m_first->setNext(m_first); + m_first->setPrev(m_first); + m_isOrientedCounterClockwise = true; + m_boundingBoxDirty = false; + m_fillSide = LoopBlinnConstants::RightSide; + } + + void add(Segment* segment) + { + if (m_first == &m_sentinel) { + // First element is the sentinel. Replace it with the incoming + // segment. + segment->setNext(m_first); + segment->setPrev(m_first); + m_first->setNext(segment); + m_first->setPrev(segment); + m_first = segment; + } else { + // m_first->prev() is the sentinel. + ASSERT(m_first->prev() == &m_sentinel); + Segment* last = m_sentinel.prev(); + last->setNext(segment); + segment->setPrev(last); + segment->setNext(&m_sentinel); + m_sentinel.setPrev(segment); + } + m_boundingBoxDirty = true; + } + + // Subdivides the given segment at the given parametric value. + // Returns a pointer to the first of the two portions of the + // subdivided segment. + Segment* subdivide(Segment* segment, float param) + { + Segment* left = segment->subdivide(param); + if (m_first == segment) + m_first = left; + return left; + } + + // Subdivides the given segment at the halfway point. Returns a + // pointer to the first of the two portions of the subdivided + // segment. + Segment* subdivide(Segment* segment) + { + Segment* left = segment->subdivide(); + if (m_first == segment) + m_first = left; + return left; + } + + // Returns the first segment in the contour for iteration. + Segment* begin() const { return m_first; } + + // Returns the last segment in the contour for iteration. Callers + // should not iterate over this segment. In other words: + // for (Segment* cur = contour->begin(); + // cur != contour->end(); + // cur = cur->next()) { + // // .. process cur ... + // } + Segment* end() + { + ASSERT(m_first->prev() == &m_sentinel); + return &m_sentinel; + } + + bool isOrientedCounterClockwise() const { return m_isOrientedCounterClockwise; } + void setIsOrientedCounterClockwise(bool isOrientedCounterClockwise) { m_isOrientedCounterClockwise = isOrientedCounterClockwise; } + + const FloatRect& boundingBox() + { + if (m_boundingBoxDirty) { + bool first = true; + for (Segment* cur = begin(); cur != end(); cur = cur->next()) { + if (first) + m_boundingBox = cur->boundingBox(); + else + m_boundingBox.unite(cur->boundingBox()); + first = false; + } + + m_boundingBoxDirty = false; + } + return m_boundingBox; + } + + // Returns which side of this contour is filled. + LoopBlinnConstants::FillSide fillSide() const + { + return m_fillSide; + } + + void setFillSide(LoopBlinnConstants::FillSide fillSide) + { + m_fillSide = fillSide; + } + +private: + // The start of the segment chain. The segments are kept in a + // circular doubly linked list for rapid access to the beginning and + // end. + Segment* m_first; + + // The sentinel element at the end of the chain, needed for + // reasonable iteration semantics. + Segment m_sentinel; + + bool m_isOrientedCounterClockwise; + + FloatRect m_boundingBox; + bool m_boundingBoxDirty; + + // Which side of this contour should be filled. + LoopBlinnConstants::FillSide m_fillSide; +}; + +//---------------------------------------------------------------------- +// Segment +// + +// Definition of Segment::triangulate(), which must come after +// declaration of Contour. +void Segment::triangulate(LoopBlinnLocalTriangulator::InsideEdgeComputation computeInsideEdges, + const LoopBlinnTextureCoords::Result* texCoords) +{ + ASSERT(m_kind == Cubic); + if (!m_triangulator) + m_triangulator = m_arena->allocateObject<LoopBlinnLocalTriangulator>(); + m_triangulator->reset(); + for (int i = 0; i < 4; i++) { + LoopBlinnLocalTriangulator::Vertex* vertex = m_triangulator->getVertex(i); + if (texCoords) { + vertex->set(getPoint(i).x(), + getPoint(i).y(), + texCoords->klmCoordinates[i].x(), + texCoords->klmCoordinates[i].y(), + texCoords->klmCoordinates[i].z()); + } else { + vertex->set(getPoint(i).x(), + getPoint(i).y(), + // No texture coordinates yet + 0, 0, 0); + } + } + m_triangulator->triangulate(computeInsideEdges, contour()->fillSide()); +} + +} // namespace LoopBlinnPathProcessorImplementation + +//---------------------------------------------------------------------- +// LoopBlinnPathProcessor +// + +LoopBlinnPathProcessor::LoopBlinnPathProcessor() + : m_arena(PODArena::create()) +#ifndef NDEBUG + , m_verboseLogging(false) +#endif +{ +} + +LoopBlinnPathProcessor::LoopBlinnPathProcessor(PassRefPtr<PODArena> arena) + : m_arena(arena) +#ifndef NDEBUG + , m_verboseLogging(false) +#endif +{ +} + +LoopBlinnPathProcessor::~LoopBlinnPathProcessor() +{ +} + +void LoopBlinnPathProcessor::process(const Path& path, LoopBlinnPathCache& cache) +{ + buildContours(path); + + // Run plane-sweep algorithm to determine overlaps of control point + // curves and subdivide curves appropriately. + subdivideCurves(); + + // Determine orientations of countours. Based on orientation and the + // number of curve crossings at a random point on the contour, + // determine whether to fill the left or right side of the contour. + determineSidesToFill(); + + // Classify curves, compute texture coordinates and subdivide as + // necessary to eliminate rendering artifacts. Do the final + // triangulation of the curve segments, determining the path along + // the interior of the shape. + for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) { + Contour* cur = *iter; + for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) { + if (seg->kind() == Segment::Cubic) { + LoopBlinnClassifier::Result classification = LoopBlinnClassifier::classify(seg->getPoint(0), + seg->getPoint(1), + seg->getPoint(2), + seg->getPoint(3)); +#ifndef NDEBUG + if (m_verboseLogging) + LOG_ERROR("Classification: %d", (int) classification.curveType); +#endif + LoopBlinnTextureCoords::Result texCoords = + LoopBlinnTextureCoords::compute(classification, cur->fillSide()); + if (texCoords.hasRenderingArtifact) { + // FIXME: there is a problem where the algorithm + // sometimes fails to converge when splitting at the + // subdivision parameter value. For the time being, + // split halfway. + cur->subdivide(seg); + // Next iteration will handle the newly subdivided curves + } else { + if (!texCoords.isLineOrPoint) { + seg->triangulate(LoopBlinnLocalTriangulator::ComputeInsideEdges, &texCoords); + for (int i = 0; i < seg->numberOfTriangles(); i++) { + LoopBlinnLocalTriangulator::Triangle* triangle = seg->getTriangle(i); + for (int j = 0; j < 3; j++) { + LoopBlinnLocalTriangulator::Vertex* vert = triangle->getVertex(j); + cache.addVertex(vert->xyCoordinates().x(), + vert->xyCoordinates().y(), + vert->klmCoordinates().x(), + vert->klmCoordinates().y(), + vert->klmCoordinates().z()); + } + } +#ifdef LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES + // Show the end user the interior edges as well + for (int i = 1; i < seg->numberOfInteriorVertices(); i++) { + FloatPoint vert = seg->getInteriorVertex(i); + // Duplicate previous vertex to be able to draw GL_LINES + FloatPoint prev = seg->getInteriorVertex(i - 1); + cache.addInteriorEdgeVertex(prev.x(), prev.y()); + cache.addInteriorEdgeVertex(vert.x(), vert.y()); + } +#endif // LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES + } + } + } + } + } + + // Run the interior paths through a tessellation algorithm + // supporting multiple contours. + tessellateInterior(cache); +} + +void LoopBlinnPathProcessor::buildContours(const Path& path) +{ + // Clear out the contours + m_contours.clear(); +#if PLATFORM(SKIA) + SkPath::Iter iter(*path.platformPath(), false); + SkPoint points[4]; + SkPath::Verb verb; + Contour* contour = 0; + SkPoint curPoint = { 0 }; + SkPoint moveToPoint = { 0 }; + do { + verb = iter.next(points); + if (verb != SkPath::kMove_Verb) { + if (!contour) { + contour = m_arena->allocateObject<Contour>(); + m_contours.append(contour); + } + } + switch (verb) { + case SkPath::kMove_Verb: { + contour = m_arena->allocateObject<Contour>(); + m_contours.append(contour); + curPoint = points[0]; + moveToPoint = points[0]; +#ifndef NDEBUG + if (m_verboseLogging) + LOG_ERROR("MoveTo (%f, %f)", points[0].fX, points[0].fY); +#endif + break; + } + case SkPath::kLine_Verb: { + Segment* segment = m_arena->allocateObject<Segment>(); + if (iter.isCloseLine()) { + segment->setup(m_arena.get(), contour, curPoint, points[1]); +#ifndef NDEBUG + if (m_verboseLogging) + LOG_ERROR("CloseLineTo (%f, %f), (%f, %f)", curPoint.fX, curPoint.fY, points[1].fX, points[1].fY); +#endif + contour->add(segment); + contour = 0; + } else { + segment->setup(m_arena.get(), contour, points[0], points[1]); +#ifndef NDEBUG + if (m_verboseLogging) + LOG_ERROR("LineTo (%f, %f), (%f, %f)", points[0].fX, points[0].fY, points[1].fX, points[1].fY); +#endif + contour->add(segment); + curPoint = points[1]; + } + break; + } + case SkPath::kQuad_Verb: { + // Need to degree elevate the quadratic into a cubic + SkPoint cubic[4]; + SkConvertQuadToCubic(points, cubic); + Segment* segment = m_arena->allocateObject<Segment>(); + segment->setup(m_arena.get(), contour, + cubic[0], cubic[1], cubic[2], cubic[3]); +#ifndef NDEBUG + if (m_verboseLogging) + LOG_ERROR("Quad->CubicTo (%f, %f), (%f, %f), (%f, %f), (%f, %f)", cubic[0].fX, cubic[0].fY, cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY); +#endif + contour->add(segment); + curPoint = cubic[3]; + break; + } + case SkPath::kCubic_Verb: { + Segment* segment = m_arena->allocateObject<Segment>(); + segment->setup(m_arena.get(), contour, points[0], points[1], points[2], points[3]); +#ifndef NDEBUG + if (m_verboseLogging) + LOG_ERROR("CubicTo (%f, %f), (%f, %f), (%f, %f), (%f, %f)", points[0].fX, points[0].fY, points[1].fX, points[1].fY, points[2].fX, points[2].fY, points[3].fX, points[3].fY); +#endif + contour->add(segment); + curPoint = points[3]; + break; + } + case SkPath::kClose_Verb: { + Segment* segment = m_arena->allocateObject<Segment>(); + segment->setup(m_arena.get(), contour, curPoint, moveToPoint); +#ifndef NDEBUG + if (m_verboseLogging) + LOG_ERROR("Close (%f, %f) -> (%f, %f)", curPoint.fX, curPoint.fY, moveToPoint.fX, moveToPoint.fY); +#endif + contour->add(segment); + contour = 0; + } + case SkPath::kDone_Verb: + break; + } + } while (verb != SkPath::kDone_Verb); +#else // !PLATFORM(SKIA) + // Must port to your platform. + ASSERT_NOT_REACHED(); +#endif +} + +#ifndef NDEBUG +Vector<Segment*> LoopBlinnPathProcessor::allSegmentsOverlappingY(Contour* queryContour, float x, float y) +{ + Vector<Segment*> res; + for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) { + Contour* cur = *iter; + for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) { + const FloatRect& boundingBox = seg->boundingBox(); + if (boundingBox.y() <= y && y <= boundingBox.maxY()) + res.append(seg); + } + } + return res; +} +#endif + +// Uncomment this to debug the orientation computation. +// #define GPU_PATH_PROCESSOR_DEBUG_ORIENTATION + +void LoopBlinnPathProcessor::determineSidesToFill() +{ + // Loop and Blinn's algorithm can only easily emulate the even/odd + // fill rule, and only for non-intersecting curves. We can determine + // which side of each curve segment to fill based on its + // clockwise/counterclockwise orientation and how many other + // contours surround it. + + // To optimize the query of all curve segments intersecting a + // horizontal line going to x=+infinity, we build up an interval + // tree whose keys are the y extents of the segments. + PODIntervalTree<float, Segment*> tree(m_arena); + typedef PODIntervalTree<float, Segment*>::IntervalType IntervalType; + + for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) { + Contour* cur = *iter; + determineOrientation(cur); + for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) { + const FloatRect& boundingBox = seg->boundingBox(); + tree.add(tree.createInterval(boundingBox.y(), boundingBox.maxY(), seg)); + } + } + + // Now iterate through the contours and pick a random segment (in + // this case we use the first) and a random point on that segment. + // Find all segments from other contours which intersect this one + // and count the number of crossings a horizontal line to + // x=+infinity makes with those contours. This combined with the + // orientation of the curve tells us which side to fill -- again, + // assuming an even/odd fill rule, which is all we can easily + // handle. + for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) { + Contour* cur = *iter; + + bool ambiguous = true; + int numCrossings = 0; + + // For each contour, attempt to find a point on the contour which, + // when we cast an XRay, does not intersect the other contours at + // an ambiguous point (the junction between two curves or at a + // tangent point). Ambiguous points make the determination of + // whether this contour is contained within another fragile. Note + // that this loop is only an approximation to the selection of a + // good casting point. We could as well evaluate a segment to + // determine a point upon it. + for (Segment* seg = cur->begin(); + ambiguous && seg != cur->end(); + seg = seg->next()) { + numCrossings = 0; + // We use a zero-sized vertical interval for the query. + Vector<IntervalType> overlaps = tree.allOverlaps(tree.createInterval(seg->getPoint(0).y(), + seg->getPoint(0).y(), + 0)); +#if defined(GPU_PATH_PROCESSOR_DEBUG_ORIENTATION) && !defined(NDEBUG) + Vector<Segment*> slowOverlaps = allSegmentsOverlappingY(cur, seg->getPoint(0).x(), seg->getPoint(0).y()); + if (overlaps.size() != slowOverlaps.size()) { + LOG_ERROR("For query point (%f, %f) on contour 0x%p:", seg->getPoint(0).x(), seg->getPoint(0).y(), cur); + LOG_ERROR(" overlaps:"); + for (size_t i = 0; i < overlaps.size(); i++) + LOG_ERROR(" %d: %s", i+1, overlaps[i].data()->toString().ascii().data()); + LOG_ERROR(" slowOverlaps:"); + for (size_t i = 0; i < slowOverlaps.size(); i++) + LOG_ERROR(" %d: %s", (i+1) slowOverlaps[i]->toString()); + LOG_ERROR("Interval tree:"); + tree.dump(); + } + ASSERT(overlaps.size() == slowOverlaps.size()); +#endif // defined(GPU_PATH_PROCESSOR_DEBUG_ORIENTATION) && !defined(NDEBUG) + for (Vector<IntervalType>::iterator iter = overlaps.begin(); iter != overlaps.end(); ++iter) { + const IntervalType& interval = *iter; + Segment* querySegment = interval.data(); + // Ignore segments coming from the same contour. + if (querySegment->contour() != cur) { + // Only perform queries that can affect the computation. + const FloatRect& boundingBox = querySegment->contour()->boundingBox(); + if (seg->getPoint(0).x() >= boundingBox.x() + && seg->getPoint(0).x() <= boundingBox.maxX()) { + numCrossings += querySegment->numCrossingsForXRay(seg->getPoint(0), + ambiguous); + if (ambiguous) { +#ifndef NDEBUG + if (m_verboseLogging) { + LOG_ERROR("Ambiguous intersection query at point (%f, %f)", seg->getPoint(0).x(), seg->getPoint(0).y()); + LOG_ERROR("Query segment: %s", querySegment->toString().ascii().data()); + } +#endif + break; // Abort iteration over overlaps. + } + } + } + } + } // for (Segment* seg = cur->begin(); ... + + cur->setFillSide((cur->isOrientedCounterClockwise() ^ (numCrossings & 1)) ? LoopBlinnConstants::LeftSide : LoopBlinnConstants::RightSide); + } +} + +void LoopBlinnPathProcessor::determineOrientation(Contour* contour) +{ + // Determine signed area of the polygon represented by the points + // along the segments. Consider this an approximation to the true + // orientation of the polygon; it probably won't handle + // self-intersecting curves correctly. + // + // There is also a pretty basic assumption here that the contour is + // closed. + float signedArea = 0; + for (Segment* seg = contour->begin(); + seg != contour->end(); + seg = seg->next()) { + int limit = (seg->kind() == Segment::Cubic) ? 4 : 2; + for (int i = 1; i < limit; i++) { + const FloatPoint& prevPoint = seg->getPoint(i - 1); + const FloatPoint& point = seg->getPoint(i); + float curArea = prevPoint.x() * point.y() - prevPoint.y() * point.x(); +#ifndef NDEBUG + if (m_verboseLogging) + LOG_ERROR("Adding to signed area (%f, %f) -> (%f, %f) = %f", prevPoint.x(), prevPoint.y(), point.x(), point.y(), curArea); +#endif + signedArea += curArea; + } + } + + if (signedArea > 0) + contour->setIsOrientedCounterClockwise(true); + else + contour->setIsOrientedCounterClockwise(false); +} + +namespace { + +//---------------------------------------------------------------------- +// Classes and typedefs needed for curve subdivision. These can't be scoped +// within the subdivideCurves() method itself, because templates then fail +// to instantiate. + +// The user data which is placed in the PODIntervalTree. +struct SweepData { + SweepData() + : triangle(0) + , segment(0) + { + } + + // The triangle this interval is associated with + LoopBlinnLocalTriangulator::Triangle* triangle; + // The segment the triangle is associated with + Segment* segment; +}; + +typedef PODIntervalTree<float, SweepData*> SweepTree; +typedef SweepTree::IntervalType SweepInterval; + +// The entry / exit events which occur at the minimum and maximum x +// coordinates of the control point triangles' bounding boxes. +// +// Note that this class requires its copy constructor and assignment +// operator since it needs to be stored in a Vector. +class SweepEvent { +public: + SweepEvent() + : m_x(0) + , m_entry(false) + , m_interval(0, 0, 0) + { + } + + // Initializes the SweepEvent. + void setup(float x, bool entry, SweepInterval interval) + { + m_x = x; + m_entry = entry; + m_interval = interval; + } + + float x() const { return m_x; } + bool entry() const { return m_entry; } + const SweepInterval& interval() const { return m_interval; } + + bool operator<(const SweepEvent& other) const + { + return m_x < other.m_x; + } + +private: + float m_x; + bool m_entry; + SweepInterval m_interval; +}; + +bool trianglesOverlap(LoopBlinnLocalTriangulator::Triangle* t0, + LoopBlinnLocalTriangulator::Triangle* t1) +{ + return trianglesOverlap(t0->getVertex(0)->xyCoordinates(), + t0->getVertex(1)->xyCoordinates(), + t0->getVertex(2)->xyCoordinates(), + t1->getVertex(0)->xyCoordinates(), + t1->getVertex(1)->xyCoordinates(), + t1->getVertex(2)->xyCoordinates()); +} + +} // anonymous namespace + +void LoopBlinnPathProcessor::subdivideCurves() +{ + // We need to determine all overlaps of all control point triangles + // (from different segments, not the same segment) and, if any + // exist, subdivide the associated curves. + // + // The plane-sweep algorithm determines all overlaps of a set of + // rectangles in the 2D plane. Our problem maps very well to this + // algorithm and significantly reduces the complexity compared to a + // naive implementation. + // + // Each bounding box of a control point triangle is converted into + // an "entry" event at its smallest X coordinate and an "exit" event + // at its largest X coordinate. Each event has an associated + // one-dimensional interval representing the Y span of the bounding + // box. We sort these events by increasing X coordinate. We then + // iterate through them. For each entry event we add the interval to + // a side interval tree, and query this tree for overlapping + // intervals. Any overlapping interval corresponds to an overlapping + // bounding box. For each exit event we remove the associated + // interval from the interval tree. + + Vector<Segment*> curSegments; + Vector<Segment*> nextSegments; + + // Start things off by considering all of the segments + for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) { + Contour* cur = *iter; + for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) { + if (seg->kind() == Segment::Cubic) { + seg->triangulate(LoopBlinnLocalTriangulator::DontComputeInsideEdges, 0); + curSegments.append(seg); + } + } + } + + // Subdivide curves at most this many times + const int MaxIterations = 5; + Vector<SweepInterval> overlaps; + + for (int currentIteration = 0; currentIteration < MaxIterations; ++currentIteration) { + if (!curSegments.size()) + // Done + break; + + Vector<SweepEvent> events; + SweepTree tree(m_arena); + for (Vector<Segment*>::iterator iter = curSegments.begin(); iter != curSegments.end(); ++iter) { + Segment* seg = *iter; + ASSERT(seg->kind() == Segment::Cubic); + for (int i = 0; i < seg->numberOfTriangles(); i++) { + LoopBlinnLocalTriangulator::Triangle* triangle = seg->getTriangle(i); + FloatRect boundingBox; + boundingBox.fitToPoints(triangle->getVertex(0)->xyCoordinates(), + triangle->getVertex(1)->xyCoordinates(), + triangle->getVertex(2)->xyCoordinates()); + // Ignore zero-width triangles to avoid issues with + // coincident entry and exit events for the same triangle + if (boundingBox.maxX() > boundingBox.x()) { + SweepData* data = m_arena->allocateObject<SweepData>(); + data->triangle = triangle; + data->segment = seg; + SweepInterval interval = tree.createInterval(boundingBox.y(), boundingBox.maxY(), data); + // Add entry and exit events + SweepEvent event; + event.setup(boundingBox.x(), true, interval); + events.append(event); + event.setup(boundingBox.maxX(), false, interval); + events.append(event); + } + } + } + + // Sort events by increasing X coordinate + std::sort(events.begin(), events.end()); +#ifndef NDEBUG + for (size_t ii = 1; ii < events.size(); ++ii) + ASSERT(events[ii - 1].x() <= events[ii].x()); +#endif + + // Now iterate through the events + for (Vector<SweepEvent>::iterator iter = events.begin(); iter != events.end(); ++iter) { + SweepEvent event = *iter; + if (event.entry()) { + // See whether the associated segment has been subdivided yet + if (!event.interval().data()->segment->markedForSubdivision()) { + // Query the tree + overlaps.clear(); + tree.allOverlaps(event.interval(), overlaps); + // Now see exactly which triangles overlap this one + for (Vector<SweepInterval>::iterator iter = overlaps.begin(); iter != overlaps.end(); ++iter) { + SweepInterval overlap = *iter; + // Only pay attention to overlaps from a different Segment + if (event.interval().data()->segment != overlap.data()->segment) { + // See whether the triangles actually overlap + if (trianglesOverlap(event.interval().data()->triangle, + overlap.data()->triangle)) { + // Actually subdivide the segments. + // Each one might already have been subdivided. + Segment* seg = event.interval().data()->segment; + conditionallySubdivide(seg, nextSegments); + seg = overlap.data()->segment; + conditionallySubdivide(seg, nextSegments); + } + } + } + } + // Add this interval into the tree + tree.add(event.interval()); + } else { + // Remove this interval from the tree + tree.remove(event.interval()); + } + } + + curSegments.swap(nextSegments); + nextSegments.clear(); + } +} + +void LoopBlinnPathProcessor::conditionallySubdivide(Segment* seg, Vector<Segment*>& nextSegments) +{ + if (!seg->markedForSubdivision()) { + seg->setMarkedForSubdivision(true); + Segment* next = seg->contour()->subdivide(seg); + // Triangulate the newly subdivided segments. + next->triangulate(LoopBlinnLocalTriangulator::DontComputeInsideEdges, 0); + next->next()->triangulate(LoopBlinnLocalTriangulator::DontComputeInsideEdges, 0); + // Add them for the next iteration. + nextSegments.append(next); + nextSegments.append(next->next()); + } +} + +#ifndef NDEBUG +void LoopBlinnPathProcessor::subdivideCurvesSlow() +{ + // Alternate, significantly slower algorithm for curve subdivision + // for use in debugging. + Vector<Segment*> curSegments; + Vector<Segment*> nextSegments; + + // Start things off by considering all of the segments + for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) { + Contour* cur = *iter; + for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) { + if (seg->kind() == Segment::Cubic) { + seg->triangulate(LoopBlinnLocalTriangulator::DontComputeInsideEdges, 0); + curSegments.append(seg); + } + } + } + + // Subdivide curves at most this many times + const int MaxIterations = 5; + + for (int currentIteration = 0; currentIteration < MaxIterations; ++currentIteration) { + if (!curSegments.size()) + // Done + break; + + for (Vector<Segment*>::iterator iter = curSegments.begin(); iter != curSegments.end(); ++iter) { + Segment* seg = *iter; + ASSERT(seg->kind() == Segment::Cubic); + for (Vector<Segment*>::iterator iter2 = curSegments.begin(); + iter2 != curSegments.end(); + iter2++) { + Segment* seg2 = *iter2; + ASSERT(seg2->kind() == Segment::Cubic); + if (seg != seg2) { + for (int i = 0; i < seg->numberOfTriangles(); i++) { + LoopBlinnLocalTriangulator::Triangle* triangle = seg->getTriangle(i); + for (int j = 0; j < seg2->numberOfTriangles(); j++) { + LoopBlinnLocalTriangulator::Triangle* triangle2 = seg2->getTriangle(j); + if (trianglesOverlap(triangle, triangle2)) { + conditionallySubdivide(seg, nextSegments); + conditionallySubdivide(seg2, nextSegments); + } + } + } + } + } + } + + curSegments.swap(nextSegments); + nextSegments.clear(); + } +} +#endif + +namespace { + +//---------------------------------------------------------------------- +// Structures and callbacks for tessellation of the interior region of +// the contours. + +// The user data for the GLU tessellator. +struct TessellationState { + TessellationState(LoopBlinnPathCache& inputCache) + : cache(inputCache) { } + + LoopBlinnPathCache& cache; + Vector<void*> allocatedPointers; +}; + +static void vertexCallback(void* vertexData, void* data) +{ + TessellationState* state = static_cast<TessellationState*>(data); + GLdouble* location = static_cast<GLdouble*>(vertexData); + state->cache.addInteriorVertex(static_cast<float>(location[0]), + static_cast<float>(location[1])); +} + +static void combineCallback(GLdouble coords[3], void* vertexData[4], + GLfloat weight[4], void** outData, + void* polygonData) +{ + TessellationState* state = static_cast<TessellationState*>(polygonData); + GLdouble* outVertex = static_cast<GLdouble*>(fastMalloc(3 * sizeof(GLdouble))); + state->allocatedPointers.append(outVertex); + outVertex[0] = coords[0]; + outVertex[1] = coords[1]; + outVertex[2] = coords[2]; + *outData = outVertex; +} + +static void edgeFlagCallback(GLboolean) +{ + // No-op just to prevent triangle strips and fans from being passed to us. + // See the OpenGL Programming Guide, Chapter 11, "Tessellators and Quadrics". +} + +} // anonymous namespace + +void LoopBlinnPathProcessor::tessellateInterior(LoopBlinnPathCache& cache) +{ + // Because the GLU tessellator requires its input in + // double-precision format, we need to make a separate copy of the + // data. + Vector<GLdouble> vertexData; + Vector<size_t> contourEndings; + // For avoiding adding coincident vertices. + float curX = 0, curY = 0; + for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) { + Contour* cur = *iter; + bool first = true; + for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) { + int numberOfInteriorVertices = seg->numberOfInteriorVertices(); + for (int i = 0; i < numberOfInteriorVertices - 1; i++) { + FloatPoint point = seg->getInteriorVertex(i); + if (first) { + first = false; + vertexData.append(point.x()); + vertexData.append(point.y()); + vertexData.append(0); + curX = point.x(); + curY = point.y(); + } else if (point.x() != curX || point.y() != curY) { + vertexData.append(point.x()); + vertexData.append(point.y()); + vertexData.append(0); + curX = point.x(); + curY = point.y(); + } + } + } + contourEndings.append(vertexData.size()); + } + // Now that we have all of the vertex data in a stable location in + // memory, call the tessellator. + GLUtesselator* tess = internal_gluNewTess(); + TessellationState state(cache); + internal_gluTessCallback(tess, GLU_TESS_VERTEX_DATA, + reinterpret_cast<GLvoid (*)()>(vertexCallback)); + internal_gluTessCallback(tess, GLU_TESS_COMBINE_DATA, + reinterpret_cast<GLvoid (*)()>(combineCallback)); + internal_gluTessCallback(tess, GLU_TESS_EDGE_FLAG, + reinterpret_cast<GLvoid (*)()>(edgeFlagCallback)); + internal_gluTessBeginPolygon(tess, &state); + internal_gluTessBeginContour(tess); + GLdouble* base = vertexData.data(); + int contourIndex = 0; + for (size_t i = 0; i < vertexData.size(); i += 3) { + if (i == contourEndings[contourIndex]) { + internal_gluTessEndContour(tess); + internal_gluTessBeginContour(tess); + ++contourIndex; + } + internal_gluTessVertex(tess, &base[i], &base[i]); + } + internal_gluTessEndContour(tess); + internal_gluTessEndPolygon(tess); + for (size_t i = 0; i < state.allocatedPointers.size(); i++) + fastFree(state.allocatedPointers[i]); + internal_gluDeleteTess(tess); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnPathProcessor.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnPathProcessor.h new file mode 100644 index 0000000..ad89bc1 --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnPathProcessor.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2011 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 AND ITS CONTRIBUTORS "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 OR ITS 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. + */ + +// The main entry point for Loop and Blinn's GPU accelerated curve +// rendering algorithm. + +#ifndef LoopBlinnPathProcessor_h +#define LoopBlinnPathProcessor_h + +#include <wtf/Noncopyable.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +// We use a namespace for classes which are simply implementation +// details of the algorithm but which we need to reference from the +// class definition. +namespace LoopBlinnPathProcessorImplementation { + +class Contour; +class Segment; + +} // namespace LoopBlinnPathProcessorImplementation + +class Path; +class LoopBlinnPathCache; +class PODArena; + +// The LoopBlinnPathProcessor turns a Path (assumed to contain one or +// more closed regions) into a set of exterior and interior triangles, +// stored in the LoopBlinnPathCache. The exterior triangles have +// associated 3D texture coordinates which are used to evaluate the +// curve's inside/outside function on a per-pixel basis. The interior +// triangles are filled with 100% opacity. +// +// Note that the fill style and management of multiple layers are +// separate concerns, handled at a higher level with shaders and +// polygon offsets. +class LoopBlinnPathProcessor { +public: + LoopBlinnPathProcessor(); + explicit LoopBlinnPathProcessor(PassRefPtr<PODArena>); + ~LoopBlinnPathProcessor(); + + // Transforms the given path into a triangle mesh for rendering + // using Loop and Blinn's shader, placing the result into the given + // LoopBlinnPathCache. + void process(const Path&, LoopBlinnPathCache&); + +#ifndef NDEBUG + // Enables or disables verbose logging in debug mode. + void setVerboseLogging(bool onOrOff); +#endif + +private: + // Builds a list of contours for the given path. + void buildContours(const Path&); + + // Determines whether the left or right side of each contour should + // be filled. + void determineSidesToFill(); + + // Determines whether the given (closed) contour is oriented + // clockwise or counterclockwise. + void determineOrientation(LoopBlinnPathProcessorImplementation::Contour*); + + // Subdivides the curves so that there are no overlaps of the + // triangles associated with the curves' control points. + void subdivideCurves(); + + // Helper function used during curve subdivision. + void conditionallySubdivide(LoopBlinnPathProcessorImplementation::Segment*, + Vector<LoopBlinnPathProcessorImplementation::Segment*>& nextSegments); + + // Tessellates the interior regions of the contours. + void tessellateInterior(LoopBlinnPathCache&); + +#ifndef NDEBUG + // For debugging the orientation computation. Returns all of the + // segments overlapping the given Y coordinate. + Vector<LoopBlinnPathProcessorImplementation::Segment*> allSegmentsOverlappingY(LoopBlinnPathProcessorImplementation::Contour*, float x, float y); + + // For debugging the curve subdivision algorithm. Subdivides the + // curves using an alternate, slow (O(n^3)) algorithm. + void subdivideCurvesSlow(); +#endif + + // PODArena from which to allocate temporary objects. + RefPtr<PODArena> m_arena; + + // The contours described by the path. + Vector<LoopBlinnPathProcessorImplementation::Contour*> m_contours; + +#ifndef NDEBUG + // Whether or not to perform verbose logging in debug mode. + bool m_verboseLogging; +#endif +}; + +} // namespace WebCore + +#endif // LoopBlinnPathProcessor_h diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnShader.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnShader.cpp new file mode 100644 index 0000000..364e6c8 --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnShader.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 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 AND ITS CONTRIBUTORS "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 OR ITS 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 "LoopBlinnShader.h" + +#include "GraphicsContext3D.h" + +namespace WebCore { + +LoopBlinnShader::LoopBlinnShader(GraphicsContext3D* context, unsigned program) + : Shader(context, program) +{ + m_worldViewProjectionLocation = context->getUniformLocation(program, "worldViewProjection"); + m_positionLocation = context->getAttribLocation(program, "position"); + m_klmLocation = context->getAttribLocation(program, "klm"); +} + +void LoopBlinnShader::use(unsigned vertexOffset, unsigned klmOffset, const AffineTransform& transform) +{ + m_context->useProgram(m_program); + + float matrix[16]; + affineTo4x4(transform, matrix); + m_context->uniformMatrix4fv(m_worldViewProjectionLocation, false /*transpose*/, matrix, 1 /*count*/); + + m_context->vertexAttribPointer(m_positionLocation, 2, GraphicsContext3D::FLOAT, false, 0, vertexOffset); + m_context->enableVertexAttribArray(m_positionLocation); + + if (m_klmLocation != -1) { + m_context->vertexAttribPointer(m_klmLocation, 3, GraphicsContext3D::FLOAT, false, 0, klmOffset); + m_context->enableVertexAttribArray(m_klmLocation); + } +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnShader.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnShader.h new file mode 100644 index 0000000..2d24dc3 --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnShader.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 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 AND ITS CONTRIBUTORS "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 OR ITS 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 LoopBlinnShader_h +#define LoopBlinnShader_h + +#include "Shader.h" + +namespace WebCore { + +class GraphicsContext3D; + +class LoopBlinnShader : public Shader { +public: + enum Region { + Interior, + Exterior + }; + +protected: + LoopBlinnShader(GraphicsContext3D*, unsigned program); + + // This assumes the vertices and klm coordinates are stored in the + // same, currently bound, buffer object, contiguously and at the + // specified offsets. + void use(unsigned vertexOffset, unsigned klmOffset, const AffineTransform&); + +private: + int m_worldViewProjectionLocation; + int m_positionLocation; + int m_klmLocation; +}; + +} // namespace WebCore + +#endif // LoopBlinnShader_h diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnSolidFillShader.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnSolidFillShader.cpp new file mode 100644 index 0000000..43a97ef --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnSolidFillShader.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 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 AND ITS CONTRIBUTORS "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 OR ITS 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 "LoopBlinnSolidFillShader.h" + +#include "GraphicsContext3D.h" + +namespace WebCore { + +PassOwnPtr<LoopBlinnSolidFillShader> LoopBlinnSolidFillShader::create(GraphicsContext3D* context, + LoopBlinnShader::Region region, + Shader::AntialiasType antialiasType) +{ + VertexType type = (region == Interior) ? LoopBlinnInterior : LoopBlinnExterior; + unsigned program = loadProgram(context, + generateVertex(type, SolidFill), + generateFragment(type, SolidFill, antialiasType)); + if (!program) + return 0; + return new LoopBlinnSolidFillShader(context, program); +} + +LoopBlinnSolidFillShader::LoopBlinnSolidFillShader(GraphicsContext3D* context, unsigned program) + : LoopBlinnShader(context, program) +{ + m_colorLocation = context->getUniformLocation(program, "color"); +} + +void LoopBlinnSolidFillShader::use(unsigned vertexOffset, unsigned klmOffset, const AffineTransform& transform, const Color& color) +{ + LoopBlinnShader::use(vertexOffset, klmOffset, transform); + + float rgba[4]; + color.getRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); + m_context->uniform4f(m_colorLocation, rgba[0] * rgba[3], rgba[1] * rgba[3], rgba[2] * rgba[3], rgba[3]); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnSolidFillShader.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnSolidFillShader.h new file mode 100644 index 0000000..36312a2 --- /dev/null +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnSolidFillShader.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 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 AND ITS CONTRIBUTORS "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 OR ITS 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 LoopBlinnSolidFillShader_h +#define LoopBlinnSolidFillShader_h + +#include "LoopBlinnShader.h" + +namespace WebCore { + +class GraphicsContext3D; + +class LoopBlinnSolidFillShader : public LoopBlinnShader { +public: + static PassOwnPtr<LoopBlinnSolidFillShader> create(GraphicsContext3D*, Region, AntialiasType); + + // This assumes the vertices and klm coordinates are stored in the + // same, currently bound, buffer object, contiguously and at the + // specified offsets. + void use(unsigned vertexOffset, unsigned klmOffset, const AffineTransform&, const Color&); + +private: + LoopBlinnSolidFillShader(GraphicsContext3D*, unsigned program); + + int m_colorLocation; +}; + +} // namespace WebCore + +#endif // LoopBlinnSolidFillShader_h diff --git a/Source/WebCore/platform/graphics/gpu/Shader.cpp b/Source/WebCore/platform/graphics/gpu/Shader.cpp index 6978322..1b9bfd5 100644 --- a/Source/WebCore/platform/graphics/gpu/Shader.cpp +++ b/Source/WebCore/platform/graphics/gpu/Shader.cpp @@ -38,6 +38,7 @@ #include "GraphicsContext3D.h" #include <wtf/text/CString.h> +#include <wtf/text/StringBuilder.h> namespace WebCore { @@ -56,14 +57,34 @@ void Shader::affineTo3x3(const AffineTransform& transform, float mat[9]) } // static -unsigned Shader::loadShader(GraphicsContext3D* context, unsigned type, const char* shaderSource) +void Shader::affineTo4x4(const AffineTransform& transform, float mat[16]) +{ + mat[0] = transform.a(); + mat[1] = transform.b(); + mat[2] = 0.0f; + mat[3] = 0.0f; + mat[4] = transform.c(); + mat[5] = transform.d(); + mat[6] = 0.0f; + mat[7] = 0.0f; + mat[8] = 0.0f; + mat[9] = 0.0f; + mat[10] = 1.0f; + mat[11] = 0.0f; + mat[12] = transform.e(); + mat[13] = transform.f(); + mat[14] = 0.0f; + mat[15] = 1.0f; +} + +// static +unsigned Shader::loadShader(GraphicsContext3D* context, unsigned type, const String& shaderSource) { unsigned shader = context->createShader(type); if (!shader) return 0; - String shaderSourceStr(shaderSource); - context->shaderSource(shader, shaderSourceStr); + context->shaderSource(shader, shaderSource); context->compileShader(shader); int compileStatus = 0; context->getShaderiv(shader, GraphicsContext3D::COMPILE_STATUS, &compileStatus); @@ -77,7 +98,7 @@ unsigned Shader::loadShader(GraphicsContext3D* context, unsigned type, const cha } // static -unsigned Shader::loadProgram(GraphicsContext3D* context, const char* vertexShaderSource, const char* fragmentShaderSource) +unsigned Shader::loadProgram(GraphicsContext3D* context, const String& vertexShaderSource, const String& fragmentShaderSource) { unsigned vertexShader = loadShader(context, GraphicsContext3D::VERTEX_SHADER, vertexShaderSource); if (!vertexShader) @@ -111,6 +132,146 @@ Shader::~Shader() m_context->deleteProgram(m_program); } +// static +String Shader::generateVertex(Shader::VertexType vertexType, Shader::FillType fillType) +{ + StringBuilder builder; + switch (vertexType) { + case TwoDimensional: + builder.append( + "uniform mat3 matrix;\n" + "attribute vec3 position;\n"); + break; + case LoopBlinnInterior: + builder.append( + "uniform mat4 worldViewProjection;\n" + "attribute vec2 position;\n"); + break; + case LoopBlinnExterior: + builder.append( + "uniform mat4 worldViewProjection;\n" + "attribute vec2 position;\n" + "attribute vec3 klm;\n" + "varying vec3 v_klm;\n"); + break; + } + + if (fillType == TextureFill) { + builder.append( + "uniform mat3 texMatrix;\n" + "varying vec3 texCoord;\n"); + } + + builder.append( + "void main() {\n"); + + if (vertexType == TwoDimensional) { + builder.append( + "gl_Position = vec4(matrix * position, 1.0);\n"); + } else { + builder.append( + "gl_Position = worldViewProjection * vec4(position, 0.0, 1.0);\n"); + if (vertexType == LoopBlinnExterior) { + builder.append( + "v_klm = klm;\n"); + } + } + + if (fillType == TextureFill) { + builder.append( + "texCoord = texMatrix * position;\n"); + } + + builder.append( + "}\n"); + + return builder.toString(); } +// static +String Shader::generateFragment(Shader::VertexType vertexType, Shader::FillType fillType, Shader::AntialiasType antialiasType) +{ + StringBuilder builder; + builder.append( + "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n"); + + if (vertexType == LoopBlinnExterior) { + if (antialiasType == Antialiased) { + builder.append( + "#extension GL_OES_standard_derivatives : enable\n"); + } + builder.append( + "varying vec3 v_klm;\n"); + } + + switch (fillType) { + case SolidFill: + builder.append( + "uniform vec4 color;\n"); + break; + case TextureFill: + builder.append( + "uniform sampler2D sampler;\n" + "uniform float globalAlpha;\n" + "varying vec3 texCoord;\n"); + break; + } + + builder.append( + "void main() {\n"); + + if (vertexType != LoopBlinnExterior) { + builder.append( + "float alpha = 1.0;\n"); + } else { + if (antialiasType == Antialiased) { + builder.append( + " // Gradients\n" + " vec3 px = dFdx(v_klm);\n" + " vec3 py = dFdy(v_klm);\n" + "\n" + " // Chain rule\n" + " float k2 = v_klm.x * v_klm.x;\n" + " float c = k2 * v_klm.x - v_klm.y * v_klm.z;\n" + " float k23 = 3.0 * k2;\n" + " float cx = k23 * px.x - v_klm.z * px.y - v_klm.y * px.z;\n" + " float cy = k23 * py.x - v_klm.z * py.y - v_klm.y * py.z;\n" + "\n" + " // Signed distance\n" + " float sd = c / sqrt(cx * cx + cy * cy);\n" + "\n" + " // Linear alpha\n" + " // FIXME: figure out why this needs to be\n" + " // negated compared to the HLSL version, and also why\n" + " // we need an adjustment by +1.0 for it to look good.\n" + " // float alpha = clamp(0.5 - sd, 0.0, 1.0);\n" + " float alpha = clamp(sd + 0.5, 0.0, 1.0);\n"); + } else { + builder.append( + " float t = v_klm.x * v_klm.x * v_klm.x - v_klm.y * v_klm.z;\n" + " float alpha = clamp(sign(t), 0.0, 1.0);\n"); + } + } + + switch (fillType) { + case SolidFill: + builder.append( + "gl_FragColor = color * alpha;\n"); + break; + case TextureFill: + builder.append( + "gl_FragColor = texture2D(sampler, texCoord.xy) * alpha * globalAlpha;\n"); + break; + } + + builder.append( + "}\n"); + + return builder.toString(); +} + +} // namespace WebCore + #endif diff --git a/Source/WebCore/platform/graphics/gpu/Shader.h b/Source/WebCore/platform/graphics/gpu/Shader.h index 4f62ca9..35d1a3b 100644 --- a/Source/WebCore/platform/graphics/gpu/Shader.h +++ b/Source/WebCore/platform/graphics/gpu/Shader.h @@ -33,6 +33,7 @@ #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> +#include <wtf/text/WTFString.h> namespace WebCore { @@ -42,13 +43,35 @@ class Color; class Shader { WTF_MAKE_NONCOPYABLE(Shader); +public: + enum VertexType { + TwoDimensional, + LoopBlinnInterior, + LoopBlinnExterior + }; + + enum FillType { + SolidFill, + TextureFill + }; + + // Currently only applies to the Loop-Blinn vertex type. + enum AntialiasType { + NotAntialiased, + Antialiased + }; + protected: Shader(GraphicsContext3D*, unsigned program); ~Shader(); + static String generateVertex(VertexType, FillType); + static String generateFragment(VertexType, FillType, AntialiasType); + static void affineTo3x3(const AffineTransform&, float mat[9]); - static unsigned loadShader(GraphicsContext3D*, unsigned type, const char* shaderSource); - static unsigned loadProgram(GraphicsContext3D*, const char* vertexShaderSource, const char* fragmentShaderSource); + static void affineTo4x4(const AffineTransform&, float mat[16]); + static unsigned loadShader(GraphicsContext3D*, unsigned type, const String& shaderSource); + static unsigned loadProgram(GraphicsContext3D*, const String& vertexShaderSource, const String& fragmentShaderSource); GraphicsContext3D* m_context; unsigned m_program; diff --git a/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp b/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp index 86079be..78381f0 100644 --- a/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp +++ b/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp @@ -49,23 +49,9 @@ SolidFillShader::SolidFillShader(GraphicsContext3D* context, unsigned program) PassOwnPtr<SolidFillShader> SolidFillShader::create(GraphicsContext3D* context) { - static const char* vertexShaderSource = - "uniform mat3 matrix;\n" - "uniform vec4 color;\n" - "attribute vec3 position;\n" - "void main() {\n" - " gl_Position = vec4(matrix * position, 1.0);\n" - "}\n"; - static const char* fragmentShaderSource = - "#ifdef GL_ES\n" - "precision mediump float;\n" - "#endif\n" - "uniform mat3 matrix;\n" - "uniform vec4 color;\n" - "void main() {\n" - " gl_FragColor = color;\n" - "}\n"; - unsigned program = loadProgram(context, vertexShaderSource, fragmentShaderSource); + unsigned program = loadProgram(context, + generateVertex(Shader::TwoDimensional, Shader::SolidFill), + generateFragment(Shader::TwoDimensional, Shader::SolidFill, Shader::NotAntialiased)); if (!program) return 0; return new SolidFillShader(context, program); diff --git a/Source/WebCore/platform/graphics/gpu/TexShader.cpp b/Source/WebCore/platform/graphics/gpu/TexShader.cpp index d7ffa17..9eb5c16 100644 --- a/Source/WebCore/platform/graphics/gpu/TexShader.cpp +++ b/Source/WebCore/platform/graphics/gpu/TexShader.cpp @@ -43,33 +43,16 @@ TexShader::TexShader(GraphicsContext3D* context, unsigned program) { m_matrixLocation = context->getUniformLocation(program, "matrix"); m_texMatrixLocation = context->getUniformLocation(program, "texMatrix"); - m_alphaLocation = context->getUniformLocation(program, "alpha"); + m_alphaLocation = context->getUniformLocation(program, "globalAlpha"); m_positionLocation = context->getAttribLocation(program, "position"); m_samplerLocation = context->getUniformLocation(program, "sampler"); } PassOwnPtr<TexShader> TexShader::create(GraphicsContext3D* context) { - static const char* vertexShaderSource = - "uniform mat3 matrix;\n" - "uniform mat3 texMatrix;\n" - "attribute vec3 position;\n" - "varying vec3 texCoord;\n" - "void main() {\n" - " texCoord = texMatrix * position;\n" - " gl_Position = vec4(matrix * position, 1.0);\n" - "}\n"; - static const char* fragmentShaderSource = - "#ifdef GL_ES\n" - "precision mediump float;\n" - "#endif\n" - "uniform sampler2D sampler;\n" - "uniform float alpha;\n" - "varying vec3 texCoord;\n" - "void main() {\n" - " gl_FragColor = texture2D(sampler, texCoord.xy)* vec4(alpha);\n" - "}\n"; - unsigned program = loadProgram(context, vertexShaderSource, fragmentShaderSource); + unsigned program = loadProgram(context, + generateVertex(Shader::TwoDimensional, Shader::TextureFill), + generateFragment(Shader::TwoDimensional, Shader::TextureFill, Shader::NotAntialiased)); if (!program) return 0; return new TexShader(context, program); diff --git a/Source/WebCore/platform/graphics/gpu/Texture.cpp b/Source/WebCore/platform/graphics/gpu/Texture.cpp index e1f8114..b1ba827 100644 --- a/Source/WebCore/platform/graphics/gpu/Texture.cpp +++ b/Source/WebCore/platform/graphics/gpu/Texture.cpp @@ -166,7 +166,7 @@ void Texture::updateSubRect(void* pixels, const IntRect& updateRect) int tempBuffSize = // Temporary buffer size is the smaller of the max texture size or the updateRectSanitized min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRectSanitized.width()) * min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRectSanitized.height()); - OwnArrayPtr<uint32_t> tempBuff(new uint32_t[tempBuffSize]); + OwnArrayPtr<uint32_t> tempBuff = adoptArrayPtr(new uint32_t[tempBuffSize]); for (int tile = 0; tile < m_tiles.numTiles(); tile++) { // Intersect with tile diff --git a/Source/WebCore/platform/graphics/gpu/TilingData.cpp b/Source/WebCore/platform/graphics/gpu/TilingData.cpp index a98add7..e7c4e4c 100644 --- a/Source/WebCore/platform/graphics/gpu/TilingData.cpp +++ b/Source/WebCore/platform/graphics/gpu/TilingData.cpp @@ -89,9 +89,9 @@ IntRect TilingData::tileBoundsWithBorder(int tile) const if (m_borderTexels) { int x1 = bounds.x(); - int x2 = bounds.right(); + int x2 = bounds.maxX(); int y1 = bounds.y(); - int y2 = bounds.bottom(); + int y2 = bounds.maxY(); if (tileXIndex(tile) > 0) x1--; @@ -182,8 +182,8 @@ IntRect TilingData::overlappedTileIndices(const WebCore::IntRect &srcRect) const { int x = tileXIndexFromSrcCoord(srcRect.x()); int y = tileYIndexFromSrcCoord(srcRect.y()); - int r = tileXIndexFromSrcCoord(srcRect.right()); - int b = tileYIndexFromSrcCoord(srcRect.bottom()); + int r = tileXIndexFromSrcCoord(srcRect.maxX()); + int b = tileYIndexFromSrcCoord(srcRect.maxY()); return IntRect(x, y, r - x, b - y); } diff --git a/Source/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm b/Source/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm index e6dfdb8..13c0968 100644 --- a/Source/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm +++ b/Source/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(3D_CANVAS) +#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(WEBGL) #include "DrawingBuffer.h" diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index c113c69..69bdeab 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -1384,11 +1384,15 @@ static HashSet<String> mimeTypeCache() // These formats are supported by GStreamer, but not // correctly advertised. - if (g_str_equal(name, "video/x-h264") - || g_str_equal(name, "audio/x-m4a")) { + if (g_str_equal(name, "video/x-h264")) { cache.add(String("video/mp4")); + cached = true; + } + + if (g_str_equal(name, "audio/x-m4a")) { cache.add(String("audio/aac")); cache.add(String("audio/mp4")); + cache.add(String("audio/x-m4a")); cached = true; } @@ -1466,6 +1470,15 @@ static HashSet<String> mimeTypeCache() for (int index = 0; extensions[index]; index++) { if (g_str_equal(extensions[index], "m4v")) cache.add(String("video/x-m4v")); + + // Workaround for + // https://bugzilla.gnome.org/show_bug.cgi?id=640709. + // typefindfunctions <= 0.10.32 doesn't + // register the H264 typefinder correctly so + // as a workaround we check the registered + // file extensions for it. + if (g_str_equal(extensions[index], "h264")) + cache.add(String("video/mp4")); } } } diff --git a/Source/WebCore/platform/graphics/gtk/FontGtk.cpp b/Source/WebCore/platform/graphics/gtk/FontGtk.cpp index 4d6f509..216fb56 100644 --- a/Source/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/Source/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -215,6 +215,11 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } +bool Font::canExpandAroundIdeographsInComplexText() +{ + return false; +} + static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point, PangoLayoutLine* layoutLine, PangoRegionType renderRegion) { ContextShadow* shadow = graphicsContext->contextShadow(); diff --git a/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp index ce7ec46..017b1e4 100644 --- a/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp @@ -31,7 +31,7 @@ FontCustomPlatformData::~FontCustomPlatformData() { } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode) { return FontPlatformData(size, bold, italic); } diff --git a/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h index 86f99b2..7ffe89a 100644 --- a/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/haiku/FontCustomPlatformData.h @@ -23,6 +23,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" +#include "FontWidthVariant.h" #include <wtf/Forward.h> namespace WebCore { @@ -38,7 +39,7 @@ namespace WebCore { static bool supportsFormat(const String&); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); }; FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*); diff --git a/Source/WebCore/platform/graphics/haiku/FontHaiku.cpp b/Source/WebCore/platform/graphics/haiku/FontHaiku.cpp index 819fecb..5a1a1d0 100644 --- a/Source/WebCore/platform/graphics/haiku/FontHaiku.cpp +++ b/Source/WebCore/platform/graphics/haiku/FontHaiku.cpp @@ -65,6 +65,11 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } +bool Font::canExpandAroundIdeographsInComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { diff --git a/Source/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp b/Source/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp index b1e7082..4ded761 100644 --- a/Source/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp +++ b/Source/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp @@ -48,11 +48,11 @@ void SimpleFontData::platformInit() font_height height; font->GetHeight(&height); - m_ascent = static_cast<int>(height.ascent); - m_descent = static_cast<int>(height.descent); - m_lineSpacing = m_ascent + m_descent; - m_xHeight = height.ascent * 0.56f; // Hack taken from the win port. - m_lineGap = height.leading; + m_fontMetrics.setAscent(height.ascent); + m_fontMetrics.setDescent(height.descent); + m_fontMetrics.setXHeight(height.ascent * 0.56f); // Hack taken from the win port. + m_fontMetrics.setLineGap(height.leading); + m_fontMetrics.setLineSpacing(lroundf(height.ascent) + lroundf(height.descent) + lroundf(height.leading)); } void SimpleFontData::platformCharWidthInit() diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp index 86f6bec..1fe3d28 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp +++ b/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,14 +25,13 @@ #include "config.h" #include "ComplexTextController.h" -#include <ApplicationServices/ApplicationServices.h> -#include "CharacterNames.h" #include "FloatSize.h" #include "Font.h" #include "TextBreakIterator.h" #include "TextRun.h" - +#include <ApplicationServices/ApplicationServices.h> #include <wtf/StdLibExtras.h> +#include <wtf/unicode/CharacterNames.h> #if defined(BUILDING_ON_LEOPARD) // Undefined when compiling agains the 10.5 SDK. @@ -71,7 +70,8 @@ ComplexTextController::ComplexTextController(const Font* font, const TextRun& ru , m_glyphInCurrentRun(0) , m_characterInCurrentGlyph(0) , m_finalRoundingWidth(0) - , m_padding(run.padding()) + , m_expansion(run.expansion()) + , m_afterExpansion(true) , m_fallbackFonts(fallbackFonts) , m_minGlyphBoundingBoxX(numeric_limits<float>::max()) , m_maxGlyphBoundingBoxX(numeric_limits<float>::min()) @@ -79,19 +79,18 @@ ComplexTextController::ComplexTextController(const Font* font, const TextRun& ru , m_maxGlyphBoundingBoxY(numeric_limits<float>::min()) , m_lastRoundingGlyph(0) { - if (!m_padding) - m_padPerSpace = 0; + if (!m_expansion) + m_expansionPerOpportunity = 0; else { - int numSpaces = 0; - for (int s = 0; s < m_run.length(); s++) { - if (Font::treatAsSpace(m_run[s])) - numSpaces++; - } + bool isAfterExpansion = true; + unsigned expansionOpportunityCount = Font::expansionOpportunityCount(m_run.characters(), m_end, m_run.ltr() ? LTR : RTL, isAfterExpansion); + if (isAfterExpansion && !m_run.allowsTrailingExpansion()) + expansionOpportunityCount--; - if (!numSpaces) - m_padPerSpace = 0; + if (!expansionOpportunityCount) + m_expansionPerOpportunity = 0; else - m_padPerSpace = m_padding / numSpaces; + m_expansionPerOpportunity = m_expansion / expansionOpportunityCount; } collectComplexTextRuns(); @@ -118,9 +117,9 @@ int ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs) CFIndex hitGlyphStart = complexTextRun.indexAt(j); CFIndex hitGlyphEnd; if (m_run.ltr()) - hitGlyphEnd = max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : static_cast<CFIndex>(complexTextRun.stringLength())); + hitGlyphEnd = max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : static_cast<CFIndex>(complexTextRun.indexEnd())); else - hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : static_cast<CFIndex>(complexTextRun.stringLength())); + hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : static_cast<CFIndex>(complexTextRun.indexEnd())); // FIXME: Instead of dividing the glyph's advance equally between the characters, this // could use the glyph's "ligature carets". However, there is no Core Text API to get the @@ -311,6 +310,7 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* font , m_characters(characters) , m_stringLocation(stringLocation) , m_stringLength(stringLength) + , m_indexEnd(stringLength) , m_isMonotonic(true) { #if USE(CORE_TEXT) && USE(ATSUI) @@ -335,7 +335,7 @@ void ComplexTextController::ComplexTextRun::setIsNonMonotonic() m_glyphEndOffsets.grow(m_glyphCount); for (size_t i = 0; i < m_glyphCount; ++i) { - CFIndex nextMappedIndex = m_stringLength; + CFIndex nextMappedIndex = m_indexEnd; for (size_t j = indexAt(i) + 1; j < m_stringLength; ++j) { if (mappedIndices[j]) { nextMappedIndex = j; @@ -370,9 +370,9 @@ void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) unsigned glyphEndOffset; if (complexTextRun.isMonotonic()) { if (ltr) - glyphEndOffset = max<unsigned>(glyphStartOffset, g + 1 < glyphCount ? static_cast<unsigned>(complexTextRun.indexAt(g + 1)) : complexTextRun.stringLength()); + glyphEndOffset = max<unsigned>(glyphStartOffset, static_cast<unsigned>(g + 1 < glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.indexEnd())); else - glyphEndOffset = max<unsigned>(glyphStartOffset, g > 0 ? static_cast<unsigned>(complexTextRun.indexAt(g - 1)) : complexTextRun.stringLength()); + glyphEndOffset = max<unsigned>(glyphStartOffset, static_cast<unsigned>(g > 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.indexEnd())); } else glyphEndOffset = complexTextRun.endOffsetAt(g); @@ -386,7 +386,7 @@ void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph; m_characterInCurrentGlyph = min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset; - // FIXME: Instead of dividing the glyph's advance equially between the characters, this + // FIXME: Instead of dividing the glyph's advance equally between the characters, this // could use the glyph's "ligature carets". However, there is no Core Text API to get the // ligature carets. if (glyphStartOffset == glyphEndOffset) { @@ -421,6 +421,7 @@ void ComplexTextController::adjustGlyphsAndAdvances() { CGFloat widthSinceLastRounding = 0; size_t runCount = m_complexTextRuns.size(); + bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_expansion) && !m_run.spacingDisabled(); for (size_t r = 0; r < runCount; ++r) { ComplexTextRun& complexTextRun = *m_complexTextRuns[r]; unsigned glyphCount = complexTextRun.glyphCount(); @@ -433,7 +434,6 @@ void ComplexTextController::adjustGlyphsAndAdvances() const UChar* cp = complexTextRun.characters(); CGFloat roundedSpaceWidth = roundCGFloat(fontData->spaceWidth()); bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances(); - bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_padding) && !m_run.spacingDisabled(); CGPoint glyphOrigin = CGPointZero; CFIndex lastCharacterIndex = m_run.ltr() ? numeric_limits<CFIndex>::min() : numeric_limits<CFIndex>::max(); bool isMonotonic = true; @@ -489,25 +489,29 @@ void ComplexTextController::adjustGlyphsAndAdvances() advance.width += m_font.letterSpacing(); // Handle justification and word-spacing. - if (treatAsSpace) { - // Account for padding. WebCore uses space padding to justify text. - // We distribute the specified padding over the available spaces in the run. - if (m_padding) { - // Use leftover padding if not evenly divisible by number of spaces. - if (m_padding < m_padPerSpace) { - advance.width += m_padding; - m_padding = 0; - } else { - float previousPadding = m_padding; - m_padding -= m_padPerSpace; - advance.width += roundf(previousPadding) - roundf(m_padding); + if (treatAsSpace || Font::isCJKIdeographOrSymbol(ch)) { + // Distribute the run's total expansion evenly over all expansion opportunities in the run. + if (m_expansion && (!lastGlyph || m_run.allowsTrailingExpansion())) { + float previousExpansion = m_expansion; + if (!treatAsSpace && !m_afterExpansion) { + // Take the expansion opportunity before this ideograph. + m_expansion -= m_expansionPerOpportunity; + int expansion = roundf(previousExpansion) - roundf(m_expansion); + m_totalWidth += expansion; + m_adjustedAdvances.last().width += expansion; + previousExpansion = m_expansion; } - } + m_expansion -= m_expansionPerOpportunity; + advance.width += roundf(previousExpansion) - roundf(m_expansion); + m_afterExpansion = true; + } else + m_afterExpansion = false; // Account for word-spacing. - if (characterIndex > 0 && !Font::treatAsSpace(*m_run.data(characterIndex - 1)) && m_font.wordSpacing()) + if (treatAsSpace && characterIndex > 0 && !Font::treatAsSpace(*m_run.data(characterIndex - 1)) && m_font.wordSpacing()) advance.width += m_font.wordSpacing(); - } + } else + m_afterExpansion = false; } // Deal with the float/integer impedance mismatch between CG and WebCore. "Words" (characters @@ -549,9 +553,9 @@ void ComplexTextController::adjustGlyphsAndAdvances() FloatRect glyphBounds = fontData->boundsForGlyph(glyph); glyphBounds.move(glyphOrigin.x, glyphOrigin.y); m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphBounds.x()); - m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.right()); + m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.maxX()); m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphBounds.y()); - m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.bottom()); + m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.maxY()); glyphOrigin.x += advance.width; glyphOrigin.y += advance.height; diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextController.h b/Source/WebCore/platform/graphics/mac/ComplexTextController.h index 9cf80a6..63f93a2 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextController.h +++ b/Source/WebCore/platform/graphics/mac/ComplexTextController.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -72,9 +72,9 @@ private: class ComplexTextRun : public RefCounted<ComplexTextRun> { public: #if USE(CORE_TEXT) - static PassRefPtr<ComplexTextRun> create(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) + static PassRefPtr<ComplexTextRun> create(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, CFRange runRange) { - return adoptRef(new ComplexTextRun(ctRun, fontData, characters, stringLocation, stringLength)); + return adoptRef(new ComplexTextRun(ctRun, fontData, characters, stringLocation, stringLength, runRange)); } #endif #if USE(ATSUI) @@ -94,6 +94,7 @@ private: unsigned stringLocation() const { return m_stringLocation; } size_t stringLength() const { return m_stringLength; } ALWAYS_INLINE CFIndex indexAt(size_t i) const; + CFIndex indexEnd() const { return m_indexEnd; } CFIndex endOffsetAt(size_t i) const { ASSERT(!m_isMonotonic); return m_glyphEndOffsets[i]; } const CGGlyph* glyphs() const { return m_glyphs; } const CGSize* advances() const { return m_advances; } @@ -102,7 +103,7 @@ private: private: #if USE(CORE_TEXT) - ComplexTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength); + ComplexTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, CFRange runRange); void createTextRunFromFontDataCoreText(bool ltr); #endif #if USE(ATSUI) @@ -133,6 +134,7 @@ private: #if USE(ATSUI) Vector<CFIndex, 64> m_atsuiIndices; #endif + CFIndex m_indexEnd; Vector<CFIndex, 64> m_glyphEndOffsets; Vector<CGGlyph, 64> m_glyphsVector; const CGGlyph* m_glyphs; @@ -175,8 +177,9 @@ private: unsigned m_glyphInCurrentRun; unsigned m_characterInCurrentGlyph; float m_finalRoundingWidth; - float m_padding; - float m_padPerSpace; + float m_expansion; + float m_expansionPerOpportunity; + bool m_afterExpansion; HashSet<const SimpleFontData*>* m_fallbackFonts; diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp index 9c2ab6b..b367fdf 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp +++ b/Source/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp @@ -25,10 +25,10 @@ #if USE(ATSUI) -#include "CharacterNames.h" #include "Font.h" #include "ShapeArabic.h" #include "TextRun.h" +#include <wtf/unicode/CharacterNames.h> #ifdef __LP64__ // ATSUTextInserted() is SPI in 64-bit. @@ -146,6 +146,7 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(ATSUTextLayout atsuTextLay , m_characters(characters) , m_stringLocation(stringLocation) , m_stringLength(stringLength) + , m_indexEnd(stringLength) , m_directionalOverride(directionalOverride) , m_isMonotonic(true) { diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp index 07fb153..239113f 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp +++ b/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp @@ -42,12 +42,13 @@ extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel; namespace WebCore { -ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) +ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, CFRange runRange) : m_coreTextRun(ctRun) , m_fontData(fontData) , m_characters(characters) , m_stringLocation(stringLocation) , m_stringLength(stringLength) + , m_indexEnd(runRange.location + runRange.length) , m_isMonotonic(true) { m_glyphCount = CTRunGetGlyphCount(m_coreTextRun.get()); @@ -165,7 +166,8 @@ void ComplexTextController::collectComplexTextRunsForCharactersCoreText(const UC for (CFIndex r = 0; r < runCount; r++) { CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); - m_complexTextRuns.append(ComplexTextRun::create(ctRun, fontData, cp, stringLocation, length)); + CFRange runRange = CTRunGetStringRange(ctRun); + m_complexTextRuns.append(ComplexTextRun::create(ctRun, fontData, cp, stringLocation, length, runRange)); } } diff --git a/Source/WebCore/platform/graphics/mac/FontCacheMac.mm b/Source/WebCore/platform/graphics/mac/FontCacheMac.mm index 068bd8e..c254906 100644 --- a/Source/WebCore/platform/graphics/mac/FontCacheMac.mm +++ b/Source/WebCore/platform/graphics/mac/FontCacheMac.mm @@ -211,7 +211,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD bool syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight); bool syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait); - return new FontPlatformData(platformFont, size, syntheticBold, syntheticOblique, fontDescription.orientation()); + return new FontPlatformData(platformFont, size, syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.widthVariant()); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp b/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp index 02bac9c..865051d 100644 --- a/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp +++ b/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp @@ -111,8 +111,8 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon { ComplexTextController controller(this, run, true, fallbackFonts); if (glyphOverflow) { - glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - ascent()); - glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - descent()); + glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - fontMetrics().ascent()); + glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - fontMetrics().descent()); glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX())); glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.totalWidth())); } diff --git a/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp index d04d0e4..f2bc33d 100644 --- a/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -38,9 +38,9 @@ FontCustomPlatformData::~FontCustomPlatformData() CGFontRelease(m_cgFont); } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, FontWidthVariant widthVariant, FontRenderingMode) { - return FontPlatformData(m_cgFont, size, bold, italic, orientation); + return FontPlatformData(m_cgFont, size, bold, italic, orientation, widthVariant); } FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) diff --git a/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h index 7043d7e..c7ae1ca 100644 --- a/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/mac/FontCustomPlatformData.h @@ -23,6 +23,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" +#include "FontWidthVariant.h" #include <CoreFoundation/CFBase.h> #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -47,7 +48,7 @@ public: ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); diff --git a/Source/WebCore/platform/graphics/mac/FontMac.mm b/Source/WebCore/platform/graphics/mac/FontMac.mm index 8519667..acd7562 100644 --- a/Source/WebCore/platform/graphics/mac/FontMac.mm +++ b/Source/WebCore/platform/graphics/mac/FontMac.mm @@ -47,6 +47,11 @@ bool Font::canReturnFallbackFontsForComplexText() return true; } +bool Font::canExpandAroundIdeographsInComplexText() +{ + return true; +} + static void showGlyphsWithAdvances(const SimpleFontData* font, CGContextRef context, const CGGlyph* glyphs, const CGSize* advances, size_t count) { const FontPlatformData& platformData = font->platformData(); @@ -60,8 +65,8 @@ static void showGlyphsWithAdvances(const SimpleFontData* font, CGContextRef cont savedMatrix = CGContextGetTextMatrix(context); CGAffineTransform runMatrix = CGAffineTransformConcat(savedMatrix, rotateLeftTransform); // Move start point to put glyphs into original region. - runMatrix.tx = savedMatrix.tx + font->ascent(); - runMatrix.ty = savedMatrix.ty + font->descent(); + runMatrix.tx = savedMatrix.tx + font->fontMetrics().ascent(); + runMatrix.ty = savedMatrix.ty + font->fontMetrics().descent(); CGContextSetTextMatrix(context, runMatrix); } diff --git a/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp b/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp index 5388c24..8b04ffa 100644 --- a/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp +++ b/Source/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp @@ -39,8 +39,8 @@ namespace WebCore { #ifndef BUILDING_ON_TIGER static bool shouldUseCoreText(UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { - if (fontData->orientation() == Vertical && !fontData->isBrokenIdeographFont()) { - // Ideographs don't have a vertical variant. + if (fontData->platformData().widthVariant() != RegularWidth || (fontData->orientation() == Vertical && !fontData->isBrokenIdeographFont())) { + // Ideographs don't have a vertical variant or width variants. for (unsigned i = 0; i < bufferLength; ++i) { if (!Font::isCJKIdeograph(buffer[i])) return true; diff --git a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm index 21eb59d..aaa250b 100644 --- a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm +++ b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "GraphicsContext3D.h" @@ -245,6 +245,10 @@ bool GraphicsContext3D::isGLES2Compliant() const return false; } +void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>) +{ +} + } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index 2361f6a..8b1fb92 100644 --- a/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -616,7 +616,7 @@ QTTime MediaPlayerPrivateQTKit::createQTTime(float time) const if (!metaDataAvailable()) return QTMakeTime(0, 600); long timeScale = [[m_qtMovie.get() attributeForKey:QTMovieTimeScaleAttribute] longValue]; - return QTMakeTime(time * timeScale, timeScale); + return QTMakeTime(lroundf(time * timeScale), timeScale); } void MediaPlayerPrivateQTKit::resumeLoad() diff --git a/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index 92585c6..3094498 100644 --- a/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -218,19 +218,20 @@ void SimpleFontData::platformInit() int iAscent; int iDescent; int iLineGap; + unsigned unitsPerEm; #ifdef BUILDING_ON_TIGER - wkGetFontMetrics(m_platformData.cgFont(), &iAscent, &iDescent, &iLineGap, &m_unitsPerEm); + wkGetFontMetrics(m_platformData.cgFont(), &iAscent, &iDescent, &iLineGap, &unitsPerEm); #else iAscent = CGFontGetAscent(m_platformData.cgFont()); iDescent = CGFontGetDescent(m_platformData.cgFont()); iLineGap = CGFontGetLeading(m_platformData.cgFont()); - m_unitsPerEm = CGFontGetUnitsPerEm(m_platformData.cgFont()); + unitsPerEm = CGFontGetUnitsPerEm(m_platformData.cgFont()); #endif float pointSize = m_platformData.m_size; - float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize; - float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize; - float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize; + float ascent = scaleEmToUnits(iAscent, unitsPerEm) * pointSize; + float descent = -scaleEmToUnits(iDescent, unitsPerEm) * pointSize; + float lineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize; // We need to adjust Times, Helvetica, and Courier to closely match the // vertical metrics of their Microsoft counterparts that are the de facto @@ -239,25 +240,23 @@ void SimpleFontData::platformInit() // and add it to the ascent. NSString *familyName = [m_platformData.font() familyName]; if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"]) - fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f); + ascent += floorf(((ascent + descent) * 0.15f) + 0.5f); else if ([familyName isEqualToString:@"Geeza Pro"]) { // Geeza Pro has glyphs that draw slightly above the ascent or far below the descent. Adjust // those vertical metrics to better match reality, so that diacritics at the bottom of one line // do not overlap diacritics at the top of the next line. - fAscent *= 1.08f; - fDescent *= 2.f; + ascent *= 1.08f; + descent *= 2.f; } - m_ascent = lroundf(fAscent); - m_descent = lroundf(fDescent); - m_lineGap = lroundf(fLineGap); - m_lineSpacing = m_ascent + m_descent + m_lineGap; - + // Compute and store line spacing, before the line metrics hacks are applied. + m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); + // Hack Hiragino line metrics to allow room for marked text underlines. // <rdar://problem/5386183> - if (m_descent < 3 && m_lineGap >= 3 && [familyName hasPrefix:@"Hiragino"]) { - m_lineGap -= 3 - m_descent; - m_descent = 3; + if (descent < 3 && lineGap >= 3 && [familyName hasPrefix:@"Hiragino"]) { + lineGap -= 3 - descent; + descent = 3; } if (m_orientation == Vertical) { @@ -278,6 +277,8 @@ void SimpleFontData::platformInit() m_orientation = Horizontal; } + float xHeight; + // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font. // Unfortunately, NSFont will round this for us so we don't quite get the right value. GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); @@ -288,21 +289,27 @@ void SimpleFontData::platformInit() // and web pages that foolishly use this metric for width will be laid out // poorly if we return an accurate height. Classic case is Times 13 point, // which has an "x" that is 7x6 pixels. - m_xHeight = static_cast<float>(max(CGRectGetMaxX(xBox), -CGRectGetMinY(xBox))); + xHeight = static_cast<float>(max(CGRectGetMaxX(xBox), -CGRectGetMinY(xBox))); } else { #ifndef BUILDING_ON_TIGER - m_xHeight = static_cast<float>(CGFontGetXHeight(m_platformData.cgFont())) / m_unitsPerEm; + xHeight = static_cast<float>(CGFontGetXHeight(m_platformData.cgFont())) / unitsPerEm; #else - m_xHeight = m_platformData.font() ? [m_platformData.font() xHeight] : 0; + xHeight = m_platformData.font() ? [m_platformData.font() xHeight] : 0; #endif // CGFontGetXHeight() returns a wrong value for "Apple Symbols" font (a float close to 0, but not strictly 0). - // The following code makes a guess for m_xHeight in that case. + // The following code makes a guess for xHeight in that case. // The int cast is a workaround for the "almost" zero value returned by CGFontGetXHeight(). - if (!static_cast<int>(m_xHeight) && fAscent) - m_xHeight = 2 * fAscent / 3; + if (!static_cast<int>(xHeight) && ascent) + xHeight = 2 * ascent / 3; } + + m_fontMetrics.setUnitsPerEm(unitsPerEm); + m_fontMetrics.setAscent(ascent); + m_fontMetrics.setDescent(descent); + m_fontMetrics.setLineGap(lineGap); + m_fontMetrics.setXHeight(xHeight); } - + static CFDataRef copyFontTableForTag(FontPlatformData& platformData, FourCharCode tableName) { #ifdef BUILDING_ON_TIGER @@ -337,7 +344,7 @@ void SimpleFontData::platformCharWidthInit() if (os2Table && CFDataGetLength(os2Table.get()) >= 4) { const UInt8* os2 = CFDataGetBytePtr(os2Table.get()); SInt16 os2AvgCharWidth = os2[2] * 256 + os2[3]; - m_avgCharWidth = scaleEmToUnits(os2AvgCharWidth, m_unitsPerEm) * m_platformData.m_size; + m_avgCharWidth = scaleEmToUnits(os2AvgCharWidth, m_fontMetrics.unitsPerEm()) * m_platformData.m_size; } RetainPtr<CFDataRef> headTable(AdoptCF, copyFontTableForTag(m_platformData, 'head')); @@ -348,7 +355,7 @@ void SimpleFontData::platformCharWidthInit() SInt16 xMin = static_cast<SInt16>(uxMin); SInt16 xMax = static_cast<SInt16>(uxMax); float diff = static_cast<float>(xMax - xMin); - m_maxCharWidth = scaleEmToUnits(diff, m_unitsPerEm) * m_platformData.m_size; + m_maxCharWidth = scaleEmToUnits(diff, m_fontMetrics.unitsPerEm()) * m_platformData.m_size; } // Fallback to a cross-platform estimate, which will populate these values if they are non-positive. @@ -387,7 +394,7 @@ SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescri BEGIN_BLOCK_OBJC_EXCEPTIONS; float size = m_platformData.size() * scaleFactor; - FontPlatformData scaledFontData([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size], size); + FontPlatformData scaledFontData([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size], size, false, false, m_platformData.orientation()); // AppKit resets the type information (screen/printer) when you convert a font to a different size. // We have to fix up the font that we're handed back. @@ -470,13 +477,13 @@ FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const #ifndef BUILDING_ON_TIGER boundingBox = CTFontGetBoundingRectsForGlyphs(m_platformData.ctFont(), orientation() == Vertical ? kCTFontVerticalOrientation : kCTFontHorizontalOrientation, &glyph, 0, 1); - boundingBox.setY(-boundingBox.bottom()); + boundingBox.setY(-boundingBox.maxY()); #else // FIXME: Custom fonts don't have NSFonts, so this function doesn't compute correct bounds for these on Tiger. if (!m_platformData.font()) return boundingBox; boundingBox = [m_platformData.font() boundingRectForGlyph:glyph]; - boundingBox.setY(-boundingBox.bottom()); + boundingBox.setY(-boundingBox.maxY()); #endif if (m_syntheticBoldOffset) boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset); diff --git a/Source/WebCore/platform/graphics/mac/WebGLLayer.mm b/Source/WebCore/platform/graphics/mac/WebGLLayer.mm index c24181b..d1007b9 100644 --- a/Source/WebCore/platform/graphics/mac/WebGLLayer.mm +++ b/Source/WebCore/platform/graphics/mac/WebGLLayer.mm @@ -26,7 +26,7 @@ #include "config.h" #if USE(ACCELERATED_COMPOSITING) -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #import "WebGLLayer.h" @@ -163,5 +163,5 @@ static void freeData(void *, const void *data, size_t /* size */) @end -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp index 3eb5196..df45147 100644 --- a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "Extensions3DOpenGL.h" @@ -79,6 +79,10 @@ bool Extensions3DOpenGL::supports(const String& name) if (name == "GL_ANGLE_framebuffer_multisample") return m_availableExtensions.contains("GL_EXT_framebuffer_multisample"); + // Desktop GL always supports GL_OES_rgb8_rgba8. + if (name == "GL_OES_rgb8_rgba8") + return true; + // If GL_ARB_texture_float is available then we report GL_OES_texture_float and // GL_OES_texture_half_float as available. if (name == "GL_OES_texture_float" || name == "GL_OES_texture_half_float") @@ -125,4 +129,4 @@ void Extensions3DOpenGL::renderbufferStorageMultisample(unsigned long target, un } // namespace WebCore -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp index 7c103f3..c224e20 100644 --- a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "GraphicsContext3D.h" @@ -83,7 +83,7 @@ void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* co int rowBytes = m_currentWidth * 4; int totalBytes = rowBytes * m_currentHeight; - OwnArrayPtr<unsigned char> pixels(new unsigned char[totalBytes]); + OwnArrayPtr<unsigned char> pixels = adoptArrayPtr(new unsigned char[totalBytes]); if (!pixels) return; @@ -1437,28 +1437,6 @@ void GraphicsContext3D::deleteTexture(Platform3DObject texture) glDeleteTextures(1, &texture); } -uint32_t GraphicsContext3D::sizeInBytes(GC3Denum type) -{ - switch (type) { - case GL_BYTE: - return sizeof(GLbyte); - case GL_UNSIGNED_BYTE: - return sizeof(GLubyte); - case GL_SHORT: - return sizeof(GLshort); - case GL_UNSIGNED_SHORT: - return sizeof(GLushort); - case GL_INT: - return sizeof(GLint); - case GL_UNSIGNED_INT: - return sizeof(GLuint); - case GL_FLOAT: - return sizeof(GLfloat); - default: - return 0; - } -} - void GraphicsContext3D::synthesizeGLError(GC3Denum error) { m_syntheticErrors.add(error); @@ -1473,4 +1451,4 @@ Extensions3D* GraphicsContext3D::getExtensions() } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp index 03f9b7c..2e2082d 100644 --- a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp @@ -390,7 +390,7 @@ void TextureMapperGL::drawTexture(const BitmapTexture& texture, const IntRect& t const GLfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1}; GL_CMD(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, unitRect)) - TransformationMatrix matrix = TransformationMatrix(data().projectionMatrix).multLeft(modelViewMatrix).multLeft(TransformationMatrix( + TransformationMatrix matrix = TransformationMatrix(data().projectionMatrix).multiply(modelViewMatrix).multiply(TransformationMatrix( targetRect.width(), 0, 0, 0, 0, targetRect.height(), 0, 0, 0, 0, 1, 0, @@ -606,7 +606,7 @@ void TextureMapperGL::paintToTarget(const BitmapTexture& aSurface, const IntSize const BitmapTextureGL& surface = static_cast<const BitmapTextureGL&>(aSurface); // Create the model-view-projection matrix to display on screen. - TransformationMatrix matrix = createProjectionMatrix(surfaceSize, true).multLeft(transform).multLeft( + TransformationMatrix matrix = createProjectionMatrix(surfaceSize, true).multiply(transform).multiply( TransformationMatrix( surface.m_actualSize.width(), 0, 0, 0, 0, surface.m_actualSize.height(), 0, 0, diff --git a/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp b/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp index a158689..f9d36d3 100644 --- a/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp +++ b/Source/WebCore/platform/graphics/pango/FontCustomPlatformDataPango.cpp @@ -30,7 +30,7 @@ FontCustomPlatformData::~FontCustomPlatformData() { } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode) { return FontPlatformData(m_fontFace, size, bold, italic); } diff --git a/Source/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp b/Source/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp index d0bf836..3fe15b3 100644 --- a/Source/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp +++ b/Source/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp @@ -49,21 +49,27 @@ void SimpleFontData::platformInit() cairo_font_extents_t font_extents; cairo_text_extents_t text_extents; cairo_scaled_font_extents(m_platformData.m_scaledFont, &font_extents); - m_ascent = static_cast<int>(lroundf(font_extents.ascent)); - m_descent = static_cast<int>(lroundf(font_extents.descent)); - m_lineSpacing = static_cast<int>(lroundf(font_extents.height)); + + m_fontMetrics.setAscent(font_extents.ascent); + m_fontMetrics.setDescent(font_extents.descent); + // There seems to be some rounding error in cairo (or in how we // use cairo) with some fonts, like DejaVu Sans Mono, which makes // cairo report a height smaller than ascent + descent, which is // wrong and confuses WebCore's layout system. Workaround this // while we figure out what's going on. - if (m_lineSpacing < m_ascent + m_descent) - m_lineSpacing = m_ascent + m_descent; + float lineSpacing = font_extents.height; + if (lineSpacing < font_extents.ascent + font_extents.descent) + lineSpacing = font_extents.ascent + font_extents.descent; + m_fontMetrics.setLineSpacing(lroundf(lineSpacing)); + m_fontMetrics.setLineGap(lineSpacing - font_extents.ascent - font_extents.descent); + cairo_scaled_font_text_extents(m_platformData.m_scaledFont, "x", &text_extents); - m_xHeight = text_extents.height; + m_fontMetrics.setXHeight(text_extents.height); + cairo_scaled_font_text_extents(m_platformData.m_scaledFont, " ", &text_extents); - m_spaceWidth = static_cast<float>(text_extents.x_advance); - m_lineGap = m_lineSpacing - m_ascent - m_descent; + m_spaceWidth = static_cast<float>(text_extents.x_advance); + m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; } diff --git a/Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp b/Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp index 37d6b44..9eb31a7 100644 --- a/Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp +++ b/Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp @@ -57,7 +57,7 @@ private: ShadowBuffer::ShadowBuffer(QObject* parent) : QObject(parent) - , timerId(0) + , timerId(-1) { } @@ -89,7 +89,8 @@ QImage* ShadowBuffer::scratchImage(const QSize& size) void ShadowBuffer::schedulePurge() { static const double BufferPurgeDelay = 2; // seconds - killTimer(timerId); + if (timerId >= 0) + killTimer(timerId); timerId = startTimer(BufferPurgeDelay * 1000); } diff --git a/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp index cd28f0e..5238d46 100644 --- a/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "Extensions3DQt.h" @@ -58,4 +58,4 @@ int Extensions3DQt::getGraphicsResetStatusARB() } // namespace WebCore -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h index 54fa679..e8441d2 100644 --- a/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h @@ -24,6 +24,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" +#include "FontWidthVariant.h" #include <wtf/FastAllocBase.h> #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -42,7 +43,7 @@ public: // for use with QFontDatabase::addApplicationFont/removeApplicationFont int m_handle; - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); }; diff --git a/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp b/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp index e2f009b..ec8747d 100644 --- a/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp +++ b/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp @@ -34,7 +34,7 @@ FontCustomPlatformData::~FontCustomPlatformData() QFontDatabase::removeApplicationFont(m_handle); } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode) { QFont font; font.setFamily(QFontDatabase::applicationFontFamilies(m_handle)[0]); diff --git a/Source/WebCore/platform/graphics/qt/FontQt.cpp b/Source/WebCore/platform/graphics/qt/FontQt.cpp index 778a13f..646cd0e 100644 --- a/Source/WebCore/platform/graphics/qt/FontQt.cpp +++ b/Source/WebCore/platform/graphics/qt/FontQt.cpp @@ -61,14 +61,14 @@ static const QString fromRawDataWithoutRef(const String& string, int start = 0, static QTextLine setupLayout(QTextLayout* layout, const TextRun& style) { int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; - if (style.padding()) + if (style.expansion()) 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()); + if (style.expansion()) + line.setLineWidth(line.naturalTextWidth() + style.expansion()); layout->endLayout(); return line; } @@ -107,7 +107,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float textStrokePen = QPen(QColor(ctx->strokeColor()), ctx->strokeThickness()); } - String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); + String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString string = fromRawDataWithoutRef(sanitized); QPointF pt(point.x(), point.y()); @@ -196,7 +196,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float p->save(); p->setPen(ctxShadow->m_color); p->translate(ctxShadow->offset()); - p->drawText(pt, string, flags, run.padding()); + p->drawText(pt, string, flags, run.expansion()); p->restore(); } else { QFontMetrics fm(font); @@ -210,7 +210,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float // Since it will be blurred anyway, we don't care about render hints. shadowPainter->setFont(p->font()); shadowPainter->setPen(ctxShadow->m_color); - shadowPainter->drawText(pt, string, flags, run.padding()); + shadowPainter->drawText(pt, string, flags, run.expansion()); ctxShadow->endShadowLayer(ctx); } } @@ -243,7 +243,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float if (ctx->textDrawingMode() & TextModeFill) { QPen previousPen = p->pen(); p->setPen(textFillPen); - p->drawText(pt, string, flags, run.padding()); + p->drawText(pt, string, flags, run.expansion()); p->setPen(previousPen); } } @@ -299,7 +299,7 @@ float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer if (!run.length()) return 0; - String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); + String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString string = fromRawDataWithoutRef(sanitized); int w = QFontMetrics(font()).width(string, -1, Qt::TextBypassShaping); @@ -308,7 +308,7 @@ float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer if (treatAsSpace(run[0])) w -= m_wordSpacing; - return w + run.padding(); + return w + run.expansion(); #else Q_ASSERT(false); return 0; @@ -324,9 +324,9 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon return 0; if (run.length() == 1 && treatAsSpace(run[0])) - return QFontMetrics(font()).width(space) + run.padding(); + return QFontMetrics(font()).width(space) + run.expansion(); - String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); + String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString string = fromRawDataWithoutRef(sanitized); int w = QFontMetrics(font()).width(string); @@ -334,13 +334,13 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon if (treatAsSpace(run[0])) w -= m_wordSpacing; - return w + run.padding(); + return w + run.expansion(); } int Font::offsetForPositionForSimpleText(const TextRun& run, float position, bool includePartialGlyphs) const { #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) - String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); + String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString string = fromRawDataWithoutRef(sanitized); QFontMetrics fm(font()); @@ -367,7 +367,7 @@ int Font::offsetForPositionForSimpleText(const TextRun& run, float position, boo int Font::offsetForPositionForComplexText(const TextRun& run, float position, bool) const { - String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); + String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString string = fromRawDataWithoutRef(sanitized); QTextLayout layout(string, font()); @@ -378,7 +378,7 @@ int Font::offsetForPositionForComplexText(const TextRun& run, float position, bo FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& pt, int h, int from, int to) const { #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) - String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); + String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString wholeText = fromRawDataWithoutRef(sanitized); QString selectedText = fromRawDataWithoutRef(sanitized, from, qMin(to - from, wholeText.length() - from)); @@ -394,7 +394,7 @@ FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& pt, int h, int from, int to) const { - String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); + String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString string = fromRawDataWithoutRef(sanitized); QTextLayout layout(string, font()); @@ -413,6 +413,11 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } +bool Font::canExpandAroundIdeographsInComplexText() +{ + return false; +} + bool Font::primaryFontHasGlyphForCharacter(UChar32) const { notImplemented(); diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index 295212c..8b87f5f 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -34,7 +34,7 @@ #include <wtf/UnusedParam.h> #include <wtf/text/CString.h> -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) namespace WebCore { @@ -1611,28 +1611,6 @@ void GraphicsContext3D::deleteTexture(Platform3DObject texture) glDeleteTextures(1, &texture); } -unsigned int GraphicsContext3D::sizeInBytes(GC3Denum type) -{ - switch (type) { - case GraphicsContext3D::BYTE: - return sizeof(GLbyte); - case GraphicsContext3D::UNSIGNED_BYTE: - return sizeof(GLubyte); - case GraphicsContext3D::SHORT: - return sizeof(GLshort); - case GraphicsContext3D::UNSIGNED_SHORT: - return sizeof(GLushort); - case GraphicsContext3D::INT: - return sizeof(GLint); - case GraphicsContext3D::UNSIGNED_INT: - return sizeof(GLuint); - case GraphicsContext3D::FLOAT: - return sizeof(GLfloat); - default: - return 0; - } -} - void GraphicsContext3D::synthesizeGLError(GC3Denum error) { m_internal->m_syntheticErrors.add(error); @@ -1669,6 +1647,10 @@ bool GraphicsContext3D::getImageData(Image* image, format, type, neededAlphaOp, outputVector.data()); } +void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>) +{ +} + } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 4dabe09..bf2826c 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -62,14 +62,11 @@ #include <QPolygonF> #include <QStack> #include <QVector> - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif +#include <wtf/MathExtras.h> namespace WebCore { -QPainter::CompositionMode GraphicsContext::toQtCompositionMode(CompositeOperator op) +static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op) { switch (op) { case CompositeClear: @@ -231,8 +228,15 @@ GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p, cons if (!painter) return; +#if OS(SYMBIAN) + if (painter->paintEngine()->type() == QPaintEngine::OpenVG) + antiAliasingForRectsAndLines = true; + else + antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing); +#else // Use the default the QPainter was constructed with. antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing); +#endif // Used for default image interpolation quality. initialSmoothPixmapTransformHint = painter->testRenderHint(QPainter::SmoothPixmapTransform); @@ -784,7 +788,7 @@ void GraphicsContext::clipPath(const Path& path, WindRule clipRule) p->setClipPath(platformPath, Qt::IntersectClip); } -void drawFocusRingForPath(QPainter* p, const QPainterPath& path, int width, const Color& color, bool antiAliasing) +void drawFocusRingForPath(QPainter* p, const QPainterPath& path, const Color& color, bool antiAliasing) { const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, antiAliasing); @@ -794,9 +798,8 @@ void drawFocusRingForPath(QPainter* p, const QPainterPath& path, int width, cons QPen nPen = p->pen(); nPen.setColor(color); - nPen.setWidth(width); p->setBrush(Qt::NoBrush); - nPen.setStyle(Qt::SolidLine); + nPen.setStyle(Qt::DotLine); p->strokePath(path, nPen); p->setBrush(oldBrush); @@ -805,14 +808,14 @@ void drawFocusRingForPath(QPainter* p, const QPainterPath& path, int width, cons p->setRenderHint(QPainter::Antialiasing, antiAlias); } -void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color) +void GraphicsContext::drawFocusRing(const Path& path, int /* width */, int offset, const Color& color) { // FIXME: Use 'offset' for something? http://webkit.org/b/49909 if (paintingDisabled() || !color.isValid()) return; - drawFocusRingForPath(m_data->p(), path.platformPath(), width, color, m_data->antiAliasingForRectsAndLines); + drawFocusRingForPath(m_data->p(), path.platformPath(), color, m_data->antiAliasingForRectsAndLines); } /** @@ -840,8 +843,7 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int tmpPath.addRoundedRect(rect, radius, radius); path = path.united(tmpPath); } - - drawFocusRingForPath(m_data->p(), path, width, color, m_data->antiAliasingForRectsAndLines); + drawFocusRingForPath(m_data->p(), path, color, m_data->antiAliasingForRectsAndLines); } void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool) @@ -896,7 +898,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) qreal deviceScaleY = sqrtf(deviceTransform.m21() * deviceTransform.m21() + deviceTransform.m22() * deviceTransform.m22()); QPoint deviceOrigin(frect.x() * deviceScaleX, frect.y() * deviceScaleY); - QPoint deviceLowerRight(frect.right() * deviceScaleX, frect.bottom() * deviceScaleY); + QPoint deviceLowerRight(frect.maxX() * deviceScaleX, frect.maxY() * deviceScaleY); // Don't let the height or width round to 0 unless either was originally 0 if (deviceOrigin.y() == deviceLowerRight.y() && frect.height()) @@ -1135,7 +1137,7 @@ void GraphicsContext::rotate(float radians) if (paintingDisabled()) return; - m_data->p()->rotate(180 / M_PI*radians); + m_data->p()->rotate(rad2deg(qreal(radians))); } void GraphicsContext::scale(const FloatSize& s) diff --git a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp index 75fb427..0d7aa45 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp @@ -305,7 +305,7 @@ public: } } m_state; -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) const GraphicsContext3D* m_gc3D; #endif @@ -335,7 +335,7 @@ GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer) #if ENABLE(TILED_BACKING_STORE) , m_tiledBackingStore(0) #endif -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) , m_gc3D(0) #endif { @@ -529,12 +529,12 @@ void GraphicsLayerQtImpl::updateTransform() // have to maintain that ourselves for 3D. localTransform .translate3d(originX + m_state.pos.x(), originY + m_state.pos.y(), m_state.anchorPoint.z()) - .multLeft(m_baseTransform) + .multiply(m_baseTransform) .translate3d(-originX, -originY, -m_state.anchorPoint.z()); // This is the actual 3D transform of this item, with the ancestors' transform baked in. m_transformRelativeToRootLayer = TransformationMatrix(parent ? parent->m_transformRelativeToRootLayer : TransformationMatrix()) - .multLeft(localTransform); + .multiply(localTransform); // Now we have enough information to determine if the layer is facing backwards. if (!m_state.backfaceVisibility && m_transformRelativeToRootLayer.inverse().m33() < 0) { @@ -562,7 +562,7 @@ void GraphicsLayerQtImpl::updateTransform() if (!m_state.childrenTransform.isIdentity()) { m_transformRelativeToRootLayer .translate(m_size.width() / 2, m_size.height() /2) - .multLeft(m_state.childrenTransform) + .multiply(m_state.childrenTransform) .translate(-m_size.width() / 2, -m_size.height() /2); } @@ -647,7 +647,7 @@ void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsIte case MediaContentType: // we don't need to paint anything: we have a QGraphicsItem from the media element break; -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) case Canvas3DContentType: m_gc3D->paint(painter, option->rect); break; @@ -791,7 +791,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform setFlag(ItemHasNoContents, !m_layer->drawsContent()); break; -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) case Canvas3DContentType: if (m_pendingContent.contentType != m_currentContent.contentType) update(); @@ -1250,7 +1250,7 @@ void GraphicsLayerQt::setContentsBackgroundColor(const Color& color) GraphicsLayer::setContentsBackgroundColor(color); } -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) void GraphicsLayerQt::setContentsToGraphicsContext3D(const GraphicsContext3D* ctx) { if (ctx == m_impl->m_gc3D) diff --git a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h index 8027143..569bd8d 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h +++ b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h @@ -20,7 +20,7 @@ #ifndef GraphicsLayerQt_h #define GraphicsLayerQt_h -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "GraphicsContext3D.h" #endif #include "GraphicsLayer.h" @@ -79,7 +79,7 @@ public: virtual void setContentsNeedsDisplay(); virtual void setContentsToMedia(PlatformLayer*); virtual void setContentsBackgroundColor(const Color&); -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*); virtual void setGraphicsContext3DNeedsDisplay(); #endif diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp index d1567ec..62f5c3e 100644 --- a/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -188,7 +188,7 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& i RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); unsigned char* data = result->data(); - if (rect.x() < 0 || rect.y() < 0 || rect.right() > size.width() || rect.bottom() > size.height()) + if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) memset(data, 0, result->length()); int originx = rect.x(); @@ -197,7 +197,7 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& i destx = -originx; originx = 0; } - int endx = rect.right(); + int endx = rect.maxX(); if (endx > size.width()) endx = size.width(); int numColumns = endx - originx; @@ -208,7 +208,7 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& i desty = -originy; originy = 0; } - int endy = rect.bottom(); + int endy = rect.maxY(); if (endy > size.height()) endy = size.height(); int numRows = endy - originy; @@ -302,9 +302,9 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& ASSERT(destx >= 0); ASSERT(destx < size.width()); ASSERT(originx >= 0); - ASSERT(originx <= sourceRect.right()); + ASSERT(originx <= sourceRect.maxX()); - int endx = destPoint.x() + sourceRect.right(); + int endx = destPoint.x() + sourceRect.maxX(); ASSERT(endx <= size.width()); int numColumns = endx - destx; @@ -314,9 +314,9 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& ASSERT(desty >= 0); ASSERT(desty < size.height()); ASSERT(originy >= 0); - ASSERT(originy <= sourceRect.bottom()); + ASSERT(originy <= sourceRect.maxY()); - int endy = destPoint.y() + sourceRect.bottom(); + int endy = destPoint.y() + sourceRect.maxY(); ASSERT(endy <= size.height()); int numRows = endy - desty; diff --git a/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 71352e4..3540994 100644 --- a/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -213,7 +213,7 @@ bool ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) // now into the ImageFrame - even if the image is not ImageFrame* const buffer = &m_frameBufferCache[frameIndex]; - buffer->setRect(m_reader->currentImageRect()); + buffer->setOriginalFrameRect(m_reader->currentImageRect()); buffer->setStatus(ImageFrame::FrameComplete); buffer->setDuration(m_reader->nextImageDelay()); buffer->setPixmap(pixmap); diff --git a/Source/WebCore/platform/graphics/qt/ImageQt.cpp b/Source/WebCore/platform/graphics/qt/ImageQt.cpp index 58f82ef..0c8ce9e 100644 --- a/Source/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/Source/WebCore/platform/graphics/qt/ImageQt.cpp @@ -120,11 +120,9 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const CompositeOperator previousOperator = ctxt->compositeOperation(); - ctxt->setCompositeOperation(op); - QPainter* p = ctxt->platformContext(); - if (!pixmap.hasAlpha() && p->compositionMode() == QPainter::CompositionMode_SourceOver) - p->setCompositionMode(QPainter::CompositionMode_Source); + ctxt->setCompositeOperation(!pixmap.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); + QPainter* p = ctxt->platformContext(); QTransform transform(patternTransform); // If this would draw more than one scaled tile, we scale the pixmap first and then use the result to draw. @@ -223,15 +221,8 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, return; } - QPainter* painter(ctxt->platformContext()); - - QPainter::CompositionMode compositionMode = GraphicsContext::toQtCompositionMode(op); - - if (!image->hasAlpha() && painter->compositionMode() == QPainter::CompositionMode_SourceOver) - compositionMode = QPainter::CompositionMode_Source; - - QPainter::CompositionMode lastCompositionMode = painter->compositionMode(); - painter->setCompositionMode(compositionMode); + CompositeOperator previousOperator = ctxt->compositeOperation(); + ctxt->setCompositeOperation(!image->hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); ContextShadow* shadow = ctxt->contextShadow(); if (shadow->m_type != ContextShadow::NoShadow) { @@ -243,11 +234,9 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, } } - // Test using example site at - // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html - painter->drawPixmap(normalizedDst, *image, normalizedSrc); + ctxt->platformContext()->drawPixmap(normalizedDst, *image, normalizedSrc); - painter->setCompositionMode(lastCompositionMode); + ctxt->setCompositeOperation(previousOperator); if (imageObserver()) imageObserver()->didDraw(this); diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp index b881036..fab4db1 100644 --- a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp +++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -102,7 +102,7 @@ MediaPlayerPrivatePhonon::MediaPlayerPrivatePhonon(MediaPlayer* player) // Make sure we get updates for each frame m_videoWidget->installEventFilter(this); - foreach (QWidget* widget, qFindChildren<QWidget*>(m_videoWidget)) + foreach (QWidget* widget, m_videoWidget->findChildren<QWidget*>()) widget->installEventFilter(this); connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp index 0a4c0f6..caf9c2d 100644 --- a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp +++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -215,7 +215,7 @@ void MediaPlayerPrivateQt::commitLoad(const String& url) // Don't set the header if there are no cookies. // This prevents a warning from being emitted. if (!cookies.isEmpty()) - request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies)); + request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookies)); // Set the refferer, but not when requesting insecure content from a secure page QUrl documentUrl = QUrl(QString(document->documentURI())); @@ -543,7 +543,7 @@ void MediaPlayerPrivateQt::updateStates() m_readyState = MediaPlayer::HaveCurrentData; } else if (currentStatus == QMediaPlayer::BufferedMedia || currentStatus == QMediaPlayer::EndOfMedia) { - m_networkState = MediaPlayer::Idle; + m_networkState = MediaPlayer::Loaded; m_readyState = MediaPlayer::HaveEnoughData; } else if (currentStatus == QMediaPlayer::InvalidMedia) { m_networkState = MediaPlayer::NetworkError; @@ -618,6 +618,21 @@ void MediaPlayerPrivateQt::paint(GraphicsContext* context, const IntRect& rect) m_videoScene->render(painter, QRectF(QRect(rect)), m_videoItem->sceneBoundingRect()); } +void MediaPlayerPrivateQt::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect) +{ + if (context->paintingDisabled()) + return; + + if (!m_isVisible) + return; + + // Grab the painter and widget + QPainter* painter = context->platformContext(); + + // Render the video, using the item as it might not be in the scene + m_videoItem->paint(painter, 0, 0); +} + void MediaPlayerPrivateQt::repaint() { m_webCorePlayer->repaint(); diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h index 2621432..e4133db 100644 --- a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h +++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h @@ -89,6 +89,8 @@ public: void setSize(const IntSize&); void paint(GraphicsContext*, const IntRect&); + // reimplemented for canvas drawImage(HTMLVideoElement) + void paintCurrentFrameInContext(GraphicsContext*, const IntRect&); bool supportsFullscreen() const { return true; } diff --git a/Source/WebCore/platform/graphics/qt/PathQt.cpp b/Source/WebCore/platform/graphics/qt/PathQt.cpp index 571b405..ad482f7 100644 --- a/Source/WebCore/platform/graphics/qt/PathQt.cpp +++ b/Source/WebCore/platform/graphics/qt/PathQt.cpp @@ -39,15 +39,9 @@ #include <QPainterPath> #include <QTransform> #include <QString> +#include <wtf/MathExtras.h> #include <wtf/OwnPtr.h> -#define _USE_MATH_DEFINES -#include <math.h> - -#ifndef M_PI -# define M_PI 3.14159265358979323846 -#endif - namespace WebCore { Path::Path() @@ -263,7 +257,6 @@ 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(); @@ -280,8 +273,8 @@ void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool antic anticlockwise = !anticlockwise; //end hack - float sa = DEGREES(sar); - float ea = DEGREES(ear); + float sa = rad2deg(sar); + float ea = rad2deg(ear); double span = 0; @@ -438,6 +431,14 @@ float Path::normalAngleAtLength(float length, bool& ok) qreal percent = m_path.percentAtLength(length); qreal angle = m_path.angleAtPercent(percent); + // Normalize angle value. + // QPainterPath returns angle values with the origo being at the top left corner. + // In case of moveTo(0, 0) and addLineTo(0, 10) the angle is 270, + // while the caller expects it to be 90. + // Normalize the value by mirroring it to the x-axis. + // For more info look at pathLengthApplierFunction(). + if (angle > 0) + angle = 360 - angle; return angle; } diff --git a/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp index 47ddf02..9e43558 100644 --- a/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp +++ b/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -24,7 +24,7 @@ #include "config.h" #include "SimpleFontData.h" -#include <QFontMetrics> +#include <QFontMetricsF> namespace WebCore { @@ -41,25 +41,19 @@ bool SimpleFontData::containsCharacters(const UChar*, int) const void SimpleFontData::platformInit() { if (!m_platformData.size()) { - m_ascent = 0; - m_descent = 0; - m_lineGap = 0; - m_lineSpacing = 0; + m_fontMetrics.reset(); m_avgCharWidth = 0; m_maxCharWidth = 0; - m_xHeight = 0; - m_unitsPerEm = 0; return; } - QFontMetrics fm(m_platformData.font()); - - m_ascent = fm.ascent(); - m_descent = fm.descent(); - m_lineSpacing = fm.lineSpacing(); - m_xHeight = fm.xHeight(); + QFontMetricsF fm(m_platformData.font()); + m_fontMetrics.setAscent(fm.ascent()); + m_fontMetrics.setDescent(fm.descent()); + m_fontMetrics.setXHeight(fm.xHeight()); + m_fontMetrics.setLineGap(fm.leading()); + m_fontMetrics.setLineSpacing(fm.lineSpacing()); m_spaceWidth = fm.width(QLatin1Char(' ')); - m_lineGap = fm.leading(); } void SimpleFontData::platformGlyphInit() diff --git a/Source/WebCore/platform/graphics/qt/TransparencyLayer.h b/Source/WebCore/platform/graphics/qt/TransparencyLayer.h index ff9ef20..f13deb0 100644 --- a/Source/WebCore/platform/graphics/qt/TransparencyLayer.h +++ b/Source/WebCore/platform/graphics/qt/TransparencyLayer.h @@ -59,9 +59,8 @@ public: painter.setPen(p->pen()); painter.setBrush(p->brush()); painter.setTransform(p->transform(), true); - painter.setOpacity(p->opacity()); painter.setFont(p->font()); - painter.setCompositionMode(p->compositionMode()); + painter.setOpacity(1); } TransparencyLayer() diff --git a/Source/WebCore/platform/graphics/skia/FloatRectSkia.cpp b/Source/WebCore/platform/graphics/skia/FloatRectSkia.cpp index a10371f..23045ba 100644 --- a/Source/WebCore/platform/graphics/skia/FloatRectSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/FloatRectSkia.cpp @@ -43,7 +43,7 @@ FloatRect::FloatRect(const SkRect& r) FloatRect::operator SkRect() const { - SkRect rect = { x(), y(), right(), bottom() }; + SkRect rect = { x(), y(), maxX(), maxY() }; return rect; } diff --git a/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp index 0b31dfa..0e68c21 100644 --- a/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp @@ -65,7 +65,7 @@ FontCustomPlatformData::~FontCustomPlatformData() #endif } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, FontRenderingMode mode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation orientation, FontWidthVariant, FontRenderingMode mode) { #if OS(WINDOWS) ASSERT(m_fontReference); @@ -114,13 +114,12 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b // not allow access from CSS. static String createUniqueFontName() { - Vector<char> fontUuid(sizeof(GUID)); - CoCreateGuid(reinterpret_cast<GUID*>(fontUuid.data())); + GUID fontUuid; + CoCreateGuid(&fontUuid); - Vector<char> fontNameVector; - base64Encode(fontUuid, fontNameVector); - ASSERT(fontNameVector.size() < LF_FACESIZE); - return String(fontNameVector.data(), fontNameVector.size()); + String fontName = base64Encode(reinterpret_cast<char*>(&fontUuid), sizeof(fontUuid)); + ASSERT(fontName.length() < LF_FACESIZE); + return fontName; } #endif diff --git a/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h index 4228b40..2dee3ab 100644 --- a/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/skia/FontCustomPlatformData.h @@ -34,6 +34,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" +#include "FontWidthVariant.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -65,7 +66,7 @@ public: ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp b/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp index c4b753b..5950c35 100644 --- a/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "GraphicsContext3D.h" @@ -87,4 +87,4 @@ bool GraphicsContext3D::getImageData(Image* image, } // namespace WebCore -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index 1a7112b..9f2ed32 100644 --- a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -309,20 +309,6 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness platformContext()->clipPathAntiAliased(path); } -void GraphicsContext::addPath(const Path& path) -{ - if (paintingDisabled()) - return; - platformContext()->addPath(*path.platformPath()); -} - -void GraphicsContext::beginPath() -{ - if (paintingDisabled()) - return; - platformContext()->beginPath(); -} - void GraphicsContext::clearPlatformShadow() { if (paintingDisabled()) @@ -431,11 +417,7 @@ void GraphicsContext::clipPath(const Path& pathToClip, WindRule clipRule) if (platformContext()->useGPU()) platformContext()->gpuCanvas()->clipPath(pathToClip); - // FIXME: Be smarter about this. - beginPath(); - addPath(pathToClip); - - SkPath path = platformContext()->currentPathInLocalCoordinates(); + SkPath path = *pathToClip.platformPath(); if (!isPathSkiaSafe(getCTM(), path)) return; @@ -738,17 +720,13 @@ void GraphicsContext::fillPath(const Path& pathToFill) if (paintingDisabled()) return; - // FIXME: Be smarter about this. - beginPath(); - addPath(pathToFill); - if (platformContext()->useGPU() && platformContext()->canAccelerate()) { platformContext()->prepareForHardwareDraw(); platformContext()->gpuCanvas()->fillPath(pathToFill); return; } - SkPath path = platformContext()->currentPathInLocalCoordinates(); + SkPath path = *pathToFill.platformPath(); if (!isPathSkiaSafe(getCTM(), path)) return; @@ -1204,11 +1182,7 @@ void GraphicsContext::strokePath(const Path& pathToStroke) if (paintingDisabled()) return; - // FIXME: Be smarter about this. - beginPath(); - addPath(pathToStroke); - - SkPath path = platformContext()->currentPathInLocalCoordinates(); + SkPath path = *pathToStroke.platformPath(); if (!isPathSkiaSafe(getCTM(), path)) return; diff --git a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index 2c489ef..2721523 100644 --- a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -2,11 +2,11 @@ * Copyright (c) 2008, Google Inc. All rights reserved. * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -16,7 +16,7 @@ * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -162,12 +162,14 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) } template <Multiply multiplied> -PassRefPtr<ByteArray> getImageData(const IntRect& rect, const SkBitmap& bitmap, +PassRefPtr<ByteArray> getImageData(const IntRect& rect, SkDevice& srcDevice, const IntSize& size) { RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); - if (bitmap.config() == SkBitmap::kNo_Config) { + SkBitmap::Config srcConfig = srcDevice.accessBitmap(false).config(); + + if (srcConfig == SkBitmap::kNo_Config) { // This is an empty SkBitmap that could not be configured. ASSERT(!size.width() || !size.height()); return result.release(); @@ -177,8 +179,8 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const SkBitmap& bitmap, if (rect.x() < 0 || rect.y() < 0 - || rect.right() > size.width() - || rect.bottom() > size.height()) + || rect.maxX() > size.width() + || rect.maxY() > size.height()) memset(data, 0, result->length()); int originX = rect.x(); @@ -187,12 +189,12 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const SkBitmap& bitmap, destX = -originX; originX = 0; } - int endX = rect.right(); + int endX = rect.maxX(); if (endX > size.width()) endX = size.width(); int numColumns = endX - originX; - if (numColumns <= 0) + if (numColumns <= 0) return result.release(); int originY = rect.y(); @@ -201,38 +203,42 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const SkBitmap& bitmap, destY = -originY; originY = 0; } - int endY = rect.bottom(); + int endY = rect.maxY(); if (endY > size.height()) endY = size.height(); int numRows = endY - originY; - if (numRows <= 0) + if (numRows <= 0) return result.release(); - ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); - SkAutoLockPixels bitmapLock(bitmap); + ASSERT(srcConfig == SkBitmap::kARGB_8888_Config); unsigned destBytesPerRow = 4 * rect.width(); + + SkBitmap srcBitmap; + srcDevice.readPixels(SkIRect::MakeXYWH(originX, originY, numColumns, numRows), &srcBitmap); + unsigned char* destRow = data + destY * destBytesPerRow + destX * 4; + // Do conversion of byte order and alpha divide (if necessary) for (int y = 0; y < numRows; ++y) { - uint32_t* srcRow = bitmap.getAddr32(originX, originY + y); + SkPMColor* srcBitmapRow = srcBitmap.getAddr32(0, y); for (int x = 0; x < numColumns; ++x) { + SkPMColor srcPMColor = srcBitmapRow[x]; unsigned char* destPixel = &destRow[x * 4]; if (multiplied == Unmultiplied) { - SkColor color = srcRow[x]; - unsigned a = SkColorGetA(color); - destPixel[0] = a ? SkColorGetR(color) * 255 / a : 0; - destPixel[1] = a ? SkColorGetG(color) * 255 / a : 0; - destPixel[2] = a ? SkColorGetB(color) * 255 / a : 0; + unsigned char a = SkGetPackedA32(srcPMColor); + destPixel[0] = a ? SkGetPackedR32(srcPMColor) * 255 / a : 0; + destPixel[1] = a ? SkGetPackedG32(srcPMColor) * 255 / a : 0; + destPixel[2] = a ? SkGetPackedB32(srcPMColor) * 255 / a : 0; destPixel[3] = a; } else { // Input and output are both pre-multiplied, we just need to re-arrange the // bytes from the bitmap format to RGBA. - destPixel[0] = SkGetPackedR32(srcRow[x]); - destPixel[1] = SkGetPackedG32(srcRow[x]); - destPixel[2] = SkGetPackedB32(srcRow[x]); - destPixel[3] = SkGetPackedA32(srcRow[x]); + destPixel[0] = SkGetPackedR32(srcPMColor); + destPixel[1] = SkGetPackedG32(srcPMColor); + destPixel[2] = SkGetPackedB32(srcPMColor); + destPixel[3] = SkGetPackedA32(srcPMColor); } } destRow += destBytesPerRow; @@ -244,18 +250,18 @@ PassRefPtr<ByteArray> getImageData(const IntRect& rect, const SkBitmap& bitmap, PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const { context()->platformContext()->syncSoftwareCanvas(); - return getImageData<Unmultiplied>(rect, *context()->platformContext()->bitmap(), m_size); + return getImageData<Unmultiplied>(rect, *context()->platformContext()->canvas()->getDevice(), m_size); } PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const { context()->platformContext()->syncSoftwareCanvas(); - return getImageData<Premultiplied>(rect, *context()->platformContext()->bitmap(), m_size); + return getImageData<Premultiplied>(rect, *context()->platformContext()->canvas()->getDevice(), m_size); } template <Multiply multiplied> -void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, - const SkBitmap& bitmap, const IntSize& size) +void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, + SkDevice* dstDevice, const IntSize& size) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); @@ -265,9 +271,9 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& ASSERT(destX >= 0); ASSERT(destX < size.width()); ASSERT(originX >= 0); - ASSERT(originX < sourceRect.right()); + ASSERT(originX < sourceRect.maxX()); - int endX = destPoint.x() + sourceRect.right(); + int endX = destPoint.x() + sourceRect.maxX(); ASSERT(endX <= size.width()); int numColumns = endX - destX; @@ -277,21 +283,33 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& ASSERT(destY >= 0); ASSERT(destY < size.height()); ASSERT(originY >= 0); - ASSERT(originY < sourceRect.bottom()); + ASSERT(originY < sourceRect.maxY()); - int endY = destPoint.y() + sourceRect.bottom(); + int endY = destPoint.y() + sourceRect.maxY(); ASSERT(endY <= size.height()); int numRows = endY - destY; - ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); - SkAutoLockPixels bitmapLock(bitmap); - unsigned srcBytesPerRow = 4 * sourceSize.width(); - const unsigned char* srcRow = source->data() + originY * srcBytesPerRow + originX * 4; + SkBitmap deviceBitmap = dstDevice->accessBitmap(true); + SkAutoLockPixels deviceAutoLock(deviceBitmap); + // If the device's bitmap doesn't have pixels we will make a temp and call writePixels on the device. + bool temporaryBitmap = !deviceBitmap.getPixels(); + SkBitmap destBitmap; + + if (temporaryBitmap) { + destBitmap.setConfig(SkBitmap::kARGB_8888_Config, numColumns, numRows, srcBytesPerRow); + if (!destBitmap.allocPixels()) + CRASH(); + } else + deviceBitmap.extractSubset(&destBitmap, SkIRect::MakeXYWH(destX, destY, numColumns, numRows)); + + // Whether we made a temporary or not destBitmap is always configured to be written at 0,0 + SkAutoLockPixels destAutoLock(destBitmap); + const unsigned char* srcRow = source->data() + originY * srcBytesPerRow + originX * 4; for (int y = 0; y < numRows; ++y) { - uint32_t* destRow = bitmap.getAddr32(destX, destY + y); + SkPMColor* destRow = destBitmap.getAddr32(0, y); for (int x = 0; x < numColumns; ++x) { const unsigned char* srcPixel = &srcRow[x * 4]; if (multiplied == Unmultiplied) { @@ -301,22 +319,26 @@ void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& unsigned char b = SkMulDiv255Ceiling(srcPixel[2], alpha); destRow[x] = SkPackARGB32(alpha, r, g, b); } else - destRow[x] = SkPackARGB32(srcPixel[3], srcPixel[0], - srcPixel[1], srcPixel[2]); + destRow[x] = SkPackARGB32(srcPixel[3], srcPixel[0], srcPixel[1], srcPixel[2]); } srcRow += srcBytesPerRow; } + + // If we used a temporary then write it to the device + if (temporaryBitmap) + dstDevice->writePixels(destBitmap, destX, destY); } void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) { - context()->platformContext()->prepareForSoftwareDraw(); - putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size); + context()->platformContext()->syncSoftwareCanvas(); + putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, context()->platformContext()->canvas()->getDevice(), m_size); } void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) { - putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size); + context()->platformContext()->syncSoftwareCanvas(); + putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, context()->platformContext()->canvas()->getDevice(), m_size); } String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const @@ -324,14 +346,27 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); Vector<unsigned char> encodedImage; + SkDevice* device = context()->platformContext()->canvas()->getDevice(); + SkBitmap bitmap = device->accessBitmap(false); + + // if we can't see the pixels directly, call readPixels() to get a copy. + // this could happen if the device is backed by a GPU. + bitmap.lockPixels(); // balanced by our destructor, or explicitly if getPixels() fails + if (!bitmap.getPixels()) { + bitmap.unlockPixels(); + SkIRect bounds = SkIRect::MakeWH(device->width(), device->height()); + if (!device->readPixels(bounds, &bitmap)) + return "data:,"; + } + if (mimeType == "image/jpeg") { int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality; if (quality && *quality >= 0.0 && *quality <= 1.0) compressionQuality = static_cast<int>(*quality * 100 + 0.5); - if (!JPEGImageEncoder::encode(*context()->platformContext()->bitmap(), compressionQuality, &encodedImage)) + if (!JPEGImageEncoder::encode(bitmap, compressionQuality, &encodedImage)) return "data:,"; } else { - if (!PNGImageEncoder::encode(*context()->platformContext()->bitmap(), &encodedImage)) + if (!PNGImageEncoder::encode(bitmap, &encodedImage)) return "data:,"; ASSERT(mimeType == "image/png"); } diff --git a/Source/WebCore/platform/graphics/skia/IntRectSkia.cpp b/Source/WebCore/platform/graphics/skia/IntRectSkia.cpp index ea138ee..0024086 100644 --- a/Source/WebCore/platform/graphics/skia/IntRectSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/IntRectSkia.cpp @@ -37,14 +37,14 @@ namespace WebCore { IntRect::operator SkIRect() const { - SkIRect rect = { x(), y(), right(), bottom() }; + SkIRect rect = { x(), y(), maxX(), maxY() }; return rect; } IntRect::operator SkRect() const { SkRect rect; - rect.set(SkIntToScalar(x()), SkIntToScalar(y()), SkIntToScalar(right()), SkIntToScalar(bottom())); + rect.set(SkIntToScalar(x()), SkIntToScalar(y()), SkIntToScalar(maxX()), SkIntToScalar(maxY())); return rect; } diff --git a/Source/WebCore/platform/graphics/skia/PathSkia.cpp b/Source/WebCore/platform/graphics/skia/PathSkia.cpp index 89323c4..6318c21 100644 --- a/Source/WebCore/platform/graphics/skia/PathSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/PathSkia.cpp @@ -227,28 +227,20 @@ void Path::transform(const AffineTransform& xform) m_path->transform(xform); } -// Computes the bounding box for the stroke and style currently selected into -// the given bounding box. This also takes into account the stroke width. -static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context) -{ - SkPaint paint; - context->platformContext()->setupPaintForStroking(&paint, 0, 0); - SkPath boundingPath; - paint.getFillPath(context->platformContext()->currentPathInLocalCoordinates(), &boundingPath); - return boundingPath.getBounds(); -} - FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) { GraphicsContext* scratch = scratchContext(); scratch->save(); - scratch->beginPath(); - scratch->addPath(*this); if (applier) applier->strokeStyle(scratch); - FloatRect r = boundingBoxForCurrentStroke(scratch); + SkPaint paint; + scratch->platformContext()->setupPaintForStroking(&paint, 0, 0); + SkPath boundingPath; + paint.getFillPath(*platformPath(), &boundingPath); + + FloatRect r = boundingPath.getBounds(); scratch->restore(); return r; } diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index d852e9b..5e08b3c 100644 --- a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -51,6 +51,12 @@ #include "SkDashPathEffect.h" #include "SkShader.h" +#if ENABLE(SKIA_GPU) +#include "GrContext.h" +#include "SkGpuDevice.h" +#include "SkGpuDeviceFactory.h" +#endif + #include <wtf/MathExtras.h> #include <wtf/OwnArrayPtr.h> #include <wtf/Vector.h> @@ -62,6 +68,18 @@ namespace WebCore { +#if ENABLE(SKIA_GPU) +GrContext* GetGlobalGrContext() +{ + static GrContext* gGR; + if (!gGR) { + gGR = GrContext::CreateGLShaderContext(); + gGR->setTextureCacheLimits(512, 50 * 1024 * 1024); + } + return gGR; +} +#endif + extern bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path); // State ----------------------------------------------------------------------- @@ -266,7 +284,7 @@ void PlatformContextSkia::beginLayerClippedToImage(const FloatRect& rect, // create the resulting image. m_state->m_clip = rect; SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), - SkFloatToScalar(rect.right()), SkFloatToScalar(rect.bottom()) }; + SkFloatToScalar(rect.maxX()), SkFloatToScalar(rect.maxY()) }; canvas()->clipRect(bounds); canvas()->saveLayerAlpha(&bounds, 255, @@ -550,38 +568,12 @@ SkColor PlatformContextSkia::effectiveStrokeColor() const return m_state->applyAlpha(m_state->m_strokeColor); } -void PlatformContextSkia::beginPath() -{ - m_path.reset(); -} - -void PlatformContextSkia::addPath(const SkPath& path) -{ - m_path.addPath(path, m_canvas->getTotalMatrix()); -} - -SkPath PlatformContextSkia::currentPathInLocalCoordinates() const -{ - SkPath localPath = m_path; - const SkMatrix& matrix = m_canvas->getTotalMatrix(); - SkMatrix inverseMatrix; - if (!matrix.invert(&inverseMatrix)) - return SkPath(); - localPath.transform(inverseMatrix); - return localPath; -} - void PlatformContextSkia::canvasClipPath(const SkPath& path) { m_state->m_canvasClipApplied = true; m_canvas->clipPath(path); } -void PlatformContextSkia::setFillRule(SkPath::FillType fr) -{ - m_path.setFillType(fr); -} - void PlatformContextSkia::setFillShader(SkShader* fillShader) { if (fillShader) @@ -625,7 +617,11 @@ const SkBitmap* PlatformContextSkia::bitmap() const bool PlatformContextSkia::isPrinting() { +#if ENABLE(SKIA_GPU) + return true; +#else return m_canvas->getTopPlatformDevice().IsVectorial(); +#endif } void PlatformContextSkia::getImageResamplingHint(IntSize* srcSize, FloatSize* dstSize) const @@ -739,6 +735,19 @@ void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* co m_gpuCanvas = new GLES2Canvas(context, drawingBuffer, size); m_uploadTexture.clear(); drawingBuffer->setWillPublishCallback(WillPublishCallbackImpl::create(this)); + +#if ENABLE(SKIA_GPU) + m_useGPU = false; + context->makeContextCurrent(); + m_gpuCanvas->bindFramebuffer(); + + GrContext* gr = GetGlobalGrContext(); + gr->resetContext(); + SkDeviceFactory* factory = new SkGpuDeviceFactory(gr, SkGpuDevice::Current3DApiRenderTarget()); + SkDevice* device = factory->newDevice(m_canvas, SkBitmap::kARGB_8888_Config, drawingBuffer->size().width(), drawingBuffer->size().height(), false, false); + m_canvas->setDevice(device)->unref(); + m_canvas->setDeviceFactory(factory); +#endif } else { syncSoftwareCanvas(); m_uploadTexture.clear(); @@ -750,8 +759,13 @@ void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* co void PlatformContextSkia::prepareForSoftwareDraw() const { - if (!m_useGPU) + if (!m_useGPU) { +#if ENABLE(SKIA_GPU) + if (m_gpuCanvas) + m_gpuCanvas->context()->makeContextCurrent(); +#endif return; + } if (m_backingStoreState == Hardware) { // Depending on the blend mode we need to do one of a few things: @@ -804,8 +818,13 @@ void PlatformContextSkia::prepareForHardwareDraw() const void PlatformContextSkia::syncSoftwareCanvas() const { - if (!m_useGPU) + if (!m_useGPU) { +#if ENABLE(SKIA_GPU) + if (m_gpuCanvas) + m_gpuCanvas->bindFramebuffer(); +#endif return; + } if (m_backingStoreState == Hardware) readbackHardwareToSoftware(); @@ -865,7 +884,7 @@ void PlatformContextSkia::readbackHardwareToSoftware() const const SkBitmap& bitmap = m_canvas->getDevice()->accessBitmap(true); SkAutoLockPixels lock(bitmap); int width = bitmap.width(), height = bitmap.height(); - OwnArrayPtr<uint32_t> buf(new uint32_t[width]); + OwnArrayPtr<uint32_t> buf = adoptArrayPtr(new uint32_t[width]); SharedGraphicsContext3D* context = m_gpuCanvas->context(); m_gpuCanvas->bindFramebuffer(); // Flips the image vertically. diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h index 0304486..d7dd6a9 100644 --- a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -118,7 +118,6 @@ public: void setAlpha(float); void setLineCap(SkPaint::Cap); void setLineJoin(SkPaint::Join); - void setFillRule(SkPath::FillType); void setXfermodeMode(SkXfermode::Mode); void setFillColor(SkColor); void setFillShader(SkShader*); @@ -137,10 +136,6 @@ public: float getAlpha() const; int getNormalizedAlpha() const; - void beginPath(); - void addPath(const SkPath&); - SkPath currentPathInLocalCoordinates() const; - void canvasClipPath(const SkPath&); // Returns the fill color. The returned color has it's alpha adjusted @@ -220,9 +215,6 @@ private: // mStateStack.back(). State* m_state; - // Current path in global coordinates. - SkPath m_path; - // Stores image sizes for a hint to compute image resampling modes. // Values are used in ImageSkia.cpp IntSize m_imageResamplingHintSrcSize; diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h index 85fa3ee..47a27c6 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h @@ -26,7 +26,7 @@ #include "Image.h" #include "TextureMapperNode.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) #include "GraphicsContext3D.h" #endif @@ -73,7 +73,7 @@ public: virtual void setContentsToImage(Image*); virtual void setContentsToMedia(PlatformLayer*); virtual void setContentsBackgroundColor(const Color&); -#if ENABLE(3D_CANVAS) +#if ENABLE(WEBGL) virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*); virtual void setGraphicsContext3DNeedsDisplay(); #endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp index 09051f9..bf53e61 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp @@ -318,7 +318,7 @@ void TextureMapperNode::computeLocalTransform() m_transforms.local = TransformationMatrix() .translate3d(originX + m_state.pos.x(), originY + m_state.pos.y(), m_state.anchorPoint.z()) - .multLeft(m_state.transform) + .multiply(m_state.transform) .translate3d(-originX, -originY, -m_state.anchorPoint.z()); m_transforms.localDirty = false; } @@ -352,7 +352,7 @@ void TextureMapperNode::computeReplicaTransform() m_nearestSurfaceSize = nearestSurfaceSize(); if (m_layerType != TransparencyLayer) { - m_transforms.replica = TransformationMatrix(m_transforms.target).multLeft(m_state.replicaLayer->m_transforms.local); + m_transforms.replica = TransformationMatrix(m_transforms.target).multiply(m_state.replicaLayer->m_transforms.local); return; } @@ -361,7 +361,7 @@ void TextureMapperNode::computeReplicaTransform() m_transforms.replica = TransformationMatrix() .translate(originX, originY) - .multLeft(m_state.replicaLayer->m_transforms.local) + .multiply(m_state.replicaLayer->m_transforms.local) .translate(-originX, -originY); } @@ -377,7 +377,7 @@ void TextureMapperNode::computeTransformations() TextureMapperNode* parent = m_parent; computeLocalTransform(); - m_transforms.target = TransformationMatrix(parent ? parent->m_transforms.forDescendants : TransformationMatrix()).multLeft(m_transforms.local); + m_transforms.target = TransformationMatrix(parent ? parent->m_transforms.forDescendants : TransformationMatrix()).multiply(m_transforms.local); m_transforms.forDescendants = (m_layerType == ClipLayer ? TransformationMatrix() : m_transforms.target); if (m_effectTarget) @@ -408,10 +408,10 @@ void TextureMapperNode::computeTransformations() if (m_transforms.perspectiveDirty) m_transforms.perspective = TransformationMatrix() .translate(centerPoint.x(), centerPoint.y()) - .multLeft(m_state.childrenTransform) + .multiply(m_state.childrenTransform) .translate(-centerPoint.x(), -centerPoint.y()); m_transforms.perspectiveDirty = false; - m_transforms.forDescendants.multLeft(m_transforms.perspective); + m_transforms.forDescendants.multiply(m_transforms.perspective); } void TextureMapperNode::uploadTextureFromContent(TextureMapper* textureMapper, const IntRect& visibleRect, GraphicsLayer* layer) diff --git a/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp b/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp index 3f88140..a1ffa30 100644 --- a/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp +++ b/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp @@ -222,14 +222,6 @@ AffineTransform& AffineTransform::translate(double tx, double ty) return *this; } -// *this = translation * *this -AffineTransform& AffineTransform::translateRight(double tx, double ty) -{ - m_transform[4] += tx; - m_transform[5] += ty; - return *this; -} - AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy) { return scale(sx, sy); @@ -324,9 +316,9 @@ FloatRect AffineTransform::mapRect(const FloatRect& rect) const FloatQuad result; result.setP1(mapPoint(rect.location())); - result.setP2(mapPoint(FloatPoint(rect.right(), rect.y()))); - result.setP3(mapPoint(FloatPoint(rect.right(), rect.bottom()))); - result.setP4(mapPoint(FloatPoint(rect.x(), rect.bottom()))); + result.setP2(mapPoint(FloatPoint(rect.maxX(), rect.y()))); + result.setP3(mapPoint(FloatPoint(rect.maxX(), rect.maxY()))); + result.setP4(mapPoint(FloatPoint(rect.x(), rect.maxY()))); return result.boundingBox(); } diff --git a/Source/WebCore/platform/graphics/transforms/AffineTransform.h b/Source/WebCore/platform/graphics/transforms/AffineTransform.h index 50d0655..3e3995f 100644 --- a/Source/WebCore/platform/graphics/transforms/AffineTransform.h +++ b/Source/WebCore/platform/graphics/transforms/AffineTransform.h @@ -103,7 +103,6 @@ public: AffineTransform& rotate(double d); AffineTransform& rotateFromVector(double x, double y); AffineTransform& translate(double tx, double ty); - AffineTransform& translateRight(double tx, double ty); AffineTransform& shear(double sx, double sy); AffineTransform& flipX(); AffineTransform& flipY(); @@ -172,6 +171,11 @@ public: operator wxGraphicsMatrix() const; #endif + static AffineTransform translation(double x, double y) + { + return AffineTransform(1, 0, 0, 1, x, y); + } + private: void setMatrix(const Transform m) { diff --git a/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h b/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h index 0a0aaf0..dd5dae2 100644 --- a/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h +++ b/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h @@ -55,7 +55,7 @@ private: virtual bool apply(TransformationMatrix& transform, const IntSize&) const { - transform.multLeft(TransformationMatrix(m_matrix)); + transform.multiply(TransformationMatrix(m_matrix)); return false; } diff --git a/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h b/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h index fd9b27e..6f4e725 100644 --- a/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h +++ b/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h @@ -62,7 +62,7 @@ private: virtual bool apply(TransformationMatrix& transform, const IntSize&) const { TransformationMatrix matrix(m_a, m_b, m_c, m_d, m_e, m_f); - transform.multLeft(TransformationMatrix(matrix)); + transform.multiply(matrix); return false; } diff --git a/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp index 9fd03a1..18bfe37 100644 --- a/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp +++ b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "PerspectiveTransformOperation.h" -#include <algorithm> +#include <wtf/MathExtras.h> using namespace std; @@ -37,22 +37,29 @@ PassRefPtr<TransformOperation> PerspectiveTransformOperation::blend(const Transf if (from && !from->isSameType(*this)) return this; - if (blendToIdentity) - return PerspectiveTransformOperation::create(m_p + (1. - m_p) * progress); + if (blendToIdentity) { + double p = m_p.calcFloatValue(1); + p = p + (1. - p) * progress; // FIXME: this seems wrong. https://bugs.webkit.org/show_bug.cgi?id=52700 + return PerspectiveTransformOperation::create(Length(clampToPositiveInteger(p), Fixed)); + } const PerspectiveTransformOperation* fromOp = static_cast<const PerspectiveTransformOperation*>(from); - double fromP = fromOp ? fromOp->m_p : 0; - double toP = m_p; + Length fromP = fromOp ? fromOp->m_p : Length(m_p.type()); + Length toP = m_p; TransformationMatrix fromT; TransformationMatrix toT; - fromT.applyPerspective(fromP); - toT.applyPerspective(toP); + fromT.applyPerspective(fromP.calcFloatValue(1)); + toT.applyPerspective(toP.calcFloatValue(1)); toT.blend(fromT, progress); TransformationMatrix::DecomposedType decomp; toT.decompose(decomp); - - return PerspectiveTransformOperation::create(decomp.perspectiveZ ? -1.0 / decomp.perspectiveZ : 0.0); + + if (decomp.perspectiveZ) { + double val = -1.0 / decomp.perspectiveZ; + return PerspectiveTransformOperation::create(Length(clampToPositiveInteger(val), Fixed)); + } + return PerspectiveTransformOperation::create(Length(0, Fixed)); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h index 834cc83..886d3dc 100644 --- a/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h +++ b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h @@ -26,21 +26,22 @@ #ifndef PerspectiveTransformOperation_h #define PerspectiveTransformOperation_h +#include "Length.h" #include "TransformOperation.h" namespace WebCore { class PerspectiveTransformOperation : public TransformOperation { public: - static PassRefPtr<PerspectiveTransformOperation> create(double p) + static PassRefPtr<PerspectiveTransformOperation> create(const Length& p) { return adoptRef(new PerspectiveTransformOperation(p)); } - double perspective() const { return m_p; } + Length perspective() const { return m_p; } private: - virtual bool isIdentity() const { return m_p == 0; } + virtual bool isIdentity() const { return m_p.calcFloatValue(1) == 0; } virtual OperationType getOperationType() const { return PERSPECTIVE; } virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == PERSPECTIVE; } @@ -54,18 +55,19 @@ private: virtual bool apply(TransformationMatrix& transform, const IntSize&) const { - transform.applyPerspective(m_p); + transform.applyPerspective(m_p.calcFloatValue(1)); return false; } virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); - PerspectiveTransformOperation(double p) + PerspectiveTransformOperation(const Length& p) : m_p(p) { + ASSERT(p.isFixed()); } - double m_p; + Length m_p; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp index 357a140..c7283a5 100644 --- a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp +++ b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp @@ -55,21 +55,17 @@ namespace WebCore { // webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes // with no guarantee. -// A Note About row-major vs. column major matrixes +// A clarification about the storage of matrix elements // -// The clients of this class (CSSMatrix and SVGMatrix) assume a column-major ordering. -// That means that when the matrix is initialized with 16 values, the first 4 values -// go in the 4 rows of the first column, etc. And in the dereferencing calls, the first -// digit is the column (e.g., m23() is column 2 row 3). Because C++ uses row-major arrays -// the internal matrix is stored in row-major order, so m[2][0] means row 2, column 0. This -// has no bearing on how the matrix is viewed on the outside, since all access is done -// with function calls. But it does help make the code more clear if you know that. +// This class uses a 2 dimensional array internally to store the elements of the matrix. The first index into +// the array refers to the column that the element lies in; the second index refers to the row. // -// FIXME: Multiply calls are named for what they do in the internal, row-major world. -// multLeft is actually a multRight in a column-major world, and multiply is a multLeft -// in a column-major world. For now I've left it that way to avoid too many confusing -// changes to the code. In particular AffineTransform uses these same terms for the -// opposite operations. So we have to be VERY careful when we change them. +// In other words, this is the layout of the matrix: +// +// | m_matrix[0][0] m_matrix[1][0] m_matrix[2][0] m_matrix[3][0] | +// | m_matrix[0][1] m_matrix[1][1] m_matrix[2][1] m_matrix[3][1] | +// | m_matrix[0][2] m_matrix[1][2] m_matrix[2][2] m_matrix[3][2] | +// | m_matrix[0][3] m_matrix[1][3] m_matrix[2][3] m_matrix[3][3] | typedef double Vector4[4]; typedef double Vector3[3]; @@ -634,7 +630,7 @@ TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy mat.m_matrix[0][0] = sx; mat.m_matrix[1][1] = sy; - multLeft(mat); + multiply(mat); return *this; } @@ -645,7 +641,7 @@ TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double mat.m_matrix[1][1] = sy; mat.m_matrix[2][2] = sz; - multLeft(mat); + multiply(mat); return *this; } @@ -732,7 +728,7 @@ TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; mat.m_matrix[3][3] = 1.0f; } - multLeft(mat); + multiply(mat); return *this; } @@ -783,7 +779,7 @@ TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, doubl mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; mat.m_matrix[3][3] = 1.0f; - rmat.multLeft(mat); + rmat.multiply(mat); rx /= 2.0f; sinA = sin(rx); @@ -803,9 +799,9 @@ TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, doubl mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; mat.m_matrix[3][3] = 1.0f; - rmat.multLeft(mat); + rmat.multiply(mat); - multLeft(rmat); + multiply(rmat); return *this; } @@ -869,7 +865,7 @@ TransformationMatrix& TransformationMatrix::skew(double sx, double sy) mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row - multLeft(mat); + multiply(mat); return *this; } @@ -879,7 +875,7 @@ TransformationMatrix& TransformationMatrix::applyPerspective(double p) if (p != 0) mat.m_matrix[2][3] = -1/p; - multLeft(mat); + multiply(mat); return *this; } @@ -896,7 +892,7 @@ TransformationMatrix TransformationMatrix::rectToRect(const FloatRect& from, con // // *this = mat * *this // -TransformationMatrix& TransformationMatrix::multLeft(const TransformationMatrix& mat) +TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& mat) { Matrix4 tmp; @@ -1105,25 +1101,25 @@ void TransformationMatrix::recompose(const DecomposedType& decomp) 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0, 0, 0, 0, 1); - multLeft(rotationMatrix); + multiply(rotationMatrix); // now apply skew if (decomp.skewYZ) { TransformationMatrix tmp; tmp.setM32((float) decomp.skewYZ); - multLeft(tmp); + multiply(tmp); } if (decomp.skewXZ) { TransformationMatrix tmp; tmp.setM31((float) decomp.skewXZ); - multLeft(tmp); + multiply(tmp); } if (decomp.skewXY) { TransformationMatrix tmp; tmp.setM21((float) decomp.skewXY); - multLeft(tmp); + multiply(tmp); } // finally, apply scale diff --git a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h index c883675..fa27c0e 100644 --- a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h +++ b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -208,11 +208,8 @@ public: void setF(double f) { m_matrix[3][1] = f; } // this = this * mat - TransformationMatrix& multiply(const TransformationMatrix& t) { return *this *= t; } + TransformationMatrix& multiply(const TransformationMatrix&); - // this = mat * this - TransformationMatrix& multLeft(const TransformationMatrix& mat); - TransformationMatrix& scale(double); TransformationMatrix& scaleNonUniform(double sx, double sy); TransformationMatrix& scale3d(double sx, double sy, double sz); @@ -296,19 +293,18 @@ public: } bool operator!=(const TransformationMatrix& other) const { return !(*this == other); } - - // *this = *this * t (i.e., a multRight) + + // *this = *this * t TransformationMatrix& operator*=(const TransformationMatrix& t) { - *this = *this * t; - return *this; + return multiply(t); } - // result = *this * t (i.e., a multRight) + // result = *this * t TransformationMatrix operator*(const TransformationMatrix& t) const { - TransformationMatrix result = t; - result.multLeft(*this); + TransformationMatrix result = *this; + result.multiply(t); return result; } diff --git a/Source/WebCore/platform/graphics/win/FontCGWin.cpp b/Source/WebCore/platform/graphics/win/FontCGWin.cpp index 8012722..fe26c43 100644 --- a/Source/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontCGWin.cpp @@ -167,8 +167,12 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData drawIntoBitmap = true; // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges. // FIXME: Can get glyphs' optical bounds (even from CG) to get this right. - int lineGap = font->lineGap(); - textRect = IntRect(point.x() - (font->ascent() + font->descent()) / 2, point.y() - font->ascent() - lineGap, totalWidth + font->ascent() + font->descent(), font->lineSpacing()); + const FontMetrics& fontMetrics = font->fontMetrics(); + int lineGap = fontMetrics.lineGap(); + textRect = IntRect(point.x() - (fontMetrics.ascent() + fontMetrics.descent()) / 2, + point.y() - fontMetrics.ascent() - lineGap, + totalWidth + fontMetrics.ascent() + fontMetrics.descent(), + fontMetrics.lineSpacing()); bitmap.set(graphicsContext->createWindowsBitmap(textRect.size())); memset(bitmap->buffer(), 255, bitmap->bufferLength()); hdc = bitmap->hdc(); @@ -288,7 +292,7 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData buffer[i + 2] = fillColor.red(); buffer[i + 3] = alpha; } - graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.topLeft()); + graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.location()); } else graphicsContext->releaseWindowsContext(hdc, textRect, true, false); } diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp index 9cae99b..4aee6cd 100644 --- a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp @@ -59,7 +59,7 @@ FontCustomPlatformData::~FontCustomPlatformData() } } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode renderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode renderingMode) { ASSERT(m_fontReference); ASSERT(T2embedLibrary()); @@ -154,13 +154,12 @@ static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned // not allow access from CSS. static String createUniqueFontName() { - Vector<char> fontUuid(sizeof(GUID)); - CoCreateGuid(reinterpret_cast<GUID*>(fontUuid.data())); + GUID fontUuid; + CoCreateGuid(&fontUuid); - Vector<char> fontNameVector; - base64Encode(fontUuid, fontNameVector); - ASSERT(fontNameVector.size() < LF_FACESIZE); - return String(fontNameVector.data(), fontNameVector.size()); + String fontName = base64Encode(reinterpret_cast<char*>(&fontUuid), sizeof(fontUuid)); + ASSERT(fontName.length() < LF_FACESIZE); + return fontName; } FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h index de33c63..abdb356 100644 --- a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h @@ -23,6 +23,7 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" +#include "FontWidthVariant.h" #include "PlatformString.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -45,7 +46,7 @@ public: ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp index c3decbf..fd30a6d 100644 --- a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp +++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp @@ -32,7 +32,7 @@ FontCustomPlatformData::~FontCustomPlatformData() cairo_font_face_destroy(m_fontFace); } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant) { return FontPlatformData(m_fontFace, size, bold, italic); } diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h index 9c67037..ea3ae38 100644 --- a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h +++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h @@ -42,7 +42,7 @@ public: } ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth); static bool supportsFormat(const String&); diff --git a/Source/WebCore/platform/graphics/win/FontWin.cpp b/Source/WebCore/platform/graphics/win/FontWin.cpp index 2ed9eb3..47c44bc 100644 --- a/Source/WebCore/platform/graphics/win/FontWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontWin.cpp @@ -45,6 +45,11 @@ bool Font::canReturnFallbackFontsForComplexText() return true; } +bool Font::canExpandAroundIdeographsInComplexText() +{ + return false; +} + FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const { @@ -122,8 +127,8 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon UniscribeController controller(this, run, fallbackFonts); controller.advance(run.length()); if (glyphOverflow) { - glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - ascent()); - glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - descent()); + glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - fontMetrics().ascent()); + glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - fontMetrics().descent()); glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX())); glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.runWidthSoFar())); } diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp index f1953e4..bb22024 100644 --- a/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp +++ b/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp @@ -154,7 +154,7 @@ void GraphicsContextPlatformPrivate::clip(const FloatRect& clipRect) { if (!m_hdc) return; - IntersectClipRect(m_hdc, clipRect.x(), clipRect.y(), clipRect.right(), clipRect.bottom()); + IntersectClipRect(m_hdc, clipRect.x(), clipRect.y(), clipRect.maxX(), clipRect.maxY()); } void GraphicsContextPlatformPrivate::clip(const Path&) diff --git a/Source/WebCore/platform/graphics/win/IconWin.cpp b/Source/WebCore/platform/graphics/win/IconWin.cpp index 4d4d219..7e03362 100644 --- a/Source/WebCore/platform/graphics/win/IconWin.cpp +++ b/Source/WebCore/platform/graphics/win/IconWin.cpp @@ -25,7 +25,6 @@ #include "GraphicsContext.h" #include "LocalWindowsContext.h" #include "PlatformString.h" -#include <tchar.h> #include <windows.h> #if OS(WINCE) @@ -68,16 +67,16 @@ PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) #if OS(WINCE) return 0; #else - TCHAR buffer[MAX_PATH]; - UINT length = ::GetSystemDirectory(buffer, WTF_ARRAY_LENGTH(buffer)); + WCHAR buffer[MAX_PATH]; + UINT length = ::GetSystemDirectoryW(buffer, WTF_ARRAY_LENGTH(buffer)); if (!length) return 0; - - if (_tcscat_s(buffer, TEXT("\\shell32.dll"))) + + if (wcscat_s(buffer, L"\\shell32.dll")) return 0; HICON hIcon; - if (!::ExtractIconEx(buffer, shell32MultipleFileIconIndex, 0, &hIcon, 1)) + if (!::ExtractIconExW(buffer, shell32MultipleFileIconIndex, 0, &hIcon, 1)) return 0; return adoptRef(new Icon(hIcon)); #endif diff --git a/Source/WebCore/platform/graphics/win/IntRectWin.cpp b/Source/WebCore/platform/graphics/win/IntRectWin.cpp index fe25a7f..6af6735 100644 --- a/Source/WebCore/platform/graphics/win/IntRectWin.cpp +++ b/Source/WebCore/platform/graphics/win/IntRectWin.cpp @@ -38,7 +38,7 @@ IntRect::IntRect(const RECT& r) IntRect::operator RECT() const { - RECT rect = { x(), y(), right(), bottom() }; + RECT rect = { x(), y(), maxX(), maxY() }; return rect; } diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp index 01db7f2..dd3cd32 100644 --- a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp +++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp @@ -34,6 +34,11 @@ #include <CoreGraphics/CGColor.h> #endif +#if USE(ACCELERATED_COMPOSITING) +#include "CACFLayerTreeHost.h" +#include "PlatformCALayer.h" +#endif + namespace WebCore { MediaPlayerPrivateFullscreenWindow::MediaPlayerPrivateFullscreenWindow(MediaPlayerPrivateFullscreenClient* client) @@ -47,8 +52,11 @@ MediaPlayerPrivateFullscreenWindow::MediaPlayerPrivateFullscreenWindow(MediaPlay MediaPlayerPrivateFullscreenWindow::~MediaPlayerPrivateFullscreenWindow() { - if (m_hwnd) - close(); + if (!m_hwnd) + return; + + ::DestroyWindow(m_hwnd); + ASSERT(!m_hwnd); } void MediaPlayerPrivateFullscreenWindow::createWindow(HWND parentHwnd) @@ -65,8 +73,7 @@ void MediaPlayerPrivateFullscreenWindow::createWindow(HWND parentHwnd) windowAtom = ::RegisterClassEx(&wcex); } - if (m_hwnd) - close(); + ASSERT(!m_hwnd); MONITORINFO mi = {0}; mi.cbSize = sizeof(MONITORINFO); @@ -87,12 +94,6 @@ void MediaPlayerPrivateFullscreenWindow::createWindow(HWND parentHwnd) ::SetFocus(m_hwnd); } -void MediaPlayerPrivateFullscreenWindow::close() -{ - ::DestroyWindow(m_hwnd); - ASSERT(!m_hwnd); -} - #if USE(ACCELERATED_COMPOSITING) void MediaPlayerPrivateFullscreenWindow::setRootChildLayer(PassRefPtr<PlatformCALayer> rootChild) { diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h index c1ae762..e07bbac 100644 --- a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h +++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h @@ -26,9 +26,10 @@ #ifndef MediaPlayerPrivateFullscreenWindow_h #define MediaPlayerPrivateFullscreenWindow_h +#include <wtf/RefPtr.h> + #if USE(ACCELERATED_COMPOSITING) -#include "CACFLayerTreeHost.h" -#include "PlatformCALayer.h" +#include "CACFLayerTreeHostClient.h" #endif typedef unsigned WPARAM; @@ -40,6 +41,11 @@ typedef unsigned int UINT; namespace WebCore { +#if USE(ACCELERATED_COMPOSITING) +class CACFLayerTreeHost; +class PlatformCALayer; +#endif + class MediaPlayerPrivateFullscreenClient { public: virtual LRESULT fullscreenClientWndProc(HWND, UINT message, WPARAM, LPARAM) = 0; @@ -53,13 +59,10 @@ public: ~MediaPlayerPrivateFullscreenWindow(); void createWindow(HWND ownerWindow); - void close(); HWND hwnd() const { return m_hwnd; } #if USE(ACCELERATED_COMPOSITING) - CACFLayerTreeHost* layerView() const { return m_layerTreeHost.get(); } - PlatformCALayer* rootChildLayer() const { return m_rootChild.get(); } void setRootChildLayer(PassRefPtr<PlatformCALayer>); #endif diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp index 0b91455..d47de2b 100644 --- a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp +++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp @@ -1059,7 +1059,7 @@ float MediaPlayerPrivateQuickTimeVisualContext::mediaTimeForTimeValue(float time if (m_readyState < MediaPlayer::HaveMetadata || !(timeScale = m_movie->timeScale())) return timeValue; - long mediaTimeValue = static_cast<long>(timeValue * timeScale); + long mediaTimeValue = lroundf(timeValue * timeScale); return static_cast<float>(mediaTimeValue) / timeScale; } diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index 431d624..07b7621 100644 --- a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -622,7 +622,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r) m_qtGWorld->paint(hdc, r.x(), r.y()); if (usingTempBitmap) - p->drawWindowsBitmap(bitmap.get(), r.topLeft()); + p->drawWindowsBitmap(bitmap.get(), r.location()); else p->releaseWindowsContext(hdc, r); diff --git a/Source/WebCore/platform/graphics/win/QTMovie.cpp b/Source/WebCore/platform/graphics/win/QTMovie.cpp index dfa1d36..4cd8161 100644 --- a/Source/WebCore/platform/graphics/win/QTMovie.cpp +++ b/Source/WebCore/platform/graphics/win/QTMovie.cpp @@ -33,7 +33,9 @@ #include <Movies.h> #include <QTML.h> #include <QuickTimeComponents.h> +#include <WebKitSystemInterface/WebKitSystemInterface.h> #include <wtf/Assertions.h> +#include <wtf/MathExtras.h> #include <wtf/Noncopyable.h> #include <wtf/Vector.h> @@ -46,7 +48,6 @@ static const long subTitleTrackType = 'sbtl'; static const long mpeg4ObjectDescriptionTrackType = 'odsm'; static const long mpeg4SceneDescriptionTrackType = 'sdsm'; static const long closedCaptionDisplayPropertyID = 'disp'; -static LPCTSTR fullscreenQTMoviePointerProp = TEXT("fullscreenQTMoviePointer"); // Resizing GWorlds is slow, give them a minimum size so size of small // videos can be animated smoothly @@ -60,7 +61,7 @@ union UppParam { void* ptr; }; -static Vector<CFStringRef>* gSupportedTypes = 0; +static CFMutableArrayRef gSupportedTypes = 0; static SInt32 quickTimeVersion = 0; class QTMoviePrivate : public QTMovieTaskClient { @@ -374,10 +375,10 @@ void QTMovie::setCurrentTime(float time) const m_private->m_seeking = true; TimeScale scale = GetMovieTimeScale(m_private->m_movie); if (m_private->m_movieController) { - QTRestartAtTimeRecord restart = { time * scale , 0 }; + QTRestartAtTimeRecord restart = { lroundf(time * scale) , 0 }; MCDoAction(m_private->m_movieController, mcActionRestartAtTime, (void *)&restart); } else - SetMovieTimeValue(m_private->m_movie, TimeValue(time * scale)); + SetMovieTimeValue(m_private->m_movie, TimeValue(lroundf(time * scale))); QTMovieTask::sharedTask()->updateTaskTimer(); } @@ -747,112 +748,59 @@ long QTMovie::timeScale() const return GetMovieTimeScale(m_private->m_movie); } +static void getMIMETypeCallBack(const char* type); + static void initializeSupportedTypes() { if (gSupportedTypes) return; - gSupportedTypes = new Vector<CFStringRef>; + gSupportedTypes = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); if (quickTimeVersion < minimumQuickTimeVersion) { LOG_ERROR("QuickTime version %x detected, at least %x required. Returning empty list of supported media MIME types.", quickTimeVersion, minimumQuickTimeVersion); return; } // QuickTime doesn't have an importer for video/quicktime. Add it manually. - gSupportedTypes->append(CFSTR("video/quicktime")); - - for (int index = 0; index < 2; index++) { - ComponentDescription findCD; - - // look at all movie importers that can import in place and are installed. - findCD.componentType = MovieImportType; - findCD.componentSubType = 0; - findCD.componentManufacturer = 0; - findCD.componentFlagsMask = cmpIsMissing | movieImportSubTypeIsFileExtension | canMovieImportInPlace | dontAutoFileMovieImport; - - // look at those registered by HFS file types the first time through, by file extension the second time - findCD.componentFlags = canMovieImportInPlace | (index ? movieImportSubTypeIsFileExtension : 0); - - long componentCount = CountComponents(&findCD); - if (!componentCount) - continue; + CFArrayAppendValue(gSupportedTypes, CFSTR("video/quicktime")); + + wkGetQuickTimeMIMETypeList(getMIMETypeCallBack); +} - Component comp = 0; - while (comp = FindNextComponent(comp, &findCD)) { - // Does this component have a MIME type container? - ComponentDescription infoCD; - OSErr err = GetComponentInfo(comp, &infoCD, nil /*name*/, nil /*info*/, nil /*icon*/); - if (err) - continue; - if (!(infoCD.componentFlags & hasMovieImportMIMEList)) - continue; - QTAtomContainer mimeList = 0; - err = MovieImportGetMIMETypeList((ComponentInstance)comp, &mimeList); - if (err || !mimeList) - continue; +static void getMIMETypeCallBack(const char* type) +{ + ASSERT(type); + CFStringRef cfType = CFStringCreateWithCString(kCFAllocatorDefault, type, kCFStringEncodingMacRoman); + if (!cfType) + return; - // Grab every type from the container. - QTLockContainer(mimeList); - int typeCount = QTCountChildrenOfType(mimeList, kParentAtomIsContainer, kMimeInfoMimeTypeTag); - for (int typeIndex = 1; typeIndex <= typeCount; typeIndex++) { - QTAtom mimeTag = QTFindChildByIndex(mimeList, 0, kMimeInfoMimeTypeTag, typeIndex, 0); - if (!mimeTag) - continue; - char* atomData; - long typeLength; - if (noErr != QTGetAtomDataPtr(mimeList, mimeTag, &typeLength, &atomData)) - continue; - - char typeBuffer[256]; - if (typeLength >= sizeof(typeBuffer)) - continue; - memcpy(typeBuffer, atomData, typeLength); - typeBuffer[typeLength] = 0; - - // Only add "audio/..." and "video/..." types. - if (strncmp(typeBuffer, "audio/", 6) && strncmp(typeBuffer, "video/", 6)) - continue; - - CFStringRef cfMimeType = CFStringCreateWithCString(0, typeBuffer, kCFStringEncodingUTF8); - if (!cfMimeType) - continue; - - // Only add each type once. - bool alreadyAdded = false; - for (int addedIndex = 0; addedIndex < gSupportedTypes->size(); addedIndex++) { - CFStringRef type = gSupportedTypes->at(addedIndex); - if (kCFCompareEqualTo == CFStringCompare(cfMimeType, type, kCFCompareCaseInsensitive)) { - alreadyAdded = true; - break; - } - } - if (!alreadyAdded) - gSupportedTypes->append(cfMimeType); - else - CFRelease(cfMimeType); - } - DisposeHandle(mimeList); - } + // Filter out all non-audio or -video MIME Types, and only add each type once: + if (CFStringHasPrefix(cfType, CFSTR("audio/")) || CFStringHasPrefix(cfType, CFSTR("video/"))) { + CFRange range = CFRangeMake(0, CFArrayGetCount(gSupportedTypes)); + if (!CFArrayContainsValue(gSupportedTypes, range, cfType)) + CFArrayAppendValue(gSupportedTypes, cfType); } + + CFRelease(cfType); } unsigned QTMovie::countSupportedTypes() { initializeSupportedTypes(); - return static_cast<unsigned>(gSupportedTypes->size()); + return static_cast<unsigned>(CFArrayGetCount(gSupportedTypes)); } void QTMovie::getSupportedType(unsigned index, const UChar*& str, unsigned& len) { initializeSupportedTypes(); - ASSERT(index < gSupportedTypes->size()); + ASSERT(index < CFArrayGetCount(gSupportedTypes)); // Allocate sufficient buffer to hold any MIME type static UniChar* staticBuffer = 0; if (!staticBuffer) staticBuffer = new UniChar[32]; - CFStringRef cfstr = gSupportedTypes->at(index); + CFStringRef cfstr = (CFStringRef)CFArrayGetValueAtIndex(gSupportedTypes, index); len = CFStringGetLength(cfstr); CFRange range = { 0, len }; CFStringGetCharacters(cfstr, range, staticBuffer); diff --git a/Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp b/Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp index e13f732..4be1bbb 100644 --- a/Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp +++ b/Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp @@ -40,7 +40,7 @@ using namespace std; static const long minimumQuickTimeVersion = 0x07300000; // 7.3 -static LPCTSTR fullscreenQTMovieGWorldPointerProp = TEXT("fullscreenQTMovieGWorldPointer"); +static LPCWSTR fullscreenQTMovieGWorldPointerProp = L"fullscreenQTMovieGWorldPointer"; // Resizing GWorlds is slow, give them a minimum size so size of small // videos can be animated smoothly @@ -378,10 +378,10 @@ bool QTMovieGWorld::isDisabled() const LRESULT QTMovieGWorld::fullscreenWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) { - QTMovieGWorld* movie = static_cast<QTMovieGWorld*>(GetProp(wnd, fullscreenQTMovieGWorldPointerProp)); + QTMovieGWorld* movie = static_cast<QTMovieGWorld*>(GetPropW(wnd, fullscreenQTMovieGWorldPointerProp)); if (message == WM_DESTROY) - RemoveProp(wnd, fullscreenQTMovieGWorldPointerProp); + RemovePropW(wnd, fullscreenQTMovieGWorldPointerProp); if (!movie) return DefWindowProc(wnd, message, wParam, lParam); @@ -423,7 +423,7 @@ HWND QTMovieGWorld::enterFullscreen(QTMovieGWorldFullscreenClient* client) // Set the 'this' pointer on the HWND HWND wnd = static_cast<HWND>(GetPortNativeWindow(m_private->m_fullscreenWindow)); - SetProp(wnd, fullscreenQTMovieGWorldPointerProp, static_cast<HANDLE>(this)); + SetPropW(wnd, fullscreenQTMovieGWorldPointerProp, static_cast<HANDLE>(this)); return wnd; } diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp index 20d42ff..30a931e 100644 --- a/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp +++ b/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp @@ -29,20 +29,19 @@ #include "config.h" #include "SimpleFontData.h" -#include <winsock2.h> #include "Font.h" #include "FontCache.h" #include "FloatRect.h" #include "FontDescription.h" #include "PlatformString.h" -#include <wtf/MathExtras.h> -#include <wtf/RetainPtr.h> -#include <unicode/uchar.h> -#include <unicode/unorm.h> #include <ApplicationServices/ApplicationServices.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> #include <mlang.h> -#include <tchar.h> +#include <unicode/uchar.h> +#include <unicode/unorm.h> +#include <winsock2.h> +#include <wtf/MathExtras.h> +#include <wtf/RetainPtr.h> namespace WebCore { @@ -64,19 +63,19 @@ void SimpleFontData::platformInit() int iAscent = CGFontGetAscent(font); int iDescent = CGFontGetDescent(font); int iLineGap = CGFontGetLeading(font); - m_unitsPerEm = CGFontGetUnitsPerEm(font); + unsigned unitsPerEm = CGFontGetUnitsPerEm(font); float pointSize = m_platformData.size(); - float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize; - float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize; - float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize; + float fAscent = scaleEmToUnits(iAscent, unitsPerEm) * pointSize; + float fDescent = -scaleEmToUnits(iDescent, unitsPerEm) * pointSize; + float fLineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize; if (!isCustomFont()) { HDC dc = GetDC(0); HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); int faceLength = GetTextFace(dc, 0, 0); - Vector<TCHAR> faceName(faceLength); + Vector<WCHAR> faceName(faceLength); GetTextFace(dc, faceLength, faceName.data()); - m_isSystemFont = !_tcscmp(faceName.data(), _T("Lucida Grande")); + m_isSystemFont = !wcscmp(faceName.data(), L"Lucida Grande"); SelectObject(dc, oldFont); ReleaseDC(0, dc); @@ -88,15 +87,15 @@ void SimpleFontData::platformInit() // web standard. The AppKit adjustment of 20% is too big and is // incorrectly added to line spacing, so we use a 15% adjustment instead // and add it to the ascent. - if (!_tcscmp(faceName.data(), _T("Times")) || !_tcscmp(faceName.data(), _T("Helvetica")) || !_tcscmp(faceName.data(), _T("Courier"))) + if (!wcscmp(faceName.data(), L"Times") || !wcscmp(faceName.data(), L"Helvetica") || !wcscmp(faceName.data(), L"Courier")) fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f); } } - m_ascent = lroundf(fAscent); - m_descent = lroundf(fDescent); - m_lineGap = lroundf(fLineGap); - m_lineSpacing = m_ascent + m_descent + m_lineGap; + m_fontMetrics.setAscent(fAscent); + m_fontMetrics.setDescent(fDescent); + m_fontMetrics.setLineGap(fLineGap); + m_fontMetrics.setLineSpacing(lroundf(fAscent) + lroundf(fDescent) + lroundf(fLineGap)); // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font. // Unfortunately, NSFont will round this for us so we don't quite get the right value. @@ -109,11 +108,13 @@ void SimpleFontData::platformInit() // and web pages that foolishly use this metric for width will be laid out // poorly if we return an accurate height. Classic case is Times 13 point, // which has an "x" that is 7x6 pixels. - m_xHeight = scaleEmToUnits(max(CGRectGetMaxX(xBox), CGRectGetMaxY(xBox)), m_unitsPerEm) * pointSize; + m_fontMetrics.setXHeight(scaleEmToUnits(max(CGRectGetMaxX(xBox), CGRectGetMaxY(xBox)), unitsPerEm) * pointSize); } else { int iXHeight = CGFontGetXHeight(font); - m_xHeight = scaleEmToUnits(iXHeight, m_unitsPerEm) * pointSize; + m_fontMetrics.setXHeight(scaleEmToUnits(iXHeight, unitsPerEm) * pointSize); } + + m_fontMetrics.setUnitsPerEm(unitsPerEm); } void SimpleFontData::platformCharWidthInit() @@ -133,7 +134,7 @@ FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const CGRect box; CGFontGetGlyphBBoxes(m_platformData.cgFont(), &glyph, 1, &box); float pointSize = m_platformData.size(); - CGFloat scale = pointSize / unitsPerEm(); + CGFloat scale = pointSize / fontMetrics().unitsPerEm(); FloatRect boundingBox = CGRectApplyAffineTransform(box, CGAffineTransformMakeScale(scale, -scale)); if (m_syntheticBoldOffset) boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset); diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp index 62ea060..277a13f 100644 --- a/Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp +++ b/Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp @@ -37,7 +37,6 @@ #include <cairo.h> #include <cairo-win32.h> #include <mlang.h> -#include <tchar.h> #include <wtf/MathExtras.h> namespace WebCore { @@ -63,13 +62,16 @@ void SimpleFontData::platformInit() TEXTMETRIC textMetrics; GetTextMetrics(hdc, &textMetrics); - m_ascent = lroundf(textMetrics.tmAscent * metricsMultiplier); - m_descent = lroundf(textMetrics.tmDescent * metricsMultiplier); - m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. - m_lineGap = lroundf(textMetrics.tmExternalLeading * metricsMultiplier); - m_lineSpacing = m_ascent + m_descent + m_lineGap; - m_avgCharWidth = lroundf(textMetrics.tmAveCharWidth * metricsMultiplier); - m_maxCharWidth = lroundf(textMetrics.tmMaxCharWidth * metricsMultiplier); + float ascent = textMetrics.tmAscent * metricsMultiplier; + float descent = textMetrics.tmDescent * metricsMultiplier; + float xHeight = ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. + float lineGap = textMetrics.tmExternalLeading * metricsMultiplier; + m_fontMetrics.setAscent(ascent); + m_fontMetrics.setDescent(descent); + m_fontMetrics.setLineGap(lineGap); + m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); + m_avgCharWidth = textMetrics.tmAveCharWidth * metricsMultiplier; + m_maxCharWidth = textMetrics.tmMaxCharWidth * metricsMultiplier; OUTLINETEXTMETRIC metrics; if (GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics) > 0) { @@ -78,9 +80,10 @@ void SimpleFontData::platformInit() MAT2 mat = { 1, 0, 0, 1 }; DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat); if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0) - m_xHeight = gm.gmptGlyphOrigin.y * metricsMultiplier; + xHeight = gm.gmptGlyphOrigin.y * metricsMultiplier; } + m_fontMetrics.setXHeight(xHeight); cairo_win32_scaled_font_done_font(scaledFont); m_isSystemFont = false; diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp index 60afe6a..323ff73 100644 --- a/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp +++ b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp @@ -29,16 +29,15 @@ #include "config.h" #include "SimpleFontData.h" -#include <winsock2.h> #include "Font.h" #include "FontCache.h" #include "FloatRect.h" #include "FontDescription.h" -#include <wtf/MathExtras.h> +#include <mlang.h> #include <unicode/uchar.h> #include <unicode/unorm.h> -#include <mlang.h> -#include <tchar.h> +#include <winsock2.h> +#include <wtf/MathExtras.h> #if PLATFORM(CG) #include <ApplicationServices/ApplicationServices.h> @@ -66,14 +65,9 @@ bool SimpleFontData::shouldApplyMacAscentHack() void SimpleFontData::initGDIFont() { if (!m_platformData.size()) { - m_ascent = 0; - m_descent = 0; - m_lineGap = 0; - m_lineSpacing = 0; + m_fontMetrics.reset(); m_avgCharWidth = 0; m_maxCharWidth = 0; - m_xHeight = 0; - m_unitsPerEm = 0; return; } @@ -82,21 +76,25 @@ void SimpleFontData::initGDIFont() OUTLINETEXTMETRIC metrics; GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics); TEXTMETRIC& textMetrics = metrics.otmTextMetrics; - m_ascent = textMetrics.tmAscent; - m_descent = textMetrics.tmDescent; - m_lineGap = textMetrics.tmExternalLeading; - m_lineSpacing = m_ascent + m_descent + m_lineGap; + float ascent = textMetrics.tmAscent; + float descent = textMetrics.tmDescent; + float lineGap = textMetrics.tmExternalLeading; + m_fontMetrics.setAscent(ascent); + m_fontMetrics.setDescent(descent); + m_fontMetrics.setLineGap(lineGap); + m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); m_avgCharWidth = textMetrics.tmAveCharWidth; m_maxCharWidth = textMetrics.tmMaxCharWidth; - m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present. + float xHeight = ascent * 0.56f; // Best guess for xHeight if no x glyph is present. GLYPHMETRICS gm; MAT2 mat = { 1, 0, 0, 1 }; DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat); if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0) - m_xHeight = gm.gmptGlyphOrigin.y; + xHeight = gm.gmptGlyphOrigin.y; - m_unitsPerEm = metrics.otmEMSquare; + m_fontMetrics.setXHeight(xHeight); + m_fontMetrics.setUnitsPerEm(metrics.otmEMSquare); SelectObject(hdc, oldFont); ReleaseDC(0, hdc); diff --git a/Source/WebCore/platform/graphics/win/UniscribeController.cpp b/Source/WebCore/platform/graphics/win/UniscribeController.cpp index dac6c3e..ebbed51 100644 --- a/Source/WebCore/platform/graphics/win/UniscribeController.cpp +++ b/Source/WebCore/platform/graphics/win/UniscribeController.cpp @@ -49,7 +49,7 @@ UniscribeController::UniscribeController(const Font* font, const TextRun& run, H , m_end(run.length()) , m_currentCharacter(0) , m_runWidthSoFar(0) - , m_padding(run.padding()) + , m_padding(run.expansion()) , m_computingOffsetPosition(false) , m_includePartialGlyphs(false) , m_offsetX(0) @@ -394,9 +394,9 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S FloatRect glyphBounds = fontData->boundsForGlyph(glyph); glyphBounds.move(m_glyphOrigin.x(), m_glyphOrigin.y()); m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphBounds.x()); - m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.right()); + m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.maxX()); m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphBounds.y()); - m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.bottom()); + m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.maxY()); m_glyphOrigin.move(advance + offsetX, -offsetY); // Mutate the glyph array to contain our altered advances. diff --git a/Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp b/Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp index c2a178b..c8f2116 100644 --- a/Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp +++ b/Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp @@ -24,11 +24,11 @@ */ #include "config.h" +#include "WKCAImageQueue.h" #if USE(ACCELERATED_COMPOSITING) -#include "WKCAImageQueue.h" - +#include <CoreFoundation/CoreFoundation.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> #include <wtf/RetainPtr.h> diff --git a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp index f61ae8e..fb97fe1 100644 --- a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp @@ -45,7 +45,7 @@ FontCustomPlatformData::~FontCustomPlatformData() g_customFontCache->unregisterFont(m_name); } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode renderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode renderingMode) { FontDescription fontDesc; fontDesc.setComputedSize(size); @@ -59,16 +59,14 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b // not allow access from CSS. static String createUniqueFontName() { - Vector<char> fontUuid(sizeof(GUID)); + GUID fontUuid; - unsigned int* ptr = reinterpret_cast<unsigned int*>(fontUuid.data()); + unsigned int* ptr = reinterpret_cast<unsigned int*>(&fontUuid); for (int i = 0; i < sizeof(GUID) / sizeof(int) ; ++i) *(ptr + i) = static_cast<unsigned int>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)); - Vector<char> fontNameVector; - base64Encode(fontUuid, fontNameVector); - ASSERT(fontNameVector.size() < LF_FACESIZE); - String fontName(fontNameVector.data(), fontNameVector.size()); + String fontName = base64Encode(reinterpret_cast<char*>(&fontUuid), sizeof(fontUuid)); + ASSERT(fontName.length() < LF_FACESIZE); return fontName.replace('/', '_'); } diff --git a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h index 0508246..fe7ee94 100644 --- a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h @@ -23,6 +23,7 @@ #include "FontDescription.h" #include "FontRenderingMode.h" +#include "FontWidthVariant.h" #include "PlatformString.h" #include <wtf/Noncopyable.h> @@ -47,7 +48,7 @@ namespace WebCore { ~FontCustomPlatformData(); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation fontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); static bool supportsFormat(const String&); diff --git a/Source/WebCore/platform/graphics/wince/FontWinCE.cpp b/Source/WebCore/platform/graphics/wince/FontWinCE.cpp index 5a4c8da..c3e6ce4 100644 --- a/Source/WebCore/platform/graphics/wince/FontWinCE.cpp +++ b/Source/WebCore/platform/graphics/wince/FontWinCE.cpp @@ -86,6 +86,7 @@ public: TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o) : m_textRun(start, length, parentTextRun.allowTabs(), 0, 0 + , parentTextRun.allowsTrailingExpansion() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion , parentTextRun.rtl() , parentTextRun.directionalOverride() , parentTextRun.applyRunRounding() @@ -112,7 +113,7 @@ static int generateComponents(TextRunComponents* components, const Font &font, c { int letterSpacing = font.letterSpacing(); int wordSpacing = font.wordSpacing(); - int padding = run.padding(); + int padding = run.expansion(); int numSpaces = 0; if (padding) { for (int i = 0; i < run.length(); i++) @@ -340,4 +341,9 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } +bool Font::canExpandAroundIdeographsInComplexText() +{ + return false; +} + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp b/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp index 9b672d2..7b1c27b 100644 --- a/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp +++ b/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp @@ -23,7 +23,6 @@ #include "GraphicsContext.h" #include "AffineTransform.h" -#include "CharacterNames.h" #include "Font.h" #include "GDIExtras.h" #include "GlyphBuffer.h" @@ -33,9 +32,9 @@ #include "PlatformPathWinCE.h" #include "SharedBitmap.h" #include "SimpleFontData.h" -#include <wtf/OwnPtr.h> - #include <windows.h> +#include <wtf/OwnPtr.h> +#include <wtf/unicode/CharacterNames.h> namespace WebCore { @@ -62,7 +61,7 @@ static inline int stableRound(double d) // Unlike enclosingIntRect(), this function does strict rounding. static inline IntRect roundRect(const FloatRect& r) { - return IntRect(stableRound(r.x()), stableRound(r.y()), stableRound(r.right()) - stableRound(r.x()), stableRound(r.bottom()) - stableRound(r.y())); + return IntRect(stableRound(r.x()), stableRound(r.y()), stableRound(r.maxX()) - stableRound(r.x()), stableRound(r.maxY()) - stableRound(r.y())); } // Rotation transformation @@ -129,8 +128,8 @@ template<class Transform, class Rect, class Value> static inline Rect mapRect(co { Value x[4], y[4]; Value l, t, r, b; - r = rect.right() - 1; - b = rect.bottom() - 1; + r = rect.maxX() - 1; + b = rect.maxY() - 1; transform.map(rect.x(), rect.y(), x, y); transform.map(rect.x(), b, x + 1, y + 1); transform.map(r, b, x + 2, y + 2); @@ -503,10 +502,10 @@ TransparentLayerDC::TransparentLayerDC(GraphicsContextPlatformPrivate* data, Int m_rotation.m_postShiftX -= m_origRect.x(); m_rotation.m_postShiftY -= m_origRect.y(); - FloatPoint topLeft = m_data->m_transform.mapPoint(FloatPoint(rectBeforeTransform->topLeft())); - FloatPoint topRight(rectBeforeTransform->right() - 1, rectBeforeTransform->y()); + FloatPoint topLeft = m_data->m_transform.mapPoint(FloatPoint(rectBeforeTransform->location())); + FloatPoint topRight(rectBeforeTransform->maxX() - 1, rectBeforeTransform->y()); topRight = m_data->m_transform.mapPoint(topRight); - FloatPoint bottomLeft(rectBeforeTransform->x(), rectBeforeTransform->bottom() - 1); + FloatPoint bottomLeft(rectBeforeTransform->x(), rectBeforeTransform->maxY() - 1); bottomLeft = m_data->m_transform.mapPoint(bottomLeft); FloatSize sideTop = topRight - topLeft; FloatSize sideLeft = bottomLeft - topLeft; @@ -656,7 +655,7 @@ void GraphicsContext::drawRect(const IntRect& rect) if (trRect.height() <= 0) trRect.setHeight(1); - Rectangle(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + Rectangle(dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY()); } SelectObject(dc, oldPen); @@ -726,7 +725,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect) oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); if (brush || pen) - Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + Ellipse(dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY()); SelectObject(dc, oldPen); SelectObject(dc, oldBrush); @@ -839,7 +838,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp } HGDIOBJ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH)); - Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + Ellipse(dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY()); SelectObject(dc, oldBrush); if (newClip) @@ -960,9 +959,9 @@ void GraphicsContext::clip(const FloatRect& rect) OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0)); if (GetClipRgn(m_data->m_dc, clipRgn.get()) > 0) - IntersectClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + IntersectClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY()); else { - clipRgn.set(CreateRectRgn(trRect.x(), trRect.y(), trRect.right(), trRect.bottom())); + clipRgn.set(CreateRectRgn(trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY())); SelectClipRgn(m_data->m_dc, clipRgn.get()); } } @@ -977,7 +976,7 @@ void GraphicsContext::clipOut(const IntRect& rect) IntRect trRect = m_data->mapRect(rect); - ExcludeClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + ExcludeClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY()); } void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color) @@ -1093,8 +1092,8 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width) OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); HGDIOBJ oldPen = SelectObject(dc, pen.get()); - int right = trRect.right() - 1; - int bottom = trRect.bottom() - 1; + int right = trRect.maxX() - 1; + int bottom = trRect.maxY() - 1; const POINT intPoints[5] = { { trRect.x(), trRect.y() }, @@ -1536,8 +1535,8 @@ void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPo float oldOpacity = m_data->m_opacity; m_data->m_opacity *= fillColor().alpha() / 255.0; - FloatRect textRect = font.selectionRectForText(run, point, font.height(), from, to); - textRect.setY(textRect.y() - font.ascent()); + FloatRect textRect = font.selectionRectForText(run, point, font.fontMetrics().height(), from, to); + textRect.setY(textRect.y() - font.fontMetrics().ascent()); IntRect trRect = enclosingIntRect(m_data->mapRect(textRect)); RECT bmpRect; AlphaPaintType alphaPaintType = mustSupportAlpha ? AlphaPaintOther : AlphaPaintNone; @@ -1546,7 +1545,7 @@ void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPo GraphicsContext gc(0); gc.setBitmap(bmp); gc.scale(FloatSize(m_data->m_transform.a(), m_data->m_transform.d())); - font.drawText(&gc, run, IntPoint(0, font.ascent()), from, to); + font.drawText(&gc, run, IntPoint(0, font.fontMetrics().ascent()), from, to); } unsigned key1; HDC memDC = bmp->getDC(&key1); @@ -1591,7 +1590,7 @@ void GraphicsContext::drawText(const SimpleFontData* fontData, const GlyphBuffer ? fontData->platformData().getScaledFontHandle(height, scaleX == scaleY ? 0 : width) : 0; - FloatPoint startPoint(point.x(), point.y() - fontData->ascent()); + FloatPoint startPoint(point.x(), point.y() - fontData->fontMetrics().ascent()); FloatPoint trPoint = m_data->mapPoint(startPoint); int y = stableRound(trPoint.y()); diff --git a/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp b/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp index 8534f89..8efe661 100644 --- a/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp +++ b/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp @@ -119,7 +119,7 @@ static inline void bezier(int segments, Vector<PathPoint>& pts, const PathPoint* static bool containsPoint(const FloatRect& r, const FloatPoint& p) { - return p.x() >= r.x() && p.y() >= r.y() && p.x() < r.right() && p.y() < r.bottom(); + return p.x() >= r.x() && p.y() >= r.y() && p.x() < r.maxX() && p.y() < r.maxY(); } static void normalizeAngle(float& angle) @@ -146,7 +146,7 @@ static void inflateRectToContainPoint(FloatRect& r, float x, float y) return; } if (x < r.x()) { - r.setWidth(r.right() - x); + r.setWidth(r.maxX() - x); r.setX(x); } else { float w = x - r.x() + 1; @@ -154,7 +154,7 @@ static void inflateRectToContainPoint(FloatRect& r, float x, float y) r.setWidth(w); } if (y < r.y()) { - r.setHeight(r.bottom() - y); + r.setHeight(r.maxY() - y); r.setY(y); } else { float h = y - r.y() + 1; @@ -740,8 +740,8 @@ void PlatformPath::addRect(const FloatRect& r) { moveTo(r.location()); - float right = r.right() - 1; - float bottom = r.bottom() - 1; + float right = r.maxX() - 1; + float bottom = r.maxY() - 1; addLineTo(FloatPoint(right, r.y())); addLineTo(FloatPoint(right, bottom)); addLineTo(FloatPoint(r.x(), bottom)); diff --git a/Source/WebCore/platform/graphics/wince/SharedBitmap.cpp b/Source/WebCore/platform/graphics/wince/SharedBitmap.cpp index 168a5e2..2bf0028 100644 --- a/Source/WebCore/platform/graphics/wince/SharedBitmap.cpp +++ b/Source/WebCore/platform/graphics/wince/SharedBitmap.cpp @@ -135,7 +135,7 @@ bool SharedBitmap::to16bit() int width = newBmpInfo.width(); int paddedWidth = newBmpInfo.paddedWidth(); int bufferSize = paddedWidth * newBmpInfo.height(); - OwnArrayPtr<unsigned> newPixelData(new unsigned[bufferSize / 2]); + OwnArrayPtr<unsigned> newPixelData = adoptArrayPtr(new unsigned[bufferSize / 2]); void* newPixels = newPixelData.get(); if (!newPixels) @@ -481,8 +481,8 @@ void SharedBitmap::drawPattern(HDC hdc, const AffineTransform& transform, const RECT dstRectWin = { stableRound(trRect.x()), stableRound(trRect.y()), - stableRound(trRect.right()), - stableRound(trRect.bottom()), + stableRound(trRect.maxX()), + stableRound(trRect.maxY()), }; if (dstRectWin.right <= dstRectWin.left || dstRectWin.bottom <= dstRectWin.top) return; @@ -497,8 +497,8 @@ void SharedBitmap::drawPattern(HDC hdc, const AffineTransform& transform, const RECT srcRectWin = { 0, 0, - stableRound(visibleDstRect.right()) - stableRound(visibleDstRect.x()), - stableRound(visibleDstRect.bottom()) - stableRound(visibleDstRect.y()) + stableRound(visibleDstRect.maxX()) - stableRound(visibleDstRect.x()), + stableRound(visibleDstRect.maxY()) - stableRound(visibleDstRect.y()) }; if (srcRectWin.right <= 0 || srcRectWin.bottom <= 0) return; diff --git a/Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp b/Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp index 27a021e..8abafbd 100644 --- a/Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp +++ b/Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp @@ -27,7 +27,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include "config.h" #include "SimpleFontData.h" @@ -35,9 +34,8 @@ #include "Font.h" #include "FontCache.h" #include "FontDescription.h" -#include <wtf/MathExtras.h> #include <mlang.h> -#include <tchar.h> +#include <wtf/MathExtras.h> namespace WebCore { @@ -51,11 +49,14 @@ void SimpleFontData::platformInit() const TEXTMETRIC& tm = m_platformData.metrics(); m_isSystemFont = m_platformData.isSystemFont(); - m_ascent = (tm.tmAscent * m_platformData.size() + 36) / 72; - m_descent = (tm.tmDescent * m_platformData.size() + 36) / 72; - m_lineGap = (tm.tmExternalLeading * m_platformData.size() + 36) / 72; - m_lineSpacing = m_ascent + m_descent + m_lineGap; - m_xHeight = m_ascent * 0.56f; + float ascent = (tm.tmAscent * m_platformData.size() + 36) / 72.0f; + float descent = (tm.tmDescent * m_platformData.size() + 36) / 72.0f; + float lineGap = (tm.tmExternalLeading * m_platformData.size() + 36) / 72.0f; + m_fontMetrics.setAscent(ascent); + m_fontMetrics.setDescent(descent); + m_fontMetrics.setLineGap(lineGap); + m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); + m_fontMetrics.setXHeight(ascent * 0.56f); } void SimpleFontData::platformDestroy() diff --git a/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.cpp index 6133372..055f0fc 100644 --- a/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.cpp +++ b/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.cpp @@ -31,7 +31,7 @@ FontCustomPlatformData::~FontCustomPlatformData() { } -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode) +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontWidthVariant, FontRenderingMode) { return FontPlatformData(size, bold, italic); } diff --git a/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.h index 86f99b2..c975296 100644 --- a/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.h +++ b/Source/WebCore/platform/graphics/wx/FontCustomPlatformData.h @@ -23,7 +23,9 @@ #include "FontOrientation.h" #include "FontRenderingMode.h" +#include "FontWidthVariant.h" #include <wtf/Forward.h> +#include <wtf/Noncopyable.h> namespace WebCore { @@ -38,7 +40,7 @@ namespace WebCore { static bool supportsFormat(const String&); - FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode); + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth, FontRenderingMode = NormalRenderingMode); }; FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*); diff --git a/Source/WebCore/platform/graphics/wx/FontPlatformData.h b/Source/WebCore/platform/graphics/wx/FontPlatformData.h index 9ae8b54..3ef0179 100644 --- a/Source/WebCore/platform/graphics/wx/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/wx/FontPlatformData.h @@ -30,6 +30,7 @@ #define FontPlatformData_h #include "FontDescription.h" +#include "FontWidthVariant.h" #include "FontOrientation.h" #include "StringImpl.h" #include <wtf/Forward.h> @@ -150,6 +151,9 @@ public: FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. + // We don't support this yet, so just return the default value for now. + FontWidthVariant widthVariant() const { return RegularWidth; } + #if OS(WINDOWS) bool useGDI() const; HFONT hfont() const; diff --git a/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp index 66c69ee..c125b7c 100644 --- a/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp +++ b/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp @@ -126,7 +126,7 @@ unsigned FontPlatformData::computeHash() const thisFont->GetStyle(), thisFont->GetWeight(), thisFont->GetUnderlined(), - StringImpl::computeHash(thisFont->GetFaceName().utf8_str()) + WTF::StringHasher::createHash(thisFont->GetFaceName().utf8_str().data()) }; return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes); diff --git a/Source/WebCore/platform/graphics/wx/FontWx.cpp b/Source/WebCore/platform/graphics/wx/FontWx.cpp index c01e249..c48f3c7 100644 --- a/Source/WebCore/platform/graphics/wx/FontWx.cpp +++ b/Source/WebCore/platform/graphics/wx/FontWx.cpp @@ -32,6 +32,7 @@ #include "IntRect.h" #include "NotImplemented.h" #include "SimpleFontData.h" +#include "TextRun.h" #if OS(WINDOWS) #include "UniscribeController.h" @@ -57,6 +58,15 @@ bool Font::canReturnFallbackFontsForComplexText() #endif } +bool Font::canExpandAroundIdeographsInComplexText() +{ +#if OS(DARWIN) + return true; +#else + return false; +#endif +} + void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { diff --git a/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index f1c09c5..991be79 100644 --- a/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -515,7 +515,7 @@ void GraphicsContext::fillPath(const Path& path) #if USE(WXGC) wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); if (gc) - gc->FillPath(path.platformPath()); + gc->FillPath(*path.platformPath()); #endif } @@ -524,7 +524,7 @@ void GraphicsContext::strokePath(const Path& path) #if USE(WXGC) wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); if (gc) - gc->StrokePath(path.platformPath()); + gc->StrokePath(*path.platformPath()); #endif } diff --git a/Source/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/Source/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp index 0e24bfc..4f24e4c 100644 --- a/Source/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp +++ b/Source/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp @@ -53,12 +53,12 @@ void SimpleFontData::platformInit() wxFont *font = m_platformData.font(); if (font && font->IsOk()) { wxFontProperties props = wxFontProperties(font); - m_ascent = props.GetAscent(); - m_descent = props.GetDescent(); - m_lineSpacing = props.GetLineSpacing(); - m_xHeight = props.GetXHeight(); - m_unitsPerEm = 1; // FIXME! - m_lineGap = props.GetLineGap(); + m_fontMetrics.setAscent(props.GetAscent()); + m_fontMetrics.setDescent(props.GetDescent()); + m_fontMetrics.setXHeight(props.GetXHeight()); + m_fontMetrics.setUnitsPerEm(1); // FIXME! + m_fontMetrics.setLineGap(props.GetLineGap()); + m_fontMetrics.setLineSpacing(props.GetLineSpacing()); } m_syntheticBoldOffset = 0.0f; |