summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering')
-rw-r--r--WebCore/rendering/AutoTableLayout.cpp10
-rw-r--r--WebCore/rendering/AutoTableLayout.h2
-rw-r--r--WebCore/rendering/BidiRun.cpp74
-rw-r--r--WebCore/rendering/BidiRun.h65
-rw-r--r--WebCore/rendering/CounterNode.cpp215
-rw-r--r--WebCore/rendering/CounterNode.h27
-rw-r--r--WebCore/rendering/EllipsisBox.cpp49
-rw-r--r--WebCore/rendering/EllipsisBox.h8
-rw-r--r--WebCore/rendering/FixedTableLayout.cpp25
-rw-r--r--WebCore/rendering/FixedTableLayout.h2
-rw-r--r--WebCore/rendering/HitTestRequest.h2
-rw-r--r--WebCore/rendering/HitTestResult.cpp15
-rw-r--r--WebCore/rendering/HitTestResult.h3
-rw-r--r--WebCore/rendering/InlineBox.cpp7
-rw-r--r--WebCore/rendering/InlineBox.h5
-rw-r--r--WebCore/rendering/InlineFlowBox.cpp296
-rw-r--r--WebCore/rendering/InlineFlowBox.h67
-rw-r--r--WebCore/rendering/InlineIterator.h266
-rw-r--r--WebCore/rendering/InlineRunBox.h2
-rw-r--r--WebCore/rendering/InlineTextBox.cpp123
-rw-r--r--WebCore/rendering/InlineTextBox.h10
-rw-r--r--WebCore/rendering/MediaControlElements.cpp270
-rw-r--r--WebCore/rendering/MediaControlElements.h65
-rw-r--r--WebCore/rendering/PointerEventsHitRules.cpp2
-rw-r--r--WebCore/rendering/PointerEventsHitRules.h2
-rw-r--r--WebCore/rendering/RenderArena.cpp2
-rw-r--r--WebCore/rendering/RenderArena.h3
-rw-r--r--WebCore/rendering/RenderBR.cpp2
-rw-r--r--WebCore/rendering/RenderBR.h2
-rw-r--r--WebCore/rendering/RenderBlock.cpp816
-rw-r--r--WebCore/rendering/RenderBlock.h77
-rw-r--r--WebCore/rendering/RenderBlockLineLayout.cpp441
-rw-r--r--WebCore/rendering/RenderBox.cpp316
-rw-r--r--WebCore/rendering/RenderBox.h55
-rw-r--r--WebCore/rendering/RenderBoxModelObject.cpp425
-rw-r--r--WebCore/rendering/RenderBoxModelObject.h8
-rw-r--r--WebCore/rendering/RenderButton.cpp6
-rw-r--r--WebCore/rendering/RenderButton.h2
-rw-r--r--WebCore/rendering/RenderCounter.cpp365
-rw-r--r--WebCore/rendering/RenderCounter.h9
-rw-r--r--WebCore/rendering/RenderEmbeddedObject.cpp352
-rw-r--r--WebCore/rendering/RenderEmbeddedObject.h64
-rw-r--r--WebCore/rendering/RenderFieldset.cpp8
-rw-r--r--WebCore/rendering/RenderFileUploadControl.cpp23
-rw-r--r--WebCore/rendering/RenderFileUploadControl.h13
-rw-r--r--WebCore/rendering/RenderFlexibleBox.cpp159
-rw-r--r--WebCore/rendering/RenderForeignObject.cpp16
-rw-r--r--WebCore/rendering/RenderForeignObject.h16
-rw-r--r--WebCore/rendering/RenderFrame.cpp54
-rw-r--r--WebCore/rendering/RenderFrame.h1
-rw-r--r--WebCore/rendering/RenderFrameSet.cpp142
-rw-r--r--WebCore/rendering/RenderFrameSet.h4
-rw-r--r--WebCore/rendering/RenderHTMLCanvas.cpp20
-rw-r--r--WebCore/rendering/RenderHTMLCanvas.h3
-rw-r--r--WebCore/rendering/RenderImage.cpp98
-rw-r--r--WebCore/rendering/RenderImage.h18
-rw-r--r--WebCore/rendering/RenderInline.cpp181
-rw-r--r--WebCore/rendering/RenderInline.h8
-rw-r--r--WebCore/rendering/RenderLayer.cpp550
-rw-r--r--WebCore/rendering/RenderLayer.h55
-rw-r--r--WebCore/rendering/RenderLayerBacking.cpp404
-rw-r--r--WebCore/rendering/RenderLayerBacking.h56
-rw-r--r--WebCore/rendering/RenderLayerCompositor.cpp386
-rw-r--r--WebCore/rendering/RenderLayerCompositor.h35
-rw-r--r--WebCore/rendering/RenderLineBoxList.cpp23
-rw-r--r--WebCore/rendering/RenderListBox.cpp11
-rw-r--r--WebCore/rendering/RenderListBox.h2
-rw-r--r--WebCore/rendering/RenderListItem.cpp76
-rw-r--r--WebCore/rendering/RenderListItem.h4
-rw-r--r--WebCore/rendering/RenderListMarker.cpp884
-rw-r--r--WebCore/rendering/RenderListMarker.h1
-rw-r--r--WebCore/rendering/RenderMarquee.cpp7
-rw-r--r--WebCore/rendering/RenderMarquee.h2
-rw-r--r--WebCore/rendering/RenderMedia.cpp156
-rw-r--r--WebCore/rendering/RenderMedia.h22
-rw-r--r--WebCore/rendering/RenderMediaControls.cpp40
-rw-r--r--WebCore/rendering/RenderMediaControlsChromium.cpp306
-rw-r--r--WebCore/rendering/RenderMediaControlsChromium.h46
-rw-r--r--WebCore/rendering/RenderMenuList.cpp82
-rw-r--r--WebCore/rendering/RenderMenuList.h7
-rw-r--r--WebCore/rendering/RenderObject.cpp337
-rw-r--r--WebCore/rendering/RenderObject.h124
-rw-r--r--WebCore/rendering/RenderObjectChildList.cpp23
-rw-r--r--WebCore/rendering/RenderObjectChildList.h3
-rw-r--r--WebCore/rendering/RenderOverflow.h153
-rw-r--r--WebCore/rendering/RenderPart.cpp1
-rw-r--r--WebCore/rendering/RenderPart.h4
-rw-r--r--WebCore/rendering/RenderPartObject.cpp324
-rw-r--r--WebCore/rendering/RenderPartObject.h12
-rw-r--r--WebCore/rendering/RenderPath.cpp276
-rw-r--r--WebCore/rendering/RenderPath.h24
-rw-r--r--WebCore/rendering/RenderReplaced.cpp129
-rw-r--r--WebCore/rendering/RenderReplaced.h8
-rw-r--r--WebCore/rendering/RenderReplica.cpp2
-rw-r--r--WebCore/rendering/RenderReplica.h4
-rw-r--r--WebCore/rendering/RenderRuby.cpp197
-rw-r--r--WebCore/rendering/RenderRuby.h91
-rw-r--r--WebCore/rendering/RenderRubyBase.cpp190
-rw-r--r--WebCore/rendering/RenderRubyBase.h67
-rw-r--r--WebCore/rendering/RenderRubyRun.cpp228
-rw-r--r--WebCore/rendering/RenderRubyRun.h85
-rw-r--r--WebCore/rendering/RenderRubyText.cpp54
-rw-r--r--WebCore/rendering/RenderRubyText.h56
-rw-r--r--WebCore/rendering/RenderSVGBlock.h2
-rw-r--r--WebCore/rendering/RenderSVGContainer.cpp59
-rw-r--r--WebCore/rendering/RenderSVGContainer.h11
-rw-r--r--WebCore/rendering/RenderSVGGradientStop.cpp2
-rw-r--r--WebCore/rendering/RenderSVGHiddenContainer.cpp12
-rw-r--r--WebCore/rendering/RenderSVGHiddenContainer.h3
-rw-r--r--WebCore/rendering/RenderSVGImage.cpp123
-rw-r--r--WebCore/rendering/RenderSVGImage.h19
-rw-r--r--WebCore/rendering/RenderSVGInline.h5
-rw-r--r--WebCore/rendering/RenderSVGModelObject.h2
-rw-r--r--WebCore/rendering/RenderSVGRoot.cpp95
-rw-r--r--WebCore/rendering/RenderSVGRoot.h18
-rw-r--r--WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp101
-rw-r--r--WebCore/rendering/RenderSVGShadowTreeRootContainer.h50
-rw-r--r--WebCore/rendering/RenderSVGText.cpp32
-rw-r--r--WebCore/rendering/RenderSVGText.h11
-rw-r--r--WebCore/rendering/RenderSVGTransformableContainer.cpp18
-rw-r--r--WebCore/rendering/RenderSVGTransformableContainer.h6
-rw-r--r--WebCore/rendering/RenderSVGViewportContainer.cpp63
-rw-r--r--WebCore/rendering/RenderSVGViewportContainer.h18
-rw-r--r--WebCore/rendering/RenderScrollbar.cpp10
-rw-r--r--WebCore/rendering/RenderScrollbarPart.cpp16
-rw-r--r--WebCore/rendering/RenderScrollbarTheme.cpp2
-rw-r--r--WebCore/rendering/RenderSelectionInfo.h2
-rw-r--r--WebCore/rendering/RenderSlider.cpp74
-rw-r--r--WebCore/rendering/RenderTable.cpp81
-rw-r--r--WebCore/rendering/RenderTableCell.cpp54
-rw-r--r--WebCore/rendering/RenderTableCell.h6
-rw-r--r--WebCore/rendering/RenderTableRow.cpp2
-rw-r--r--WebCore/rendering/RenderTableSection.cpp95
-rw-r--r--WebCore/rendering/RenderTableSection.h9
-rw-r--r--WebCore/rendering/RenderText.cpp68
-rw-r--r--WebCore/rendering/RenderText.h3
-rw-r--r--WebCore/rendering/RenderTextControl.cpp75
-rw-r--r--WebCore/rendering/RenderTextControl.h22
-rw-r--r--WebCore/rendering/RenderTextControlMultiLine.cpp44
-rw-r--r--WebCore/rendering/RenderTextControlMultiLine.h3
-rw-r--r--WebCore/rendering/RenderTextControlSingleLine.cpp63
-rw-r--r--WebCore/rendering/RenderTextControlSingleLine.h10
-rw-r--r--WebCore/rendering/RenderTextFragment.cpp4
-rw-r--r--WebCore/rendering/RenderTheme.cpp94
-rw-r--r--WebCore/rendering/RenderTheme.h15
-rw-r--r--WebCore/rendering/RenderThemeChromiumLinux.cpp82
-rw-r--r--WebCore/rendering/RenderThemeChromiumLinux.h33
-rw-r--r--WebCore/rendering/RenderThemeChromiumMac.h306
-rw-r--r--WebCore/rendering/RenderThemeChromiumMac.mm1281
-rw-r--r--WebCore/rendering/RenderThemeChromiumSkia.cpp299
-rw-r--r--WebCore/rendering/RenderThemeChromiumSkia.h12
-rw-r--r--WebCore/rendering/RenderThemeChromiumWin.cpp138
-rw-r--r--WebCore/rendering/RenderThemeChromiumWin.h1
-rw-r--r--WebCore/rendering/RenderThemeMac.h3
-rw-r--r--WebCore/rendering/RenderThemeMac.mm134
-rw-r--r--WebCore/rendering/RenderThemeSafari.cpp54
-rw-r--r--WebCore/rendering/RenderThemeWin.cpp29
-rw-r--r--WebCore/rendering/RenderThemeWin.h2
-rw-r--r--WebCore/rendering/RenderThemeWince.cpp23
-rw-r--r--WebCore/rendering/RenderTreeAsText.cpp143
-rw-r--r--WebCore/rendering/RenderTreeAsText.h26
-rw-r--r--WebCore/rendering/RenderVideo.cpp158
-rw-r--r--WebCore/rendering/RenderVideo.h17
-rw-r--r--WebCore/rendering/RenderView.cpp70
-rw-r--r--WebCore/rendering/RenderView.h16
-rw-r--r--WebCore/rendering/RenderWidget.cpp181
-rw-r--r--WebCore/rendering/RenderWidget.h9
-rw-r--r--WebCore/rendering/RenderWidgetProtector.h53
-rw-r--r--WebCore/rendering/RootInlineBox.cpp80
-rw-r--r--WebCore/rendering/RootInlineBox.h103
-rw-r--r--WebCore/rendering/SVGCharacterLayoutInfo.cpp4
-rw-r--r--WebCore/rendering/SVGCharacterLayoutInfo.h76
-rw-r--r--WebCore/rendering/SVGInlineTextBox.cpp105
-rw-r--r--WebCore/rendering/SVGInlineTextBox.h21
-rw-r--r--WebCore/rendering/SVGMarkerData.h134
-rw-r--r--WebCore/rendering/SVGMarkerLayoutInfo.cpp124
-rw-r--r--WebCore/rendering/SVGMarkerLayoutInfo.h74
-rw-r--r--WebCore/rendering/SVGRenderSupport.cpp125
-rw-r--r--WebCore/rendering/SVGRenderSupport.h25
-rw-r--r--WebCore/rendering/SVGRenderTreeAsText.cpp8
-rw-r--r--WebCore/rendering/SVGRenderTreeAsText.h4
-rw-r--r--WebCore/rendering/SVGRootInlineBox.cpp165
-rw-r--r--WebCore/rendering/SVGRootInlineBox.h7
-rw-r--r--WebCore/rendering/SVGShadowTreeElements.cpp80
-rw-r--r--WebCore/rendering/SVGShadowTreeElements.h67
-rw-r--r--WebCore/rendering/TableLayout.h6
-rw-r--r--WebCore/rendering/TrailingFloatsRootInlineBox.h48
-rw-r--r--WebCore/rendering/TransformState.cpp8
-rw-r--r--WebCore/rendering/TransformState.h2
-rw-r--r--WebCore/rendering/break_lines.cpp70
-rw-r--r--WebCore/rendering/break_lines.h2
-rw-r--r--WebCore/rendering/style/ContentData.h6
-rw-r--r--WebCore/rendering/style/CounterContent.h2
-rw-r--r--WebCore/rendering/style/FillLayer.cpp68
-rw-r--r--WebCore/rendering/style/FillLayer.h74
-rw-r--r--WebCore/rendering/style/LineClampValue.h69
-rw-r--r--WebCore/rendering/style/RenderStyle.cpp9
-rw-r--r--WebCore/rendering/style/RenderStyle.h82
-rw-r--r--WebCore/rendering/style/RenderStyleConstants.h108
-rw-r--r--WebCore/rendering/style/SVGRenderStyle.cpp60
-rw-r--r--WebCore/rendering/style/SVGRenderStyle.h344
-rw-r--r--WebCore/rendering/style/SVGRenderStyleDefs.cpp21
-rw-r--r--WebCore/rendering/style/SVGRenderStyleDefs.h34
-rw-r--r--WebCore/rendering/style/ShadowData.h3
-rw-r--r--WebCore/rendering/style/StyleBackgroundData.cpp2
-rw-r--r--WebCore/rendering/style/StyleInheritedData.cpp5
-rw-r--r--WebCore/rendering/style/StyleInheritedData.h1
-rw-r--r--WebCore/rendering/style/StyleRareInheritedData.cpp5
-rw-r--r--WebCore/rendering/style/StyleRareInheritedData.h1
-rw-r--r--WebCore/rendering/style/StyleRareNonInheritedData.h3
210 files changed, 11864 insertions, 5711 deletions
diff --git a/WebCore/rendering/AutoTableLayout.cpp b/WebCore/rendering/AutoTableLayout.cpp
index c37fba4..2a4958a 100644
--- a/WebCore/rendering/AutoTableLayout.cpp
+++ b/WebCore/rendering/AutoTableLayout.cpp
@@ -382,7 +382,7 @@ int AutoTableLayout::calcEffectiveWidth()
float spanMax = max(maxWidth, cMaxWidth);
tMaxWidth = max(tMaxWidth, spanMax * 100 * percentScaleFactor / w.rawValue());
- // all non percent columns in the span get percent vlaues to sum up correctly.
+ // all non percent columns in the span get percent values to sum up correctly.
int percentMissing = w.rawValue() - totalPercent;
float totalWidth = 0;
for (unsigned int pos = col; pos < lastCol; pos++) {
@@ -495,10 +495,10 @@ void AutoTableLayout::insertSpanCell(RenderTableCell *cell)
void AutoTableLayout::layout()
{
-#ifdef ANDROID_LAYOUT
+#ifdef ANDROID_LAYOUT
if (m_table->isSingleColumn())
return;
-#endif
+#endif
// table layout based on the values collected in the layout structure.
int tableWidth = m_table->width() - m_table->bordersPaddingAndSpacing();
int available = tableWidth;
@@ -668,8 +668,8 @@ void AutoTableLayout::layout()
}
}
- // if we have overallocated, reduce every cell according to the difference between desired width and minwidth
- // this seems to produce to the pixel exaxt results with IE. Wonder is some of this also holds for width distributing.
+ // If we have overallocated, reduce every cell according to the difference between desired width and minwidth
+ // this seems to produce to the pixel exact results with IE. Wonder is some of this also holds for width distributing.
if (available < 0) {
// Need to reduce cells with the following prioritization:
// (1) Auto
diff --git a/WebCore/rendering/AutoTableLayout.h b/WebCore/rendering/AutoTableLayout.h
index 641a68b..f1ef768 100644
--- a/WebCore/rendering/AutoTableLayout.h
+++ b/WebCore/rendering/AutoTableLayout.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the HTML rendering engine for KDE.
- *
* Copyright (C) 2002 Lars Knoll (knoll@kde.org)
* (C) 2002 Dirk Mueller (mueller@kde.org)
*
diff --git a/WebCore/rendering/BidiRun.cpp b/WebCore/rendering/BidiRun.cpp
new file mode 100644
index 0000000..ac13046
--- /dev/null
+++ b/WebCore/rendering/BidiRun.cpp
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "BidiRun.h"
+#include "InlineBox.h"
+#include "RenderArena.h"
+#include <wtf/RefCountedLeakCounter.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+#ifndef NDEBUG
+static RefCountedLeakCounter bidiRunCounter("BidiRun");
+
+static bool inBidiRunDestroy;
+#endif
+
+void BidiRun::destroy()
+{
+#ifndef NDEBUG
+ inBidiRunDestroy = true;
+#endif
+ RenderArena* renderArena = m_object->renderArena();
+ delete this;
+#ifndef NDEBUG
+ inBidiRunDestroy = false;
+#endif
+
+ // Recover the size left there for us by operator delete and free the memory.
+ renderArena->free(*reinterpret_cast<size_t*>(this), this);
+}
+
+void* BidiRun::operator new(size_t sz, RenderArena* renderArena) throw()
+{
+#ifndef NDEBUG
+ bidiRunCounter.increment();
+#endif
+ return renderArena->allocate(sz);
+}
+
+void BidiRun::operator delete(void* ptr, size_t sz)
+{
+#ifndef NDEBUG
+ bidiRunCounter.decrement();
+#endif
+ ASSERT(inBidiRunDestroy);
+
+ // Stash size where destroy() can find it.
+ *(size_t*)ptr = sz;
+}
+
+}
diff --git a/WebCore/rendering/BidiRun.h b/WebCore/rendering/BidiRun.h
new file mode 100644
index 0000000..542081a
--- /dev/null
+++ b/WebCore/rendering/BidiRun.h
@@ -0,0 +1,65 @@
+/**
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
+ *
+ * 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 BidiRun_h
+#define BidiRun_h
+
+#include <wtf/StdLibExtras.h>
+#include "BidiResolver.h"
+#include "RenderText.h"
+
+namespace WebCore {
+
+class BidiContext;
+class InlineBox;
+
+struct BidiRun : BidiCharacterRun {
+ BidiRun(int start, int stop, RenderObject* object, BidiContext* context, WTF::Unicode::Direction dir)
+ : BidiCharacterRun(start, stop, context, dir)
+ , m_object(object)
+ , m_box(0)
+ {
+ }
+
+ void destroy();
+
+ // Overloaded new operator.
+ void* operator new(size_t, RenderArena*) throw();
+
+ // Overridden to prevent the normal delete from being called.
+ void operator delete(void*, size_t);
+
+ BidiRun* next() { return static_cast<BidiRun*>(m_next); }
+
+private:
+ // The normal operator new is disallowed.
+ void* operator new(size_t) throw();
+
+public:
+ RenderObject* m_object;
+ InlineBox* m_box;
+};
+
+}
+
+#endif // BidiRun_h
diff --git a/WebCore/rendering/CounterNode.cpp b/WebCore/rendering/CounterNode.cpp
index c30ca9a..c164c81 100644
--- a/WebCore/rendering/CounterNode.cpp
+++ b/WebCore/rendering/CounterNode.cpp
@@ -1,6 +1,4 @@
/*
- * This file is part of the HTML rendering engine for KDE.
- *
* Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
*
@@ -24,20 +22,14 @@
#include "config.h"
#include "CounterNode.h"
+#include "RenderCounter.h"
#include "RenderObject.h"
#include <stdio.h>
-// FIXME: There's currently no strategy for getting the counter tree updated when new
-// elements with counter-reset and counter-increment styles are added to the render tree.
-// Also, the code can't handle changes where an existing node needs to change into a
-// "reset" node, or from a "reset" node back to not a "reset" node. As of this writing,
-// at least some of these problems manifest as failures in the t1204-increment and
-// t1204-reset tests in the CSS 2.1 test suite.
-
namespace WebCore {
-CounterNode::CounterNode(RenderObject* o, bool isReset, int value)
- : m_isReset(isReset)
+CounterNode::CounterNode(RenderObject* o, bool hasResetType, int value)
+ : m_hasResetType(hasResetType)
, m_value(value)
, m_countInParent(0)
, m_renderer(o)
@@ -46,32 +38,95 @@ CounterNode::CounterNode(RenderObject* o, bool isReset, int value)
, m_nextSibling(0)
, m_firstChild(0)
, m_lastChild(0)
-{
+{
+}
+
+CounterNode* CounterNode::nextInPreOrderAfterChildren(const CounterNode* stayWithin) const
+{
+ if (this == stayWithin)
+ return 0;
+
+ const CounterNode* current = this;
+ CounterNode* next;
+ while (!(next = current->m_nextSibling)) {
+ current = current->m_parent;
+ if (!current || current == stayWithin)
+ return 0;
+ }
+ return next;
+}
+
+CounterNode* CounterNode::nextInPreOrder(const CounterNode* stayWithin) const
+{
+ if (CounterNode* next = m_firstChild)
+ return next;
+
+ return nextInPreOrderAfterChildren(stayWithin);
+}
+
+CounterNode* CounterNode::lastDescendant() const
+{
+ CounterNode* last = m_lastChild;
+ if (!last)
+ return 0;
+
+ while (CounterNode* lastChild = last->m_lastChild)
+ last = lastChild;
+
+ return last;
+}
+
+CounterNode* CounterNode::previousInPreOrder() const
+{
+ CounterNode* previous = m_previousSibling;
+ if (!previous)
+ return m_parent;
+
+ while (CounterNode* lastChild = previous->m_lastChild)
+ previous = lastChild;
+
+ return previous;
}
int CounterNode::computeCountInParent() const
{
- int increment = m_isReset ? 0 : m_value;
+ int increment = actsAsReset() ? 0 : m_value;
if (m_previousSibling)
return m_previousSibling->m_countInParent + increment;
ASSERT(m_parent->m_firstChild == this);
return m_parent->m_value + increment;
}
-void CounterNode::recount()
+void CounterNode::resetRenderer(const AtomicString& identifier) const
{
- for (CounterNode* c = this; c; c = c->m_nextSibling) {
- int oldCount = c->m_countInParent;
- int newCount = c->computeCountInParent();
- c->m_countInParent = newCount;
+ if (!m_renderer || m_renderer->documentBeingDestroyed())
+ return;
+ if (RenderObjectChildList* children = m_renderer->virtualChildren())
+ children->invalidateCounters(m_renderer, identifier);
+}
+
+void CounterNode::resetRenderers(const AtomicString& identifier) const
+{
+ const CounterNode* node = this;
+ do {
+ node->resetRenderer(identifier);
+ node = node->nextInPreOrder(this);
+ } while (node);
+}
+
+void CounterNode::recount(const AtomicString& identifier)
+{
+ for (CounterNode* node = this; node; node = node->m_nextSibling) {
+ int oldCount = node->m_countInParent;
+ int newCount = node->computeCountInParent();
if (oldCount == newCount)
break;
- if (c->m_renderer->isCounter())
- c->m_renderer->setNeedsLayoutAndPrefWidthsRecalc();
+ node->m_countInParent = newCount;
+ node->resetRenderers(identifier);
}
}
-void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild)
+void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild, const AtomicString& identifier)
{
ASSERT(newChild);
ASSERT(!newChild->m_parent);
@@ -79,6 +134,11 @@ void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild)
ASSERT(!newChild->m_nextSibling);
ASSERT(!refChild || refChild->m_parent == this);
+ if (newChild->m_hasResetType) {
+ while (m_lastChild != refChild)
+ RenderCounter::destroyCounterNode(m_lastChild->renderer(), identifier);
+ }
+
CounterNode* next;
if (refChild) {
@@ -89,91 +149,106 @@ void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild)
m_firstChild = newChild;
}
- if (next) {
- ASSERT(next->m_previousSibling == refChild);
- next->m_previousSibling = newChild;
- } else {
- ASSERT(m_lastChild == refChild);
- m_lastChild = newChild;
- }
-
newChild->m_parent = this;
newChild->m_previousSibling = refChild;
- newChild->m_nextSibling = next;
- newChild->m_countInParent = newChild->computeCountInParent();
+ if (!newChild->m_firstChild || newChild->m_hasResetType) {
+ newChild->m_nextSibling = next;
+ if (next) {
+ ASSERT(next->m_previousSibling == refChild);
+ next->m_previousSibling = newChild;
+ } else {
+ ASSERT(m_lastChild == refChild);
+ m_lastChild = newChild;
+ }
+
+ newChild->m_countInParent = newChild->computeCountInParent();
+ newChild->resetRenderers(identifier);
+ if (next)
+ next->recount(identifier);
+ return;
+ }
+
+ // The code below handles the case when a formerly root increment counter is loosing its root position
+ // and therefore its children become next siblings.
+ CounterNode* last = newChild->m_lastChild;
+ CounterNode* first = newChild->m_firstChild;
+
+ newChild->m_nextSibling = first;
+ first->m_previousSibling = newChild;
+ // The case when the original next sibling of the inserted node becomes a child of
+ // one of the former children of the inserted node is not handled as it is believed
+ // to be impossible since:
+ // 1. if the increment counter node lost it's root position as a result of another
+ // counter node being created, it will be inserted as the last child so next is null.
+ // 2. if the increment counter node lost it's root position as a result of a renderer being
+ // inserted into the document's render tree, all its former children counters are attached
+ // to children of the inserted renderer and hence cannot be in scope for counter nodes
+ // attached to renderers that were already in the document's render tree.
+ last->m_nextSibling = next;
if (next)
- next->recount();
+ next->m_previousSibling = last;
+ else
+ m_lastChild = last;
+ for (next = first; ; next = next->m_nextSibling) {
+ next->m_parent = this;
+ if (last == next)
+ break;
+ }
+ newChild->m_firstChild = 0;
+ newChild->m_lastChild = 0;
+ newChild->m_countInParent = newChild->computeCountInParent();
+ newChild->resetRenderer(identifier);
+ first->recount(identifier);
}
-void CounterNode::removeChild(CounterNode* oldChild)
+void CounterNode::removeChild(CounterNode* oldChild, const AtomicString& identifier)
{
ASSERT(oldChild);
ASSERT(!oldChild->m_firstChild);
ASSERT(!oldChild->m_lastChild);
CounterNode* next = oldChild->m_nextSibling;
- CounterNode* prev = oldChild->m_previousSibling;
+ CounterNode* previous = oldChild->m_previousSibling;
oldChild->m_nextSibling = 0;
oldChild->m_previousSibling = 0;
oldChild->m_parent = 0;
- if (prev)
- prev->m_nextSibling = next;
+ if (previous)
+ previous->m_nextSibling = next;
else {
ASSERT(m_firstChild == oldChild);
m_firstChild = next;
}
-
+
if (next)
- next->m_previousSibling = prev;
+ next->m_previousSibling = previous;
else {
ASSERT(m_lastChild == oldChild);
- m_lastChild = prev;
+ m_lastChild = previous;
}
-
+
if (next)
- next->recount();
+ next->recount(identifier);
}
#ifndef NDEBUG
-static const CounterNode* nextInPreOrderAfterChildren(const CounterNode* node)
-{
- CounterNode* next = node->nextSibling();
- if (!next) {
- next = node->parent();
- while (next && !next->nextSibling())
- next = next->parent();
- if (next)
- next = next->nextSibling();
- }
- return next;
-}
-
-static const CounterNode* nextInPreOrder(const CounterNode* node)
-{
- if (CounterNode* child = node->firstChild())
- return child;
- return nextInPreOrderAfterChildren(node);
-}
-
static void showTreeAndMark(const CounterNode* node)
{
const CounterNode* root = node;
while (root->parent())
root = root->parent();
- for (const CounterNode* c = root; c; c = nextInPreOrder(c)) {
- if (c == node)
- fprintf(stderr, "*");
- for (const CounterNode* d = c; d && d != root; d = d->parent())
- fprintf(stderr, "\t");
- if (c->isReset())
- fprintf(stderr, "reset: %d\n", c->value());
- else
- fprintf(stderr, "increment: %d\n", c->value());
+ for (const CounterNode* current = root; current; current = current->nextInPreOrder()) {
+ fwrite((current == node) ? "*" : " ", 1, 1, stderr);
+ for (const CounterNode* parent = current; parent && parent != root; parent = parent->parent())
+ fwrite(" ", 1, 2, stderr);
+ fprintf(stderr, "%p %s: %d %d P:%p PS:%p NS:%p R:%p\n",
+ current, current->actsAsReset() ? "reset____" : "increment", current->value(),
+ current->countInParent(), current->parent(), current->previousSibling(),
+ current->nextSibling(), current->renderer());
}
}
diff --git a/WebCore/rendering/CounterNode.h b/WebCore/rendering/CounterNode.h
index b432e1d..15f2eb8 100644
--- a/WebCore/rendering/CounterNode.h
+++ b/WebCore/rendering/CounterNode.h
@@ -35,13 +35,15 @@
namespace WebCore {
+class AtomicString;
class RenderObject;
class CounterNode : public Noncopyable {
public:
CounterNode(RenderObject*, bool isReset, int value);
- bool isReset() const { return m_isReset; }
+ bool actsAsReset() const { return m_hasResetType || !m_parent; }
+ bool hasResetType() const { return m_hasResetType; }
int value() const { return m_value; }
int countInParent() const { return m_countInParent; }
RenderObject* renderer() const { return m_renderer; }
@@ -51,15 +53,30 @@ public:
CounterNode* nextSibling() const { return m_nextSibling; }
CounterNode* firstChild() const { return m_firstChild; }
CounterNode* lastChild() const { return m_lastChild; }
+ CounterNode* lastDescendant() const;
+ CounterNode* previousInPreOrder() const;
+ CounterNode* nextInPreOrder(const CounterNode* stayWithin = 0) const;
+ CounterNode* nextInPreOrderAfterChildren(const CounterNode* stayWithin = 0) const;
- void insertAfter(CounterNode* newChild, CounterNode* beforeChild);
- void removeChild(CounterNode*);
+ void insertAfter(CounterNode* newChild, CounterNode* beforeChild, const AtomicString& identifier);
+
+ // identifier must match the identifier of this counter.
+ void removeChild(CounterNode*, const AtomicString& identifier);
private:
int computeCountInParent() const;
- void recount();
+ void recount(const AtomicString& identifier);
+
+ // Invalidates the text in the renderer of this counter, if any.
+ // identifier must match the identifier of this counter.
+ void resetRenderer(const AtomicString& identifier) const;
+
+ // Invalidates the text in the renderer of this counter, if any,
+ // and in the renderers of all descendants of this counter, if any.
+ // identifier must match the identifier of this counter.
+ void resetRenderers(const AtomicString& identifier) const;
- bool m_isReset;
+ bool m_hasResetType;
int m_value;
int m_countInParent;
RenderObject* m_renderer;
diff --git a/WebCore/rendering/EllipsisBox.cpp b/WebCore/rendering/EllipsisBox.cpp
index db9a101..6ec3195 100644
--- a/WebCore/rendering/EllipsisBox.cpp
+++ b/WebCore/rendering/EllipsisBox.cpp
@@ -1,6 +1,4 @@
/**
-* This file is part of the html renderer for KDE.
- *
* Copyright (C) 2003, 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -25,6 +23,7 @@
#include "Document.h"
#include "GraphicsContext.h"
#include "HitTestResult.h"
+#include "RootInlineBox.h"
namespace WebCore {
@@ -34,17 +33,30 @@ void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
RenderStyle* style = m_renderer->style(m_firstLine);
Color textColor = style->color();
if (textColor != context->fillColor())
- context->setFillColor(textColor);
+ context->setFillColor(textColor, style->colorSpace());
bool setShadow = false;
if (style->textShadow()) {
context->setShadow(IntSize(style->textShadow()->x, style->textShadow()->y),
- style->textShadow()->blur, style->textShadow()->color);
+ style->textShadow()->blur, style->textShadow()->color, style->colorSpace());
setShadow = true;
}
+ if (selectionState() != RenderObject::SelectionNone) {
+ paintSelection(context, tx, ty, style, style->font());
+
+ // Select the correct color for painting the text.
+ Color foreground = paintInfo.forceBlackText ? Color::black : renderer()->selectionForegroundColor();
+ if (foreground.isValid() && foreground != textColor)
+ context->setFillColor(foreground, style->colorSpace());
+ }
+
const String& str = m_str;
context->drawText(style->font(), TextRun(str.characters(), str.length(), false, 0, 0, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + style->font().ascent()));
+ // Restore the regular fill color.
+ if (textColor != context->fillColor())
+ context->setFillColor(textColor, style->colorSpace());
+
if (setShadow)
context->clearShadow();
@@ -56,6 +68,35 @@ void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
}
}
+IntRect EllipsisBox::selectionRect(int tx, int ty)
+{
+ RenderStyle* style = m_renderer->style(m_firstLine);
+ const Font& f = style->font();
+ return enclosingIntRect(f.selectionRectForText(TextRun(m_str.characters(), m_str.length(), false, 0, 0, false, style->visuallyOrdered()),
+ IntPoint(m_x + tx, m_y + ty + root()->selectionTop()), root()->selectionHeight()));
+}
+
+void EllipsisBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font& font)
+{
+ Color textColor = style->color();
+ Color c = m_renderer->selectionBackgroundColor();
+ if (!c.isValid() || !c.alpha())
+ return;
+
+ // If the text color ends up being the same as the selection background, invert the selection
+ // background.
+ if (textColor == c)
+ c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue());
+
+ context->save();
+ int y = root()->selectionTop();
+ int h = root()->selectionHeight();
+ context->clip(IntRect(m_x + tx, y + ty, m_width, h));
+ context->drawHighlightForText(font, TextRun(m_str.characters(), m_str.length(), false, 0, 0, false, style->visuallyOrdered()),
+ IntPoint(m_x + tx, m_y + ty + y), h, c, style->colorSpace());
+ context->restore();
+}
+
bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
{
tx += m_x;
diff --git a/WebCore/rendering/EllipsisBox.h b/WebCore/rendering/EllipsisBox.h
index 9dbd27f..087fc72 100644
--- a/WebCore/rendering/EllipsisBox.h
+++ b/WebCore/rendering/EllipsisBox.h
@@ -1,6 +1,4 @@
/**
-* This file is part of the html renderer for KDE.
- *
* Copyright (C) 2003, 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -37,18 +35,24 @@ public:
, m_height(height)
, m_str(ellipsisStr)
, m_markupBox(markupBox)
+ , m_selectionState(RenderObject::SelectionNone)
{
}
virtual void paint(RenderObject::PaintInfo&, int tx, int ty);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty);
+ void setSelectionState(RenderObject::SelectionState s) { m_selectionState = s; }
+ IntRect selectionRect(int tx, int ty);
private:
virtual int height() const { return m_height; }
+ virtual RenderObject::SelectionState selectionState() { return m_selectionState; }
+ void paintSelection(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&);
int m_height;
AtomicString m_str;
InlineBox* m_markupBox;
+ RenderObject::SelectionState m_selectionState;
};
} // namespace WebCore
diff --git a/WebCore/rendering/FixedTableLayout.cpp b/WebCore/rendering/FixedTableLayout.cpp
index ee3e75a..09af518 100644
--- a/WebCore/rendering/FixedTableLayout.cpp
+++ b/WebCore/rendering/FixedTableLayout.cpp
@@ -1,6 +1,4 @@
/*
- * This file is part of the HTML rendering engine for KDE.
- *
* Copyright (C) 2002 Lars Knoll (knoll@kde.org)
* (C) 2002 Dirk Mueller (mueller@kde.org)
* Copyright (C) 2003, 2006 Apple Computer, Inc.
@@ -188,6 +186,11 @@ int FixedTableLayout::calcWidthArray(int)
return usedWidth;
}
+// Use a very large value (in effect infinite). But not too large!
+// numeric_limits<int>::max() will too easily overflow widths.
+// Keep this in synch with BLOCK_MAX_WIDTH in RenderBlock.cpp
+#define TABLE_MAX_WIDTH 15000
+
void FixedTableLayout::calcPrefWidths(int& minWidth, int& maxWidth)
{
// FIXME: This entire calculation is incorrect for both minwidth and maxwidth.
@@ -206,6 +209,24 @@ void FixedTableLayout::calcPrefWidths(int& minWidth, int& maxWidth)
minWidth = max(mw, tableWidth);
maxWidth = minWidth;
+
+ // This quirk is very similar to one that exists in RenderBlock::calcBlockPrefWidths().
+ // Here's the example for this one:
+ /*
+ <table style="width:100%; background-color:red"><tr><td>
+ <table style="background-color:blue"><tr><td>
+ <table style="width:100%; background-color:green; table-layout:fixed"><tr><td>
+ Content
+ </td></tr></table>
+ </td></tr></table>
+ </td></tr></table>
+ */
+ // In this example, the two inner tables should be as large as the outer table.
+ // We can achieve this effect by making the maxwidth of fixed tables with percentage
+ // widths be infinite.
+ if (m_table->style()->htmlHacks() && m_table->style()->width().isPercent()
+ && maxWidth < TABLE_MAX_WIDTH)
+ maxWidth = TABLE_MAX_WIDTH;
}
void FixedTableLayout::layout()
diff --git a/WebCore/rendering/FixedTableLayout.h b/WebCore/rendering/FixedTableLayout.h
index ed7c089..758ddbb 100644
--- a/WebCore/rendering/FixedTableLayout.h
+++ b/WebCore/rendering/FixedTableLayout.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the HTML rendering engine for KDE.
- *
* Copyright (C) 2002 Lars Knoll (knoll@kde.org)
* (C) 2002 Dirk Mueller (mueller@kde.org)
*
diff --git a/WebCore/rendering/HitTestRequest.h b/WebCore/rendering/HitTestRequest.h
index 46dd7b8..ca1445a 100644
--- a/WebCore/rendering/HitTestRequest.h
+++ b/WebCore/rendering/HitTestRequest.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the HTML rendering engine for KDE.
- *
* Copyright (C) 2006 Apple Computer, Inc.
* Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
*
diff --git a/WebCore/rendering/HitTestResult.cpp b/WebCore/rendering/HitTestResult.cpp
index b7de46b..50933c6 100644
--- a/WebCore/rendering/HitTestResult.cpp
+++ b/WebCore/rendering/HitTestResult.cpp
@@ -123,17 +123,6 @@ Frame* HitTestResult::targetFrame() const
return frame->tree()->find(m_innerURLElement->target());
}
-IntRect HitTestResult::boundingBox() const
-{
- if (m_innerNonSharedNode) {
- RenderObject* renderer = m_innerNonSharedNode->renderer();
- if (renderer)
- return renderer->absoluteBoundingBoxRect();
- }
-
- return IntRect();
-}
-
bool HitTestResult::isSelected() const
{
if (!m_innerNonSharedNode)
@@ -209,7 +198,7 @@ String HitTestResult::altDisplayString() const
if (m_innerNonSharedNode->hasTagName(imgTag)) {
HTMLImageElement* image = static_cast<HTMLImageElement*>(m_innerNonSharedNode.get());
- return displayString(image->alt(), m_innerNonSharedNode.get());
+ return displayString(image->getAttribute(altAttr), m_innerNonSharedNode.get());
}
if (m_innerNonSharedNode->hasTagName(inputTag)) {
@@ -246,7 +235,7 @@ IntRect HitTestResult::imageRect() const
{
if (!image())
return IntRect();
- return m_innerNonSharedNode->renderBox()->absoluteContentBox();
+ return m_innerNonSharedNode->renderBox()->absoluteContentQuad().enclosingBoundingBox();
}
KURL HitTestResult::absoluteImageURL() const
diff --git a/WebCore/rendering/HitTestResult.h b/WebCore/rendering/HitTestResult.h
index f29ca41..d1906ba 100644
--- a/WebCore/rendering/HitTestResult.h
+++ b/WebCore/rendering/HitTestResult.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the HTML rendering engine for KDE.
- *
* Copyright (C) 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -63,7 +61,6 @@ public:
void setIsOverWidget(bool b) { m_isOverWidget = b; }
Frame* targetFrame() const;
- IntRect boundingBox() const;
bool isSelected() const;
String spellingToolTip(TextDirection&) const;
String replacedString() const;
diff --git a/WebCore/rendering/InlineBox.cpp b/WebCore/rendering/InlineBox.cpp
index bbf11b3..2575fb7 100644
--- a/WebCore/rendering/InlineBox.cpp
+++ b/WebCore/rendering/InlineBox.cpp
@@ -98,18 +98,11 @@ int InlineBox::height() const
return toRenderBox(m_renderer)->height();
ASSERT(isInlineFlowBox());
- const InlineFlowBox* flowBox = static_cast<const InlineFlowBox*>(this);
RenderBoxModelObject* flowObject = boxModelObject();
const Font& font = renderer()->style(m_firstLine)->font();
int result = font.height();
- bool strictMode = renderer()->document()->inStrictMode();
if (parent())
result += flowObject->borderTop() + flowObject->paddingTop() + flowObject->borderBottom() + flowObject->paddingBottom();
- if (strictMode || flowBox->hasTextChildren() || flowObject->hasHorizontalBordersOrPadding())
- return result;
- int bottom = root()->bottomOverflow();
- if (y() + result > bottom)
- result = bottom - y();
return result;
}
diff --git a/WebCore/rendering/InlineBox.h b/WebCore/rendering/InlineBox.h
index c03758d..e165f0c 100644
--- a/WebCore/rendering/InlineBox.h
+++ b/WebCore/rendering/InlineBox.h
@@ -208,11 +208,6 @@ public:
inline int baselinePosition(bool isRootLineBox) const { return renderer()->baselinePosition(m_firstLine, isRootLineBox); }
inline int lineHeight(bool isRootLineBox) const { return renderer()->lineHeight(m_firstLine, isRootLineBox); }
- virtual int topOverflow() const { return y(); }
- virtual int bottomOverflow() const { return y() + height(); }
- virtual int leftOverflow() const { return x(); }
- virtual int rightOverflow() const { return x() + width(); }
-
virtual int caretMinOffset() const;
virtual int caretMaxOffset() const;
virtual unsigned caretMaxRenderedOffset() const;
diff --git a/WebCore/rendering/InlineFlowBox.cpp b/WebCore/rendering/InlineFlowBox.cpp
index 543c190..34eec30 100644
--- a/WebCore/rendering/InlineFlowBox.cpp
+++ b/WebCore/rendering/InlineFlowBox.cpp
@@ -29,6 +29,7 @@
#include "RootInlineBox.h"
#include "RenderBlock.h"
#include "RenderInline.h"
+#include "RenderLayer.h"
#include "RenderListMarker.h"
#include "RenderTableCell.h"
#include "RootInlineBox.h"
@@ -167,6 +168,8 @@ void InlineFlowBox::adjustPosition(int dx, int dy)
InlineRunBox::adjustPosition(dx, dy);
for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
child->adjustPosition(dx, dy);
+ if (m_overflow)
+ m_overflow->move(dx, dy);
}
RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const
@@ -248,16 +251,21 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en
}
}
-int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& rightPosition, bool& needsWordSpacing)
+int InlineFlowBox::placeBoxesHorizontally(int xPos, bool& needsWordSpacing)
{
// Set our x position.
setX(xPos);
+ int leftLayoutOverflow = xPos;
+ int rightLayoutOverflow = xPos;
+ int leftVisualOverflow = xPos;
+ int rightVisualOverflow = xPos;
+
int boxShadowLeft;
int boxShadowRight;
renderer()->style(m_firstLine)->getBoxShadowHorizontalExtent(boxShadowLeft, boxShadowRight);
- leftPosition = min(xPos + boxShadowLeft, leftPosition);
+ leftVisualOverflow = min(xPos + boxShadowLeft, leftVisualOverflow);
int startX = xPos;
xPos += borderLeft() + paddingLeft();
@@ -275,23 +283,24 @@ int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& righ
int strokeOverflow = static_cast<int>(ceilf(rt->style()->textStrokeWidth() / 2.0f));
- // If letter-spacing is negative, we should factor that into right overflow. (Even in RTL, letter-spacing is
+ // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is
// applied to the right, so this is not an issue with left overflow.
int letterSpacing = min(0, (int)rt->style(m_firstLine)->font().letterSpacing());
-
+ rightLayoutOverflow = max(xPos + text->width() - letterSpacing, rightLayoutOverflow);
+
int leftGlyphOverflow = -strokeOverflow;
int rightGlyphOverflow = strokeOverflow - letterSpacing;
- int visualOverflowLeft = leftGlyphOverflow;
- int visualOverflowRight = rightGlyphOverflow;
+ int childOverflowLeft = leftGlyphOverflow;
+ int childOverflowRight = rightGlyphOverflow;
for (ShadowData* shadow = rt->style()->textShadow(); shadow; shadow = shadow->next) {
- visualOverflowLeft = min(visualOverflowLeft, shadow->x - shadow->blur + leftGlyphOverflow);
- visualOverflowRight = max(visualOverflowRight, shadow->x + shadow->blur + rightGlyphOverflow);
+ childOverflowLeft = min(childOverflowLeft, shadow->x - shadow->blur + leftGlyphOverflow);
+ childOverflowRight = max(childOverflowRight, shadow->x + shadow->blur + rightGlyphOverflow);
}
- leftPosition = min(xPos + visualOverflowLeft, leftPosition);
- rightPosition = max(xPos + text->width() + visualOverflowRight, rightPosition);
- m_maxHorizontalVisualOverflow = max(max(visualOverflowRight, -visualOverflowLeft), (int)m_maxHorizontalVisualOverflow);
+ leftVisualOverflow = min(xPos + childOverflowLeft, leftVisualOverflow);
+ rightVisualOverflow = max(xPos + text->width() + childOverflowRight, rightVisualOverflow);
+
xPos += text->width();
} else {
if (curr->renderer()->isPositioned()) {
@@ -307,13 +316,26 @@ int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& righ
if (curr->renderer()->isRenderInline()) {
InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
xPos += flow->marginLeft();
- xPos = flow->placeBoxesHorizontally(xPos, leftPosition, rightPosition, needsWordSpacing);
+ xPos = flow->placeBoxesHorizontally(xPos, needsWordSpacing);
xPos += flow->marginRight();
+ leftLayoutOverflow = min(leftLayoutOverflow, flow->leftLayoutOverflow());
+ rightLayoutOverflow = max(rightLayoutOverflow, flow->rightLayoutOverflow());
+ leftVisualOverflow = min(leftVisualOverflow, flow->leftVisualOverflow());
+ rightVisualOverflow = max(rightVisualOverflow, flow->rightVisualOverflow());
} else if (!curr->renderer()->isListMarker() || toRenderListMarker(curr->renderer())->isInside()) {
xPos += curr->boxModelObject()->marginLeft();
curr->setX(xPos);
- leftPosition = min(xPos + toRenderBox(curr->renderer())->overflowLeft(false), leftPosition);
- rightPosition = max(xPos + toRenderBox(curr->renderer())->overflowWidth(false), rightPosition);
+
+ RenderBox* box = toRenderBox(curr->renderer());
+ int childLeftOverflow = box->hasOverflowClip() ? 0 : box->leftLayoutOverflow();
+ int childRightOverflow = box->hasOverflowClip() ? curr->width() : box->rightLayoutOverflow();
+
+ leftLayoutOverflow = min(xPos + childLeftOverflow, leftLayoutOverflow);
+ rightLayoutOverflow = max(xPos + childRightOverflow, rightLayoutOverflow);
+
+ leftVisualOverflow = min(xPos + box->leftVisualOverflow(), leftVisualOverflow);
+ rightVisualOverflow = max(xPos + box->rightVisualOverflow(), rightVisualOverflow);
+
xPos += curr->width() + curr->boxModelObject()->marginRight();
}
}
@@ -321,45 +343,13 @@ int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& righ
xPos += borderRight() + paddingRight();
setWidth(xPos - startX);
- rightPosition = max(x() + width() + boxShadowRight, rightPosition);
+ rightVisualOverflow = max(x() + width() + boxShadowRight, rightVisualOverflow);
+ rightLayoutOverflow = max(x() + width(), rightLayoutOverflow);
+ setHorizontalOverflowPositions(leftLayoutOverflow, rightLayoutOverflow, leftVisualOverflow, rightVisualOverflow);
return xPos;
}
-int InlineFlowBox::verticallyAlignBoxes(int heightOfBlock)
-{
- int maxPositionTop = 0;
- int maxPositionBottom = 0;
- int maxAscent = 0;
- int maxDescent = 0;
-
- // Figure out if we're in strict mode. Note that we can't simply use !style()->htmlHacks(),
- // because that would match almost strict mode as well.
- RenderObject* curr = renderer();
- while (curr && !curr->node())
- curr = curr->container();
- bool strictMode = (curr && curr->document()->inStrictMode());
-
- computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode);
-
- if (maxAscent + maxDescent < max(maxPositionTop, maxPositionBottom))
- adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
-
- int maxHeight = maxAscent + maxDescent;
- int topPosition = heightOfBlock;
- int bottomPosition = heightOfBlock;
- int selectionTop = heightOfBlock;
- int selectionBottom = heightOfBlock;
- placeBoxesVertically(heightOfBlock, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom);
-
- setVerticalOverflowPositions(topPosition, bottomPosition);
- setVerticalSelectionPositions(selectionTop, selectionBottom);
-
- heightOfBlock += maxHeight;
-
- return heightOfBlock;
-}
-
void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
int maxPositionTop, int maxPositionBottom)
{
@@ -479,11 +469,10 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi
}
}
-void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, bool strictMode,
- int& topPosition, int& bottomPosition, int& selectionTop, int& selectionBottom)
+void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, bool strictMode, int& selectionTop, int& selectionBottom)
{
if (isRootInlineBox())
- setY(yPos + max(0, maxAscent - baselinePosition(true))); // Place our root box.
+ setY(yPos + maxAscent - baselinePosition(true)); // Place our root box.
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
if (curr->renderer()->isPositioned())
@@ -493,7 +482,7 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent,
// line-height).
bool isInlineFlow = curr->isInlineFlowBox();
if (isInlineFlow)
- static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(yPos, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom);
+ static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(yPos, maxHeight, maxAscent, strictMode, selectionTop, selectionBottom);
bool childAffectsTopBottomPos = true;
if (curr->y() == PositionTop)
@@ -504,43 +493,18 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent,
if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasHorizontalBordersOrPadding() && !strictMode)
childAffectsTopBottomPos = false;
int posAdjust = maxAscent - curr->baselinePosition(false);
- if (!childAffectsTopBottomPos)
- posAdjust = max(0, posAdjust);
curr->setY(curr->y() + yPos + posAdjust);
}
- // FIXME: By only considering overflow as part of the root line box, we can't get an accurate picture regarding what the line
- // actually needs to paint. A line box that is part of a self-painting layer technically shouldn't contribute to the overflow
- // of the line, but in order to not do this and paint accurately, we have to track the overflow somewhere else (either by storing overflow
- // in each InlineFlowBox up the chain or in the layer itself). Relative positioned objects on a line will cause scrollbars
- // to appear when they shouldn't until we fix this issue.
int newY = curr->y();
- int overflowTop = 0;
- int overflowBottom = 0;
if (curr->isText() || curr->isInlineFlowBox()) {
const Font& font = curr->renderer()->style(m_firstLine)->font();
newY += curr->baselinePosition(false) - font.ascent();
-
- curr->renderer()->style(m_firstLine)->getBoxShadowVerticalExtent(overflowTop, overflowBottom);
-
- for (ShadowData* textShadow = curr->renderer()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) {
- overflowTop = min(overflowTop, textShadow->y - textShadow->blur);
- overflowBottom = max(overflowBottom, textShadow->y + textShadow->blur);
- }
-
- if (curr->renderer()->hasReflection()) {
- RenderBox* box = toRenderBox(curr->renderer());
- overflowTop = min(overflowTop, box->reflectionBox().y());
- overflowBottom = max(overflowBottom, box->reflectionBox().bottom());
- }
-
if (curr->isInlineFlowBox())
newY -= curr->boxModelObject()->borderTop() + curr->boxModelObject()->paddingTop();
} else if (!curr->renderer()->isBR()) {
RenderBox* box = toRenderBox(curr->renderer());
newY += box->marginTop();
- overflowTop = box->overflowTop(false);
- overflowBottom = box->overflowHeight(false) - box->height();
}
curr->setY(newY);
@@ -549,8 +513,6 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent,
int boxHeight = curr->height();
selectionTop = min(selectionTop, newY);
selectionBottom = max(selectionBottom, newY + boxHeight);
- topPosition = min(topPosition, newY + overflowTop);
- bottomPosition = max(bottomPosition, newY + boxHeight + overflowBottom);
}
}
@@ -564,8 +526,85 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent,
}
}
+void InlineFlowBox::computeVerticalOverflow(int lineTop, int lineBottom, bool strictMode)
+{
+ int boxHeight = height();
+
+ // Any spillage outside of the line top and bottom is not considered overflow. We just ignore this, since it only happens
+ // from the "your ascent/descent don't affect the line" quirk.
+ int topOverflow = max(y(), lineTop);
+ int bottomOverflow = min(y() + boxHeight, lineBottom);
+
+ int topLayoutOverflow = topOverflow;
+ int bottomLayoutOverflow = bottomOverflow;
+
+ int topVisualOverflow = topOverflow;
+ int bottomVisualOverflow = bottomOverflow;
+
+ // box-shadow on root line boxes is applying to the block and not to the lines.
+ if (parent()) {
+ int boxShadowTop;
+ int boxShadowBottom;
+ renderer()->style(m_firstLine)->getBoxShadowVerticalExtent(boxShadowTop, boxShadowBottom);
+
+ topVisualOverflow = min(y() + boxShadowTop, topVisualOverflow);
+ bottomVisualOverflow = max(y() + boxHeight + boxShadowBottom, bottomVisualOverflow);
+ }
+
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->renderer()->isPositioned())
+ continue; // Positioned placeholders don't affect calculations.
+
+ if (curr->renderer()->isText()) {
+ InlineTextBox* text = static_cast<InlineTextBox*>(curr);
+ RenderText* rt = toRenderText(text->renderer());
+ if (rt->isBR())
+ continue;
+
+ int strokeOverflow = static_cast<int>(ceilf(rt->style()->textStrokeWidth() / 2.0f));
+
+ int topGlyphOverflow = -strokeOverflow;
+ int bottomGlyphOverflow = strokeOverflow;
+
+ int childOverflowTop = topGlyphOverflow;
+ int childOverflowBottom = bottomGlyphOverflow;
+ for (ShadowData* shadow = rt->style()->textShadow(); shadow; shadow = shadow->next) {
+ childOverflowTop = min(childOverflowTop, shadow->y - shadow->blur + topGlyphOverflow);
+ childOverflowBottom = max(childOverflowBottom, shadow->y + shadow->blur + bottomGlyphOverflow);
+ }
+
+ topVisualOverflow = min(curr->y() + childOverflowTop, topVisualOverflow);
+ bottomVisualOverflow = max(curr->y() + text->height() + childOverflowBottom, bottomVisualOverflow);
+ } else if (curr->renderer()->isRenderInline()) {
+ InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
+ flow->computeVerticalOverflow(lineTop, lineBottom, strictMode);
+ topLayoutOverflow = min(topLayoutOverflow, flow->topLayoutOverflow());
+ bottomLayoutOverflow = max(bottomLayoutOverflow, flow->bottomLayoutOverflow());
+ topVisualOverflow = min(topVisualOverflow, flow->topVisualOverflow());
+ bottomVisualOverflow = max(bottomVisualOverflow, flow->bottomVisualOverflow());
+ } else if (!curr->boxModelObject()->hasSelfPaintingLayer()){
+ // Only include overflow from replaced inlines if they do not paint themselves.
+ RenderBox* box = toRenderBox(curr->renderer());
+ int boxY = curr->y();
+ int childTopOverflow = box->hasOverflowClip() ? 0 : box->topLayoutOverflow();
+ int childBottomOverflow = box->hasOverflowClip() ? curr->height() : box->bottomLayoutOverflow();
+ topLayoutOverflow = min(boxY + childTopOverflow, topLayoutOverflow);
+ bottomLayoutOverflow = max(boxY + childBottomOverflow, bottomLayoutOverflow);
+ topVisualOverflow = min(boxY + box->topVisualOverflow(), topVisualOverflow);
+ bottomVisualOverflow = max(boxY + box->bottomVisualOverflow(), bottomVisualOverflow);
+ }
+ }
+
+ setVerticalOverflowPositions(topLayoutOverflow, bottomLayoutOverflow, topVisualOverflow, bottomVisualOverflow, boxHeight);
+}
+
bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
{
+ IntRect overflowRect(visibleOverflowRect());
+ overflowRect.move(tx, ty);
+ if (!overflowRect.contains(x, y))
+ return false;
+
// Check children first.
for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, x, y, tx, ty)) {
@@ -586,23 +625,14 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
{
- int xPos = tx + m_x - renderer()->maximalOutlineSize(paintInfo.phase);
- int w = width() + 2 * renderer()->maximalOutlineSize(paintInfo.phase);
- int shadowLeft;
- int shadowRight;
-
- renderer()->style(m_firstLine)->getBoxShadowHorizontalExtent(shadowLeft, shadowRight);
-
- for (ShadowData* textShadow = renderer()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) {
- shadowLeft = min(textShadow->x - textShadow->blur, shadowLeft);
- shadowRight = max(textShadow->x + textShadow->blur, shadowRight);
- }
-
- xPos += shadowLeft;
- w += -shadowLeft + shadowRight;
- bool intersectsDamageRect = xPos < paintInfo.rect.right() && xPos + w > paintInfo.rect.x();
+ IntRect overflowRect(visibleOverflowRect());
+ overflowRect.inflate(renderer()->maximalOutlineSize(paintInfo.phase));
+ overflowRect.move(tx, ty);
+
+ if (!paintInfo.rect.intersects(overflowRect))
+ return;
- if (intersectsDamageRect && paintInfo.phase != PaintPhaseChildOutlines) {
+ if (paintInfo.phase != PaintPhaseChildOutlines) {
if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) {
// Add ourselves to the paint info struct's list of inlines that need to paint their
// outlines.
@@ -645,7 +675,7 @@ void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
}
// 4. Paint our strike-through
- if (intersectsDamageRect && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
+ if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)
paintTextDecorations(paintInfo, tx, ty, true);
}
@@ -702,13 +732,24 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int
if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground)
return;
- // Move x/y to our coordinates.
- tx += m_x;
- ty += m_y;
-
+ int x = m_x;
+ int y = m_y;
int w = width();
int h = height();
+ // Constrain our background/border painting to the line top and bottom if necessary.
+ bool strictMode = renderer()->document()->inStrictMode();
+ if (!hasTextChildren() && !strictMode) {
+ RootInlineBox* rootBox = root();
+ int bottom = min(rootBox->lineBottom(), y + h);
+ y = max(rootBox->lineTop(), y);
+ h = bottom - y;
+ }
+
+ // Move x/y to our coordinates.
+ tx += x;
+ ty += y;
+
GraphicsContext* context = paintInfo.context;
// You can use p::first-line to specify a background. If so, the root line boxes for
@@ -767,25 +808,41 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty
if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
return;
- // Move x/y to our coordinates.
- tx += m_x;
- ty += m_y;
-
+ int x = m_x;
+ int y = m_y;
int w = width();
int h = height();
- // Figure out if we need to push a transparency layer to render our mask.
- bool pushTransparencyLayer = false;
+ // Constrain our background/border painting to the line top and bottom if necessary.
+ bool strictMode = renderer()->document()->inStrictMode();
+ if (!hasTextChildren() && !strictMode) {
+ RootInlineBox* rootBox = root();
+ int bottom = min(rootBox->lineBottom(), y + h);
+ y = max(rootBox->lineTop(), y);
+ h = bottom - y;
+ }
+
+ // Move x/y to our coordinates.
+ tx += x;
+ ty += y;
+
const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage();
StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image();
- if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next())
- pushTransparencyLayer = true;
-
- CompositeOperator compositeOp = CompositeDestinationIn;
- if (pushTransparencyLayer) {
- paintInfo.context->setCompositeOperation(CompositeDestinationIn);
- paintInfo.context->beginTransparencyLayer(1.0f);
- compositeOp = CompositeSourceOver;
+
+ // Figure out if we need to push a transparency layer to render our mask.
+ bool pushTransparencyLayer = false;
+ bool compositedMask = renderer()->hasLayer() && boxModelObject()->layer()->hasCompositedMask();
+ CompositeOperator compositeOp = CompositeSourceOver;
+ if (!compositedMask) {
+ if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next())
+ pushTransparencyLayer = true;
+
+ compositeOp = CompositeDestinationIn;
+ if (pushTransparencyLayer) {
+ paintInfo.context->setCompositeOperation(CompositeDestinationIn);
+ paintInfo.context->beginTransparencyLayer(1.0f);
+ compositeOp = CompositeSourceOver;
+ }
}
paintFillLayers(paintInfo, Color(), renderer()->style()->maskLayers(), tx, ty, w, h, compositeOp);
@@ -936,6 +993,7 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int
setClip = true;
}
+ ColorSpace colorSpace = renderer()->style()->colorSpace();
bool setShadow = false;
do {
if (shadow) {
@@ -944,24 +1002,24 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int
ty -= extraOffset;
extraOffset = 0;
}
- context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color);
+ context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color, colorSpace);
setShadow = true;
shadow = shadow->next;
}
if (paintUnderline) {
- context->setStrokeColor(underline);
+ context->setStrokeColor(underline, colorSpace);
context->setStrokeStyle(SolidStroke);
// Leave one pixel of white between the baseline and the underline.
context->drawLineForText(IntPoint(tx, ty + baselinePos + 1), w, isPrinting);
}
if (paintOverline) {
- context->setStrokeColor(overline);
+ context->setStrokeColor(overline, colorSpace);
context->setStrokeStyle(SolidStroke);
context->drawLineForText(IntPoint(tx, ty), w, isPrinting);
}
if (paintLineThrough) {
- context->setStrokeColor(linethrough);
+ context->setStrokeColor(linethrough, colorSpace);
context->setStrokeStyle(SolidStroke);
context->drawLineForText(IntPoint(tx, ty + 2 * baselinePos / 3), w, isPrinting);
}
diff --git a/WebCore/rendering/InlineFlowBox.h b/WebCore/rendering/InlineFlowBox.h
index 809fd54..23b5cc9 100644
--- a/WebCore/rendering/InlineFlowBox.h
+++ b/WebCore/rendering/InlineFlowBox.h
@@ -22,6 +22,7 @@
#define InlineFlowBox_h
#include "InlineRunBox.h"
+#include "RenderOverflow.h"
namespace WebCore {
@@ -35,10 +36,8 @@ public:
: InlineRunBox(obj)
, m_firstChild(0)
, m_lastChild(0)
- , m_maxHorizontalVisualOverflow(0)
, m_includeLeftEdge(false)
, m_includeRightEdge(false)
- , m_hasTextChildren(true)
#ifndef NDEBUG
, m_hasBadChildList(false)
#endif
@@ -121,18 +120,13 @@ public:
void determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject);
int getFlowSpacingWidth();
bool onEndChain(RenderObject* endObject);
- virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing);
- virtual int verticallyAlignBoxes(int heightOfBlock);
+ virtual int placeBoxesHorizontally(int x, bool& needsWordSpacing);
void computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom,
int& maxAscent, int& maxDescent, bool strictMode);
void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
int maxPositionTop, int maxPositionBottom);
- void placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode,
- int& topPosition, int& bottomPosition, int& selectionTop, int& selectionBottom);
-
- virtual void setVerticalOverflowPositions(int /*top*/, int /*bottom*/) { }
- virtual void setVerticalSelectionPositions(int /*top*/, int /*bottom*/) { }
- short maxHorizontalVisualOverflow() const { return m_maxHorizontalVisualOverflow; }
+ void placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom);
+ void computeVerticalOverflow(int lineTop, int lineBottom, bool strictMode);
void removeChild(InlineBox* child);
@@ -146,12 +140,35 @@ public:
void checkConsistency() const;
void setHasBadChildList();
+ int topVisibleOverflow() const { return std::min(topLayoutOverflow(), topVisualOverflow()); }
+ int bottomVisibleOverflow() const { return std::max(bottomLayoutOverflow(), bottomVisualOverflow()); }
+ int leftVisibleOverflow() const { return std::min(leftLayoutOverflow(), leftVisualOverflow()); }
+ int rightVisibleOverflow() const { return std::max(rightLayoutOverflow(), rightVisualOverflow()); }
+ IntRect visibleOverflowRect() const { return m_overflow ? m_overflow->visibleOverflowRect() : IntRect(m_x, m_y, m_width, height()); }
+
+ int topLayoutOverflow() const { return m_overflow ? m_overflow->topLayoutOverflow() : m_y; }
+ int bottomLayoutOverflow() const { return m_overflow ? m_overflow->bottomLayoutOverflow() : m_y + height(); }
+ int leftLayoutOverflow() const { return m_overflow ? m_overflow->leftLayoutOverflow() : m_x; }
+ int rightLayoutOverflow() const { return m_overflow ? m_overflow->rightLayoutOverflow() : m_x + m_width; }
+ IntRect layoutOverflowRect() const { return m_overflow ? m_overflow->layoutOverflowRect() : IntRect(m_x, m_y, m_width, height()); }
+
+ int topVisualOverflow() const { return m_overflow ? m_overflow->topVisualOverflow() : m_y; }
+ int bottomVisualOverflow() const { return m_overflow ? m_overflow->bottomVisualOverflow() : m_y + height(); }
+ int leftVisualOverflow() const { return m_overflow ? m_overflow->leftVisualOverflow() : m_x; }
+ int rightVisualOverflow() const { return m_overflow ? m_overflow->rightVisualOverflow() : m_x + m_width; }
+ IntRect visualOverflowRect() const { return m_overflow ? m_overflow->visualOverflowRect() : IntRect(m_x, m_y, m_width, height()); }
+
+ void setHorizontalOverflowPositions(int leftLayoutOverflow, int rightLayoutOverflow, int leftVisualOverflow, int rightVisualOverflow);
+ void setVerticalOverflowPositions(int topLayoutOverflow, int bottomLayoutOverflow, int topVisualOverflow, int bottomVisualOverflow, int boxHeight);
+
+protected:
+ OwnPtr<RenderOverflow> m_overflow;
+
private:
virtual bool isInlineFlowBox() const { return true; }
InlineBox* m_firstChild;
InlineBox* m_lastChild;
- short m_maxHorizontalVisualOverflow;
bool m_includeLeftEdge : 1;
bool m_includeRightEdge : 1;
@@ -162,6 +179,34 @@ private:
#endif
};
+inline void InlineFlowBox::setHorizontalOverflowPositions(int leftLayoutOverflow, int rightLayoutOverflow, int leftVisualOverflow, int rightVisualOverflow)
+{
+ if (!m_overflow) {
+ if (leftLayoutOverflow == m_x && rightLayoutOverflow == m_x + m_width && leftVisualOverflow == m_x && rightVisualOverflow == m_x + m_width)
+ return;
+ m_overflow.set(new RenderOverflow(IntRect(m_x, m_y, m_width, m_renderer->style(m_firstLine)->font().height())));
+ }
+
+ m_overflow->setLeftLayoutOverflow(leftLayoutOverflow);
+ m_overflow->setRightLayoutOverflow(rightLayoutOverflow);
+ m_overflow->setLeftVisualOverflow(leftVisualOverflow);
+ m_overflow->setRightVisualOverflow(rightVisualOverflow);
+}
+
+inline void InlineFlowBox::setVerticalOverflowPositions(int topLayoutOverflow, int bottomLayoutOverflow, int topVisualOverflow, int bottomVisualOverflow, int boxHeight)
+{
+ if (!m_overflow) {
+ if (topLayoutOverflow == m_y && bottomLayoutOverflow == m_y + boxHeight && topVisualOverflow == m_y && bottomVisualOverflow == m_y + boxHeight)
+ return;
+ m_overflow.set(new RenderOverflow(IntRect(m_x, m_y, m_width, boxHeight)));
+ }
+
+ m_overflow->setTopLayoutOverflow(topLayoutOverflow);
+ m_overflow->setBottomLayoutOverflow(bottomLayoutOverflow);
+ m_overflow->setTopVisualOverflow(topVisualOverflow);
+ m_overflow->setBottomVisualOverflow(bottomVisualOverflow);
+}
+
#ifdef NDEBUG
inline void InlineFlowBox::checkConsistency() const
{
diff --git a/WebCore/rendering/InlineIterator.h b/WebCore/rendering/InlineIterator.h
new file mode 100644
index 0000000..9310ea8
--- /dev/null
+++ b/WebCore/rendering/InlineIterator.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All right reserved.
+ * Copyright (C) 2010 Google 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
+ * 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 InlineIterator_h
+#define InlineIterator_h
+
+#include "BidiRun.h"
+#include "RenderBlock.h"
+#include "RenderText.h"
+#include <wtf/AlwaysInline.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+class InlineIterator {
+public:
+ InlineIterator()
+ : block(0)
+ , obj(0)
+ , pos(0)
+ , nextBreakablePosition(-1)
+ {
+ }
+
+ InlineIterator(RenderBlock* b, RenderObject* o, unsigned p)
+ : block(b)
+ , obj(o)
+ , pos(p)
+ , nextBreakablePosition(-1)
+ {
+ }
+
+ void increment(InlineBidiResolver* resolver = 0);
+ bool atEnd() const;
+
+ UChar current() const;
+ WTF::Unicode::Direction direction() const;
+
+ RenderBlock* block;
+ RenderObject* obj;
+ unsigned pos;
+ int nextBreakablePosition;
+};
+
+inline bool operator==(const InlineIterator& it1, const InlineIterator& it2)
+{
+ return it1.pos == it2.pos && it1.obj == it2.obj;
+}
+
+inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2)
+{
+ return it1.pos != it2.pos || it1.obj != it2.obj;
+}
+
+static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, InlineBidiResolver* resolver = 0, bool skipInlines = true, bool* endOfInlinePtr = 0)
+{
+ RenderObject* next = 0;
+ bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false;
+ bool endOfInline = false;
+
+ while (current) {
+ next = 0;
+ if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned() && !current->isText()) {
+ next = current->firstChild();
+ if (next && resolver && next->isRenderInline()) {
+ EUnicodeBidi ub = next->style()->unicodeBidi();
+ if (ub != UBNormal) {
+ TextDirection dir = next->style()->direction();
+ WTF::Unicode::Direction d = (ub == Embed
+ ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding : WTF::Unicode::LeftToRightEmbedding)
+ : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride));
+ resolver->embed(d);
+ }
+ }
+ }
+
+ if (!next) {
+ if (!skipInlines && !oldEndOfInline && current->isRenderInline()) {
+ next = current;
+ endOfInline = true;
+ break;
+ }
+
+ while (current && current != block) {
+ if (resolver && current->isRenderInline() && current->style()->unicodeBidi() != UBNormal)
+ resolver->embed(WTF::Unicode::PopDirectionalFormat);
+
+ next = current->nextSibling();
+ if (next) {
+ if (resolver && next->isRenderInline()) {
+ EUnicodeBidi ub = next->style()->unicodeBidi();
+ if (ub != UBNormal) {
+ TextDirection dir = next->style()->direction();
+ WTF::Unicode::Direction d = (ub == Embed
+ ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding: WTF::Unicode::LeftToRightEmbedding)
+ : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride));
+ resolver->embed(d);
+ }
+ }
+ break;
+ }
+
+ current = current->parent();
+ if (!skipInlines && current && current != block && current->isRenderInline()) {
+ next = current;
+ endOfInline = true;
+ break;
+ }
+ }
+ }
+
+ if (!next)
+ break;
+
+ if (next->isText() || next->isFloating() || next->isReplaced() || next->isPositioned()
+ || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines.
+ && next->isRenderInline()))
+ break;
+ current = next;
+ }
+
+ if (endOfInlinePtr)
+ *endOfInlinePtr = endOfInline;
+
+ return next;
+}
+
+static inline RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* resolver, bool skipInlines = true)
+{
+ if (!block->firstChild())
+ return 0;
+
+ RenderObject* o = block->firstChild();
+ if (o->isRenderInline()) {
+ if (resolver) {
+ EUnicodeBidi ub = o->style()->unicodeBidi();
+ if (ub != UBNormal) {
+ TextDirection dir = o->style()->direction();
+ WTF::Unicode::Direction d = (ub == Embed
+ ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding : WTF::Unicode::LeftToRightEmbedding)
+ : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride));
+ resolver->embed(d);
+ }
+ }
+ if (skipInlines && o->firstChild())
+ o = bidiNext(block, o, resolver, skipInlines);
+ else {
+ // Never skip empty inlines.
+ if (resolver)
+ resolver->commitExplicitEmbedding();
+ return o;
+ }
+ }
+
+ if (o && !o->isText() && !o->isReplaced() && !o->isFloating() && !o->isPositioned())
+ o = bidiNext(block, o, resolver, skipInlines);
+
+ if (resolver)
+ resolver->commitExplicitEmbedding();
+ return o;
+}
+
+inline void InlineIterator::increment(InlineBidiResolver* resolver)
+{
+ if (!obj)
+ return;
+ if (obj->isText()) {
+ pos++;
+ if (pos >= toRenderText(obj)->textLength()) {
+ obj = bidiNext(block, obj, resolver);
+ pos = 0;
+ nextBreakablePosition = -1;
+ }
+ } else {
+ obj = bidiNext(block, obj, resolver);
+ pos = 0;
+ nextBreakablePosition = -1;
+ }
+}
+
+inline bool InlineIterator::atEnd() const
+{
+ return !obj;
+}
+
+inline UChar InlineIterator::current() const
+{
+ if (!obj || !obj->isText())
+ return 0;
+
+ RenderText* text = toRenderText(obj);
+ if (pos >= text->textLength())
+ return 0;
+
+ return text->characters()[pos];
+}
+
+ALWAYS_INLINE WTF::Unicode::Direction InlineIterator::direction() const
+{
+ if (UChar c = current())
+ return WTF::Unicode::direction(c);
+
+ if (obj && obj->isListMarker())
+ return obj->style()->direction() == LTR ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
+
+ return WTF::Unicode::OtherNeutral;
+}
+
+template<>
+inline void InlineBidiResolver::increment()
+{
+ current.increment(this);
+}
+
+template <>
+inline void InlineBidiResolver::appendRun()
+{
+ if (!emptyRun && !eor.atEnd()) {
+ int start = sor.pos;
+ RenderObject *obj = sor.obj;
+ while (obj && obj != eor.obj && obj != endOfLine.obj) {
+ RenderBlock::appendRunsForObject(start, obj->length(), obj, *this);
+ start = 0;
+ obj = bidiNext(sor.block, obj);
+ }
+ if (obj) {
+ unsigned pos = obj == eor.obj ? eor.pos : UINT_MAX;
+ if (obj == endOfLine.obj && endOfLine.pos <= pos) {
+ reachedEndOfLine = true;
+ pos = endOfLine.pos;
+ }
+ // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be
+ int end = obj->length() ? pos+1 : 0;
+ RenderBlock::appendRunsForObject(start, end, obj, *this);
+ }
+
+ eor.increment();
+ sor = eor;
+ }
+
+ m_direction = WTF::Unicode::OtherNeutral;
+ m_status.eor = WTF::Unicode::OtherNeutral;
+}
+
+}
+
+#endif // InlineIterator_h
diff --git a/WebCore/rendering/InlineRunBox.h b/WebCore/rendering/InlineRunBox.h
index 0f7c29b..cbc82d5 100644
--- a/WebCore/rendering/InlineRunBox.h
+++ b/WebCore/rendering/InlineRunBox.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the line box implementation for KDE.
- *
* Copyright (C) 2003, 2006 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
diff --git a/WebCore/rendering/InlineTextBox.cpp b/WebCore/rendering/InlineTextBox.cpp
index 619fb95..b7e6de2 100644
--- a/WebCore/rendering/InlineTextBox.cpp
+++ b/WebCore/rendering/InlineTextBox.cpp
@@ -23,9 +23,11 @@
#include "config.h"
#include "InlineTextBox.h"
+#include "Chrome.h"
#include "ChromeClient.h"
#include "Document.h"
#include "Editor.h"
+#include "EllipsisBox.h"
#include "Frame.h"
#include "GraphicsContext.h"
#include "HitTestResult.h"
@@ -81,6 +83,23 @@ RenderObject::SelectionState InlineTextBox::selectionState()
else if (state == RenderObject::SelectionBoth)
state = RenderObject::SelectionNone;
}
+
+ // If there are ellipsis following, make sure their selection is updated.
+ if (m_truncation != cNoTruncation && root()->ellipsisBox()) {
+ EllipsisBox* ellipsis = root()->ellipsisBox();
+ if (state != RenderObject::SelectionNone) {
+ int start, end;
+ selectionStartEnd(start, end);
+ // The ellipsis should be considered to be selected if the end of
+ // the selection is past the beginning of the truncation and the
+ // beginning of the selection is before or at the beginning of the
+ // truncation.
+ ellipsis->setSelectionState(end >= m_truncation && start <= m_truncation ?
+ RenderObject::SelectionInside : RenderObject::SelectionNone);
+ } else
+ ellipsis->setSelectionState(RenderObject::SelectionNone);
+ }
+
return state;
}
@@ -89,7 +108,7 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos)
int sPos = max(startPos - m_start, 0);
int ePos = min(endPos - m_start, (int)m_len);
- if (sPos >= ePos)
+ if (sPos > ePos)
return IntRect();
RenderText* textObj = textRenderer();
@@ -214,7 +233,7 @@ Color correctedTextColor(Color textColor, Color backgroundColor)
return textColor.light();
}
-void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness)
+void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness, ColorSpace colorSpace)
{
int mode = context->textDrawingMode();
if (strokeThickness > 0) {
@@ -225,12 +244,12 @@ void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, con
}
}
- if (mode & cTextFill && fillColor != context->fillColor())
- context->setFillColor(fillColor);
+ if (mode & cTextFill && (fillColor != context->fillColor() || colorSpace != context->fillColorSpace()))
+ context->setFillColor(fillColor, colorSpace);
if (mode & cTextStroke) {
if (strokeColor != context->strokeColor())
- context->setStrokeColor(strokeColor);
+ context->setStrokeColor(strokeColor, colorSpace);
if (strokeThickness != context->strokeThickness())
context->setStrokeThickness(strokeThickness);
}
@@ -254,12 +273,13 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, in
return false;
}
-static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked)
+static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, int truncationPoint, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked)
{
Color fillColor = context->fillColor();
+ ColorSpace fillColorSpace = context->fillColorSpace();
bool opaque = fillColor.alpha() == 255;
if (!opaque)
- context->setFillColor(Color::black);
+ context->setFillColor(Color::black, fillColorSpace);
do {
IntSize extraOffset;
@@ -279,17 +299,17 @@ static void paintTextWithShadows(GraphicsContext* context, const Font& font, con
extraOffset = IntSize(0, 2 * h + max(0, shadowOffset.height()) + shadowBlur);
shadowOffset -= extraOffset;
}
- context->setShadow(shadowOffset, shadowBlur, shadowColor);
+ context->setShadow(shadowOffset, shadowBlur, shadowColor, fillColorSpace);
} else if (!opaque)
- context->setFillColor(fillColor);
+ context->setFillColor(fillColor, fillColorSpace);
if (startOffset <= endOffset)
context->drawText(font, textRun, textOrigin + extraOffset, startOffset, endOffset);
else {
if (endOffset > 0)
context->drawText(font, textRun, textOrigin + extraOffset, 0, endOffset);
- if (startOffset < textRun.length())
- context->drawText(font, textRun, textOrigin + extraOffset, startOffset);
+ if (startOffset < truncationPoint)
+ context->drawText(font, textRun, textOrigin + extraOffset, startOffset, truncationPoint);
}
if (!shadow)
@@ -312,8 +332,12 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines);
- int xPos = tx + m_x - parent()->maxHorizontalVisualOverflow();
- int w = width() + 2 * parent()->maxHorizontalVisualOverflow();
+ // FIXME: Technically we're potentially incorporating other visual overflow that had nothing to do with us.
+ // Would it be simpler to just check our own shadow and stroke overflow by hand here?
+ int leftOverflow = parent()->x() - parent()->leftVisualOverflow();
+ int rightOverflow = parent()->rightVisualOverflow() - (parent()->x() + parent()->width());
+ int xPos = tx + m_x - leftOverflow;
+ int w = width() + leftOverflow + rightOverflow;
if (xPos >= paintInfo.rect.right() || xPos + w <= paintInfo.rect.x())
return;
@@ -455,18 +479,25 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
if (paintSelectedTextOnly || paintSelectedTextSeparately)
selectionStartEnd(sPos, ePos);
+ int length = m_len;
+ if (m_truncation != cNoTruncation) {
+ sPos = min<int>(sPos, m_truncation);
+ ePos = min<int>(ePos, m_truncation);
+ length = m_truncation;
+ }
+
if (!paintSelectedTextOnly) {
// For stroked painting, we have to change the text drawing mode. It's probably dangerous to leave that mutated as a side
// effect, so only when we know we're stroking, do a save/restore.
if (textStrokeWidth > 0)
context->save();
- updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth);
+ updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace());
if (!paintSelectedTextSeparately || ePos <= sPos) {
// FIXME: Truncate right-to-left text correctly.
- paintTextWithShadows(context, font, textRun, 0, m_truncation == cNoTruncation ? m_len : m_truncation, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
+ paintTextWithShadows(context, font, textRun, 0, length, length, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
} else
- paintTextWithShadows(context, font, textRun, ePos, sPos, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
+ paintTextWithShadows(context, font, textRun, ePos, sPos, length, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
if (textStrokeWidth > 0)
context->restore();
@@ -477,8 +508,8 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
if (selectionStrokeWidth > 0)
context->save();
- updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth);
- paintTextWithShadows(context, font, textRun, sPos, ePos, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0);
+ updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth, styleToUse->colorSpace());
+ paintTextWithShadows(context, font, textRun, sPos, ePos, length, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0);
if (selectionStrokeWidth > 0)
context->restore();
@@ -486,7 +517,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
// Paint decorations
if (d != TDNONE && paintInfo.phase != PaintPhaseSelection && styleToUse->htmlHacks()) {
- context->setStrokeColor(styleToUse->color());
+ context->setStrokeColor(styleToUse->color(), styleToUse->colorSpace());
paintDecoration(context, tx, ty, d, textShadow);
}
@@ -557,13 +588,16 @@ void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, Ren
c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue());
context->save();
- updateGraphicsContext(context, c, c, 0); // Don't draw text at all!
+ updateGraphicsContext(context, c, c, 0, style->colorSpace()); // Don't draw text at all!
int y = selectionTop();
int h = selectionHeight();
+ // If the text is truncated, let the thing being painted in the truncation
+ // draw its own highlight.
+ int length = m_truncation != cNoTruncation ? m_truncation : m_len;
context->clip(IntRect(m_x + tx, y + ty, m_width, h));
- context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd,
+ context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, length, textRenderer()->allowTabs(), textPos(), m_toAdd,
direction() == RTL, m_dirOverride || style->visuallyOrdered()),
- IntPoint(m_x + tx, y + ty), h, c, sPos, ePos);
+ IntPoint(m_x + tx, y + ty), h, c, style->colorSpace(), sPos, ePos);
context->restore();
}
@@ -580,13 +614,13 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx,
Color c = Color(225, 221, 85);
- updateGraphicsContext(context, c, c, 0); // Don't draw text at all!
+ updateGraphicsContext(context, c, c, 0, style->colorSpace()); // Don't draw text at all!
int y = selectionTop();
int h = selectionHeight();
context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd,
direction() == RTL, m_dirOverride || style->visuallyOrdered()),
- IntPoint(m_x + tx, y + ty), h, c, sPos, ePos);
+ IntPoint(m_x + tx, y + ty), h, c, style->colorSpace(), sPos, ePos);
context->restore();
}
@@ -656,6 +690,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in
setClip = true;
}
+ ColorSpace colorSpace = renderer()->style()->colorSpace();
bool setShadow = false;
do {
@@ -665,24 +700,24 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in
ty -= extraOffset;
extraOffset = 0;
}
- context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color);
+ context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color, colorSpace);
setShadow = true;
shadow = shadow->next;
}
if (deco & UNDERLINE) {
- context->setStrokeColor(underline);
+ context->setStrokeColor(underline, colorSpace);
context->setStrokeStyle(SolidStroke);
// Leave one pixel of white between the baseline and the underline.
context->drawLineForText(IntPoint(tx, ty + baseline + 1), width, isPrinting);
}
if (deco & OVERLINE) {
- context->setStrokeColor(overline);
+ context->setStrokeColor(overline, colorSpace);
context->setStrokeStyle(SolidStroke);
context->drawLineForText(IntPoint(tx, ty), width, isPrinting);
}
if (deco & LINE_THROUGH) {
- context->setStrokeColor(linethrough);
+ context->setStrokeColor(linethrough, colorSpace);
context->setStrokeStyle(SolidStroke);
context->drawLineForText(IntPoint(tx, ty + 2 * baseline / 3), width, isPrinting);
}
@@ -694,7 +729,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in
context->clearShadow();
}
-void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font, bool grammar)
+void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, const DocumentMarker& marker, RenderStyle* style, const Font& font, bool grammar)
{
// Never print spelling/grammar markers (5327887)
if (textRenderer()->document()->printing())
@@ -733,8 +768,11 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in
// Store rendered rects for bad grammar markers, so we can hit-test against it elsewhere in order to
// display a toolTip. We don't do this for misspelling markers.
- if (grammar)
+ if (grammar) {
+ markerRect.move(-tx, -ty);
+ markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect);
+ }
}
// IMPORTANT: The misspelling underline is not considered when calculating the text bounds, so we have to
@@ -757,7 +795,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in
pt->drawLineForMisspellingOrBadGrammar(IntPoint(tx + m_x + start, ty + m_y + underlineOffset), width, grammar);
}
-void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font)
+void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, const DocumentMarker& marker, RenderStyle* style, const Font& font)
{
// Use same y positioning and height as for selection, so that when the selection and this highlight are on
// the same word there are no pieces sticking out.
@@ -767,10 +805,10 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, Do
int sPos = max(marker.startOffset - m_start, (unsigned)0);
int ePos = min(marker.endOffset - m_start, (unsigned)m_len);
TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered());
- IntPoint startPoint = IntPoint(m_x + tx, y + ty);
- // Always compute and store the rect associated with this marker
- IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, sPos, ePos));
+ // Always compute and store the rect associated with this marker. The computed rect is in absolute coordinates.
+ IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, IntPoint(m_x, y), h, sPos, ePos));
+ markerRect = root()->block()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect);
// Optionally highlight the text
@@ -779,14 +817,14 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, Do
renderer()->theme()->platformActiveTextSearchHighlightColor() :
renderer()->theme()->platformInactiveTextSearchHighlightColor();
pt->save();
- updateGraphicsContext(pt, color, color, 0); // Don't draw text at all!
+ updateGraphicsContext(pt, color, color, 0, style->colorSpace()); // Don't draw text at all!
pt->clip(IntRect(tx + m_x, ty + y, m_width, h));
- pt->drawHighlightForText(font, run, startPoint, h, color, sPos, ePos);
+ pt->drawHighlightForText(font, run, IntPoint(m_x + tx, y + ty), h, color, style->colorSpace(), sPos, ePos);
pt->restore();
}
}
-void InlineTextBox::computeRectForReplacementMarker(int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font)
+void InlineTextBox::computeRectForReplacementMarker(int /*tx*/, int /*ty*/, const DocumentMarker& marker, RenderStyle* style, const Font& font)
{
// Replacement markers are not actually drawn, but their rects need to be computed for hit testing.
int y = selectionTop();
@@ -795,10 +833,11 @@ void InlineTextBox::computeRectForReplacementMarker(int tx, int ty, DocumentMark
int sPos = max(marker.startOffset - m_start, (unsigned)0);
int ePos = min(marker.endOffset - m_start, (unsigned)m_len);
TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered());
- IntPoint startPoint = IntPoint(m_x + tx, y + ty);
+ IntPoint startPoint = IntPoint(m_x, y);
// Compute and store the rect associated with this marker.
IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, sPos, ePos));
+ markerRect = root()->block()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect);
}
@@ -813,7 +852,7 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, Re
// Give any document markers that touch this run a chance to draw before the text has been drawn.
// Note end() points at the last char, not one past it like endOffset and ranges do.
for ( ; markerIt != markers.end(); markerIt++) {
- DocumentMarker marker = *markerIt;
+ const DocumentMarker& marker = *markerIt;
// Paint either the background markers or the foreground markers, but not both
switch (marker.type) {
@@ -907,7 +946,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int
start += 1;
width -= 2;
- ctx->setStrokeColor(underline.color);
+ ctx->setStrokeColor(underline.color, renderer()->style()->colorSpace());
ctx->setStrokeThickness(lineThickness);
ctx->drawLineForText(IntPoint(tx + start, ty + height() - lineThickness), width, textRenderer()->document()->printing());
}
@@ -932,7 +971,7 @@ int InlineTextBox::textPos() const
if (x() == 0)
return 0;
- RenderBlock *blockElement = renderer()->containingBlock();
+ RenderBlock* blockElement = renderer()->containingBlock();
return direction() == RTL ? x() - blockElement->borderRight() - blockElement->paddingRight()
: x() - blockElement->borderLeft() - blockElement->paddingLeft();
}
@@ -943,7 +982,7 @@ int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const
return 0;
RenderText* text = toRenderText(renderer());
- RenderStyle *style = text->style(m_firstLine);
+ RenderStyle* style = text->style(m_firstLine);
const Font* f = &style->font();
return f->offsetForPosition(TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
_x - m_x, includePartialGlyphs);
diff --git a/WebCore/rendering/InlineTextBox.h b/WebCore/rendering/InlineTextBox.h
index 3bbb453..0a83ddd 100644
--- a/WebCore/rendering/InlineTextBox.h
+++ b/WebCore/rendering/InlineTextBox.h
@@ -34,7 +34,7 @@ const unsigned short cNoTruncation = USHRT_MAX;
const unsigned short cFullTruncation = USHRT_MAX - 1;
// Helper functions shared by InlineTextBox / SVGRootInlineBox
-void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness);
+void updateGraphicsContext(GraphicsContext*, const Color& fillColor, const Color& strokeColor, float strokeThickness, ColorSpace);
Color correctedTextColor(Color textColor, Color backgroundColor);
class InlineTextBox : public InlineRunBox {
@@ -62,6 +62,8 @@ public:
void setFallbackFonts(const HashSet<const SimpleFontData*>&);
void takeFallbackFonts(Vector<const SimpleFontData*>&);
+ unsigned short truncation() { return m_truncation; }
+
private:
virtual int selectionTop();
virtual int selectionHeight();
@@ -131,9 +133,9 @@ protected:
private:
void paintDecoration(GraphicsContext*, int tx, int ty, int decoration, ShadowData*);
void paintSelection(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&);
- void paintSpellingOrGrammarMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font&, bool grammar);
- void paintTextMatchMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font&);
- void computeRectForReplacementMarker(int tx, int ty, DocumentMarker, RenderStyle*, const Font&);
+ void paintSpellingOrGrammarMarker(GraphicsContext*, int tx, int ty, const DocumentMarker&, RenderStyle*, const Font&, bool grammar);
+ void paintTextMatchMarker(GraphicsContext*, int tx, int ty, const DocumentMarker&, RenderStyle*, const Font&);
+ void computeRectForReplacementMarker(int tx, int ty, const DocumentMarker&, RenderStyle*, const Font&);
};
inline RenderText* InlineTextBox::textRenderer() const
diff --git a/WebCore/rendering/MediaControlElements.cpp b/WebCore/rendering/MediaControlElements.cpp
index 352f270..2b7a8c8 100644
--- a/WebCore/rendering/MediaControlElements.cpp
+++ b/WebCore/rendering/MediaControlElements.cpp
@@ -32,28 +32,38 @@
#include "MediaControlElements.h"
-#include "LocalizedStrings.h"
#include "EventNames.h"
#include "FloatConversion.h"
#include "Frame.h"
#include "HTMLNames.h"
+#include "LocalizedStrings.h"
#include "MouseEvent.h"
+#include "Page.h"
#include "RenderMedia.h"
#include "RenderSlider.h"
#include "RenderTheme.h"
-#include "CString.h"
namespace WebCore {
using namespace HTMLNames;
-// FIXME: These constants may need to be tweaked to better match the seeking in the QT plugin
+HTMLMediaElement* toParentMediaElement(RenderObject* o)
+{
+ Node* node = o->node();
+ Node* mediaNode = node ? node->shadowAncestorNode() : 0;
+ if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag)))
+ return 0;
+
+ return static_cast<HTMLMediaElement*>(mediaNode);
+}
+
+// FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
static const float cSeekRepeatDelay = 0.1f;
static const float cStepTime = 0.07f;
static const float cSeekTime = 0.2f;
-MediaControlShadowRootElement::MediaControlShadowRootElement(Document* doc, HTMLMediaElement* mediaElement)
- : HTMLDivElement(divTag, doc)
+MediaControlShadowRootElement::MediaControlShadowRootElement(Document* document, HTMLMediaElement* mediaElement)
+ : HTMLDivElement(divTag, document)
, m_mediaElement(mediaElement)
{
RefPtr<RenderStyle> rootStyle = RenderStyle::create();
@@ -76,14 +86,36 @@ void MediaControlShadowRootElement::updateStyle()
}
// ----------------------------
-
-MediaControlElement::MediaControlElement(Document* doc, PseudoId pseudo, HTMLMediaElement* mediaElement)
- : HTMLDivElement(divTag, doc)
+MediaControlElement::MediaControlElement(Document* document, PseudoId pseudo, HTMLMediaElement* mediaElement)
+ : HTMLDivElement(divTag, document)
, m_mediaElement(mediaElement)
, m_pseudoStyleId(pseudo)
{
setInDocument(true);
+ switch (pseudo) {
+ case MEDIA_CONTROLS_CURRENT_TIME_DISPLAY:
+ m_displayType = MediaCurrentTimeDisplay;
+ break;
+ case MEDIA_CONTROLS_TIME_REMAINING_DISPLAY:
+ m_displayType = MediaTimeRemainingDisplay;
+ break;
+ case MEDIA_CONTROLS_TIMELINE_CONTAINER:
+ m_displayType = MediaTimelineContainer;
+ break;
+ case MEDIA_CONTROLS_STATUS_DISPLAY:
+ m_displayType = MediaStatusDisplay;
+ break;
+ case MEDIA_CONTROLS_PANEL:
+ m_displayType = MediaControlsPanel;
+ break;
+ case MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER:
+ m_displayType = MediaVolumeSliderContainer;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
}
void MediaControlElement::attachToParent(Element* parent)
@@ -114,7 +146,10 @@ PassRefPtr<RenderStyle> MediaControlElement::styleForElement()
bool MediaControlElement::rendererIsNeeded(RenderStyle* style)
{
- return HTMLDivElement::rendererIsNeeded(style) && parent() && parent()->renderer();
+ ASSERT(document()->page());
+
+ return HTMLDivElement::rendererIsNeeded(style) && parent() && parent()->renderer()
+ && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), m_mediaElement));
}
void MediaControlElement::attach()
@@ -165,8 +200,8 @@ void MediaControlElement::updateStyle()
// ----------------------------
-MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(Document* doc, HTMLMediaElement* element)
-: MediaControlElement(doc, MEDIA_CONTROLS_TIMELINE_CONTAINER, element)
+MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(Document* document, HTMLMediaElement* element)
+ : MediaControlElement(document, MEDIA_CONTROLS_TIMELINE_CONTAINER, element)
{
}
@@ -185,12 +220,54 @@ bool MediaControlTimelineContainerElement::rendererIsNeeded(RenderStyle* style)
return !isnan(duration) && !isinf(duration);
}
-
// ----------------------------
-MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(Document* doc, HTMLMediaElement* element)
-: MediaControlElement(doc, MEDIA_CONTROLS_STATUS_DISPLAY, element)
-, m_stateBeingDisplayed(Nothing)
+MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(Document* doc, HTMLMediaElement* element)
+ : MediaControlElement(doc, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER, element)
+ , m_isVisible(false)
+ , m_x(0)
+ , m_y(0)
+{
+}
+
+PassRefPtr<RenderStyle> MediaControlVolumeSliderContainerElement::styleForElement()
+{
+ RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
+ style->setPosition(AbsolutePosition);
+ style->setLeft(Length(m_x, Fixed));
+ style->setTop(Length(m_y, Fixed));
+ style->setDisplay(m_isVisible ? BLOCK : NONE);
+ return style;
+}
+
+void MediaControlVolumeSliderContainerElement::setVisible(bool visible)
+{
+ if (visible == m_isVisible)
+ return;
+ m_isVisible = visible;
+}
+
+void MediaControlVolumeSliderContainerElement::setPosition(int x, int y)
+{
+ if (x == m_x && y == m_y)
+ return;
+ m_x = x;
+ m_y = y;
+}
+
+bool MediaControlVolumeSliderContainerElement::hitTest(const IntPoint& absPoint)
+{
+ if (renderer() && renderer()->style()->hasAppearance())
+ return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
+
+ return false;
+}
+
+// ----------------------------
+
+MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(Document* document, HTMLMediaElement* element)
+ : MediaControlElement(document, MEDIA_CONTROLS_STATUS_DISPLAY, element)
+ , m_stateBeingDisplayed(Nothing)
{
}
@@ -235,14 +312,49 @@ bool MediaControlStatusDisplayElement::rendererIsNeeded(RenderStyle* style)
// ----------------------------
-MediaControlInputElement::MediaControlInputElement(Document* doc, PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement, MediaControlElementType displayType)
- : HTMLInputElement(inputTag, doc)
+MediaControlInputElement::MediaControlInputElement(Document* document, PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement)
+ : HTMLInputElement(inputTag, document)
, m_mediaElement(mediaElement)
, m_pseudoStyleId(pseudo)
- , m_displayType(displayType)
{
setInputType(type);
setInDocument(true);
+
+ switch (pseudo) {
+ case MEDIA_CONTROLS_MUTE_BUTTON:
+ m_displayType = MediaMuteButton;
+ break;
+ case MEDIA_CONTROLS_PLAY_BUTTON:
+ m_displayType = MediaPlayButton;
+ break;
+ case MEDIA_CONTROLS_SEEK_FORWARD_BUTTON:
+ m_displayType = MediaSeekForwardButton;
+ break;
+ case MEDIA_CONTROLS_SEEK_BACK_BUTTON:
+ m_displayType = MediaSeekBackButton;
+ break;
+ case MEDIA_CONTROLS_FULLSCREEN_BUTTON:
+ m_displayType = MediaFullscreenButton;
+ break;
+ case MEDIA_CONTROLS_TIMELINE:
+ m_displayType = MediaSlider;
+ break;
+ case MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON:
+ m_displayType = MediaReturnToRealtimeButton;
+ break;
+ case MEDIA_CONTROLS_REWIND_BUTTON:
+ m_displayType = MediaRewindButton;
+ break;
+ case MEDIA_CONTROLS_VOLUME_SLIDER:
+ m_displayType = MediaVolumeSlider;
+ break;
+ case MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON:
+ m_displayType = MediaShowClosedCaptionsButton;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
}
void MediaControlInputElement::attachToParent(Element* parent)
@@ -265,7 +377,10 @@ PassRefPtr<RenderStyle> MediaControlInputElement::styleForElement()
bool MediaControlInputElement::rendererIsNeeded(RenderStyle* style)
{
- return HTMLInputElement::rendererIsNeeded(style) && parent() && parent()->renderer();
+ ASSERT(document()->page());
+
+ return HTMLInputElement::rendererIsNeeded(style) && parent() && parent()->renderer()
+ && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), m_mediaElement));
}
void MediaControlInputElement::attach()
@@ -324,14 +439,14 @@ void MediaControlInputElement::setDisplayType(MediaControlElementType displayTyp
return;
m_displayType = displayType;
- if (RenderObject* o = renderer())
- o->repaint();
+ if (RenderObject* object = renderer())
+ object->repaint();
}
// ----------------------------
-MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* doc, HTMLMediaElement* element)
- : MediaControlInputElement(doc, MEDIA_CONTROLS_MUTE_BUTTON, "button", element, element->muted() ? MediaUnMuteButton : MediaMuteButton)
+MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* document, HTMLMediaElement* element)
+ : MediaControlInputElement(document, MEDIA_CONTROLS_MUTE_BUTTON, "button", element)
{
}
@@ -351,8 +466,8 @@ void MediaControlMuteButtonElement::updateDisplayType()
// ----------------------------
-MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* doc, HTMLMediaElement* element)
- : MediaControlInputElement(doc, MEDIA_CONTROLS_PLAY_BUTTON, "button", element, element->canPlay() ? MediaPlayButton : MediaPauseButton)
+MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* document, HTMLMediaElement* element)
+ : MediaControlInputElement(document, MEDIA_CONTROLS_PLAY_BUTTON, "button", element)
{
}
@@ -372,9 +487,9 @@ void MediaControlPlayButtonElement::updateDisplayType()
// ----------------------------
-MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* doc, HTMLMediaElement* element, bool forward)
- : MediaControlInputElement(doc, forward ? MEDIA_CONTROLS_SEEK_FORWARD_BUTTON : MEDIA_CONTROLS_SEEK_BACK_BUTTON,
- "button", element, forward ? MediaSeekForwardButton : MediaSeekBackButton)
+MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* document, HTMLMediaElement* element, bool forward)
+ : MediaControlInputElement(document, forward ? MEDIA_CONTROLS_SEEK_FORWARD_BUTTON : MEDIA_CONTROLS_SEEK_BACK_BUTTON,
+ "button", element)
, m_forward(forward)
, m_seeking(false)
, m_capturing(false)
@@ -389,7 +504,7 @@ void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
m_capturing = true;
frame->eventHandler()->setCapturingMouseEventsNode(this);
}
- m_mediaElement->pause();
+ m_mediaElement->pause(event->fromUserGesture());
m_seekTimer.startRepeating(cSeekRepeatDelay);
event->setDefaultHandled();
} else if (event->type() == eventNames().mouseupEvent) {
@@ -432,8 +547,8 @@ void MediaControlSeekButtonElement::detach()
// ----------------------------
-MediaControlRewindButtonElement::MediaControlRewindButtonElement(Document* doc, HTMLMediaElement* element)
-: MediaControlInputElement(doc, MEDIA_CONTROLS_REWIND_BUTTON, "button", element, MediaRewindButton)
+MediaControlRewindButtonElement::MediaControlRewindButtonElement(Document* document, HTMLMediaElement* element)
+ : MediaControlInputElement(document, MEDIA_CONTROLS_REWIND_BUTTON, "button", element)
{
}
@@ -446,44 +561,58 @@ void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
HTMLInputElement::defaultEventHandler(event);
}
-bool MediaControlRewindButtonElement::rendererIsNeeded(RenderStyle* style)
+
+// ----------------------------
+
+MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(Document* document, HTMLMediaElement* element)
+ : MediaControlInputElement(document, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, "button", element)
+{
+}
+
+void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
{
- return MediaControlInputElement::rendererIsNeeded(style) && m_mediaElement->movieLoadType() != MediaPlayer::LiveStream;
+ if (event->type() == eventNames().clickEvent) {
+ m_mediaElement->returnToRealtime();
+ event->setDefaultHandled();
+ }
+ HTMLInputElement::defaultEventHandler(event);
}
// ----------------------------
-MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(Document* doc, HTMLMediaElement* element)
-: MediaControlInputElement(doc, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, "button", element, MediaReturnToRealtimeButton)
+MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* doc, HTMLMediaElement* element)
+ : MediaControlInputElement(doc, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON, "button", element)
{
}
-void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
+void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
- m_mediaElement->returnToRealtime();
+ m_mediaElement->setClosedCaptionsVisible(!m_mediaElement->closedCaptionsVisible());
+ setChecked(m_mediaElement->closedCaptionsVisible());
event->setDefaultHandled();
}
HTMLInputElement::defaultEventHandler(event);
}
-bool MediaControlReturnToRealtimeButtonElement::rendererIsNeeded(RenderStyle* style)
+void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
{
- return MediaControlInputElement::rendererIsNeeded(style) && m_mediaElement->movieLoadType() == MediaPlayer::LiveStream;
+ setDisplayType(m_mediaElement->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
}
+
// ----------------------------
MediaControlTimelineElement::MediaControlTimelineElement(Document* document, HTMLMediaElement* element)
- : MediaControlInputElement(document, MEDIA_CONTROLS_TIMELINE, "range", element, MediaTimelineContainer)
-{
+ : MediaControlInputElement(document, MEDIA_CONTROLS_TIMELINE, "range", element)
+{
}
void MediaControlTimelineElement::defaultEventHandler(Event* event)
{
- // Left button is 0. Accepts only if mouse event is from left button.
- if (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button())
+ // Left button is 0. Rejects mouse events not from left button.
+ if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
return;
if (event->type() == eventNames().mousedownEvent)
@@ -520,29 +649,59 @@ void MediaControlTimelineElement::update(bool updateDuration)
// ----------------------------
-MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* doc, HTMLMediaElement* element)
- : MediaControlInputElement(doc, MEDIA_CONTROLS_FULLSCREEN_BUTTON, "button", element, MediaFullscreenButton)
+MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(Document* document, HTMLMediaElement* element)
+ : MediaControlInputElement(document, MEDIA_CONTROLS_VOLUME_SLIDER, "range", element)
{
}
-void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
+void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
{
- if (event->type() == eventNames().clickEvent) {
- event->setDefaultHandled();
+ // Left button is 0. Rejects mouse events not from left button.
+ if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
+ return;
+
+ MediaControlInputElement::defaultEventHandler(event);
+
+ if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
+ return;
+
+ float volume = narrowPrecisionToFloat(value().toDouble());
+ if (volume != m_mediaElement->volume()) {
+ ExceptionCode ec = 0;
+ m_mediaElement->setVolume(volume, ec);
+ ASSERT(!ec);
}
- HTMLInputElement::defaultEventHandler(event);
}
-bool MediaControlFullscreenButtonElement::rendererIsNeeded(RenderStyle* style)
+void MediaControlVolumeSliderElement::update()
{
- return MediaControlInputElement::rendererIsNeeded(style) && m_mediaElement->supportsFullscreen();
+ float volume = m_mediaElement->volume();
+ if (value().toFloat() != volume)
+ setValue(String::number(volume));
+ MediaControlInputElement::update();
}
+// ----------------------------
+
+MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* document, HTMLMediaElement* element)
+ : MediaControlInputElement(document, MEDIA_CONTROLS_FULLSCREEN_BUTTON, "button", element)
+{
+}
+
+void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
+{
+ if (event->type() == eventNames().clickEvent) {
+ m_mediaElement->enterFullscreen();
+ event->setDefaultHandled();
+ }
+ HTMLInputElement::defaultEventHandler(event);
+}
// ----------------------------
-MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* doc, PseudoId pseudo, HTMLMediaElement* element)
- : MediaControlElement(doc, pseudo, element)
+MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* document, PseudoId pseudo, HTMLMediaElement* element)
+ : MediaControlElement(document, pseudo, element)
+ , m_currentValue(0)
, m_isVisible(true)
{
}
@@ -572,6 +731,11 @@ void MediaControlTimeDisplayElement::setVisible(bool visible)
renderer()->setStyle(style.get());
}
+void MediaControlTimeDisplayElement::setCurrentValue(float time)
+{
+ m_currentValue = time;
+}
+
} //namespace WebCore
#endif // enable(video)
diff --git a/WebCore/rendering/MediaControlElements.h b/WebCore/rendering/MediaControlElements.h
index d5fa5d2..21831ce 100644
--- a/WebCore/rendering/MediaControlElements.h
+++ b/WebCore/rendering/MediaControlElements.h
@@ -54,15 +54,22 @@ enum MediaControlElementType {
MediaSliderThumb,
MediaRewindButton,
MediaReturnToRealtimeButton,
+ MediaShowClosedCaptionsButton,
+ MediaHideClosedCaptionsButton,
MediaUnMuteButton,
MediaPauseButton,
MediaTimelineContainer,
- MediaCurrentTimeDisplay,
+ MediaCurrentTimeDisplay,
MediaTimeRemainingDisplay,
MediaStatusDisplay,
- MediaControlsPanel
+ MediaControlsPanel,
+ MediaVolumeSliderContainer,
+ MediaVolumeSlider,
+ MediaVolumeSliderThumb
};
+HTMLMediaElement* toParentMediaElement(RenderObject*);
+
class MediaControlShadowRootElement : public HTMLDivElement {
public:
MediaControlShadowRootElement(Document*, HTMLMediaElement*);
@@ -89,9 +96,15 @@ public:
void update();
virtual void updateStyle();
+ MediaControlElementType displayType() const { return m_displayType; }
+
+ HTMLMediaElement* mediaElement() const { return m_mediaElement; }
+ virtual bool isMediaControlElement() const { return true; }
+
protected:
HTMLMediaElement* m_mediaElement;
PseudoId m_pseudoStyleId;
+ MediaControlElementType m_displayType; // some elements can show multiple types (e.g. play/pause)
};
// ----------------------------
@@ -104,6 +117,22 @@ public:
// ----------------------------
+class MediaControlVolumeSliderContainerElement : public MediaControlElement {
+public:
+ MediaControlVolumeSliderContainerElement(Document*, HTMLMediaElement*);
+ virtual PassRefPtr<RenderStyle> styleForElement();
+ void setVisible(bool);
+ bool isVisible() { return m_isVisible; }
+ void setPosition(int x, int y);
+ bool hitTest(const IntPoint& absPoint);
+
+private:
+ bool m_isVisible;
+ int m_x, m_y;
+};
+
+// ----------------------------
+
class MediaControlStatusDisplayElement : public MediaControlElement {
public:
MediaControlStatusDisplayElement(Document*, HTMLMediaElement*);
@@ -118,7 +147,7 @@ private:
class MediaControlInputElement : public HTMLInputElement {
public:
- MediaControlInputElement(Document*, PseudoId, const String& type, HTMLMediaElement*, MediaControlElementType);
+ MediaControlInputElement(Document*, PseudoId, const String& type, HTMLMediaElement*);
virtual void attach();
virtual bool rendererIsNeeded(RenderStyle*);
@@ -130,13 +159,16 @@ public:
bool hitTest(const IntPoint& absPoint);
MediaControlElementType displayType() const { return m_displayType; }
+ HTMLMediaElement* mediaElement() const { return m_mediaElement; }
+ virtual bool isMediaControlElement() const { return true; }
+
protected:
virtual void updateDisplayType() { }
void setDisplayType(MediaControlElementType);
HTMLMediaElement* m_mediaElement;
PseudoId m_pseudoStyleId;
- MediaControlElementType m_displayType; // some elements can show multiple types (e.g. play/pause)
+ MediaControlElementType m_displayType;
};
// ----------------------------
@@ -179,7 +211,6 @@ class MediaControlRewindButtonElement : public MediaControlInputElement {
public:
MediaControlRewindButtonElement(Document*, HTMLMediaElement*);
virtual void defaultEventHandler(Event*);
- virtual bool rendererIsNeeded(RenderStyle*);
};
// ----------------------------
@@ -188,7 +219,15 @@ class MediaControlReturnToRealtimeButtonElement : public MediaControlInputElemen
public:
MediaControlReturnToRealtimeButtonElement(Document*, HTMLMediaElement*);
virtual void defaultEventHandler(Event*);
- virtual bool rendererIsNeeded(RenderStyle*);
+};
+
+// ----------------------------
+
+class MediaControlToggleClosedCaptionsButtonElement : public MediaControlInputElement {
+public:
+ MediaControlToggleClosedCaptionsButtonElement(Document*, HTMLMediaElement*);
+ virtual void defaultEventHandler(Event*);
+ virtual void updateDisplayType();
};
// ----------------------------
@@ -202,11 +241,19 @@ public:
// ----------------------------
+class MediaControlVolumeSliderElement : public MediaControlInputElement {
+public:
+ MediaControlVolumeSliderElement(Document*, HTMLMediaElement*);
+ virtual void defaultEventHandler(Event*);
+ virtual void update();
+};
+
+// ----------------------------
+
class MediaControlFullscreenButtonElement : public MediaControlInputElement {
public:
MediaControlFullscreenButtonElement(Document*, HTMLMediaElement*);
virtual void defaultEventHandler(Event*);
- virtual bool rendererIsNeeded(RenderStyle*);
};
// ----------------------------
@@ -217,7 +264,11 @@ public:
void setVisible(bool);
virtual PassRefPtr<RenderStyle> styleForElement();
+ void setCurrentValue(float);
+ float currentValue() const { return m_currentValue; }
+
private:
+ float m_currentValue;
bool m_isVisible;
};
diff --git a/WebCore/rendering/PointerEventsHitRules.cpp b/WebCore/rendering/PointerEventsHitRules.cpp
index 214fb09..ababcfd 100644
--- a/WebCore/rendering/PointerEventsHitRules.cpp
+++ b/WebCore/rendering/PointerEventsHitRules.cpp
@@ -1,8 +1,6 @@
/*
Copyright (C) 2007 Rob Buis <buis@kde.org>
- This file is part of the KDE project
-
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
diff --git a/WebCore/rendering/PointerEventsHitRules.h b/WebCore/rendering/PointerEventsHitRules.h
index 3d8939a..c17c19c 100644
--- a/WebCore/rendering/PointerEventsHitRules.h
+++ b/WebCore/rendering/PointerEventsHitRules.h
@@ -1,8 +1,6 @@
/*
Copyright (C) 2007 Rob Buis <buis@kde.org>
- This file is part of the KDE project
-
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
diff --git a/WebCore/rendering/RenderArena.cpp b/WebCore/rendering/RenderArena.cpp
index 3ab4dff..41f33de 100644
--- a/WebCore/rendering/RenderArena.cpp
+++ b/WebCore/rendering/RenderArena.cpp
@@ -114,7 +114,7 @@ void RenderArena::free(size_t size, void* ptr)
// Use standard free so that memory debugging tools work.
RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(ptr) - 1;
ASSERT(header->signature == signature);
- ASSERT(header->size == size);
+ ASSERT_UNUSED(size, header->size == size);
ASSERT(header->arena == this);
header->signature = signatureDead;
::free(header);
diff --git a/WebCore/rendering/RenderArena.h b/WebCore/rendering/RenderArena.h
index ca35361..edf052a 100644
--- a/WebCore/rendering/RenderArena.h
+++ b/WebCore/rendering/RenderArena.h
@@ -36,12 +36,13 @@
#define RenderArena_h
#include "Arena.h"
+#include <wtf/Noncopyable.h>
namespace WebCore {
static const size_t gMaxRecycledSize = 400;
-class RenderArena {
+class RenderArena : public Noncopyable {
public:
RenderArena(unsigned arenaSize = 4096);
~RenderArena();
diff --git a/WebCore/rendering/RenderBR.cpp b/WebCore/rendering/RenderBR.cpp
index f407099..340d6b7 100644
--- a/WebCore/rendering/RenderBR.cpp
+++ b/WebCore/rendering/RenderBR.cpp
@@ -1,6 +1,4 @@
/**
- * This file is part of the DOM implementation for KDE.
- *
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
* Copyright (C) 2006 Apple Computer, Inc.
*
diff --git a/WebCore/rendering/RenderBR.h b/WebCore/rendering/RenderBR.h
index 7eae8ea..8850d46 100644
--- a/WebCore/rendering/RenderBR.h
+++ b/WebCore/rendering/RenderBR.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the DOM implementation for KDE.
- *
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
*
* This library is free software; you can redistribute it and/or
diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp
index 73648d1..eabb054 100644
--- a/WebCore/rendering/RenderBlock.cpp
+++ b/WebCore/rendering/RenderBlock.cpp
@@ -2,7 +2,7 @@
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2007 David Smith (catfish.man@gmail.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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,6 +33,7 @@
#include "HTMLNames.h"
#include "HitTestResult.h"
#include "InlineTextBox.h"
+#include "RenderFlexibleBox.h"
#include "RenderImage.h"
#include "RenderInline.h"
#include "RenderMarquee.h"
@@ -43,6 +44,7 @@
#include "RenderView.h"
#include "SelectionController.h"
#include "Settings.h"
+#include "TransformState.h"
#include <wtf/StdLibExtras.h>
#ifdef ANDROID_LAYOUT
@@ -61,13 +63,7 @@ static const int verticalLineClickFudgeFactor = 3;
using namespace HTMLNames;
-static void moveChild(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* from, RenderObjectChildList* fromChildList, RenderObject* child)
-{
- ASSERT(from == child->parent());
- toChildList->appendChildNode(to, fromChildList->removeChildNode(from, child, false), false);
-}
-
-struct ColumnInfo {
+struct ColumnInfo : public Noncopyable {
ColumnInfo()
: m_desiredColumnWidth(0)
, m_desiredColumnCount(1)
@@ -118,8 +114,6 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom)
m_posMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(true) : 0;
m_negMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(false) : 0;
-
- m_selfCollapsingBlockClearedFloat = false;
m_topQuirk = m_bottomQuirk = m_determinedTopQuirk = false;
}
@@ -132,10 +126,6 @@ RenderBlock::RenderBlock(Node* node)
, m_positionedObjects(0)
, m_inlineContinuation(0)
, m_maxMargin(0)
- , m_overflowHeight(0)
- , m_overflowWidth(0)
- , m_overflowLeft(0)
- , m_overflowTop(0)
, m_lineHeight(-1)
{
setChildrenInline(true);
@@ -172,18 +162,18 @@ RenderBlock::~RenderBlock()
void RenderBlock::destroy()
{
- // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
- // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
- children()->destroyLeftoverChildren();
+ // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
+ // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
+ children()->destroyLeftoverChildren();
- // Destroy our continuation before anything other than anonymous children.
- // The reason we don't destroy it before anonymous children is that they may
- // have continuations of their own that are anonymous children of our continuation.
- if (m_inlineContinuation) {
+ // Destroy our continuation before anything other than anonymous children.
+ // The reason we don't destroy it before anonymous children is that they may
+ // have continuations of their own that are anonymous children of our continuation.
+ if (m_inlineContinuation) {
m_inlineContinuation->destroy();
- m_inlineContinuation = 0;
+ m_inlineContinuation = 0;
}
-
+
if (!documentBeingDestroyed()) {
if (firstLineBox()) {
// We can't wait for RenderBox::destroy to clear the selection,
@@ -411,6 +401,44 @@ RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
m_lineBoxes.appendLineBox(rootBox);
return rootBox;
}
+
+void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* child)
+{
+ ASSERT(this == child->parent());
+ toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false);
+}
+
+void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild, RenderObject* child)
+{
+ ASSERT(this == child->parent());
+ ASSERT(!beforeChild || to == beforeChild->parent());
+ toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false);
+}
+
+void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList)
+{
+ RenderObject* nextChild = children()->firstChild();
+ while (nextChild) {
+ RenderObject* child = nextChild;
+ nextChild = child->nextSibling();
+ toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false);
+ }
+}
+
+void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild)
+{
+ ASSERT(!beforeChild || to == beforeChild->parent());
+ if (!beforeChild) {
+ moveAllChildrenTo(to, toChildList);
+ return;
+ }
+ RenderObject* nextChild = children()->firstChild();
+ while (nextChild) {
+ RenderObject* child = nextChild;
+ nextChild = child->nextSibling();
+ toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false);
+ }
+}
void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
{
@@ -448,9 +476,9 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
RenderObject* no = o;
o = no->nextSibling();
- moveChild(block, block->children(), this, children(), no);
+ moveChildTo(block, block->children(), no);
}
- moveChild(block, block->children(), this, children(), inlineRunEnd);
+ moveChildTo(block, block->children(), inlineRunEnd);
}
#ifndef NDEBUG
@@ -518,20 +546,12 @@ void RenderBlock::removeChild(RenderObject* oldChild)
// Take all the children out of the |next| block and put them in
// the |prev| block.
prev->setNeedsLayoutAndPrefWidthsRecalc();
- RenderObject* o = next->firstChild();
-
RenderBlock* nextBlock = toRenderBlock(next);
RenderBlock* prevBlock = toRenderBlock(prev);
- while (o) {
- RenderObject* no = o;
- o = no->nextSibling();
- moveChild(prevBlock, prevBlock->children(), nextBlock, nextBlock->children(), no);
- }
-
+ nextBlock->moveAllChildrenTo(prevBlock, prevBlock->children());
+ // Delete the now-empty block's lines and nuke it.
nextBlock->deleteLineBoxTree();
-
- // Nuke the now-empty block.
- next->destroy();
+ nextBlock->destroy();
}
RenderBox::removeChild(oldChild);
@@ -544,114 +564,15 @@ void RenderBlock::removeChild(RenderObject* oldChild)
setNeedsLayoutAndPrefWidthsRecalc();
RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, false));
setChildrenInline(true);
- RenderObject* o = anonBlock->firstChild();
- while (o) {
- RenderObject* no = o;
- o = no->nextSibling();
- moveChild(this, children(), anonBlock, anonBlock->children(), no);
- }
-
+ anonBlock->moveAllChildrenTo(this, children());
// Delete the now-empty block's lines and nuke it.
anonBlock->deleteLineBoxTree();
anonBlock->destroy();
}
-}
-
-int RenderBlock::overflowHeight(bool includeInterior) const
-{
- if (!includeInterior && hasOverflowClip()) {
- int shadowTop;
- int shadowBottom;
- style()->getBoxShadowVerticalExtent(shadowTop, shadowBottom);
-
- int inflatedHeight = height() + shadowBottom;
- if (hasReflection())
- inflatedHeight = max(inflatedHeight, reflectionBox().bottom());
- return inflatedHeight;
- }
- return m_overflowHeight;
-}
-
-int RenderBlock::overflowWidth(bool includeInterior) const
-{
- if (!includeInterior && hasOverflowClip()) {
- int shadowLeft;
- int shadowRight;
- style()->getBoxShadowHorizontalExtent(shadowLeft, shadowRight);
-
- int inflatedWidth = width() + shadowRight;
- if (hasReflection())
- inflatedWidth = max(inflatedWidth, reflectionBox().right());
- return inflatedWidth;
- }
- return m_overflowWidth;
-}
-
-int RenderBlock::overflowLeft(bool includeInterior) const
-{
- if (!includeInterior && hasOverflowClip()) {
- int shadowLeft;
- int shadowRight;
- style()->getBoxShadowHorizontalExtent(shadowLeft, shadowRight);
-
- int left = shadowLeft;
- if (hasReflection())
- left = min(left, reflectionBox().x());
- return left;
- }
- return m_overflowLeft;
-}
-
-int RenderBlock::overflowTop(bool includeInterior) const
-{
- if (!includeInterior && hasOverflowClip()) {
- int shadowTop;
- int shadowBottom;
- style()->getBoxShadowVerticalExtent(shadowTop, shadowBottom);
-
- int top = shadowTop;
- if (hasReflection())
- top = min(top, reflectionBox().y());
- return top;
- }
- return m_overflowTop;
-}
-
-IntRect RenderBlock::overflowRect(bool includeInterior) const
-{
- if (!includeInterior && hasOverflowClip()) {
- IntRect box = borderBoxRect();
-
- int shadowLeft;
- int shadowRight;
- int shadowTop;
- int shadowBottom;
- style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
-
- box.move(shadowLeft, shadowTop);
- box.setWidth(box.width() - shadowLeft + shadowRight);
- box.setHeight(box.height() - shadowTop + shadowBottom);
-
- if (hasReflection()) {
- IntRect reflection(reflectionBox());
- int reflectTop = min(box.y(), reflection.y());
- int reflectBottom = max(box.bottom(), reflection.bottom());
- box.setHeight(reflectBottom - reflectTop);
- box.setY(reflectTop);
-
- int reflectLeft = min(box.x(), reflection.x());
- int reflectRight = max(box.right(), reflection.right());
- box.setWidth(reflectRight - reflectLeft);
- box.setX(reflectLeft);
- }
- return box;
- }
- if (!includeInterior && hasOverflowClip())
- return borderBoxRect();
- int l = overflowLeft(includeInterior);
- int t = overflowTop(includeInterior);
- return IntRect(l, t, overflowWidth(includeInterior) - l, max(overflowHeight(includeInterior), height()) - t);
+ // If this was our last child be sure to clear out our line boxes.
+ if (childrenInline() && !firstChild())
+ lineBoxes()->deleteLineBoxes(renderArena());
}
bool RenderBlock::isSelfCollapsingBlock() const
@@ -715,15 +636,15 @@ void RenderBlock::finishDelayUpdateScrollInfo()
if (gDelayUpdateScrollInfo == 0) {
ASSERT(gDelayedUpdateScrollInfoSet);
- for (DelayedUpdateScrollInfoSet::iterator it = gDelayedUpdateScrollInfoSet->begin(); it != gDelayedUpdateScrollInfoSet->end(); ++it) {
+ OwnPtr<DelayedUpdateScrollInfoSet> infoSet(gDelayedUpdateScrollInfoSet);
+ gDelayedUpdateScrollInfoSet = 0;
+
+ for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
RenderBlock* block = *it;
if (block->hasOverflowClip()) {
block->layer()->updateScrollInfoAfterLayout();
}
}
-
- delete gDelayedUpdateScrollInfoSet;
- gDelayedUpdateScrollInfoSet = 0;
}
}
@@ -747,13 +668,9 @@ void RenderBlock::layout()
layoutBlock(false);
// It's safe to check for control clip here, since controls can never be table cells.
- if (hasControlClip()) {
- // Because of the lightweight clip, there can never be any overflow from children.
- m_overflowWidth = width();
- m_overflowHeight = height();
- m_overflowLeft = 0;
- m_overflowTop = 0;
- }
+ // If we have a lightweight clip, there can never be any overflow from children.
+ if (hasControlClip() && m_overflow)
+ clearLayoutOverflow();
}
void RenderBlock::layoutBlock(bool relayoutChildren)
@@ -779,8 +696,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
calcWidth();
calcColumnWidth();
- m_overflowWidth = width();
- m_overflowLeft = 0;
+ m_overflow.clear();
if (oldWidth != width() || oldColumnWidth != desiredColumnWidth())
relayoutChildren = true;
@@ -798,8 +714,6 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
int previousHeight = height();
setHeight(0);
- m_overflowHeight = 0;
-
// We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
// our current maximal positive and negative margins. These values are used when we
// are collapsed with adjacent blocks, so for example, if you have block A and B
@@ -864,50 +778,35 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
}
}
}
+
// We have to rebalance columns to the new height.
layoutColumns(singleColumnBottom);
-
- // If the block got expanded in size, then increase our overflowheight to match.
- if (m_overflowHeight > height())
- m_overflowHeight -= toAdd;
- if (m_overflowHeight < height())
- m_overflowHeight = height();
}
+
if (previousHeight != height())
relayoutChildren = true;
- if ((isCell || isInline() || isFloatingOrPositioned() || isRoot()) && !hasOverflowClip() && !hasControlClip())
- addVisualOverflow(floatRect());
+ // It's weird that we're treating float information as normal flow overflow, but we do this because floatRect() isn't
+ // able to be propagated up the render tree yet. Overflow information is however. This check is designed to catch anyone
+ // who wasn't going to propagate float information up to the parent and yet could potentially be painted by its ancestor.
+ if (isRoot() || expandsToEncloseOverhangingFloats())
+ addOverflowFromFloats();
- layoutPositionedObjects(relayoutChildren || isRoot());
+ // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
+ if (!hasColumns()) {
+ if (childrenInline())
+ addOverflowFromInlineChildren();
+ else
+ addOverflowFromBlockChildren();
+ }
- positionListMarker();
+ // Add visual overflow from box-shadow and reflections.
+ addShadowOverflow();
- // Always ensure our overflow width/height are at least as large as our width/height.
- m_overflowWidth = max(m_overflowWidth, width());
- m_overflowHeight = max(m_overflowHeight, height());
-
- if (!hasOverflowClip()) {
- int shadowLeft;
- int shadowRight;
- int shadowTop;
- int shadowBottom;
- style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
-
- m_overflowLeft = min(m_overflowLeft, shadowLeft);
- m_overflowWidth = max(m_overflowWidth, width() + shadowRight);
- m_overflowTop = min(m_overflowTop, shadowTop);
- m_overflowHeight = max(m_overflowHeight, height() + shadowBottom);
-
- if (hasReflection()) {
- IntRect reflection(reflectionBox());
- m_overflowLeft = min(m_overflowLeft, reflection.x());
- m_overflowWidth = max(m_overflowWidth, reflection.right());
- m_overflowTop = min(m_overflowTop, reflection.y());
- m_overflowHeight = max(m_overflowHeight, reflection.bottom());
- }
- }
+ layoutPositionedObjects(relayoutChildren || isRoot());
+ positionListMarker();
+
statePusher.pop();
// Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
@@ -917,7 +816,9 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
// Repaint with our new bounds if they are different from our old bounds.
bool didFullRepaint = repainter.repaintAfterLayout();
if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
- IntRect repaintRect(m_overflowLeft, repaintTop, m_overflowWidth - m_overflowLeft, repaintBottom - repaintTop);
+ int repaintLeft = min(leftVisualOverflow(), leftLayoutOverflow());
+ int repaintRight = max(rightVisualOverflow(), rightLayoutOverflow());
+ IntRect repaintRect(repaintLeft, repaintTop, repaintRight - repaintLeft, repaintBottom - repaintTop);
// FIXME: Deal with multiple column repainting. We have to split the repaint
// rect up into multiple rects if it spans columns.
@@ -946,6 +847,28 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
setNeedsLayout(false);
}
+void RenderBlock::addOverflowFromBlockChildren()
+{
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ if (!child->isFloatingOrPositioned())
+ addOverflowFromChild(child);
+ }
+}
+
+void RenderBlock::addOverflowFromFloats()
+{
+ IntRect result;
+ if (!m_floatingObjects)
+ return;
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for (; (r = it.current()); ++it) {
+ if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer())
+ addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()));
+ }
+ return;
+}
+
bool RenderBlock::expandsToEncloseOverhangingFloats() const
{
return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || hasColumns() || isTableCell() || isFieldset();
@@ -976,7 +899,11 @@ void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marg
}
y += (collapsedTopPos - collapsedTopNeg) - marginTop;
}
- child->layer()->setStaticY(y);
+ RenderLayer* childLayer = child->layer();
+ if (childLayer->staticY() != y) {
+ child->layer()->setStaticY(y);
+ child->setChildNeedsLayout(true, false);
+ }
}
}
@@ -1035,7 +962,10 @@ bool RenderBlock::handleRunInChild(RenderBox* child)
// See if we have a run-in element with inline children. If the
// children aren't inline, then just treat the run-in as a normal
// block.
- if (!child->isRunIn() || !child->childrenInline() && !child->isReplaced())
+ if (!child->isRunIn() || !child->childrenInline())
+ return false;
+ // FIXME: We don't handle non-block elements with run-in for now.
+ if (!child->isRenderBlock())
return false;
// Get the next non-positioned/non-floating RenderBlock.
@@ -1062,7 +992,7 @@ bool RenderBlock::handleRunInChild(RenderBox* child)
// Move the nodes from the old child to the new child, but skip any :before/:after content. It has already
// been regenerated by the new inline.
for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild; runInChild = runInChild->nextSibling()) {
- if (runInIsGenerated || runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER) {
+ if (runInIsGenerated || (runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER)) {
blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false);
inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content.
}
@@ -1169,8 +1099,6 @@ int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
if (marginInfo.margin())
marginInfo.setBottomQuirk(child->isBottomMarginQuirk() || style()->marginBottomCollapse() == MDISCARD);
-
- marginInfo.setSelfCollapsingBlockClearedFloat(false);
}
return ypos;
@@ -1186,16 +1114,26 @@ int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, i
// For self-collapsing blocks that clear, they can still collapse their
// margins with following siblings. Reset the current margins to represent
// the self-collapsing block's margins only.
- marginInfo.setPosMargin(max(child->maxTopMargin(true), child->maxBottomMargin(true)));
- marginInfo.setNegMargin(max(child->maxTopMargin(false), child->maxBottomMargin(false)));
+ // CSS2.1 states:
+ // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin.
+ // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the
+ // self-collapsing block's bottom margin.
+ bool atBottomOfBlock = true;
+ for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) {
+ if (!curr->isFloatingOrPositioned())
+ atBottomOfBlock = false;
+ }
+ if (atBottomOfBlock) {
+ marginInfo.setPosMargin(child->maxBottomMargin(true));
+ marginInfo.setNegMargin(child->maxBottomMargin(false));
+ } else {
+ marginInfo.setPosMargin(max(child->maxTopMargin(true), child->maxBottomMargin(true)));
+ marginInfo.setNegMargin(max(child->maxTopMargin(false), child->maxBottomMargin(false)));
+ }
- // Adjust our height such that we are ready to be collapsed with subsequent siblings.
+ // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom
+ // of the parent block).
setHeight(child->y() - max(0, marginInfo.margin()));
-
- // Set a flag that we cleared a float so that we know both to increase the height of the block
- // to compensate for the clear and to avoid collapsing our margins with the parent block's
- // bottom margin.
- marginInfo.setSelfCollapsingBlockClearedFloat(true);
} else
// Increase our height by the amount we had to clear.
setHeight(height() + heightIncrease);
@@ -1299,17 +1237,7 @@ void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo)
{
- // If our last flow was a self-collapsing block that cleared a float, then we don't
- // collapse it with the bottom of the block.
- if (!marginInfo.selfCollapsingBlockClearedFloat())
- marginInfo.setAtBottomOfBlock(true);
- else {
- // We have to special case the negative margin situation (where the collapsed
- // margin of the self-collapsing block is negative), since there's no need
- // to make an adjustment in that case.
- if (marginInfo.margin() < 0)
- marginInfo.clearMargin();
- }
+ marginInfo.setAtBottomOfBlock(true);
// If we can't collapse with children then go ahead and add in the bottom margin.
if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()
@@ -1323,9 +1251,6 @@ void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInf
// If this happens, ensure that the computed height is increased to the minimal height.
setHeight(max(height(), top + bottom));
- // Always make sure our overflow height is at least our height.
- m_overflowHeight = max(height(), m_overflowHeight);
-
// Update our bottom collapsed margin info.
setCollapsedBottomMargin(marginInfo);
}
@@ -1353,8 +1278,7 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom
int top = borderTop() + paddingTop();
int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
- m_overflowHeight = top;
- setHeight(m_overflowHeight);
+ setHeight(top);
// The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
MarginInfo marginInfo(this, top, bottom);
@@ -1375,9 +1299,6 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom
if (legend == child)
continue; // Skip the legend, since it has already been positioned up in the fieldset's border.
- int oldTopPosMargin = maxTopPosMargin();
- int oldTopNegMargin = maxTopNegMargin();
-
// Make sure we layout children if they need it.
// FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
// an auto value. Add a method to determine this, so that we can avoid the relayout.
@@ -1393,127 +1314,127 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom
if (handleSpecialChild(child, marginInfo))
continue;
- // The child is a normal flow object. Compute its vertical margins now.
- child->calcVerticalMargins();
+ // Lay out the child.
+ layoutBlockChild(child, marginInfo, previousFloatBottom, maxFloatBottom);
+ }
+
+ // Now do the handling of the bottom of the block, adding in our bottom border/padding and
+ // determining the correct collapsed bottom margin information.
+ handleBottomOfBlock(top, bottom, marginInfo);
+}
- // Do not allow a collapse if the margin top collapse style is set to SEPARATE.
- if (child->style()->marginTopCollapse() == MSEPARATE) {
- marginInfo.setAtTopOfBlock(false);
- marginInfo.clearMargin();
- }
+void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatBottom, int& maxFloatBottom)
+{
+ int oldTopPosMargin = maxTopPosMargin();
+ int oldTopNegMargin = maxTopNegMargin();
- // Try to guess our correct y position. In most cases this guess will
- // be correct. Only if we're wrong (when we compute the real y position)
- // will we have to potentially relayout.
- int yPosEstimate = estimateVerticalPosition(child, marginInfo);
+ // The child is a normal flow object. Compute its vertical margins now.
+ child->calcVerticalMargins();
- // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
- IntRect oldRect(child->x(), child->y() , child->width(), child->height());
+ // Do not allow a collapse if the margin top collapse style is set to SEPARATE.
+ if (child->style()->marginTopCollapse() == MSEPARATE) {
+ marginInfo.setAtTopOfBlock(false);
+ marginInfo.clearMargin();
+ }
+
+ // Try to guess our correct y position. In most cases this guess will
+ // be correct. Only if we're wrong (when we compute the real y position)
+ // will we have to potentially relayout.
+ int yPosEstimate = estimateVerticalPosition(child, marginInfo);
+
+ // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
+ IntRect oldRect(child->x(), child->y() , child->width(), child->height());
#ifndef NDEBUG
- IntSize oldLayoutDelta = view()->layoutDelta();
+ IntSize oldLayoutDelta = view()->layoutDelta();
#endif
- // Go ahead and position the child as though it didn't collapse with the top.
- view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate));
- child->setLocation(child->x(), yPosEstimate);
-
- bool markDescendantsWithFloats = false;
- if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats())
+ // Go ahead and position the child as though it didn't collapse with the top.
+ view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate));
+ child->setLocation(child->x(), yPosEstimate);
+
+ bool markDescendantsWithFloats = false;
+ if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats())
+ markDescendantsWithFloats = true;
+ else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
+ // If an element might be affected by the presence of floats, then always mark it for
+ // layout.
+ int fb = max(previousFloatBottom, floatBottom());
+ if (fb > yPosEstimate)
markDescendantsWithFloats = true;
- else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
- // If an element might be affected by the presence of floats, then always mark it for
- // layout.
- int fb = max(previousFloatBottom, floatBottom());
- if (fb > yPosEstimate)
- markDescendantsWithFloats = true;
- }
+ }
- if (child->isRenderBlock()) {
- if (markDescendantsWithFloats)
- toRenderBlock(child)->markAllDescendantsWithFloatsForLayout();
+ if (child->isRenderBlock()) {
+ if (markDescendantsWithFloats)
+ toRenderBlock(child)->markAllDescendantsWithFloatsForLayout();
- previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom());
- }
+ previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom());
+ }
- bool childHadLayout = child->m_everHadLayout;
- bool childNeededLayout = child->needsLayout();
- if (childNeededLayout)
- child->layout();
+ bool childHadLayout = child->m_everHadLayout;
+ bool childNeededLayout = child->needsLayout();
+ if (childNeededLayout)
+ child->layout();
- // Now determine the correct ypos based off examination of collapsing margin
- // values.
- int yBeforeClear = collapseMargins(child, marginInfo);
+ // Now determine the correct ypos based off examination of collapsing margin
+ // values.
+ int yBeforeClear = collapseMargins(child, marginInfo);
- // Now check for clear.
- int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear);
-
- view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear));
- child->setLocation(child->x(), yAfterClear);
+ // Now check for clear.
+ int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear);
- // Now we have a final y position. See if it really does end up being different from our estimate.
- if (yAfterClear != yPosEstimate) {
- if (child->shrinkToAvoidFloats()) {
- // The child's width depends on the line width.
- // When the child shifts to clear an item, its width can
- // change (because it has more available line width).
- // So go ahead and mark the item as dirty.
- child->setChildNeedsLayout(true, false);
- }
- if (!child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats())
- toRenderBlock(child)->markAllDescendantsWithFloatsForLayout();
- // Our guess was wrong. Make the child lay itself out again.
- child->layoutIfNeeded();
+ view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear));
+ child->setLocation(child->x(), yAfterClear);
+
+ // Now we have a final y position. See if it really does end up being different from our estimate.
+ if (yAfterClear != yPosEstimate) {
+ if (child->shrinkToAvoidFloats()) {
+ // The child's width depends on the line width.
+ // When the child shifts to clear an item, its width can
+ // change (because it has more available line width).
+ // So go ahead and mark the item as dirty.
+ child->setChildNeedsLayout(true, false);
}
+ if (!child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats())
+ toRenderBlock(child)->markAllDescendantsWithFloatsForLayout();
+ // Our guess was wrong. Make the child lay itself out again.
+ child->layoutIfNeeded();
+ }
- // We are no longer at the top of the block if we encounter a non-empty child.
- // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
- if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock())
- marginInfo.setAtTopOfBlock(false);
-
- // Now place the child in the correct horizontal position
- determineHorizontalPosition(child);
+ // We are no longer at the top of the block if we encounter a non-empty child.
+ // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
+ if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock())
+ marginInfo.setAtTopOfBlock(false);
- // Update our height now that the child has been placed in the correct position.
- setHeight(height() + child->height());
- if (child->style()->marginBottomCollapse() == MSEPARATE) {
- setHeight(height() + child->marginBottom());
- marginInfo.clearMargin();
- }
- // If the child has overhanging floats that intrude into following siblings (or possibly out
- // of this block), then the parent gets notified of the floats now.
- if (child->isBlockFlow() && toRenderBlock(child)->containsFloats())
- maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout));
-
- // Update our visual overflow in case the child spills out the block, but only if we were going to paint
- // the child block ourselves.
- if (!child->hasSelfPaintingLayer()) {
- m_overflowTop = min(m_overflowTop, child->y() + child->overflowTop(false));
- m_overflowHeight = max(m_overflowHeight, height() + child->overflowHeight(false) - child->height());
- m_overflowWidth = max(child->x() + child->overflowWidth(false), m_overflowWidth);
- m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft);
- }
+ // Now place the child in the correct horizontal position
+ determineHorizontalPosition(child);
- IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y());
- if (childOffset.width() || childOffset.height()) {
- view()->addLayoutDelta(childOffset);
+ // Update our height now that the child has been placed in the correct position.
+ setHeight(height() + child->height());
+ if (child->style()->marginBottomCollapse() == MSEPARATE) {
+ setHeight(height() + child->marginBottom());
+ marginInfo.clearMargin();
+ }
+ // If the child has overhanging floats that intrude into following siblings (or possibly out
+ // of this block), then the parent gets notified of the floats now.
+ if (child->isBlockFlow() && toRenderBlock(child)->containsFloats())
+ maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout));
- // If the child moved, we have to repaint it as well as any floating/positioned
- // descendants. An exception is if we need a layout. In this case, we know we're going to
- // repaint ourselves (and the child) anyway.
- if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
- child->repaintDuringLayoutIfMoved(oldRect);
- }
+ IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y());
+ if (childOffset.width() || childOffset.height()) {
+ view()->addLayoutDelta(childOffset);
- if (!childHadLayout && child->checkForRepaintDuringLayout()) {
- child->repaint();
- child->repaintOverhangingFloats(true);
- }
+ // If the child moved, we have to repaint it as well as any floating/positioned
+ // descendants. An exception is if we need a layout. In this case, we know we're going to
+ // repaint ourselves (and the child) anyway.
+ if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
+ child->repaintDuringLayoutIfMoved(oldRect);
+ }
- ASSERT(oldLayoutDelta == view()->layoutDelta());
+ if (!childHadLayout && child->checkForRepaintDuringLayout()) {
+ child->repaint();
+ child->repaintOverhangingFloats(true);
}
- // Now do the handling of the bottom of the block, adding in our bottom border/padding and
- // determining the correct collapsed bottom margin information.
- handleBottomOfBlock(top, bottom, marginInfo);
+ ASSERT(oldLayoutDelta == view()->layoutDelta());
}
bool RenderBlock::layoutOnlyPositionedObjects()
@@ -1537,7 +1458,7 @@ bool RenderBlock::layoutOnlyPositionedObjects()
updateScrollInfoAfterLayout();
#ifdef ANDROID_FIX
- // iframe flatten will call FrameView::layout() which calls performPostLayoutTasks,
+ // iframe flatten will call FrameView::layout() which calls performPostLayoutTasks,
// which may make us need to layout again
if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout())
return false;
@@ -1626,7 +1547,7 @@ void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty)
// FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
// paints the root's background.
if (!isRoot()) {
- IntRect overflowBox = overflowRect(false);
+ IntRect overflowBox = visibleOverflowRect();
overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
overflowBox.move(tx, ty);
if (!overflowBox.intersects(paintInfo.rect))
@@ -1641,7 +1562,7 @@ void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty)
// Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
// z-index. We paint after we painted the background/border, so that the scrollbars will
// sit above the background/border.
- if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground))
+ if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && shouldPaintWithinRoot(paintInfo))
layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect);
}
@@ -1792,7 +1713,7 @@ void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType typ
offsetForContents(tx, ty);
if (type == CursorCaret)
- document()->frame()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect);
+ document()->frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect);
else
document()->frame()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect);
}
@@ -2025,23 +1946,28 @@ bool RenderBlock::isSelectionRoot() const
return false;
}
-GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* /*repaintContainer*/)
+GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer)
{
ASSERT(!needsLayout());
if (!shouldPaintSelectionGaps())
return GapRects();
- // FIXME: this is broken with transforms and a non-null repaintContainer
- FloatPoint absContentPoint = localToAbsolute(FloatPoint());
+ // FIXME: this is broken with transforms
+ TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
+ mapLocalToContainer(repaintContainer, false, false, transformState);
+ FloatPoint offsetFromRepaintContainer = transformState.mappedPoint();
+ int x = offsetFromRepaintContainer.x();
+ int y = offsetFromRepaintContainer.y();
+
if (hasOverflowClip())
- absContentPoint -= layer()->scrolledContentOffset();
+ layer()->subtractScrolledContentOffset(x, y);
int lastTop = 0;
int lastLeft = leftSelectionOffset(this, lastTop);
int lastRight = rightSelectionOffset(this, lastTop);
- return fillSelectionGaps(this, absContentPoint.x(), absContentPoint.y(), absContentPoint.x(), absContentPoint.y(), lastTop, lastLeft, lastRight);
+ return fillSelectionGaps(this, x, y, x, y, lastTop, lastLeft, lastRight);
}
void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty)
@@ -2051,7 +1977,17 @@ void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty)
int lastLeft = leftSelectionOffset(this, lastTop);
int lastRight = rightSelectionOffset(this, lastTop);
paintInfo.context->save();
- fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &paintInfo);
+ IntRect gapRectsBounds = fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &paintInfo);
+ if (!gapRectsBounds.isEmpty()) {
+ if (RenderLayer* layer = enclosingLayer()) {
+ gapRectsBounds.move(IntSize(-tx, -ty));
+ if (!hasLayer()) {
+ FloatRect localBounds(gapRectsBounds);
+ gapRectsBounds = localToContainerQuad(localBounds, layer->renderer()).enclosingBoundingBox();
+ }
+ layer->addBlockSelectionGapsBounds(gapRectsBounds);
+ }
+ }
paintInfo.context->restore();
}
}
@@ -2163,9 +2099,9 @@ GapRects RenderBlock::fillInlineSelectionGaps(RenderBlock* rootBlock, int blockX
if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
// Go ahead and update our lastY to be the bottom of the last selected line.
- lastTop = (ty - blockY) + lastSelectedLine->bottomOverflow();
- lastLeft = leftSelectionOffset(rootBlock, lastSelectedLine->bottomOverflow());
- lastRight = rightSelectionOffset(rootBlock, lastSelectedLine->bottomOverflow());
+ lastTop = (ty - blockY) + lastSelectedLine->selectionBottom();
+ lastLeft = leftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
+ lastRight = rightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
}
return result;
}
@@ -2238,7 +2174,7 @@ IntRect RenderBlock::fillHorizontalSelectionGap(RenderObject* selObj, int xPos,
return IntRect();
IntRect gapRect(xPos, yPos, width, height);
if (paintInfo && selObj->style()->visibility() == VISIBLE)
- paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor());
+ paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
return gapRect;
}
@@ -2259,7 +2195,7 @@ IntRect RenderBlock::fillVerticalSelectionGap(int lastTop, int lastLeft, int las
IntRect gapRect(left, top, width, height);
if (paintInfo)
- paintInfo->context->fillRect(gapRect, selectionBackgroundColor());
+ paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace());
return gapRect;
}
@@ -2275,7 +2211,7 @@ IntRect RenderBlock::fillLeftSelectionGap(RenderObject* selObj, int xPos, int yP
IntRect gapRect(left, top, width, height);
if (paintInfo)
- paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor());
+ paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
return gapRect;
}
@@ -2291,7 +2227,7 @@ IntRect RenderBlock::fillRightSelectionGap(RenderObject* selObj, int xPos, int y
IntRect gapRect(left, top, width, height);
if (paintInfo)
- paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor());
+ paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
return gapRect;
}
@@ -2716,13 +2652,13 @@ RenderBlock::floatBottom() const
IntRect RenderBlock::floatRect() const
{
IntRect result;
- if (!m_floatingObjects || hasOverflowClip())
+ if (!m_floatingObjects || hasOverflowClip() || hasColumns())
return result;
FloatingObject* r;
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
for (; (r = it.current()); ++it) {
if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
- IntRect childRect = r->m_renderer->overflowRect(false);
+ IntRect childRect = r->m_renderer->visibleOverflowRect();
childRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop());
result.unite(childRect);
}
@@ -2733,10 +2669,14 @@ IntRect RenderBlock::floatRect() const
int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
{
+ int bottom = includeSelf && width() > 0 ? height() : 0;
+
if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
- return includeSelf && width() > 0 ? overflowHeight(false) : 0;
+ return bottom;
+
+ if (!firstChild() && (!width() || !height()))
+ return bottom;
- int bottom = includeSelf && width() > 0 ? height() : 0;
if (!hasColumns()) {
// FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
// For now, we have to descend into all the children, since we may have a huge abs div inside
@@ -2760,7 +2700,7 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetY() : 0;
if (includeSelf)
- bottom = max(bottom, m_overflowHeight + relativeOffset);
+ bottom = max(bottom, bottomLayoutOverflow() + relativeOffset);
if (m_positionedObjects) {
RenderBox* r;
@@ -2802,8 +2742,8 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
if (!includeSelf) {
bottom = max(bottom, borderTop() + paddingTop() + paddingBottom() + relativeOffset);
if (childrenInline()) {
- if (lastLineBox()) {
- int childBottomEdge = lastLineBox()->y() + lastLineBox()->height();
+ if (lastRootBox()) {
+ int childBottomEdge = lastRootBox()->selectionBottom();
bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset);
}
} else {
@@ -2823,10 +2763,13 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
+ int right = includeSelf && height() > 0 ? width() : 0;
+
if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
- return includeSelf && height() > 0 ? overflowWidth(false) : 0;
+ return right;
- int right = includeSelf && height() > 0 ? width() : 0;
+ if (!firstChild() && (!width() || !height()))
+ return right;
if (!hasColumns()) {
// FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
@@ -2850,7 +2793,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetX() : 0;
if (includeSelf)
- right = max(right, m_overflowWidth + relativeOffset);
+ right = max(right, rightLayoutOverflow() + relativeOffset);
if (m_positionedObjects) {
RenderBox* r;
@@ -2917,10 +2860,14 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
+ int left = includeSelf && height() > 0 ? 0 : width();
+
if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
- return includeSelf && height() > 0 ? overflowLeft(false) : width();
+ return left;
+
+ if (!firstChild() && (!width() || !height()))
+ return left;
- int left = includeSelf && height() > 0 ? 0 : width();
if (!hasColumns()) {
// FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
// For now, we have to descend into all the children, since we may have a huge abs div inside
@@ -2943,7 +2890,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetX() : 0;
if (includeSelf)
- left = min(left, m_overflowLeft + relativeOffset);
+ left = min(left, leftLayoutOverflow() + relativeOffset);
if (m_positionedObjects) {
RenderBox* r;
@@ -3018,7 +2965,7 @@ RenderBlock::rightBottom()
return bottom;
}
-void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom)
+void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest)
{
if (top >= bottom)
return;
@@ -3030,7 +2977,7 @@ void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom)
lowestDirtyLine = lowestDirtyLine->prevRootBox();
}
- while (afterLowest && afterLowest->blockHeight() >= top) {
+ while (afterLowest && afterLowest != highest && afterLowest->blockHeight() >= top) {
afterLowest->markDirty();
afterLowest = afterLowest->prevRootBox();
}
@@ -3137,9 +3084,8 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo
int lowestFloatBottom = 0;
- // Floats that will remain the child's responsiblity to paint should factor into its
- // visual overflow.
- IntRect floatsOverflowRect;
+ // Floats that will remain the child's responsibility to paint should factor into its
+ // overflow.
DeprecatedPtrListIterator<FloatingObject> it(*child->m_floatingObjects);
for (FloatingObject* r; (r = it.current()); ++it) {
int bottom = child->y() + r->m_bottom;
@@ -3180,13 +3126,9 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo
// it should paint.
r->m_shouldPaint = true;
- if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
- IntRect floatOverflowRect = r->m_renderer->overflowRect(false);
- floatOverflowRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop());
- floatsOverflowRect.unite(floatOverflowRect);
- }
+ if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer())
+ child->addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()));
}
- child->addVisualOverflow(floatsOverflowRect);
return lowestFloatBottom;
}
@@ -3299,28 +3241,39 @@ int RenderBlock::getClearDelta(RenderBox* child, int yPos)
}
// We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default).
- // FIXME: Note that the remaining space checks aren't quite accurate, since you should be able to clear only some floats (the minimum # needed
- // to fit) and not all (we should be using nextFloatBottomBelow and looping).
- // Do not allow tables to wrap in quirks or even in almost strict mode
- // (ebay on the PLT, finance.yahoo.com in the real world, versiontracker.com forces even almost strict mode not to work)
int result = clearSet ? max(0, bottom - yPos) : 0;
- if (!result && child->avoidsFloats() && child->style()->width().isFixed() &&
- child->minPrefWidth() > lineWidth(yPos, false) && child->minPrefWidth() <= availableWidth() &&
- document()->inStrictMode())
- result = max(0, floatBottom() - yPos);
+ if (!result && child->avoidsFloats()) {
+ int availableWidth = this->availableWidth();
+ if (child->minPrefWidth() > availableWidth)
+ return 0;
+
+ int y = yPos;
+ while (true) {
+ int widthAtY = lineWidth(y, false);
+ if (widthAtY == availableWidth)
+ return y - yPos;
+
+ int oldChildY = child->y();
+ int oldChildWidth = child->width();
+ child->setY(y);
+ child->calcWidth();
+ int childWidthAtY = child->width();
+ child->setY(oldChildY);
+ child->setWidth(oldChildWidth);
+
+ if (childWidthAtY <= widthAtY)
+ return y - yPos;
+
+ y = nextFloatBottomBelow(y);
+ ASSERT(y >= yPos);
+ if (y < yPos)
+ break;
+ }
+ ASSERT_NOT_REACHED();
+ }
return result;
}
-void RenderBlock::addVisualOverflow(const IntRect& r)
-{
- if (r.isEmpty())
- return;
- m_overflowLeft = min(m_overflowLeft, r.x());
- m_overflowWidth = max(m_overflowWidth, r.right());
- m_overflowTop = min(m_overflowTop, r.y());
- m_overflowHeight = max(m_overflowHeight, r.bottom());
-}
-
bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty)
{
if (!scrollsOverflow())
@@ -3336,7 +3289,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
if (!isRenderView()) {
// Check if we need to do anything at all.
- IntRect overflowBox = overflowRect(false);
+ IntRect overflowBox = visibleOverflowRect();
overflowBox.move(tx, ty);
if (!overflowBox.contains(_x, _y))
return false;
@@ -3533,7 +3486,7 @@ VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint&
RootInlineBox* firstRootBoxWithChildren = 0;
RootInlineBox* lastRootBoxWithChildren = 0;
for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
- if (!root->firstChild())
+ if (!root->firstLeafChild())
continue;
if (!firstRootBoxWithChildren)
firstRootBoxWithChildren = root;
@@ -3545,9 +3498,9 @@ VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint&
if (root->nextRootBox()) {
// FIXME: We would prefer to make the break point halfway between the bottom
// of the previous root box and the top of the next root box.
- bottom = root->nextRootBox()->topOverflow();
+ bottom = root->nextRootBox()->lineTop();
} else
- bottom = root->bottomOverflow() + verticalLineClickFudgeFactor;
+ bottom = root->lineBottom() + verticalLineClickFudgeFactor;
// check if this root line box is located at this y coordinate
if (pointInContents.y() < bottom) {
@@ -3566,7 +3519,7 @@ VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint&
}
if (closestBox) {
- if (!useWindowsBehavior && pointInContents.y() < firstRootBoxWithChildren->topOverflow() - verticalLineClickFudgeFactor) {
+ if (!useWindowsBehavior && pointInContents.y() < firstRootBoxWithChildren->lineTop() - verticalLineClickFudgeFactor) {
// y coordinate is above first root line box, so return the start of the first
return VisiblePosition(positionForBox(firstRootBoxWithChildren->firstLeafChild(), true), DOWNSTREAM);
}
@@ -3680,11 +3633,15 @@ void RenderBlock::calcColumnWidth()
desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
} else if (colGap < availWidth) {
desiredColumnCount = availWidth / colGap;
+ if (desiredColumnCount < 1)
+ desiredColumnCount = 1;
desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
}
} else if (style()->hasAutoColumnCount()) {
if (colWidth < availWidth) {
desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
+ if (desiredColumnCount < 1)
+ desiredColumnCount = 1;
desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
}
} else {
@@ -3694,6 +3651,8 @@ void RenderBlock::calcColumnWidth()
desiredColumnWidth = colWidth;
} else if (colWidth < availWidth) {
desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
+ if (desiredColumnCount < 1)
+ desiredColumnCount = 1;
desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
}
}
@@ -3702,7 +3661,7 @@ void RenderBlock::calcColumnWidth()
void RenderBlock::setDesiredColumnCountAndWidth(int count, int width)
{
- if (count == 1) {
+ if (count == 1 && style()->hasAutoColumnWidth()) {
if (hasColumns()) {
delete gColumnInfoMap->take(this);
setHasColumns(false);
@@ -3744,7 +3703,7 @@ Vector<IntRect>* RenderBlock::columnRects() const
return &gColumnInfoMap->get(this)->m_columnRects;
}
-int RenderBlock::layoutColumns(int endOfContent)
+int RenderBlock::layoutColumns(int endOfContent, int requestedColumnHeight)
{
// Don't do anything if we have no columns
if (!hasColumns())
@@ -3757,17 +3716,20 @@ int RenderBlock::layoutColumns(int endOfContent)
bool computeIntrinsicHeight = (endOfContent == -1);
- // Fill the columns in to the available height. Attempt to balance the height of the columns
- int availableHeight = contentHeight();
- int colHeight = computeIntrinsicHeight ? availableHeight / desiredColumnCount : availableHeight;
-
+ // Fill the columns in to the available height. Attempt to balance the height of the columns.
// Add in half our line-height to help with best-guess initial balancing.
int columnSlop = lineHeight(false) / 2;
int remainingSlopSpace = columnSlop * desiredColumnCount;
+ int availableHeight = contentHeight();
+ int colHeight;
+ if (computeIntrinsicHeight && requestedColumnHeight >= 0)
+ colHeight = requestedColumnHeight;
+ else if (computeIntrinsicHeight)
+ colHeight = availableHeight / desiredColumnCount + columnSlop;
+ else
+ colHeight = availableHeight;
+ int originalColHeight = colHeight;
- if (computeIntrinsicHeight)
- colHeight += columnSlop;
-
int colGap = columnGap();
// Compute a collection of column rects.
@@ -3783,7 +3745,8 @@ int RenderBlock::layoutColumns(int endOfContent)
int currY = top;
unsigned colCount = desiredColumnCount;
int maxColBottom = borderTop() + paddingTop();
- int contentBottom = top + availableHeight;
+ int contentBottom = top + availableHeight;
+ int minimumColumnHeight = -1;
for (unsigned i = 0; i < colCount; i++) {
// If we aren't constrained, then the last column can just get all the remaining space.
if (computeIntrinsicHeight && i == colCount - 1)
@@ -3803,6 +3766,11 @@ int RenderBlock::layoutColumns(int endOfContent)
paintObject(paintInfo, 0, 0);
setHasColumns(true);
+ if (computeIntrinsicHeight && v->minimumColumnHeight() > originalColHeight) {
+ // The initial column height was too small to contain one line of text.
+ minimumColumnHeight = max(minimumColumnHeight, v->minimumColumnHeight());
+ }
+
int adjustedBottom = v->bestTruncatedAt();
if (adjustedBottom <= currY)
adjustedBottom = currY + colHeight;
@@ -3839,14 +3807,21 @@ int RenderBlock::layoutColumns(int endOfContent)
colCount++;
}
- m_overflowWidth = max(width(), currX - colGap);
- m_overflowLeft = min(0, currX + desiredColumnWidth + colGap);
+ if (minimumColumnHeight >= 0) {
+ // If originalColHeight was too small, we need to try to layout again.
+ return layoutColumns(endOfContent, minimumColumnHeight);
+ }
- m_overflowHeight = maxColBottom;
+ int overflowRight = max(width(), currX - colGap);
+ int overflowLeft = min(0, currX + desiredColumnWidth + colGap);
+ int overflowHeight = maxColBottom;
int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
if (computeIntrinsicHeight)
- setHeight(m_overflowHeight + toAdd);
+ setHeight(maxColBottom + toAdd);
+
+ m_overflow.clear();
+ addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
v->setPrintRect(IntRect());
v->setTruncatedAt(0);
@@ -4317,6 +4292,10 @@ void RenderBlock::calcInlinePrefWidths()
} else
inlineMax += childMax;
}
+
+ // Ignore spaces after a list marker.
+ if (child->isListMarker())
+ stripFrontSpaces = true;
} else {
m_minPrefWidth = max(inlineMin, m_minPrefWidth);
m_maxPrefWidth = max(inlineMax, m_maxPrefWidth);
@@ -4766,7 +4745,7 @@ static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom,
if (block->childrenInline()) {
for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
if (++count == l)
- return box->bottomOverflow() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
+ return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
}
}
else {
@@ -5079,7 +5058,7 @@ IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int*
return IntRect(x, y, caretWidth, height);
}
-void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
{
// For blocks inside inlines, we go ahead and include margins so that we run right up to the
// inline boxes above and below us (thus getting merged with them to form a single irregular
@@ -5091,14 +5070,20 @@ void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, int tx, in
bool prevInlineHasLineBox = toRenderInline(inlineContinuation()->node()->renderer())->firstLineBox();
int topMargin = prevInlineHasLineBox ? collapsedMarginTop() : 0;
int bottomMargin = nextInlineHasLineBox ? collapsedMarginBottom() : 0;
- graphicsContext->addFocusRingRect(IntRect(tx, ty - topMargin,
- width(), height() + topMargin + bottomMargin));
- } else
- graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
+ IntRect rect(tx, ty - topMargin, width(), height() + topMargin + bottomMargin);
+ if (!rect.isEmpty())
+ rects.append(rect);
+ } else if (width() && height())
+ rects.append(IntRect(tx, ty, width(), height()));
if (!hasOverflowClip() && !hasControlClip()) {
- for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
- graphicsContext->addFocusRingRect(IntRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height()));
+ for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
+ int top = max(curr->lineTop(), curr->y());
+ int bottom = min(curr->lineBottom(), curr->y() + curr->height());
+ IntRect rect(tx + curr->x(), ty + top, curr->width(), bottom - top);
+ if (!rect.isEmpty())
+ rects.append(rect);
+ }
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (!curr->isText() && !curr->isListMarker() && curr->isBox()) {
@@ -5109,24 +5094,31 @@ void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, int tx, in
pos = curr->localToAbsolute();
else
pos = FloatPoint(tx + box->x(), ty + box->y());
- box->addFocusRingRects(graphicsContext, pos.x(), pos.y());
+ box->addFocusRingRects(rects, pos.x(), pos.y());
}
}
}
if (inlineContinuation())
- inlineContinuation()->addFocusRingRects(graphicsContext,
+ inlineContinuation()->addFocusRingRects(rects,
tx - x() + inlineContinuation()->containingBlock()->x(),
ty - y() + inlineContinuation()->containingBlock()->y());
}
-RenderBlock* RenderBlock::createAnonymousBlock() const
+RenderBlock* RenderBlock::createAnonymousBlock(bool isFlexibleBox) const
{
RefPtr<RenderStyle> newStyle = RenderStyle::create();
newStyle->inheritFrom(style());
- newStyle->setDisplay(BLOCK);
- RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
+ RenderBlock* newBox = 0;
+ if (isFlexibleBox) {
+ newStyle->setDisplay(BOX);
+ newBox = new (renderArena()) RenderFlexibleBox(document() /* anonymous box */);
+ } else {
+ newStyle->setDisplay(BLOCK);
+ newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
+ }
+
newBox->setStyle(newStyle.release());
return newBox;
}
diff --git a/WebCore/rendering/RenderBlock.h b/WebCore/rendering/RenderBlock.h
index 839be16..d1d105a 100644
--- a/WebCore/rendering/RenderBlock.h
+++ b/WebCore/rendering/RenderBlock.h
@@ -2,7 +2,7 @@
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2007 David Smith (catfish.man@gmail.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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
@@ -34,7 +34,6 @@ namespace WebCore {
class InlineIterator;
class RenderInline;
-class RootInlineBox;
struct BidiRun;
@@ -67,17 +66,6 @@ public:
void deleteLineBoxTree();
- // The height (and width) of a block when you include overflow spillage out of the bottom
- // of the block (e.g., a <div style="height:25px"> that has a 100px tall image inside
- // it would have an overflow height of borderTop() + paddingTop() + 100px.
- virtual int overflowHeight(bool includeInterior = true) const;
- virtual int overflowWidth(bool includeInterior = true) const;
- virtual int overflowLeft(bool includeInterior = true) const;
- virtual int overflowTop(bool includeInterior = true) const;
- virtual IntRect overflowRect(bool includeInterior = true) const;
-
- void addVisualOverflow(const IntRect&);
-
virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0);
virtual void removeChild(RenderObject*);
@@ -104,6 +92,7 @@ public:
IntRect floatRect() const;
int lineWidth(int y, bool firstLine) const;
+
virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
@@ -147,14 +136,16 @@ public:
// This function is a convenience helper for creating an anonymous block that inherits its
// style from this RenderBlock.
- RenderBlock* createAnonymousBlock() const;
+ RenderBlock* createAnonymousBlock(bool isFlexibleBox = false) const;
- Vector<IntRect>* columnRects() const;
- int columnGap() const;
+ static void appendRunsForObject(int start, int end, RenderObject*, InlineBidiResolver&);
+ static bool requiresLineBox(const InlineIterator&, bool isLineEmpty = true, bool previousLineBrokeCleanly = true);
protected:
- virtual void setOverflowHeight(int h) { m_overflowHeight = h; }
- virtual void setOverflowWidth(int w) { m_overflowWidth = w; }
+ void moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* child);
+ void moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild, RenderObject* child);
+ void moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList);
+ void moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild);
int maxTopPosMargin() const { return m_maxMargin ? m_maxMargin->m_topPos : MaxMargin::topPosDefault(this); }
int maxTopNegMargin() const { return m_maxMargin ? m_maxMargin->m_topNeg : MaxMargin::topNegDefault(this); }
@@ -207,7 +198,7 @@ protected:
virtual bool hasLineIfEmpty() const;
bool layoutOnlyPositionedObjects();
-
+
private:
virtual RenderObjectChildList* virtualChildren() { return children(); }
virtual const RenderObjectChildList* virtualChildren() const { return children(); }
@@ -275,11 +266,14 @@ private:
InlineFlowBox* createLineBoxes(RenderObject*, bool firstLine);
void computeHorizontalPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd);
void computeVerticalPositionsForLine(RootInlineBox*, BidiRun*);
- void checkLinesForOverflow();
void deleteEllipsisLineBoxes();
void checkLinesForTextOverflow();
+ void addOverflowFromInlineChildren();
// End of functions defined in RenderBlockLineLayout.cpp.
+ void addOverflowFromBlockChildren();
+ void addOverflowFromFloats();
+
void paintFloats(PaintInfo&, int tx, int ty, bool preservePhase = false);
void paintContents(PaintInfo&, int tx, int ty);
void paintColumnContents(PaintInfo&, int tx, int ty, bool paintFloats = false);
@@ -353,18 +347,32 @@ private:
int desiredColumnWidth() const;
unsigned desiredColumnCount() const;
+#if PLATFORM(ANDROID)
+public:
+#endif
+ Vector<IntRect>* columnRects() const;
+#if PLATFORM(ANDROID)
+private:
+#endif
void setDesiredColumnCountAndWidth(int count, int width);
+#if PLATFORM(ANDROID)
+public:
+#endif
+ int columnGap() const;
+#if PLATFORM(ANDROID)
+private:
+#endif
void paintContinuationOutlines(PaintInfo&, int tx, int ty);
virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
void adjustPointToColumnContents(IntPoint&) const;
void adjustForBorderFit(int x, int& left, int& right) const; // Helper function for borderFitAdjust
- void markLinesDirtyInVerticalRange(int top, int bottom);
+ void markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest = 0);
void newLine(EClear);
@@ -376,13 +384,13 @@ private:
void offsetForContents(int& tx, int& ty) const;
void calcColumnWidth();
- int layoutColumns(int endOfContent = -1);
+ int layoutColumns(int endOfContent = -1, int requestedColumnHeight = -1);
bool expandsToEncloseOverhangingFloats() const;
void updateScrollInfoAfterLayout();
- struct FloatingObject {
+ struct FloatingObject : Noncopyable {
enum Type {
FloatLeft,
FloatRight
@@ -432,10 +440,6 @@ private:
// This flag is set when we know we're examining bottom margins and we know we're at the bottom of the block.
bool m_atBottomOfBlock : 1;
- // If our last normal flow child was a self-collapsing block that cleared a float,
- // we track it in this variable.
- bool m_selfCollapsingBlockClearedFloat : 1;
-
// These variables are used to detect quirky margins that we need to collapse away (in table cells
// and in the body element).
bool m_topQuirk : 1;
@@ -452,7 +456,6 @@ private:
void setAtTopOfBlock(bool b) { m_atTopOfBlock = b; }
void setAtBottomOfBlock(bool b) { m_atBottomOfBlock = b; }
void clearMargin() { m_posMargin = m_negMargin = 0; }
- void setSelfCollapsingBlockClearedFloat(bool b) { m_selfCollapsingBlockClearedFloat = b; }
void setTopQuirk(bool b) { m_topQuirk = b; }
void setBottomQuirk(bool b) { m_bottomQuirk = b; }
void setDeterminedTopQuirk(bool b) { m_determinedTopQuirk = b; }
@@ -468,7 +471,6 @@ private:
bool canCollapseWithBottom() const { return m_atBottomOfBlock && m_canCollapseBottomWithChildren; }
bool canCollapseTopWithChildren() const { return m_canCollapseTopWithChildren; }
bool canCollapseBottomWithChildren() const { return m_canCollapseBottomWithChildren; }
- bool selfCollapsingBlockClearedFloat() const { return m_selfCollapsingBlockClearedFloat; }
bool quirkContainer() const { return m_quirkContainer; }
bool determinedTopQuirk() const { return m_determinedTopQuirk; }
bool topQuirk() const { return m_topQuirk; }
@@ -478,6 +480,7 @@ private:
int margin() const { return m_posMargin - m_negMargin; }
};
+ void layoutBlockChild(RenderBox* child, MarginInfo&, int& previousFloatBottom, int& maxFloatBottom);
void adjustPositionedBlock(RenderBox* child, const MarginInfo&);
void adjustFloatingBlock(const MarginInfo&);
bool handleSpecialChild(RenderBox* child, const MarginInfo&);
@@ -503,7 +506,7 @@ private:
RenderInline* m_inlineContinuation;
// Allocated only when some of these fields have non-default values
- struct MaxMargin {
+ struct MaxMargin : Noncopyable {
MaxMargin(const RenderBlock* o)
: m_topPos(topPosDefault(o))
, m_topNeg(topNegDefault(o))
@@ -528,15 +531,11 @@ private:
RenderObjectChildList m_children;
RenderLineBoxList m_lineBoxes; // All of the root line boxes created for this block flow. For example, <div>Hello<br>world.</div> will have two total lines for the <div>.
-protected:
- // How much content overflows out of our block vertically or horizontally.
- int m_overflowHeight;
- int m_overflowWidth;
- int m_overflowLeft;
- int m_overflowTop;
-
-private:
mutable int m_lineHeight;
+
+ // RenderRubyBase objects need to be able to split and merge, moving their children around
+ // (calling moveChildTo, moveAllChildrenTo, and makeChildrenNonInline).
+ friend class RenderRubyBase;
};
inline RenderBlock* toRenderBlock(RenderObject* object)
diff --git a/WebCore/rendering/RenderBlockLineLayout.cpp b/WebCore/rendering/RenderBlockLineLayout.cpp
index 615a369..a7f3553 100644
--- a/WebCore/rendering/RenderBlockLineLayout.cpp
+++ b/WebCore/rendering/RenderBlockLineLayout.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009 Apple Inc. All right reserved.
+ * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All right reserved.
+ * Copyright (C) 2010 Google 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
@@ -23,12 +24,14 @@
#include "BidiResolver.h"
#include "CharacterNames.h"
+#include "InlineIterator.h"
#include "InlineTextBox.h"
#include "Logging.h"
#include "RenderArena.h"
#include "RenderInline.h"
#include "RenderListMarker.h"
#include "RenderView.h"
+#include "TrailingFloatsRootInlineBox.h"
#include "break_lines.h"
#include <wtf/AlwaysInline.h>
#include <wtf/RefCountedLeakCounter.h>
@@ -51,36 +54,6 @@ namespace WebCore {
// We don't let our line box tree for a single line get any deeper than this.
const unsigned cMaxLineDepth = 200;
-class InlineIterator {
-public:
- InlineIterator()
- : block(0)
- , obj(0)
- , pos(0)
- , nextBreakablePosition(-1)
- {
- }
-
- InlineIterator(RenderBlock* b, RenderObject* o, unsigned p)
- : block(b)
- , obj(o)
- , pos(p)
- , nextBreakablePosition(-1)
- {
- }
-
- void increment(InlineBidiResolver* resolver = 0);
- bool atEnd() const;
-
- UChar current() const;
- Direction direction() const;
-
- RenderBlock* block;
- RenderObject* obj;
- unsigned pos;
- int nextBreakablePosition;
-};
-
static int getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline)
{
bool leftSide = (child->style()->direction() == LTR) ? !endOfInline : endOfInline;
@@ -105,247 +78,6 @@ static int inlineWidth(RenderObject* child, bool start = true, bool end = true)
return extraWidth;
}
-struct BidiRun : BidiCharacterRun {
- BidiRun(int start, int stop, RenderObject* object, BidiContext* context, Direction dir)
- : BidiCharacterRun(start, stop, context, dir)
- , m_object(object)
- , m_box(0)
- {
- }
-
- void destroy();
-
- // Overloaded new operator.
- void* operator new(size_t, RenderArena*) throw();
-
- // Overridden to prevent the normal delete from being called.
- void operator delete(void*, size_t);
-
- BidiRun* next() { return static_cast<BidiRun*>(m_next); }
-
-private:
- // The normal operator new is disallowed.
- void* operator new(size_t) throw();
-
-public:
- RenderObject* m_object;
- InlineBox* m_box;
-};
-
-#ifndef NDEBUG
-static RefCountedLeakCounter bidiRunCounter("BidiRun");
-
-static bool inBidiRunDestroy;
-#endif
-
-void BidiRun::destroy()
-{
-#ifndef NDEBUG
- inBidiRunDestroy = true;
-#endif
- RenderArena* renderArena = m_object->renderArena();
- delete this;
-#ifndef NDEBUG
- inBidiRunDestroy = false;
-#endif
-
- // Recover the size left there for us by operator delete and free the memory.
- renderArena->free(*reinterpret_cast<size_t*>(this), this);
-}
-
-void* BidiRun::operator new(size_t sz, RenderArena* renderArena) throw()
-{
-#ifndef NDEBUG
- bidiRunCounter.increment();
-#endif
- return renderArena->allocate(sz);
-}
-
-void BidiRun::operator delete(void* ptr, size_t sz)
-{
-#ifndef NDEBUG
- bidiRunCounter.decrement();
-#endif
- ASSERT(inBidiRunDestroy);
-
- // Stash size where destroy() can find it.
- *(size_t*)ptr = sz;
-}
-
-// ---------------------------------------------------------------------
-
-inline bool operator==(const InlineIterator& it1, const InlineIterator& it2)
-{
- return it1.pos == it2.pos && it1.obj == it2.obj;
-}
-
-inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2)
-{
- return it1.pos != it2.pos || it1.obj != it2.obj;
-}
-
-static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, InlineBidiResolver* resolver = 0, bool skipInlines = true, bool* endOfInlinePtr = 0)
-{
- RenderObject* next = 0;
- bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false;
- bool endOfInline = false;
-
- while (current) {
- next = 0;
- if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned() && !current->isText()) {
- next = current->firstChild();
- if (next && resolver && next->isRenderInline()) {
- EUnicodeBidi ub = next->style()->unicodeBidi();
- if (ub != UBNormal) {
- TextDirection dir = next->style()->direction();
- Direction d = (ub == Embed
- ? (dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding)
- : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
- resolver->embed(d);
- }
- }
- }
-
- if (!next) {
- if (!skipInlines && !oldEndOfInline && current->isRenderInline()) {
- next = current;
- endOfInline = true;
- break;
- }
-
- while (current && current != block) {
- if (resolver && current->isRenderInline() && current->style()->unicodeBidi() != UBNormal)
- resolver->embed(PopDirectionalFormat);
-
- next = current->nextSibling();
- if (next) {
- if (resolver && next->isRenderInline()) {
- EUnicodeBidi ub = next->style()->unicodeBidi();
- if (ub != UBNormal) {
- TextDirection dir = next->style()->direction();
- Direction d = (ub == Embed
- ? (dir == RTL ? RightToLeftEmbedding: LeftToRightEmbedding)
- : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
- resolver->embed(d);
- }
- }
- break;
- }
-
- current = current->parent();
- if (!skipInlines && current && current != block && current->isRenderInline()) {
- next = current;
- endOfInline = true;
- break;
- }
- }
- }
-
- if (!next)
- break;
-
- if (next->isText() || next->isFloating() || next->isReplaced() || next->isPositioned()
- || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines.
- && next->isRenderInline()))
- break;
- current = next;
- }
-
- if (endOfInlinePtr)
- *endOfInlinePtr = endOfInline;
-
- return next;
-}
-
-static RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* resolver, bool skipInlines = true)
-{
- if (!block->firstChild())
- return 0;
-
- RenderObject* o = block->firstChild();
- if (o->isRenderInline()) {
- if (resolver) {
- EUnicodeBidi ub = o->style()->unicodeBidi();
- if (ub != UBNormal) {
- TextDirection dir = o->style()->direction();
- Direction d = (ub == Embed
- ? (dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding)
- : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
- resolver->embed(d);
- }
- }
- if (skipInlines && o->firstChild())
- o = bidiNext(block, o, resolver, skipInlines);
- else {
- // Never skip empty inlines.
- if (resolver)
- resolver->commitExplicitEmbedding();
- return o;
- }
- }
-
- if (o && !o->isText() && !o->isReplaced() && !o->isFloating() && !o->isPositioned())
- o = bidiNext(block, o, resolver, skipInlines);
-
- if (resolver)
- resolver->commitExplicitEmbedding();
- return o;
-}
-
-inline void InlineIterator::increment(InlineBidiResolver* resolver)
-{
- if (!obj)
- return;
- if (obj->isText()) {
- pos++;
- if (pos >= toRenderText(obj)->textLength()) {
- obj = bidiNext(block, obj, resolver);
- pos = 0;
- nextBreakablePosition = -1;
- }
- } else {
- obj = bidiNext(block, obj, resolver);
- pos = 0;
- nextBreakablePosition = -1;
- }
-}
-
-template<>
-inline void InlineBidiResolver::increment()
-{
- current.increment(this);
-}
-
-inline bool InlineIterator::atEnd() const
-{
- return !obj;
-}
-
-inline UChar InlineIterator::current() const
-{
- if (!obj || !obj->isText())
- return 0;
-
- RenderText* text = toRenderText(obj);
- if (pos >= text->textLength())
- return 0;
-
- return text->characters()[pos];
-}
-
-ALWAYS_INLINE Direction InlineIterator::direction() const
-{
- if (UChar c = current())
- return Unicode::direction(c);
-
- if (obj && obj->isListMarker())
- return obj->style()->direction() == LTR ? LeftToRight : RightToLeft;
-
- return OtherNeutral;
-}
-
-// -------------------------------------------------------------------------------------------------
-
static void chopMidpointsAt(LineMidpointState& lineMidpointState, RenderObject* obj, unsigned pos)
{
if (!lineMidpointState.numMidpoints)
@@ -403,7 +135,7 @@ static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterat
midpoints[lineMidpointState.numMidpoints++] = midpoint;
}
-static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
+void RenderBlock::appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
{
if (start > end || obj->isFloating() ||
(obj->isPositioned() && !obj->style()->hasStaticX() && !obj->style()->hasStaticY() && !obj->container()->isRenderInline()))
@@ -446,36 +178,6 @@ static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBid
}
}
-template <>
-void InlineBidiResolver::appendRun()
-{
- if (!emptyRun && !eor.atEnd()) {
- int start = sor.pos;
- RenderObject *obj = sor.obj;
- while (obj && obj != eor.obj && obj != endOfLine.obj) {
- appendRunsForObject(start, obj->length(), obj, *this);
- start = 0;
- obj = bidiNext(sor.block, obj);
- }
- if (obj) {
- unsigned pos = obj == eor.obj ? eor.pos : UINT_MAX;
- if (obj == endOfLine.obj && endOfLine.pos <= pos) {
- reachedEndOfLine = true;
- pos = endOfLine.pos;
- }
- // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be
- int end = obj->length() ? pos+1 : 0;
- appendRunsForObject(start, end, obj, *this);
- }
-
- eor.increment();
- sor = eor;
- }
-
- m_direction = OtherNeutral;
- m_status.eor = OtherNeutral;
-}
-
static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false)
{
if (isRootLineBox)
@@ -770,11 +472,8 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, bool
// The widths of all runs are now known. We can now place every inline box (and
// compute accurate widths for the inline flow boxes).
- int leftPosition = x;
- int rightPosition = x;
needsWordSpacing = false;
- lineBox->placeBoxesHorizontally(x, leftPosition, rightPosition, needsWordSpacing);
- lineBox->setHorizontalOverflowPositions(leftPosition, rightPosition);
+ lineBox->placeBoxesHorizontally(x, needsWordSpacing);
}
void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun)
@@ -782,11 +481,6 @@ void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRu
setHeight(lineBox->verticallyAlignBoxes(height()));
lineBox->setBlockHeight(height());
- // See if the line spilled out. If so set overflow height accordingly.
- int bottomOfLine = lineBox->bottomOverflow();
- if (bottomOfLine > height() && bottomOfLine > m_overflowHeight)
- m_overflowHeight = bottomOfLine;
-
// Now make sure we place replaced render objects correctly.
for (BidiRun* r = firstRun; r; r = r->next()) {
ASSERT(r->m_box);
@@ -831,14 +525,14 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
{
bool useRepaintBounds = false;
- m_overflowHeight = 0;
+ m_overflow.clear();
setHeight(borderTop() + paddingTop());
int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
// Figure out if we should clear out our line boxes.
// FIXME: Handle resize eventually!
- bool fullLayout = !firstLineBox() || !firstChild() || selfNeedsLayout() || relayoutChildren;
+ bool fullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren;
if (fullLayout)
lineBoxes()->deleteLineBoxes(renderArena());
@@ -855,14 +549,17 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
if (firstChild()) {
#ifdef ANDROID_LAYOUT
- // if we are in fitColumnToScreen mode and viewport width is not device-width,
+ // if we are in fitColumnToScreen mode
// and the current object is not float:right in LTR or not float:left in RTL,
// and text align is auto, or justify or left in LTR, or right in RTL, we
// will wrap text around screen width so that it doesn't need to scroll
// horizontally when reading a paragraph.
+ // In case the line height is less than the font size, we skip
+ // the text wrapping since this will cause text overlapping.
+ // If a text has background image, we ignore text wrapping,
+ // otherwise the background will be potentially messed up.
const Settings* settings = document()->settings();
- bool doTextWrap = settings && settings->viewportWidth() != 0 &&
- settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen;
+ bool doTextWrap = settings && settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen;
if (doTextWrap) {
int ta = style()->textAlign();
int dir = style()->direction();
@@ -871,9 +568,12 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
// width as it may cause text to overlap.
bool positioned = isPositioned();
EFloat cssfloat = style()->floating();
+ const int lineHeight = style()->computedLineHeight();
+ const int fontSize = style()->fontSize();
doTextWrap = autowrap && !positioned &&
+ (fontSize <= lineHeight) && !style()->hasBackgroundImage() &&
(((dir == LTR && cssfloat != FRIGHT) ||
- (dir == RTL && cssfloat != FLEFT)) &&
+ (dir == RTL && cssfloat != FLEFT)) &&
((ta == TAAUTO) || (ta == JUSTIFY) ||
((ta == LEFT || ta == WEBKIT_LEFT) && (dir == LTR)) ||
((ta == RIGHT || ta == WEBKIT_RIGHT) && (dir == RTL))));
@@ -884,6 +584,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
bool endOfInline = false;
RenderObject* o = bidiFirst(this, 0, false);
Vector<FloatWithRect> floats;
+ bool hasInlineChild = false;
while (o) {
if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
RenderBox* box = toRenderBox(o);
@@ -911,6 +612,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
o->layoutIfNeeded();
}
} else if (o->isText() || (o->isRenderInline() && !endOfInline)) {
+ hasInlineChild = true;
if (fullLayout || o->selfNeedsLayout())
dirtyLineBoxesForRenderer(o, fullLayout);
o->setNeedsLayout(false);
@@ -956,7 +658,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
break;
}
if (obj->isFloating() || obj->isPositioned()) {
- // floating and absolute or fixed positioning are done out
+ // floating and absolute or fixed positioning are done out
// of normal flow. Don't need to worry about height any more.
break;
}
@@ -972,7 +674,13 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
setWidth(min(width(), maxWidth));
m_minPrefWidth = min(m_minPrefWidth, maxWidth);
m_maxPrefWidth = min(m_maxPrefWidth, maxWidth);
- m_overflowWidth = min(m_overflowWidth, maxWidth);
+
+ IntRect overflow = layoutOverflowRect();
+ if (overflow.width() > maxWidth) {
+ overflow.setWidth(maxWidth);
+ clearLayoutOverflow();
+ addLayoutOverflow(overflow);
+ }
}
}
}
@@ -984,7 +692,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
bool previousLineBrokeCleanly = true;
RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex);
- if (fullLayout && !selfNeedsLayout()) {
+ if (fullLayout && hasInlineChild && !selfNeedsLayout()) {
setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like
// we're supposed to.
RenderView* v = view();
@@ -1016,8 +724,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
RenderArena* arena = renderArena();
RootInlineBox* box = startLine;
while (box) {
- repaintTop = min(repaintTop, box->topOverflow());
- repaintBottom = max(repaintBottom, box->bottomOverflow());
+ repaintTop = min(repaintTop, box->topVisibleOverflow());
+ repaintBottom = max(repaintBottom, box->bottomVisibleOverflow());
RootInlineBox* next = box->nextRootBox();
box->deleteLine(arena);
box = next;
@@ -1153,8 +861,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
if (lineBox) {
lineBox->setLineBreakInfo(end.obj, end.pos, resolver.status());
if (useRepaintBounds) {
- repaintTop = min(repaintTop, lineBox->topOverflow());
- repaintBottom = max(repaintBottom, lineBox->bottomOverflow());
+ repaintTop = min(repaintTop, lineBox->topVisibleOverflow());
+ repaintBottom = max(repaintBottom, lineBox->bottomVisibleOverflow());
}
}
@@ -1193,8 +901,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) {
line->attachLine();
if (delta) {
- repaintTop = min(repaintTop, line->topOverflow() + min(delta, 0));
- repaintBottom = max(repaintBottom, line->bottomOverflow() + max(delta, 0));
+ repaintTop = min(repaintTop, line->topVisibleOverflow() + min(delta, 0));
+ repaintBottom = max(repaintBottom, line->bottomVisibleOverflow() + max(delta, 0));
line->adjustPosition(0, delta);
}
if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
@@ -1210,12 +918,12 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
setHeight(lastRootBox()->blockHeight());
} else {
// Delete all the remaining lines.
- InlineRunBox* line = endLine;
+ RootInlineBox* line = endLine;
RenderArena* arena = renderArena();
while (line) {
- repaintTop = min(repaintTop, line->topOverflow());
- repaintBottom = max(repaintBottom, line->bottomOverflow());
- InlineRunBox* next = line->nextLineBox();
+ repaintTop = min(repaintTop, line->topVisibleOverflow());
+ repaintBottom = max(repaintBottom, line->bottomVisibleOverflow());
+ RootInlineBox* next = line->nextRootBox();
line->deleteLine(arena);
line = next;
}
@@ -1225,6 +933,16 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
// In case we have a float on the last line, it might not be positioned up to now.
// This has to be done before adding in the bottom border/padding, or the float will
// include the padding incorrectly. -dwh
+ if (checkForFloatsFromLastLine) {
+ int bottomVisualOverflow = lastRootBox()->bottomVisualOverflow();
+ int bottomLayoutOverflow = lastRootBox()->bottomLayoutOverflow();
+ TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this);
+ m_lineBoxes.appendLineBox(trailingFloatsLineBox);
+ trailingFloatsLineBox->setConstructed();
+ trailingFloatsLineBox->verticallyAlignBoxes(height());
+ trailingFloatsLineBox->setVerticalOverflowPositions(height(), bottomLayoutOverflow, height(), bottomVisualOverflow, 0);
+ trailingFloatsLineBox->setBlockHeight(height());
+ }
if (lastFloat) {
for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
}
@@ -1253,12 +971,6 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
// Now add in the bottom border/padding.
setHeight(height() + toAdd);
- // Always make sure this is at least our height.
- m_overflowHeight = max(height(), m_overflowHeight);
-
- // See if any lines spill out of the block. If so, we need to update our overflow width.
- checkLinesForOverflow();
-
if (!firstLineBox() && hasLineIfEmpty())
setHeight(height() + lineHeight(true, true));
@@ -1293,7 +1005,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
if (floats[floatIndex].rect.size() != newSize) {
int floatTop = floats[floatIndex].rect.y();
curr->markDirty();
- markLinesDirtyInVerticalRange(curr->blockHeight(), floatTop + max(floats[floatIndex].rect.height(), newSize.height()));
+ markLinesDirtyInVerticalRange(curr->blockHeight(), floatTop + max(floats[floatIndex].rect.height(), newSize.height()), curr);
floats[floatIndex].rect.setSize(newSize);
dirtiedByFloat = true;
}
@@ -1485,8 +1197,8 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin
RootInlineBox* boxToDelete = endLine;
RenderArena* arena = renderArena();
while (boxToDelete && boxToDelete != result) {
- repaintTop = min(repaintTop, boxToDelete->topOverflow());
- repaintBottom = max(repaintBottom, boxToDelete->bottomOverflow());
+ repaintTop = min(repaintTop, boxToDelete->topVisibleOverflow());
+ repaintBottom = max(repaintBottom, boxToDelete->bottomVisibleOverflow());
RootInlineBox* next = boxToDelete->nextRootBox();
boxToDelete->deleteLine(arena);
boxToDelete = next;
@@ -1539,7 +1251,7 @@ static bool inlineFlowRequiresLineBox(RenderInline* flow)
return !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin();
}
-static inline bool requiresLineBox(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly)
+bool RenderBlock::requiresLineBox(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly)
{
if (it.obj->isFloatingOrPositioned())
return false;
@@ -1878,10 +1590,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
currentCharacterIsSpace = false;
currentCharacterIsWS = false;
trailingSpaceObject = 0;
-
+
// Optimize for a common case. If we can't find whitespace after the list
// item, then this is all moot. -dwh
- if (o->isListMarker() && !toRenderListMarker(o)->isInside()) {
+ if (o->isListMarker()) {
if (style()->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) {
// Like with inline flows, we start ignoring spaces to make sure that any
// additional spaces we see will be discarded.
@@ -1889,6 +1601,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
currentCharacterIsWS = true;
ignoringSpaces = true;
}
+ if (toRenderListMarker(o)->isInside())
+ tmpW += replacedBox->width() + replacedBox->marginLeft() + replacedBox->marginRight() + inlineWidth(o);
} else
tmpW += replacedBox->width() + replacedBox->marginLeft() + replacedBox->marginRight() + inlineWidth(o);
} else if (o->isText()) {
@@ -1908,6 +1622,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
int wordSpacing = o->style()->wordSpacing();
int lastSpaceWordSpacing = 0;
+ // Non-zero only when kerning is enabled, in which case we measure words with their trailing
+ // space, then subtract its width.
+ int wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.spaceWidth() + wordSpacing : 0;
+
int wrapW = tmpW + inlineWidth(o, !appliedStartWidth, true);
int charWidth = 0;
bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE;
@@ -2002,7 +1720,11 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
}
}
- int additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
+ int additionalTmpW;
+ if (wordTrailingSpaceWidth && currentCharacterIsSpace)
+ additionalTmpW = textWidth(t, lastSpace, pos + 1 - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing;
+ else
+ additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
tmpW += additionalTmpW;
if (!appliedStartWidth) {
tmpW += inlineWidth(o, true, false);
@@ -2034,7 +1756,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
}
}
if (lineWasTooWide || w + tmpW > width) {
- if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && !toRenderText(lBreak.obj)->isWordBreak() && toRenderText(lBreak.obj)->characters()[lBreak.pos] == '\n') {
+ if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && toRenderText(lBreak.obj)->textLength() && !toRenderText(lBreak.obj)->isWordBreak() && toRenderText(lBreak.obj)->characters()[lBreak.pos] == '\n') {
if (!stoppedIgnoringSpaces && pos > 0) {
// We need to stop right before the newline and then start up again.
addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop
@@ -2243,19 +1965,12 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
lBreak.nextBreakablePosition = -1;
}
} else if (lBreak.obj) {
- if (last != o && !last->isListMarker()) {
- // better to break between object boundaries than in the middle of a word (except for list markers)
- lBreak.obj = o;
- lBreak.pos = 0;
- lBreak.nextBreakablePosition = -1;
- } else {
- // Don't ever break in the middle of a word if we can help it.
- // There's no room at all. We just have to be on this line,
- // even though we'll spill out.
- lBreak.obj = o;
- lBreak.pos = pos;
- lBreak.nextBreakablePosition = -1;
- }
+ // Don't ever break in the middle of a word if we can help it.
+ // There's no room at all. We just have to be on this line,
+ // even though we'll spill out.
+ lBreak.obj = o;
+ lBreak.pos = pos;
+ lBreak.nextBreakablePosition = -1;
}
}
@@ -2306,14 +2021,12 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
return lBreak;
}
-void RenderBlock::checkLinesForOverflow()
+void RenderBlock::addOverflowFromInlineChildren()
{
- m_overflowWidth = width();
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
- m_overflowLeft = min(curr->leftOverflow(), m_overflowLeft);
- m_overflowTop = min(curr->topOverflow(), m_overflowTop);
- m_overflowWidth = max(curr->rightOverflow(), m_overflowWidth);
- m_overflowHeight = max(curr->bottomOverflow(), m_overflowHeight);
+ addLayoutOverflow(curr->layoutOverflowRect());
+ if (!hasOverflowClip())
+ addVisualOverflow(curr->visualOverflowRect());
}
}
diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp
index 4c2bff0..92c3d99 100644
--- a/WebCore/rendering/RenderBox.cpp
+++ b/WebCore/rendering/RenderBox.cpp
@@ -26,6 +26,7 @@
#include "RenderBox.h"
#include "CachedImage.h"
+#include "Chrome.h"
#include "ChromeClient.h"
#include "Document.h"
#include "FrameView.h"
@@ -145,6 +146,8 @@ void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyl
markContainingBlocksForLayout();
if (style()->position() == StaticPosition)
repaint();
+ else if (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition)
+ parent()->setChildNeedsLayout(true);
if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
removeFloatingOrPositionedChildFromBlockLists();
}
@@ -333,12 +336,12 @@ IntRect RenderBox::outlineBoundsForRepaint(RenderBoxModelObject* repaintContaine
return box;
}
-void RenderBox::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+void RenderBox::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
{
- graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
+ if (width() && height())
+ rects.append(IntRect(tx, ty, width(), height()));
}
-
IntRect RenderBox::reflectionBox() const
{
IntRect result;
@@ -406,16 +409,28 @@ int RenderBox::horizontalScrollbarHeight() const
return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
}
-bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
+bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
{
RenderLayer* l = layer();
- if (l && l->scroll(direction, granularity, multiplier))
+ if (l && l->scroll(direction, granularity, multiplier)) {
+ if (stopNode)
+ *stopNode = node();
+ return true;
+ }
+
+ if (stopNode && *stopNode && *stopNode == node())
return true;
+
RenderBlock* b = containingBlock();
if (b && !b->isRenderView())
- return b->scroll(direction, granularity, multiplier);
+ return b->scroll(direction, granularity, multiplier, stopNode);
return false;
}
+
+bool RenderBox::canBeScrolledAndHasScrollableArea() const
+{
+ return canBeProgramaticallyScrolled(false) && (scrollHeight() != clientHeight() || scrollWidth() != clientWidth());
+}
bool RenderBox::canBeProgramaticallyScrolled(bool) const
{
@@ -554,13 +569,14 @@ void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
{
const FillLayer* bgLayer = style()->backgroundLayers();
Color bgColor = style()->backgroundColor();
+ RenderObject* bodyObject = 0;
if (!style()->hasBackground() && node() && node()->hasTagName(HTMLNames::htmlTag)) {
// Locate the <body> element using the DOM. This is easier than trying
// to crawl around a render tree with potential :before/:after content and
// anonymous blocks created by inline <body> tags etc. We can locate the <body>
// render object very easily via the DOM.
HTMLElement* body = document()->body();
- RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
+ bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
if (bodyObject) {
bgLayer = bodyObject->style()->backgroundLayers();
bgColor = bodyObject->style()->backgroundColor();
@@ -588,7 +604,7 @@ void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
- paintFillLayers(paintInfo, bgColor, bgLayer, bx, by, bw, bh);
+ paintFillLayers(paintInfo, bgColor, bgLayer, bx, by, bw, bh, CompositeSourceOver, bodyObject);
if (style()->hasBorder() && style()->display() != INLINE)
paintBorder(paintInfo.context, tx, ty, w, h, style());
@@ -653,35 +669,58 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int
{
// Figure out if we need to push a transparency layer to render our mask.
bool pushTransparencyLayer = false;
- StyleImage* maskBoxImage = style()->maskBoxImage().image();
- if (maskBoxImage && style()->maskLayers()->hasImage()) {
- pushTransparencyLayer = true;
- } else {
- // We have to use an extra image buffer to hold the mask. Multiple mask images need
- // to composite together using source-over so that they can then combine into a single unified mask that
- // can be composited with the content using destination-in. SVG images need to be able to set compositing modes
- // as they draw images contained inside their sub-document, so we paint all our images into a separate buffer
- // and composite that buffer as the mask.
- // We have to check that the mask images to be rendered contain at least one image that can be actually used in rendering
- // before pushing the transparency layer.
- for (const FillLayer* fillLayer = style()->maskLayers()->next(); fillLayer; fillLayer = fillLayer->next()) {
- if (fillLayer->hasImage() && fillLayer->image()->canRender(style()->effectiveZoom())) {
- pushTransparencyLayer = true;
- // We found one image that can be used in rendering, exit the loop
- break;
+ bool compositedMask = hasLayer() && layer()->hasCompositedMask();
+ CompositeOperator compositeOp = CompositeSourceOver;
+
+ bool allMaskImagesLoaded = true;
+
+ if (!compositedMask) {
+ StyleImage* maskBoxImage = style()->maskBoxImage().image();
+ const FillLayer* maskLayers = style()->maskLayers();
+
+ // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
+ if (maskBoxImage)
+ allMaskImagesLoaded &= maskBoxImage->isLoaded();
+
+ if (maskLayers)
+ allMaskImagesLoaded &= maskLayers->imagesAreLoaded();
+
+ // Before all images have loaded, just use an empty transparency layer as the mask.
+ if (!allMaskImagesLoaded)
+ pushTransparencyLayer = true;
+
+ if (maskBoxImage && maskLayers->hasImage()) {
+ // We have a mask-box-image and mask-image, so need to composite them together before using the result as a mask.
+ pushTransparencyLayer = true;
+ } else {
+ // We have to use an extra image buffer to hold the mask. Multiple mask images need
+ // to composite together using source-over so that they can then combine into a single unified mask that
+ // can be composited with the content using destination-in. SVG images need to be able to set compositing modes
+ // as they draw images contained inside their sub-document, so we paint all our images into a separate buffer
+ // and composite that buffer as the mask.
+ // We have to check that the mask images to be rendered contain at least one image that can be actually used in rendering
+ // before pushing the transparency layer.
+ for (const FillLayer* fillLayer = maskLayers->next(); fillLayer; fillLayer = fillLayer->next()) {
+ if (fillLayer->hasImage() && fillLayer->image()->canRender(style()->effectiveZoom())) {
+ pushTransparencyLayer = true;
+ // We found one image that can be used in rendering, exit the loop
+ break;
+ }
}
}
- }
-
- CompositeOperator compositeOp = CompositeDestinationIn;
- if (pushTransparencyLayer) {
- paintInfo.context->setCompositeOperation(CompositeDestinationIn);
- paintInfo.context->beginTransparencyLayer(1.0f);
- compositeOp = CompositeSourceOver;
+
+ compositeOp = CompositeDestinationIn;
+ if (pushTransparencyLayer) {
+ paintInfo.context->setCompositeOperation(CompositeDestinationIn);
+ paintInfo.context->beginTransparencyLayer(1.0f);
+ compositeOp = CompositeSourceOver;
+ }
}
- paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp);
- paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp);
+ if (allMaskImagesLoaded) {
+ paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp);
+ paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp);
+ }
if (pushTransparencyLayer)
paintInfo.context->endTransparencyLayer();
@@ -706,18 +745,18 @@ IntRect RenderBox::maskClipRect()
return result;
}
-void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op)
+void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject)
{
if (!fillLayer)
return;
- paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op);
- paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op);
+ paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op, backgroundObject);
+ paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op, backgroundObject);
}
-void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op)
+void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject)
{
- paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op);
+ paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op, backgroundObject);
}
void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
@@ -927,17 +966,20 @@ void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool
}
}
- if (style()->position() == FixedPosition)
- fixed = true;
-
- RenderObject* o = container();
+ bool containerSkipped;
+ RenderObject* o = container(repaintContainer, &containerSkipped);
if (!o)
return;
+ bool isFixedPos = style()->position() == FixedPosition;
bool hasTransform = hasLayer() && layer()->transform();
- if (hasTransform)
- fixed = false; // Elements with transforms act as a containing block for fixed position descendants
-
+ if (hasTransform) {
+ // If this box has a transform, it acts as a fixed position container for fixed descendants,
+ // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
+ fixed &= isFixedPos;
+ } else
+ fixed |= isFixedPos;
+
IntSize containerOffset = offsetFromContainer(o);
bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
@@ -948,6 +990,14 @@ void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool
} else
transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
+ if (containerSkipped) {
+ // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
+ // to just subtract the delta between the repaintContainer and o.
+ IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
+ transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
+ return;
+ }
+
o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
}
@@ -956,12 +1006,14 @@ void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, Transfor
// We don't expect absoluteToLocal() to be called during layout (yet)
ASSERT(!view() || !view()->layoutStateEnabled());
- if (style()->position() == FixedPosition)
- fixed = true;
-
+ bool isFixedPos = style()->position() == FixedPosition;
bool hasTransform = hasLayer() && layer()->transform();
- if (hasTransform)
- fixed = false; // Elements with transforms act as a containing block for fixed position descendants
+ if (hasTransform) {
+ // If this box has a transform, it acts as a fixed position container for fixed descendants,
+ // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
+ fixed &= isFixedPos;
+ } else
+ fixed |= isFixedPos;
RenderObject* o = container();
if (!o)
@@ -1068,7 +1120,7 @@ IntRect RenderBox::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintCo
if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
return IntRect();
- IntRect r = overflowRect(false);
+ IntRect r = visibleOverflowRect();
RenderView* v = view();
if (v) {
@@ -1120,7 +1172,8 @@ void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, In
if (repaintContainer == this)
return;
- RenderObject* o = container();
+ bool containerSkipped;
+ RenderObject* o = container(repaintContainer, &containerSkipped);
if (!o)
return;
@@ -1177,6 +1230,13 @@ void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, In
return;
} else
rect.setLocation(topLeft);
+
+ if (containerSkipped) {
+ // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
+ IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
+ rect.move(-containerOffset);
+ return;
+ }
o->computeRectForRepaint(repaintContainer, rect, fixed);
}
@@ -1210,7 +1270,7 @@ void RenderBox::calcWidth()
}
}
#endif
-
+
if (isPositioned()) {
calcAbsoluteHorizontal();
return;
@@ -1250,10 +1310,11 @@ void RenderBox::calcWidth()
if (treatAsReplaced)
#endif
setWidth(max(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(), minPrefWidth()));
+
#ifdef ANDROID_LAYOUT
// in SSR mode with replaced box, if the box width is wider than the container width,
// it will be shrinked to fit to the container.
- if (containerWidth && (width() + m_marginLeft + m_marginRight) > containerWidth &&
+ if (containerWidth && (width() + m_marginLeft + m_marginRight) > containerWidth &&
document()->frame()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
m_marginLeft = m_marginRight = 0;
setWidth(containerWidth);
@@ -1304,8 +1365,8 @@ void RenderBox::calcWidth()
}
#ifdef ANDROID_LAYOUT
// in SSR mode with non-replaced box, we use ANDROID_SSR_MARGIN_PADDING for left/right margin.
- // If the box width is wider than the container width, it will be shrinked to fit to the container.
- if (containerWidth && !treatAsReplaced &&
+ // If the box width is wider than the container width, it will be shrinked to fit to the container.
+ if (containerWidth && !treatAsReplaced &&
document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
setWidth(width() + m_marginLeft + m_marginRight);
m_marginLeft = m_marginLeft > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginLeft;
@@ -1486,7 +1547,7 @@ void RenderBox::calcHeight()
// height since we don't set a height in RenderView when we're printing. So without this quirk, the
// height has nothing to be a percentage of, and it ends up being 0. That is bad.
bool printingNeedsBaseHeight = document()->printing() && h.isPercent()
- && (isRoot() || isBody() && document()->documentElement()->renderer()->style()->height().isPercent());
+ && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->height().isPercent()));
if (stretchesToViewHeight() || printingNeedsBaseHeight) {
int margins = collapsedMarginTop() + collapsedMarginBottom();
int visHeight = document()->printing() ? view()->frameView()->visibleHeight() : view()->viewHeight();
@@ -1520,7 +1581,7 @@ int RenderBox::calcHeightUsing(const Length& h)
int RenderBox::calcPercentageHeight(const Length& height)
{
int result = -1;
- bool includeBorderPadding = isTable();
+ bool skippedAutoHeightContainingBlock = false;
RenderBlock* cb = containingBlock();
if (style()->htmlHacks()) {
// In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
@@ -1528,6 +1589,7 @@ int RenderBox::calcPercentageHeight(const Length& height)
// specification, which states that percentage heights just revert to auto if the containing
// block has an auto height.
while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->height().isAuto()) {
+ skippedAutoHeightContainingBlock = true;
cb = cb->containingBlock();
cb->addPercentHeightDescendant(this);
}
@@ -1537,25 +1599,29 @@ int RenderBox::calcPercentageHeight(const Length& height)
// explicitly specified that can be used for any percentage computations.
bool isPositionedWithSpecifiedHeight = cb->isPositioned() && (!cb->style()->height().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
+ bool includeBorderPadding = isTable();
+
// Table cells violate what the CSS spec says to do with heights. Basically we
// don't care if the cell specified a height or not. We just always make ourselves
// be a percentage of the cell's current content height.
if (cb->isTableCell()) {
- result = cb->overrideSize();
- if (result == -1) {
- // Normally we would let the cell size intrinsically, but scrolling overflow has to be
- // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
- // While we can't get all cases right, we can at least detect when the cell has a specified
- // height or when the table has a specified height. In these cases we want to initially have
- // no size and allow the flexing of the table or the cell to its specified height to cause us
- // to grow to fill the space. This could end up being wrong in some cases, but it is
- // preferable to the alternative (sizing intrinsically and making the row end up too big).
- RenderTableCell* cell = toRenderTableCell(cb);
- if (scrollsOverflowY() && (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto()))
- return 0;
- return -1;
+ if (!skippedAutoHeightContainingBlock) {
+ result = cb->overrideSize();
+ if (result == -1) {
+ // Normally we would let the cell size intrinsically, but scrolling overflow has to be
+ // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
+ // While we can't get all cases right, we can at least detect when the cell has a specified
+ // height or when the table has a specified height. In these cases we want to initially have
+ // no size and allow the flexing of the table or the cell to its specified height to cause us
+ // to grow to fill the space. This could end up being wrong in some cases, but it is
+ // preferable to the alternative (sizing intrinsically and making the row end up too big).
+ RenderTableCell* cell = toRenderTableCell(cb);
+ if (scrollsOverflowY() && (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto()))
+ return 0;
+ return -1;
+ }
+ includeBorderPadding = true;
}
- includeBorderPadding = true;
}
// Otherwise we only use our percentage height if our containing block had a specified
// height.
@@ -1926,7 +1992,7 @@ void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBoxModelO
int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos)
{
// 'left' and 'right' cannot both be 'auto' because one would of been
- // converted to the static postion already
+ // converted to the static position already
ASSERT(!(left.isAuto() && right.isAuto()));
int leftValue = 0;
@@ -1960,7 +2026,7 @@ void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBoxModelO
if (marginLeft.isAuto() && marginRight.isAuto()) {
// Both margins auto, solve for equality
if (availableSpace >= 0) {
- marginLeftValue = availableSpace / 2; // split the diference
+ marginLeftValue = availableSpace / 2; // split the difference
marginRightValue = availableSpace - marginLeftValue; // account for odd valued differences
} else {
// see FIXME 1
@@ -2245,7 +2311,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBoxModelObject*
if (marginTop.isAuto() && marginBottom.isAuto()) {
// Both margins auto, solve for equality
// NOTE: This may result in negative values.
- marginTopValue = availableSpace / 2; // split the diference
+ marginTopValue = availableSpace / 2; // split the difference
marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences
} else if (marginTop.isAuto()) {
// Solve for top margin
@@ -2323,7 +2389,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBoxModelObject*
void RenderBox::calcAbsoluteHorizontalReplaced()
{
// The following is based off of the W3C Working Draft from April 11, 2006 of
- // CSS 2.1: Section 10.3.8 "Absolutly positioned, replaced elements"
+ // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
// <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
// (block-style-comments in this function correspond to text from the spec and
// the numbers correspond to numbers in spec)
@@ -2414,7 +2480,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced()
int difference = availableSpace - (leftValue + rightValue);
if (difference > 0) {
- m_marginLeft = difference / 2; // split the diference
+ m_marginLeft = difference / 2; // split the difference
m_marginRight = difference - m_marginLeft; // account for odd valued differences
} else {
// see FIXME 1
@@ -2485,7 +2551,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced()
// positioned, inline containing block because right now, it is using the xPos
// of the first line box when really it should use the last line box. When
// this is fixed elsewhere, this block should be removed.
- if (containerBlock->isInline() && containerBlock->style()->direction() == RTL) {
+ if (containerBlock->isRenderInline() && containerBlock->style()->direction() == RTL) {
const RenderInline* flow = toRenderInline(containerBlock);
InlineFlowBox* firstLine = flow->firstLineBox();
InlineFlowBox* lastLine = flow->lastLineBox();
@@ -2501,7 +2567,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced()
void RenderBox::calcAbsoluteVerticalReplaced()
{
// The following is based off of the W3C Working Draft from April 11, 2006 of
- // CSS 2.1: Section 10.6.5 "Absolutly positioned, replaced elements"
+ // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
// <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
// (block-style-comments in this function correspond to text from the spec and
// the numbers correspond to numbers in spec)
@@ -2565,7 +2631,7 @@ void RenderBox::calcAbsoluteVerticalReplaced()
int bottomValue = 0;
if (marginTop.isAuto() && marginBottom.isAuto()) {
- // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combinded.
+ // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
ASSERT(!(top.isAuto() || bottom.isAuto()));
topValue = top.calcValue(containerHeight);
@@ -2646,9 +2712,9 @@ IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWid
if (box) {
RootInlineBox* rootBox = box->root();
- int top = rootBox->topOverflow();
+ int top = rootBox->lineTop();
rect.setY(top);
- rect.setHeight(rootBox->bottomOverflow() - top);
+ rect.setHeight(rootBox->lineBottom() - top);
}
// If height of box is smaller than font height, use the latter one,
@@ -2701,16 +2767,11 @@ int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSe
return left;
}
-bool RenderBox::isAfterContent(RenderObject* child) const
-{
- return (child && child->style()->styleType() == AFTER && (!child->isText() || child->isBR()));
-}
-
VisiblePosition RenderBox::positionForPoint(const IntPoint& point)
{
// no children...return this render object's element, if there is one, and offset 0
if (!firstChild())
- return createVisiblePosition(firstDeepEditingPositionForNode(node()));
+ return createVisiblePosition(node() ? firstDeepEditingPositionForNode(node()) : Position(0, 0));
int xPos = point.x();
int yPos = point.y();
@@ -2813,11 +2874,86 @@ bool RenderBox::avoidsFloats() const
return isReplaced() || hasOverflowClip() || isHR();
}
+void RenderBox::addShadowOverflow()
+{
+ int shadowLeft;
+ int shadowRight;
+ int shadowTop;
+ int shadowBottom;
+ style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
+ IntRect borderBox = borderBoxRect();
+ int overflowLeft = borderBox.x() + shadowLeft;
+ int overflowRight = borderBox.right() + shadowRight;
+ int overflowTop = borderBox.y() + shadowTop;
+ int overflowBottom = borderBox.bottom() + shadowBottom;
+ addVisualOverflow(IntRect(overflowLeft, overflowTop, overflowRight - overflowLeft, overflowBottom - overflowTop));
+}
+
+void RenderBox::addOverflowFromChild(RenderBox* child, const IntSize& delta)
+{
+ // Update our overflow in case the child spills out the block, but only if we were going to paint
+ // the child block ourselves.
+ if (child->hasSelfPaintingLayer())
+ return;
+
+ // Only propagate layout overflow from the child if the child isn't clipping its overflow. If it is, then
+ // its overflow is internal to it, and we don't care about it.
+ IntRect childLayoutOverflowRect = child->hasOverflowClip() ? child->borderBoxRect() : child->layoutOverflowRect();
+ childLayoutOverflowRect.move(delta);
+ addLayoutOverflow(childLayoutOverflowRect);
+
+ // Add in visual overflow from the child. Even if the child clips its overflow, it may still
+ // have visual overflow of its own set from box shadows or reflections. It is unnecessary to propagate this
+ // overflow if we are clipping our own overflow.
+ if (hasOverflowClip())
+ return;
+ IntRect childVisualOverflowRect = child->visualOverflowRect();
+ childVisualOverflowRect.move(delta);
+ addVisualOverflow(childVisualOverflowRect);
+}
+
+void RenderBox::addLayoutOverflow(const IntRect& rect)
+{
+ IntRect borderBox = borderBoxRect();
+ if (borderBox.contains(rect))
+ return;
+
+ if (!m_overflow)
+ m_overflow.set(new RenderOverflow(borderBox));
+
+ m_overflow->addLayoutOverflow(rect);
+}
+
+void RenderBox::addVisualOverflow(const IntRect& rect)
+{
+ IntRect borderBox = borderBoxRect();
+ if (borderBox.contains(rect))
+ return;
+
+ if (!m_overflow)
+ m_overflow.set(new RenderOverflow(borderBox));
+
+ m_overflow->addVisualOverflow(rect);
+}
+
+void RenderBox::clearLayoutOverflow()
+{
+ if (!m_overflow)
+ return;
+
+ if (visualOverflowRect() == borderBoxRect()) {
+ m_overflow.clear();
+ return;
+ }
+
+ m_overflow->resetLayoutOverflow(borderBoxRect());
+}
+
#if ENABLE(SVG)
-TransformationMatrix RenderBox::localTransform() const
+AffineTransform RenderBox::localTransform() const
{
- return TransformationMatrix(1, 0, 0, 1, x(), y());
+ return AffineTransform(1, 0, 0, 1, x(), y());
}
#endif
diff --git a/WebCore/rendering/RenderBox.h b/WebCore/rendering/RenderBox.h
index cb2297b..401a46d 100644
--- a/WebCore/rendering/RenderBox.h
+++ b/WebCore/rendering/RenderBox.h
@@ -24,6 +24,7 @@
#define RenderBox_h
#include "RenderBoxModelObject.h"
+#include "RenderOverflow.h"
#include "ScrollTypes.h"
namespace WebCore {
@@ -73,23 +74,38 @@ public:
// Bounds of the outline box in absolute coords. Respects transforms
virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/) const;
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
// Use this with caution! No type checking is done!
RenderBox* previousSiblingBox() const;
RenderBox* nextSiblingBox() const;
RenderBox* parentBox() const;
- // The height of a block when you include normal flow overflow spillage out of the bottom
- // of the block (e.g., a <div style="height:25px"> that has a 100px tall image inside
- // it would have an overflow height of borderTop() + paddingTop() + 100px.
- virtual int overflowHeight(bool /*includeInterior*/ = true) const { return height(); }
- virtual int overflowWidth(bool /*includeInterior*/ = true) const { return width(); }
- virtual void setOverflowHeight(int) { }
- virtual void setOverflowWidth(int) { }
- virtual int overflowLeft(bool /*includeInterior*/ = true) const { return 0; }
- virtual int overflowTop(bool /*includeInterior*/ = true) const { return 0; }
- virtual IntRect overflowRect(bool /*includeInterior*/ = true) const { return borderBoxRect(); }
+ IntRect visibleOverflowRect() const { return hasOverflowClip() ? visualOverflowRect() : (m_overflow ? m_overflow->visibleOverflowRect() : borderBoxRect()); }
+ int topVisibleOverflow() const { return hasOverflowClip() ? topVisualOverflow() : std::min(topLayoutOverflow(), topVisualOverflow()); }
+ int bottomVisibleOverflow() const { return hasOverflowClip() ? bottomVisualOverflow() : std::max(bottomLayoutOverflow(), bottomVisualOverflow()); }
+ int leftVisibleOverflow() const { return hasOverflowClip() ? leftVisualOverflow() : std::min(leftLayoutOverflow(), leftVisualOverflow()); }
+ int rightVisibleOverflow() const { return hasOverflowClip() ? rightVisualOverflow() : std::max(rightLayoutOverflow(), rightVisualOverflow()); }
+
+ IntRect layoutOverflowRect() const { return m_overflow ? m_overflow->layoutOverflowRect() : borderBoxRect(); }
+ int topLayoutOverflow() const { return m_overflow? m_overflow->topLayoutOverflow() : 0; }
+ int bottomLayoutOverflow() const { return m_overflow ? m_overflow->bottomLayoutOverflow() : height(); }
+ int leftLayoutOverflow() const { return m_overflow ? m_overflow->leftLayoutOverflow() : 0; }
+ int rightLayoutOverflow() const { return m_overflow ? m_overflow->rightLayoutOverflow() : width(); }
+
+ IntRect visualOverflowRect() const { return m_overflow ? m_overflow->visualOverflowRect() : borderBoxRect(); }
+ int topVisualOverflow() const { return m_overflow? m_overflow->topVisualOverflow() : 0; }
+ int bottomVisualOverflow() const { return m_overflow ? m_overflow->bottomVisualOverflow() : height(); }
+ int leftVisualOverflow() const { return m_overflow ? m_overflow->leftVisualOverflow() : 0; }
+ int rightVisualOverflow() const { return m_overflow ? m_overflow->rightVisualOverflow() : width(); }
+
+ void addLayoutOverflow(const IntRect&);
+ void addVisualOverflow(const IntRect&);
+
+ void addShadowOverflow();
+ void addOverflowFromChild(RenderBox* child) { addOverflowFromChild(child, IntSize(child->x(), child->y())); }
+ void addOverflowFromChild(RenderBox* child, const IntSize& delta);
+ void clearLayoutOverflow();
int contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); }
int contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); }
@@ -229,7 +245,8 @@ public:
virtual int verticalScrollbarWidth() const;
int horizontalScrollbarHeight() const;
- virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f);
+ virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f, Node** stopNode = 0);
+ bool canBeScrolledAndHasScrollableArea() const;
virtual bool canBeProgramaticallyScrolled(bool) const;
virtual void autoscroll();
virtual void stopAutoscroll() { }
@@ -280,7 +297,7 @@ public:
virtual bool avoidsFloats() const;
#if ENABLE(SVG)
- virtual TransformationMatrix localTransform() const;
+ virtual AffineTransform localTransform() const;
#endif
protected:
@@ -288,8 +305,8 @@ protected:
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
virtual void updateBoxModelInfoFromStyle();
- void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver);
- void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver);
+ void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject);
+ void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0);
void paintMaskImages(const PaintInfo&, int tx, int ty, int width, int height);
@@ -301,7 +318,7 @@ protected:
virtual bool shouldCalculateSizeAsReplaced() const { return isReplaced() && !isInlineBlockOrInlineTable(); }
- virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const;
+ virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&) const;
virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const;
private:
@@ -333,9 +350,6 @@ private:
// These include tables, positioned objects, floats and flexible boxes.
virtual void calcPrefWidths() { setPrefWidthsDirty(false); }
-protected:
- bool isAfterContent(RenderObject* child) const;
-
private:
// The width/height of the contents + borders + padding. The x/y location is relative to our container (which is not always our parent).
IntRect m_frameRect;
@@ -360,6 +374,9 @@ protected:
// For inline replaced elements, the inline box that owns us.
InlineBox* m_inlineBoxWrapper;
+ // Our overflow information.
+ OwnPtr<RenderOverflow> m_overflow;
+
private:
// Used to store state between styleWillChange and styleDidChange
static bool s_hadOverflowClip;
diff --git a/WebCore/rendering/RenderBoxModelObject.cpp b/WebCore/rendering/RenderBoxModelObject.cpp
index 3a7ff71..f8bf05e 100644
--- a/WebCore/rendering/RenderBoxModelObject.cpp
+++ b/WebCore/rendering/RenderBoxModelObject.cpp
@@ -33,6 +33,7 @@
#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderView.h"
+#include <wtf/CurrentTime.h>
using namespace std;
@@ -44,6 +45,140 @@ bool RenderBoxModelObject::s_wasFloating = false;
bool RenderBoxModelObject::s_hadLayer = false;
bool RenderBoxModelObject::s_layerWasSelfPainting = false;
+static const double cInterpolationCutoff = 800. * 800.;
+static const double cLowQualityTimeThreshold = 0.500; // 500 ms
+
+class RenderBoxModelScaleData : public Noncopyable {
+public:
+ RenderBoxModelScaleData(RenderBoxModelObject* object, const IntSize& size, const AffineTransform& transform, double time, bool lowQualityScale)
+ : m_size(size)
+ , m_transform(transform)
+ , m_lastPaintTime(time)
+ , m_lowQualityScale(lowQualityScale)
+ , m_highQualityRepaintTimer(object, &RenderBoxModelObject::highQualityRepaintTimerFired)
+ {
+ }
+
+ ~RenderBoxModelScaleData()
+ {
+ m_highQualityRepaintTimer.stop();
+ }
+
+ Timer<RenderBoxModelObject>& hiqhQualityRepaintTimer() { return m_highQualityRepaintTimer; }
+
+ const IntSize& size() const { return m_size; }
+ void setSize(const IntSize& s) { m_size = s; }
+ double lastPaintTime() const { return m_lastPaintTime; }
+ void setLastPaintTime(double t) { m_lastPaintTime = t; }
+ bool useLowQualityScale() const { return m_lowQualityScale; }
+ const AffineTransform& transform() const { return m_transform; }
+ void setTransform(const AffineTransform& transform) { m_transform = transform; }
+ void setUseLowQualityScale(bool b)
+ {
+ m_highQualityRepaintTimer.stop();
+ m_lowQualityScale = b;
+ if (b)
+ m_highQualityRepaintTimer.startOneShot(cLowQualityTimeThreshold);
+ }
+
+private:
+ IntSize m_size;
+ AffineTransform m_transform;
+ double m_lastPaintTime;
+ bool m_lowQualityScale;
+ Timer<RenderBoxModelObject> m_highQualityRepaintTimer;
+};
+
+class RenderBoxModelScaleObserver {
+public:
+ static bool shouldPaintBackgroundAtLowQuality(GraphicsContext*, RenderBoxModelObject*, Image*, const IntSize&);
+
+ static void boxModelObjectDestroyed(RenderBoxModelObject* object)
+ {
+ if (gBoxModelObjects) {
+ RenderBoxModelScaleData* data = gBoxModelObjects->take(object);
+ delete data;
+ if (!gBoxModelObjects->size()) {
+ delete gBoxModelObjects;
+ gBoxModelObjects = 0;
+ }
+ }
+ }
+
+ static void highQualityRepaintTimerFired(RenderBoxModelObject* object)
+ {
+ RenderBoxModelScaleObserver::boxModelObjectDestroyed(object);
+ object->repaint();
+ }
+
+ static HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>* gBoxModelObjects;
+};
+
+bool RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality(GraphicsContext* context, RenderBoxModelObject* object, Image* image, const IntSize& size)
+{
+ // If the image is not a bitmap image, then none of this is relevant and we just paint at high
+ // quality.
+ if (!image || !image->isBitmapImage())
+ return false;
+
+ // Make sure to use the unzoomed image size, since if a full page zoom is in effect, the image
+ // is actually being scaled.
+ IntSize imageSize(image->width(), image->height());
+
+ // Look ourselves up in the hashtable.
+ RenderBoxModelScaleData* data = 0;
+ if (gBoxModelObjects)
+ data = gBoxModelObjects->get(object);
+
+ const AffineTransform& currentTransform = context->getCTM();
+ bool contextIsScaled = !currentTransform.isIdentityOrTranslation();
+ if (!contextIsScaled && imageSize == size) {
+ // There is no scale in effect. If we had a scale in effect before, we can just delete this data.
+ if (data) {
+ gBoxModelObjects->remove(object);
+ delete data;
+ }
+ return false;
+ }
+
+ // There is no need to hash scaled images that always use low quality mode when the page demands it. This is the iChat case.
+ if (object->document()->page()->inLowQualityImageInterpolationMode()) {
+ double totalPixels = static_cast<double>(image->width()) * static_cast<double>(image->height());
+ if (totalPixels > cInterpolationCutoff)
+ return true;
+ }
+
+ // If there is no data yet, we will paint the first scale at high quality and record the paint time in case a second scale happens
+ // very soon.
+ if (!data) {
+ data = new RenderBoxModelScaleData(object, size, currentTransform, currentTime(), false);
+ if (!gBoxModelObjects)
+ gBoxModelObjects = new HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>;
+ gBoxModelObjects->set(object, data);
+ return false;
+ }
+
+ // We are scaled, but we painted already at this size, so just keep using whatever mode we last painted with.
+ if ((!contextIsScaled || data->transform() == currentTransform) && data->size() == size)
+ return data->useLowQualityScale();
+
+ // We have data and our size just changed. If this change happened quickly, go into low quality mode and then set a repaint
+ // timer to paint in high quality mode. Otherwise it is ok to just paint in high quality mode.
+ double newTime = currentTime();
+ data->setUseLowQualityScale(newTime - data->lastPaintTime() < cLowQualityTimeThreshold);
+ data->setLastPaintTime(newTime);
+ data->setTransform(currentTransform);
+ data->setSize(size);
+ return data->useLowQualityScale();
+}
+
+HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>* RenderBoxModelScaleObserver::gBoxModelObjects = 0;
+
+void RenderBoxModelObject::highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*)
+{
+ RenderBoxModelScaleObserver::highQualityRepaintTimerFired(this);
+}
+
RenderBoxModelObject::RenderBoxModelObject(Node* node)
: RenderObject(node)
, m_layer(0)
@@ -55,6 +190,7 @@ RenderBoxModelObject::~RenderBoxModelObject()
// Our layer should have been destroyed and cleared by now
ASSERT(!hasLayer());
ASSERT(!m_layer);
+ RenderBoxModelScaleObserver::boxModelObjectDestroyed(this);
}
void RenderBoxModelObject::destroyLayer()
@@ -304,9 +440,12 @@ int RenderBoxModelObject::paddingRight(bool) const
}
-void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op)
+void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op, RenderObject* backgroundObject)
{
GraphicsContext* context = paintInfo.context;
+ if (context->paintingDisabled())
+ return;
+
bool includeLeftEdge = box ? box->includeLeftEdge() : true;
bool includeRightEdge = box ? box->includeRightEdge() : true;
int bLeft = includeLeftEdge ? borderLeft() : 0;
@@ -316,10 +455,14 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
bool clippedToBorderRadius = false;
if (style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge)) {
+ IntRect borderRect(tx, ty, w, h);
+
+ if (borderRect.isEmpty())
+ return;
+
context->save();
IntSize topLeft, topRight, bottomLeft, bottomRight;
- IntRect borderRect(tx, ty, w, h);
style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight);
context->addRoundedRectClip(borderRect, includeLeftEdge ? topLeft : IntSize(),
@@ -437,18 +580,14 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
if (baseColor.alpha() > 0) {
context->save();
context->setCompositeOperation(CompositeCopy);
- context->fillRect(rect, baseColor);
+ context->fillRect(rect, baseColor, style()->colorSpace());
context->restore();
-#ifdef ANDROID_ALLOW_TRANSPARENT_BACKGROUNDS
- }
-#else
} else
context->clearRect(rect);
-#endif
}
if (bgColor.isValid() && bgColor.alpha() > 0)
- context->fillRect(rect, bgColor);
+ context->fillRect(rect, bgColor, style()->colorSpace());
}
// no progressive loading of the background image
@@ -463,21 +602,10 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
if (!destRect.isEmpty()) {
phase += destRect.location() - destOrigin;
CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op;
- RenderObject* clientForBackgroundImage = this;
- // Check if this is the root element painting a background layer propagated from <body>,
- // and pass the body's renderer as the client in that case.
- if (isRoot && !style()->hasBackground()) {
- ASSERT(node()->hasTagName(htmlTag));
- HTMLElement* body = document()->body();
- ASSERT(body);
- ASSERT(body->hasLocalName(bodyTag));
- ASSERT(body->renderer());
- if (body) {
- if (RenderObject* bodyRenderer = body->renderer())
- clientForBackgroundImage = bodyRenderer;
- }
- }
- context->drawTiledImage(bg->image(clientForBackgroundImage, tileSize), destRect, phase, tileSize, compositeOp);
+ RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this;
+ Image* image = bg->image(clientForBackgroundImage, tileSize);
+ bool useLowQualityScaling = RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality(context, this, image, destRect.size());
+ context->drawTiledImage(image, style()->colorSpace(), destRect, phase, tileSize, compositeOp, useLowQualityScaling);
}
}
@@ -493,153 +621,141 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
context->restore();
}
-IntSize RenderBoxModelObject::calculateBackgroundSize(const FillLayer* bgLayer, int scaledWidth, int scaledHeight) const
+IntSize RenderBoxModelObject::calculateFillTileSize(const FillLayer* fillLayer, IntSize positioningAreaSize) const
{
- StyleImage* bg = bgLayer->image();
- bg->setImageContainerSize(IntSize(scaledWidth, scaledHeight)); // Use the box established by background-origin.
-
- if (bgLayer->isSizeSet()) {
- int w = scaledWidth;
- int h = scaledHeight;
- Length bgWidth = bgLayer->size().width();
- Length bgHeight = bgLayer->size().height();
-
- if (bgWidth.isFixed())
- w = bgWidth.value();
- else if (bgWidth.isPercent())
- w = bgWidth.calcValue(scaledWidth);
-
- if (bgHeight.isFixed())
- h = bgHeight.value();
- else if (bgHeight.isPercent())
- h = bgHeight.calcValue(scaledHeight);
-
- // If one of the values is auto we have to use the appropriate
- // scale to maintain our aspect ratio.
- if (bgWidth.isAuto() && !bgHeight.isAuto())
- w = bg->imageSize(this, style()->effectiveZoom()).width() * h / bg->imageSize(this, style()->effectiveZoom()).height();
- else if (!bgWidth.isAuto() && bgHeight.isAuto())
- h = bg->imageSize(this, style()->effectiveZoom()).height() * w / bg->imageSize(this, style()->effectiveZoom()).width();
- else if (bgWidth.isAuto() && bgHeight.isAuto()) {
- // If both width and height are auto, we just want to use the image's
- // intrinsic size.
- w = bg->imageSize(this, style()->effectiveZoom()).width();
- h = bg->imageSize(this, style()->effectiveZoom()).height();
+ StyleImage* image = fillLayer->image();
+ image->setImageContainerSize(positioningAreaSize); // Use the box established by background-origin.
+
+ EFillSizeType type = fillLayer->size().type;
+
+ switch (type) {
+ case SizeLength: {
+ int w = positioningAreaSize.width();
+ int h = positioningAreaSize.height();
+ Length layerWidth = fillLayer->size().size.width();
+ Length layerHeight = fillLayer->size().size.height();
+
+ if (layerWidth.isFixed())
+ w = layerWidth.value();
+ else if (layerWidth.isPercent())
+ w = layerWidth.calcValue(positioningAreaSize.width());
+
+ if (layerHeight.isFixed())
+ h = layerHeight.value();
+ else if (layerHeight.isPercent())
+ h = layerHeight.calcValue(positioningAreaSize.height());
+
+ // If one of the values is auto we have to use the appropriate
+ // scale to maintain our aspect ratio.
+ if (layerWidth.isAuto() && !layerHeight.isAuto())
+ w = image->imageSize(this, style()->effectiveZoom()).width() * h / image->imageSize(this, style()->effectiveZoom()).height();
+ else if (!layerWidth.isAuto() && layerHeight.isAuto())
+ h = image->imageSize(this, style()->effectiveZoom()).height() * w / image->imageSize(this, style()->effectiveZoom()).width();
+ else if (layerWidth.isAuto() && layerHeight.isAuto()) {
+ // If both width and height are auto, we just want to use the image's
+ // intrinsic size.
+ w = image->imageSize(this, style()->effectiveZoom()).width();
+ h = image->imageSize(this, style()->effectiveZoom()).height();
+ }
+
+ return IntSize(max(1, w), max(1, h));
}
-
- return IntSize(max(1, w), max(1, h));
- } else
- return bg->imageSize(this, style()->effectiveZoom());
+ case Contain:
+ case Cover: {
+ IntSize imageIntrinsicSize = image->imageSize(this, 1);
+ float horizontalScaleFactor = static_cast<float>(positioningAreaSize.width()) / imageIntrinsicSize.width();
+ float verticalScaleFactor = static_cast<float>(positioningAreaSize.height()) / imageIntrinsicSize.height();
+ float scaleFactor = type == Contain ? min(horizontalScaleFactor, verticalScaleFactor) : max(horizontalScaleFactor, verticalScaleFactor);
+
+ return IntSize(max<int>(1, imageIntrinsicSize.width() * scaleFactor), max<int>(1, imageIntrinsicSize.height() * scaleFactor));
+ }
+ case SizeNone:
+ break;
+ }
+ return image->imageSize(this, style()->effectiveZoom());
}
-void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgLayer, int tx, int ty, int w, int h,
+void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fillLayer, int tx, int ty, int w, int h,
IntRect& destRect, IntPoint& phase, IntSize& tileSize)
{
- int pw;
- int ph;
int left = 0;
- int right = 0;
int top = 0;
- int bottom = 0;
- int cx;
- int cy;
- int rw = 0;
- int rh = 0;
-
- // CSS2 chapter 14.2.1
- bool fixedAttachment = bgLayer->attachment() == FixedBackgroundAttachment;
+ IntSize positioningAreaSize;
+
+ // Determine the background positioning area and set destRect to the background painting area.
+ // destRect will be adjusted later if the background is non-repeating.
+ bool fixedAttachment = fillLayer->attachment() == FixedBackgroundAttachment;
+
+#if ENABLE(FAST_MOBILE_SCROLLING)
+ if (view()->frameView() && view()->frameView()->canBlitOnScroll()) {
+ // As a side effect of an optimization to blit on scroll, we do not honor the CSS
+ // property "background-attachment: fixed" because it may result in rendering
+ // artifacts. Note, these artifacts only appear if we are blitting on scroll of
+ // a page that has fixed background images.
+ fixedAttachment = false;
+ }
+#endif
+
if (!fixedAttachment) {
- // Scroll and Local
- if (bgLayer->origin() != BorderFillBox) {
+ destRect = IntRect(tx, ty, w, h);
+
+ int right = 0;
+ int bottom = 0;
+ // Scroll and Local.
+ if (fillLayer->origin() != BorderFillBox) {
left = borderLeft();
right = borderRight();
top = borderTop();
bottom = borderBottom();
- if (bgLayer->origin() == ContentFillBox) {
+ if (fillLayer->origin() == ContentFillBox) {
left += paddingLeft();
right += paddingRight();
top += paddingTop();
bottom += paddingBottom();
}
}
-
+
// The background of the box generated by the root element covers the entire canvas including
- // its margins. Since those were added in already, we have to factor them out when computing the
- // box used by background-origin/size/position.
+ // its margins. Since those were added in already, we have to factor them out when computing
+ // the background positioning area.
if (isRoot()) {
- rw = toRenderBox(this)->width() - left - right;
- rh = toRenderBox(this)->height() - top - bottom;
+ positioningAreaSize = IntSize(toRenderBox(this)->width() - left - right, toRenderBox(this)->height() - top - bottom);
left += marginLeft();
- right += marginRight();
top += marginTop();
- bottom += marginBottom();
- }
- cx = tx;
- cy = ty;
- pw = w - left - right;
- ph = h - top - bottom;
+ } else
+ positioningAreaSize = IntSize(w - left - right, h - top - bottom);
} else {
- // Fixed background attachment.
- IntRect vr = viewRect();
- cx = vr.x();
- cy = vr.y();
- pw = vr.width();
- ph = vr.height();
+ destRect = viewRect();
+ positioningAreaSize = destRect.size();
}
- int sx = 0;
- int sy = 0;
- int cw;
- int ch;
+ tileSize = calculateFillTileSize(fillLayer, positioningAreaSize);
- IntSize scaledImageSize;
- if (isRoot() && !fixedAttachment)
- scaledImageSize = calculateBackgroundSize(bgLayer, rw, rh);
- else
- scaledImageSize = calculateBackgroundSize(bgLayer, pw, ph);
-
- int scaledImageWidth = scaledImageSize.width();
- int scaledImageHeight = scaledImageSize.height();
+ EFillRepeat backgroundRepeatX = fillLayer->repeatX();
+ EFillRepeat backgroundRepeatY = fillLayer->repeatY();
- EFillRepeat backgroundRepeat = bgLayer->repeat();
-
- int xPosition;
- if (isRoot() && !fixedAttachment)
- xPosition = bgLayer->xPosition().calcMinValue(rw - scaledImageWidth, true);
- else
- xPosition = bgLayer->xPosition().calcMinValue(pw - scaledImageWidth, true);
- if (backgroundRepeat == RepeatFill || backgroundRepeat == RepeatXFill) {
- cw = pw + left + right;
- sx = scaledImageWidth ? scaledImageWidth - (xPosition + left) % scaledImageWidth : 0;
- } else {
- cx += max(xPosition + left, 0);
- sx = -min(xPosition + left, 0);
- cw = scaledImageWidth + min(xPosition + left, 0);
- }
-
- int yPosition;
- if (isRoot() && !fixedAttachment)
- yPosition = bgLayer->yPosition().calcMinValue(rh - scaledImageHeight, true);
- else
- yPosition = bgLayer->yPosition().calcMinValue(ph - scaledImageHeight, true);
- if (backgroundRepeat == RepeatFill || backgroundRepeat == RepeatYFill) {
- ch = ph + top + bottom;
- sy = scaledImageHeight ? scaledImageHeight - (yPosition + top) % scaledImageHeight : 0;
- } else {
- cy += max(yPosition + top, 0);
- sy = -min(yPosition + top, 0);
- ch = scaledImageHeight + min(yPosition + top, 0);
+ int xPosition = fillLayer->xPosition().calcMinValue(positioningAreaSize.width() - tileSize.width(), true);
+ if (backgroundRepeatX == RepeatFill)
+ phase.setX(tileSize.width() ? tileSize.width() - (xPosition + left) % tileSize.width() : 0);
+ else {
+ destRect.move(max(xPosition + left, 0), 0);
+ phase.setX(-min(xPosition + left, 0));
+ destRect.setWidth(tileSize.width() + min(xPosition + left, 0));
}
- if (fixedAttachment) {
- sx += max(tx - cx, 0);
- sy += max(ty - cy, 0);
+ int yPosition = fillLayer->yPosition().calcMinValue(positioningAreaSize.height() - tileSize.height(), true);
+ if (backgroundRepeatY == RepeatFill)
+ phase.setY(tileSize.height() ? tileSize.height() - (yPosition + top) % tileSize.height() : 0);
+ else {
+ destRect.move(0, max(yPosition + top, 0));
+ phase.setY(-min(yPosition + top, 0));
+ destRect.setHeight(tileSize.height() + min(yPosition + top, 0));
}
- destRect = IntRect(cx, cy, cw, ch);
+ if (fixedAttachment)
+ phase.move(max(tx - destRect.x(), 0), max(ty - destRect.y(), 0));
+
destRect.intersect(IntRect(tx, ty, w, h));
- phase = IntPoint(sx, sy);
- tileSize = IntSize(scaledImageWidth, scaledImageHeight);
}
int RenderBoxModelObject::verticalPosition(bool firstLine) const
@@ -729,6 +845,7 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext,
(imageHeight - topSlice - bottomSlice) > 0 && (h - topWidth - bottomWidth) > 0;
Image* image = styleImage->image(this, imageSize);
+ ColorSpace colorSpace = style->colorSpace();
if (drawLeft) {
// Paint the top and bottom left corners.
@@ -736,18 +853,18 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext,
// The top left corner rect is (tx, ty, leftWidth, topWidth)
// The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice)
if (drawTop)
- graphicsContext->drawImage(image, IntRect(tx, ty, leftWidth, topWidth),
+ graphicsContext->drawImage(image, colorSpace, IntRect(tx, ty, leftWidth, topWidth),
IntRect(0, 0, leftSlice, topSlice), op);
// The bottom left corner rect is (tx, ty + h - bottomWidth, leftWidth, bottomWidth)
// The rect to use from within the image is (0, imageHeight - bottomSlice, leftSlice, botomSlice)
if (drawBottom)
- graphicsContext->drawImage(image, IntRect(tx, ty + h - bottomWidth, leftWidth, bottomWidth),
+ graphicsContext->drawImage(image, colorSpace, IntRect(tx, ty + h - bottomWidth, leftWidth, bottomWidth),
IntRect(0, imageHeight - bottomSlice, leftSlice, bottomSlice), op);
// Paint the left edge.
// Have to scale and tile into the border rect.
- graphicsContext->drawTiledImage(image, IntRect(tx, ty + topWidth, leftWidth,
+ graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx, ty + topWidth, leftWidth,
h - topWidth - bottomWidth),
IntRect(0, topSlice, leftSlice, imageHeight - topSlice - bottomSlice),
Image::StretchTile, (Image::TileRule)vRule, op);
@@ -758,17 +875,17 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext,
// The top right corner rect is (tx + w - rightWidth, ty, rightWidth, topWidth)
// The rect to use from within the image is obtained from our slice, and is (imageWidth - rightSlice, 0, rightSlice, topSlice)
if (drawTop)
- graphicsContext->drawImage(image, IntRect(tx + w - rightWidth, ty, rightWidth, topWidth),
+ graphicsContext->drawImage(image, colorSpace, IntRect(tx + w - rightWidth, ty, rightWidth, topWidth),
IntRect(imageWidth - rightSlice, 0, rightSlice, topSlice), op);
// The bottom right corner rect is (tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth)
// The rect to use from within the image is (imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice)
if (drawBottom)
- graphicsContext->drawImage(image, IntRect(tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth),
+ graphicsContext->drawImage(image, colorSpace, IntRect(tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth),
IntRect(imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice), op);
// Paint the right edge.
- graphicsContext->drawTiledImage(image, IntRect(tx + w - rightWidth, ty + topWidth, rightWidth,
+ graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + w - rightWidth, ty + topWidth, rightWidth,
h - topWidth - bottomWidth),
IntRect(imageWidth - rightSlice, topSlice, rightSlice, imageHeight - topSlice - bottomSlice),
Image::StretchTile, (Image::TileRule)vRule, op);
@@ -776,20 +893,20 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext,
// Paint the top edge.
if (drawTop)
- graphicsContext->drawTiledImage(image, IntRect(tx + leftWidth, ty, w - leftWidth - rightWidth, topWidth),
+ graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + leftWidth, ty, w - leftWidth - rightWidth, topWidth),
IntRect(leftSlice, 0, imageWidth - rightSlice - leftSlice, topSlice),
(Image::TileRule)hRule, Image::StretchTile, op);
// Paint the bottom edge.
if (drawBottom)
- graphicsContext->drawTiledImage(image, IntRect(tx + leftWidth, ty + h - bottomWidth,
+ graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + leftWidth, ty + h - bottomWidth,
w - leftWidth - rightWidth, bottomWidth),
IntRect(leftSlice, imageHeight - bottomSlice, imageWidth - rightSlice - leftSlice, bottomSlice),
(Image::TileRule)hRule, Image::StretchTile, op);
// Paint the middle.
if (drawMiddle)
- graphicsContext->drawTiledImage(image, IntRect(tx + leftWidth, ty + topWidth, w - leftWidth - rightWidth,
+ graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + leftWidth, ty + topWidth, w - leftWidth - rightWidth,
h - topWidth - bottomWidth),
IntRect(leftSlice, topSlice, imageWidth - rightSlice - leftSlice, imageHeight - topSlice - bottomSlice),
(Image::TileRule)hRule, (Image::TileRule)vRule, op);
@@ -1221,7 +1338,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int
shadowOffset -= extraOffset;
fillRect.move(extraOffset);
- context->setShadow(shadowOffset, shadowBlur, shadowColor);
+ context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace());
if (hasBorderRadius) {
IntRect rectToClipOut = rect;
IntSize topLeftToClipOut = topLeft;
@@ -1264,7 +1381,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int
if (!rectToClipOut.isEmpty())
context->clipOutRoundedRect(rectToClipOut, topLeftToClipOut, topRightToClipOut, bottomLeftToClipOut, bottomRightToClipOut);
- context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black);
+ context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black, s->colorSpace());
} else {
IntRect rectToClipOut = rect;
@@ -1273,7 +1390,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int
// edges if they are not pixel-aligned. Those are avoided by insetting the clipping path
// by one pixel.
if (hasOpaqueBackground) {
- TransformationMatrix currentTransformation = context->getCTM();
+ AffineTransform currentTransformation = context->getCTM();
if (currentTransformation.a() != 1 || (currentTransformation.d() != 1 && currentTransformation.d() != -1)
|| currentTransformation.b() || currentTransformation.c())
rectToClipOut.inflate(-1);
@@ -1281,7 +1398,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int
if (!rectToClipOut.isEmpty())
context->clipOut(rectToClipOut);
- context->fillRect(fillRect, Color::black);
+ context->fillRect(fillRect, Color::black, s->colorSpace());
}
context->restore();
@@ -1292,9 +1409,9 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int
if (holeRect.isEmpty()) {
if (hasBorderRadius)
- context->fillRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight, shadowColor);
+ context->fillRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight, shadowColor, s->colorSpace());
else
- context->fillRect(rect, shadowColor);
+ context->fillRect(rect, shadowColor, s->colorSpace());
continue;
}
if (!begin) {
@@ -1343,8 +1460,8 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int
context->addPath(Path::createRectangle(holeRect));
context->setFillRule(RULE_EVENODD);
- context->setFillColor(fillColor);
- context->setShadow(shadowOffset, shadowBlur, shadowColor);
+ context->setFillColor(fillColor, s->colorSpace());
+ context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace());
context->fillPath();
context->restore();
diff --git a/WebCore/rendering/RenderBoxModelObject.h b/WebCore/rendering/RenderBoxModelObject.h
index baa5ecb..db7538d 100644
--- a/WebCore/rendering/RenderBoxModelObject.h
+++ b/WebCore/rendering/RenderBoxModelObject.h
@@ -90,7 +90,7 @@ public:
void paintBorder(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, bool begin = true, bool end = true);
bool paintNinePieceImage(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, const NinePieceImage&, CompositeOperator = CompositeSourceOver);
void paintBoxShadow(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, ShadowStyle, bool begin = true, bool end = true);
- void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver);
+ void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0);
// The difference between this inline's baseline position and the line's baseline position.
int verticalPosition(bool firstLine) const;
@@ -98,12 +98,16 @@ public:
// Called by RenderObject::destroy() (and RenderWidget::destroy()) and is the only way layers should ever be destroyed
void destroyLayer();
+ void highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*);
+
protected:
void calculateBackgroundImageGeometry(const FillLayer*, int tx, int ty, int w, int h, IntRect& destRect, IntPoint& phase, IntSize& tileSize);
- IntSize calculateBackgroundSize(const FillLayer*, int scaledWidth, int scaledHeight) const;
private:
virtual bool isBoxModelObject() const { return true; }
+
+ IntSize calculateFillTileSize(const FillLayer*, IntSize scaledSize) const;
+
friend class RenderView;
RenderLayer* m_layer;
diff --git a/WebCore/rendering/RenderButton.cpp b/WebCore/rendering/RenderButton.cpp
index 6d36a0f..3ecd382 100644
--- a/WebCore/rendering/RenderButton.cpp
+++ b/WebCore/rendering/RenderButton.cpp
@@ -1,6 +1,4 @@
/**
- * This file is part of the html renderer for KDE.
- *
* Copyright (C) 2005 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -52,7 +50,8 @@ void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild)
if (!m_inner) {
// Create an anonymous block.
ASSERT(!firstChild());
- m_inner = createAnonymousBlock();
+ bool isFlexibleBox = style()->display() == BOX || style()->display() == INLINE_BOX;
+ m_inner = createAnonymousBlock(isFlexibleBox);
setupInnerStyle(m_inner->style());
RenderFlexibleBox::addChild(m_inner);
}
@@ -108,6 +107,7 @@ void RenderButton::setupInnerStyle(RenderStyle* innerStyle)
// RenderBlock::createAnonymousBlock creates a new RenderStyle, so this is
// safe to modify.
innerStyle->setBoxFlex(1.0f);
+ innerStyle->setBoxOrient(style()->boxOrient());
innerStyle->setPaddingTop(Length(theme()->buttonInternalPaddingTop(), Fixed));
innerStyle->setPaddingRight(Length(theme()->buttonInternalPaddingRight(), Fixed));
diff --git a/WebCore/rendering/RenderButton.h b/WebCore/rendering/RenderButton.h
index 3a74589..7fd6ab0 100644
--- a/WebCore/rendering/RenderButton.h
+++ b/WebCore/rendering/RenderButton.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the html renderer for KDE.
- *
* Copyright (C) 2005 Apple Computer
*
* This library is free software; you can redistribute it and/or
diff --git a/WebCore/rendering/RenderCounter.cpp b/WebCore/rendering/RenderCounter.cpp
index 67e5cba..3cb9a07 100644
--- a/WebCore/rendering/RenderCounter.cpp
+++ b/WebCore/rendering/RenderCounter.cpp
@@ -38,7 +38,7 @@ using namespace HTMLNames;
typedef HashMap<RefPtr<AtomicStringImpl>, CounterNode*> CounterMap;
typedef HashMap<const RenderObject*, CounterMap*> CounterMaps;
-static CounterNode* counter(RenderObject*, const AtomicString& counterName, bool alwaysCreateCounter);
+static CounterNode* makeCounterNode(RenderObject*, const AtomicString& identifier, bool alwaysCreateCounter);
static CounterMaps& counterMaps()
{
@@ -53,31 +53,7 @@ static inline RenderObject* previousSiblingOrParent(RenderObject* object)
return object->parent();
}
-static CounterNode* lastDescendant(CounterNode* node)
-{
- CounterNode* last = node->lastChild();
- if (!last)
- return 0;
-
- while (CounterNode* lastChild = last->lastChild())
- last = lastChild;
-
- return last;
-}
-
-static CounterNode* previousInPreOrder(CounterNode* node)
-{
- CounterNode* previous = node->previousSibling();
- if (!previous)
- return node->parent();
-
- while (CounterNode* lastChild = previous->lastChild())
- previous = lastChild;
-
- return previous;
-}
-
-static bool planCounter(RenderObject* object, const AtomicString& counterName, bool& isReset, int& value)
+static bool planCounter(RenderObject* object, const AtomicString& identifier, bool& isReset, int& value)
{
ASSERT(object);
@@ -90,7 +66,7 @@ static bool planCounter(RenderObject* object, const AtomicString& counterName, b
ASSERT(style);
if (const CounterDirectiveMap* directivesMap = style->counterDirectives()) {
- CounterDirectives directives = directivesMap->get(counterName.impl());
+ CounterDirectives directives = directivesMap->get(identifier.impl());
if (directives.m_reset) {
value = directives.m_resetValue;
if (directives.m_increment)
@@ -105,7 +81,7 @@ static bool planCounter(RenderObject* object, const AtomicString& counterName, b
}
}
- if (counterName == "list-item") {
+ if (identifier == "list-item") {
if (object->isListItem()) {
if (toRenderListItem(object)->hasExplicitValue()) {
value = toRenderListItem(object)->explicitValue();
@@ -133,68 +109,142 @@ static bool planCounter(RenderObject* object, const AtomicString& counterName, b
return false;
}
-static bool findPlaceForCounter(RenderObject* object, const AtomicString& counterName,
- bool isReset, CounterNode*& parent, CounterNode*& previousSibling)
+// - Finds the insertion point for the counter described by counterOwner, isReset and
+// identifier in the CounterNode tree for identifier and sets parent and
+// previousSibling accordingly.
+// - The function returns true if the counter whose insertion point is searched is NOT
+// the root of the tree.
+// - The root of the tree is a counter reference that is not in the scope of any other
+// counter with the same identifier.
+// - All the counter references with the same identifier as this one that are in
+// children or subsequent siblings of the renderer that owns the root of the tree
+// form the rest of of the nodes of the tree.
+// - The root of the tree is always a reset type reference.
+// - A subtree rooted at any reset node in the tree is equivalent to all counter
+// references that are in the scope of the counter or nested counter defined by that
+// reset node.
+// - Non-reset CounterNodes cannot have descendants.
+
+static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& identifier, bool isReset, CounterNode*& parent, CounterNode*& previousSibling)
{
- // Find the appropriate previous sibling for insertion into the parent node
- // by searching in render tree order for a child of the counter.
- parent = 0;
+ // We cannot stop searching for counters with the same identifier before we also
+ // check this renderer, because it may affect the positioning in the tree of our counter.
+ RenderObject* searchEndRenderer = previousSiblingOrParent(counterOwner);
+ // We check renderers in preOrder from the renderer that our counter is attached to
+ // towards the begining of the document for counters with the same identifier as the one
+ // we are trying to find a place for. This is the next renderer to be checked.
+ RenderObject* currentRenderer = counterOwner->previousInPreOrder();
previousSibling = 0;
- RenderObject* resetCandidate = isReset ? object->parent() : previousSiblingOrParent(object);
- RenderObject* prevCounterCandidate = object;
- CounterNode* candidateCounter = 0;
- while ((prevCounterCandidate = prevCounterCandidate->previousInPreOrder())) {
- CounterNode* c = counter(prevCounterCandidate, counterName, false);
- if (prevCounterCandidate == resetCandidate) {
- if (!candidateCounter)
- candidateCounter = c;
- if (candidateCounter) {
- if (candidateCounter->isReset()) {
- parent = candidateCounter;
- previousSibling = 0;
- } else {
- parent = candidateCounter->parent();
- previousSibling = candidateCounter;
+ while (currentRenderer) {
+ CounterNode* currentCounter = makeCounterNode(currentRenderer, identifier, false);
+ if (searchEndRenderer == currentRenderer) {
+ // We may be at the end of our search.
+ if (currentCounter) {
+ // We have a suitable counter on the EndSearchRenderer.
+ if (previousSibling) { // But we already found another counter that we come after.
+ if (currentCounter->actsAsReset()) {
+ // We found a reset counter that is on a renderer that is a sibling of ours or a parent.
+ if (isReset && currentRenderer->parent() == counterOwner->parent()) {
+ // We are also a reset counter and the previous reset was on a sibling renderer
+ // hence we are the next sibling of that counter if that reset is not a root or
+ // we are a root node if that reset is a root.
+ parent = currentCounter->parent();
+ previousSibling = parent ? currentCounter : 0;
+ return parent;
+ }
+ // We are not a reset node or the previous reset must be on an ancestor of our renderer
+ // hence we must be a child of that reset counter.
+ parent = currentCounter;
+ ASSERT(previousSibling->parent() == currentCounter);
+ return true;
+ }
+ // CurrentCounter, the counter at the EndSearchRenderer, is not reset.
+ if (!isReset || currentRenderer->parent() != counterOwner->parent()) {
+ // If the node we are placing is not reset or we have found a counter that is attached
+ // to an ancestor of the placed counter's renderer we know we are a sibling of that node.
+ ASSERT(currentCounter->parent() == previousSibling->parent());
+ parent = currentCounter->parent();
+ return true;
+ }
+ } else {
+ // We are at the potential end of the search, but we had no previous sibling candidate
+ // In this case we follow pretty much the same logic as above but no ASSERTs about
+ // previousSibling, and when we are a sibling of the end counter we must set previousSibling
+ // to currentCounter.
+ if (currentCounter->actsAsReset()) {
+ if (isReset && currentRenderer->parent() == counterOwner->parent()) {
+ parent = currentCounter->parent();
+ previousSibling = currentCounter;
+ return parent;
+ }
+ parent = currentCounter;
+ return true;
+ }
+ if (!isReset || currentRenderer->parent() != counterOwner->parent()) {
+ parent = currentCounter->parent();
+ previousSibling = currentCounter;
+ return true;
+ }
+ previousSibling = currentCounter;
}
- return true;
}
- resetCandidate = previousSiblingOrParent(resetCandidate);
- } else if (c) {
- if (c->isReset())
- candidateCounter = 0;
- else if (!candidateCounter)
- candidateCounter = c;
+ // We come here if the previous sibling or parent of our renderer had no
+ // good counter, or we are a reset node and the counter on the previous sibling
+ // of our renderer was not a reset counter.
+ // Set a new goal for the end of the search.
+ searchEndRenderer = previousSiblingOrParent(currentRenderer);
+ } else {
+ // We are searching descendants of a previous sibling of the renderer that the
+ // counter being placed is attached to.
+ if (currentCounter) {
+ // We found a suitable counter.
+ if (previousSibling) {
+ // Since we had a suitable previous counter before, we should only consider this one as our
+ // previousSibling if it is a reset counter and hence the current previousSibling is its child.
+ if (currentCounter->actsAsReset()) {
+ previousSibling = currentCounter;
+ // We are no longer interested in previous siblings of the currentRenderer or their children
+ // as counters they may have attached cannot be the previous sibling of the counter we are placing.
+ currentRenderer = currentRenderer->parent();
+ continue;
+ }
+ } else
+ previousSibling = currentCounter;
+ currentRenderer = previousSiblingOrParent(currentRenderer);
+ continue;
+ }
}
+ // This function is designed so that the same test is not done twice in an iteration, except for this one
+ // which may be done twice in some cases. Rearranging the decision points though, to accommodate this
+ // performance improvement would create more code duplication than is worthwhile in my oppinion and may further
+ // impede the readability of this already complex algorithm.
+ if (previousSibling)
+ currentRenderer = previousSiblingOrParent(currentRenderer);
+ else
+ currentRenderer = currentRenderer->previousInPreOrder();
}
-
return false;
}
-static CounterNode* counter(RenderObject* object, const AtomicString& counterName, bool alwaysCreateCounter)
+static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& identifier, bool alwaysCreateCounter)
{
ASSERT(object);
if (object->m_hasCounterNodeMap)
if (CounterMap* nodeMap = counterMaps().get(object))
- if (CounterNode* node = nodeMap->get(counterName.impl()))
+ if (CounterNode* node = nodeMap->get(identifier.impl()))
return node;
bool isReset = false;
int value = 0;
- if (!planCounter(object, counterName, isReset, value) && !alwaysCreateCounter)
+ if (!planCounter(object, identifier, isReset, value) && !alwaysCreateCounter)
return 0;
CounterNode* newParent = 0;
CounterNode* newPreviousSibling = 0;
- CounterNode* newNode;
- if (findPlaceForCounter(object, counterName, isReset, newParent, newPreviousSibling)) {
- newNode = new CounterNode(object, isReset, value);
- newParent->insertAfter(newNode, newPreviousSibling);
- } else {
- // Make a reset node for counters that aren't inside an existing reset node.
- newNode = new CounterNode(object, true, value);
- }
-
+ CounterNode* newNode = new CounterNode(object, isReset, value);
+ if (findPlaceForCounter(object, identifier, isReset, newParent, newPreviousSibling))
+ newParent->insertAfter(newNode, newPreviousSibling, identifier);
CounterMap* nodeMap;
if (object->m_hasCounterNodeMap)
nodeMap = counterMaps().get(object);
@@ -203,8 +253,30 @@ static CounterNode* counter(RenderObject* object, const AtomicString& counterNam
counterMaps().set(object, nodeMap);
object->m_hasCounterNodeMap = true;
}
- nodeMap->set(counterName.impl(), newNode);
-
+ nodeMap->set(identifier.impl(), newNode);
+ if (newNode->parent() || !object->nextInPreOrder(object->parent()))
+ return newNode;
+ // Checking if some nodes that were previously counter tree root nodes
+ // should become children of this node now.
+ CounterMaps& maps = counterMaps();
+ RenderObject* stayWithin = object->parent();
+ for (RenderObject* currentRenderer = object->nextInPreOrder(stayWithin); currentRenderer; currentRenderer = currentRenderer->nextInPreOrder(stayWithin)) {
+ if (!currentRenderer->m_hasCounterNodeMap)
+ continue;
+ CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier.impl());
+ if (!currentCounter)
+ continue;
+ if (currentCounter->parent()) {
+ ASSERT(newNode->firstChild());
+ if (currentRenderer->lastChild())
+ currentRenderer = currentRenderer->lastChild();
+ continue;
+ }
+ if (stayWithin != currentRenderer->parent() || !currentCounter->hasResetType())
+ newNode->insertAfter(currentCounter, newNode->lastChild(), identifier);
+ if (currentRenderer->lastChild())
+ currentRenderer = currentRenderer->lastChild();
+ }
return newNode;
}
@@ -231,15 +303,15 @@ PassRefPtr<StringImpl> RenderCounter::originalText() const
return 0;
if (!m_counterNode)
- m_counterNode = counter(parent(), m_counter.identifier(), true);
+ m_counterNode = makeCounterNode(parent(), m_counter.identifier(), true);
CounterNode* child = m_counterNode;
- int value = child->isReset() ? child->value() : child->countInParent();
+ int value = child->actsAsReset() ? child->value() : child->countInParent();
String text = listMarkerText(m_counter.listStyle(), value);
if (!m_counter.separator().isNull()) {
- if (!child->isReset())
+ if (!child->actsAsReset())
child = child->parent();
while (CounterNode* parent = child->parent()) {
text = listMarkerText(m_counter.listStyle(), child->countInParent())
@@ -257,47 +329,156 @@ void RenderCounter::calcPrefWidths(int lead)
RenderText::calcPrefWidths(lead);
}
-void RenderCounter::invalidate()
+void RenderCounter::invalidate(const AtomicString& identifier)
{
+ if (m_counter.identifier() != identifier)
+ return;
m_counterNode = 0;
setNeedsLayoutAndPrefWidthsRecalc();
}
-static void destroyCounterNodeChildren(AtomicStringImpl* identifier, CounterNode* node)
+static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier, CounterNode* node)
{
CounterNode* previous;
- for (CounterNode* child = lastDescendant(node); child && child != node; child = previous) {
- previous = previousInPreOrder(child);
- child->parent()->removeChild(child);
- ASSERT(counterMaps().get(child->renderer())->get(identifier) == child);
- counterMaps().get(child->renderer())->remove(identifier);
+ for (CounterNode* child = node->lastDescendant(); child && child != node; child = previous) {
+ previous = child->previousInPreOrder();
+ child->parent()->removeChild(child, identifier);
+ ASSERT(counterMaps().get(child->renderer())->get(identifier.impl()) == child);
+ counterMaps().get(child->renderer())->remove(identifier.impl());
if (!child->renderer()->documentBeingDestroyed()) {
RenderObjectChildList* children = child->renderer()->virtualChildren();
if (children)
- children->invalidateCounters(child->renderer());
+ children->invalidateCounters(child->renderer(), identifier);
}
delete child;
}
+ RenderObject* renderer = node->renderer();
+ if (!renderer->documentBeingDestroyed()) {
+ if (RenderObjectChildList* children = renderer->virtualChildren())
+ children->invalidateCounters(renderer, identifier);
+ }
+ if (CounterNode* parent = node->parent())
+ parent->removeChild(node, identifier);
+ delete node;
}
-void RenderCounter::destroyCounterNodes(RenderObject* object)
+void RenderCounter::destroyCounterNodes(RenderObject* renderer)
{
CounterMaps& maps = counterMaps();
- CounterMap* map = maps.get(object);
- if (!map)
+ CounterMaps::iterator mapsIterator = maps.find(renderer);
+ if (mapsIterator == maps.end())
return;
- maps.remove(object);
-
+ CounterMap* map = mapsIterator->second;
CounterMap::const_iterator end = map->end();
for (CounterMap::const_iterator it = map->begin(); it != end; ++it) {
- CounterNode* node = it->second;
- destroyCounterNodeChildren(it->first.get(), node);
- if (CounterNode* parent = node->parent())
- parent->removeChild(node);
- delete node;
+ AtomicString identifier(it->first.get());
+ destroyCounterNodeWithoutMapRemoval(identifier, it->second);
}
-
+ maps.remove(mapsIterator);
delete map;
+ renderer->m_hasCounterNodeMap = false;
+}
+
+void RenderCounter::destroyCounterNode(RenderObject* renderer, const AtomicString& identifier)
+{
+ CounterMap* map = counterMaps().get(renderer);
+ if (!map)
+ return;
+ CounterMap::iterator mapIterator = map->find(identifier.impl());
+ if (mapIterator == map->end())
+ return;
+ destroyCounterNodeWithoutMapRemoval(identifier, mapIterator->second);
+ map->remove(mapIterator);
+ // We do not delete "map" here even if empty because we expect to reuse
+ // it soon. In order for a renderer to lose all its counters permanently,
+ // a style change for the renderer involving removal of all counter
+ // directives must occur, in which case, RenderCounter::destroyCounterNodes()
+ // must be called.
+ // The destruction of the Renderer (possibly caused by the removal of its
+ // associated DOM node) is the other case that leads to the permanent
+ // destruction of all counters attached to a Renderer. In this case
+ // RenderCounter::destroyCounterNodes() must be and is now called, too.
+ // RenderCounter::destroyCounterNodes() handles destruction of the counter
+ // map associated with a renderer, so there is no risk in leaking the map.
+}
+
+static void updateCounters(RenderObject* renderer)
+{
+ ASSERT(renderer->style());
+ const CounterDirectiveMap* directiveMap = renderer->style()->counterDirectives();
+ if (!directiveMap)
+ return;
+ CounterDirectiveMap::const_iterator end = directiveMap->end();
+ if (!renderer->m_hasCounterNodeMap) {
+ for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it)
+ makeCounterNode(renderer, AtomicString(it->first.get()), false);
+ return;
+ }
+ CounterMap* counterMap = counterMaps().get(renderer);
+ ASSERT(counterMap);
+ for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) {
+ CounterNode* node = counterMap->get(it->first.get());
+ if (!node) {
+ makeCounterNode(renderer, AtomicString(it->first.get()), false);
+ continue;
+ }
+ CounterNode* newParent = 0;
+ CounterNode* newPreviousSibling;
+ findPlaceForCounter(renderer, AtomicString(it->first.get()), node->hasResetType(), newParent, newPreviousSibling);
+ CounterNode* parent = node->parent();
+ if (newParent == parent && newPreviousSibling == node->previousSibling())
+ continue;
+ if (parent)
+ parent->removeChild(node, it->first.get());
+ if (newParent)
+ newParent->insertAfter(node, newPreviousSibling, it->first.get());
+ }
+}
+
+void RenderCounter::rendererSubtreeAttached(RenderObject* renderer)
+{
+ for (RenderObject* descendant = renderer; descendant; descendant = descendant->nextInPreOrder(renderer))
+ updateCounters(descendant);
+}
+
+void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderStyle* oldStyle, const RenderStyle* newStyle)
+{
+ const CounterDirectiveMap* newCounterDirectives;
+ const CounterDirectiveMap* oldCounterDirectives;
+ if (oldStyle && (oldCounterDirectives = oldStyle->counterDirectives())) {
+ if (newStyle && (newCounterDirectives = newStyle->counterDirectives())) {
+ CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives->end();
+ CounterDirectiveMap::const_iterator oldMapEnd = oldCounterDirectives->end();
+ for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begin(); it != newMapEnd; ++it) {
+ CounterDirectiveMap::const_iterator oldMapIt = oldCounterDirectives->find(it->first);
+ if (oldMapIt != oldMapEnd) {
+ if (oldMapIt->second == it->second)
+ continue;
+ RenderCounter::destroyCounterNode(renderer, it->first.get());
+ }
+ // We must create this node here, because the changed node may be a node with no display such as
+ // as those created by the increment or reset directives and the re-layout that will happen will
+ // not catch the change if the node had no children.
+ makeCounterNode(renderer, it->first.get(), false);
+ }
+ // Destroying old counters that do not exist in the new counterDirective map.
+ for (CounterDirectiveMap::const_iterator it = oldCounterDirectives->begin(); it !=oldMapEnd; ++it) {
+ if (!newCounterDirectives->contains(it->first))
+ RenderCounter::destroyCounterNode(renderer, it->first.get());
+ }
+ } else {
+ if (renderer->m_hasCounterNodeMap)
+ RenderCounter::destroyCounterNodes(renderer);
+ }
+ } else if (newStyle && (newCounterDirectives = newStyle->counterDirectives())) {
+ CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives->end();
+ for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begin(); it != newMapEnd; ++it) {
+ // We must create this node here, because the added node may be a node with no display such as
+ // as those created by the increment or reset directives and the re-layout that will happen will
+ // not catch the change if the node had no children.
+ makeCounterNode(renderer, it->first.get(), false);
+ }
+ }
}
} // namespace WebCore
diff --git a/WebCore/rendering/RenderCounter.h b/WebCore/rendering/RenderCounter.h
index 961968e..10ba1dc 100644
--- a/WebCore/rendering/RenderCounter.h
+++ b/WebCore/rendering/RenderCounter.h
@@ -33,9 +33,16 @@ class RenderCounter : public RenderText {
public:
RenderCounter(Document*, const CounterContent&);
- void invalidate();
+ // Removes the reference to the CounterNode associated with this renderer
+ // if its identifier matches the argument.
+ // This is used to cause a counter display update when the CounterNode
+ // tree for identifier changes.
+ void invalidate(const AtomicString& identifier);
static void destroyCounterNodes(RenderObject*);
+ static void destroyCounterNode(RenderObject*, const AtomicString& identifier);
+ static void rendererSubtreeAttached(RenderObject*);
+ static void rendererStyleChanged(RenderObject*, const RenderStyle* oldStyle, const RenderStyle* newStyle);
private:
virtual const char* renderName() const;
diff --git a/WebCore/rendering/RenderEmbeddedObject.cpp b/WebCore/rendering/RenderEmbeddedObject.cpp
new file mode 100644
index 0000000..db32808
--- /dev/null
+++ b/WebCore/rendering/RenderEmbeddedObject.cpp
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * (C) 2000 Stefan Schimanski (1Stein@gmx.de)
+ * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderEmbeddedObject.h"
+
+#include "Frame.h"
+#include "FrameLoaderClient.h"
+#include "HTMLEmbedElement.h"
+#include "HTMLIFrameElement.h"
+#include "HTMLNames.h"
+#include "HTMLObjectElement.h"
+#include "HTMLParamElement.h"
+#include "MIMETypeRegistry.h"
+#include "Page.h"
+#include "PluginWidget.h"
+#include "RenderView.h"
+#include "RenderWidgetProtector.h"
+#include "Text.h"
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "HTMLVideoElement.h"
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "PluginWidget.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderEmbeddedObject::RenderEmbeddedObject(Element* element)
+ : RenderPartObject(element)
+{
+ view()->frameView()->setIsVisuallyNonEmpty();
+}
+
+RenderEmbeddedObject::~RenderEmbeddedObject()
+{
+ if (frameView())
+ frameView()->removeWidgetToUpdate(this);
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+bool RenderEmbeddedObject::requiresLayer() const
+{
+ if (RenderPartObject::requiresLayer())
+ return true;
+
+ return allowsAcceleratedCompositing();
+}
+
+bool RenderEmbeddedObject::allowsAcceleratedCompositing() const
+{
+ return widget() && widget()->isPluginWidget() && static_cast<PluginWidget*>(widget())->platformLayer();
+}
+#endif
+
+static bool isURLAllowed(Document* doc, const String& url)
+{
+ if (doc->frame()->page()->frameCount() >= 200)
+ return false;
+
+ // We allow one level of self-reference because some sites depend on that.
+ // But we don't allow more than one.
+ KURL completeURL = doc->completeURL(url);
+ bool foundSelfReference = false;
+ for (Frame* frame = doc->frame(); frame; frame = frame->tree()->parent()) {
+ if (equalIgnoringFragmentIdentifier(frame->loader()->url(), completeURL)) {
+ if (foundSelfReference)
+ return false;
+ foundSelfReference = true;
+ }
+ }
+ return true;
+}
+
+typedef HashMap<String, String, CaseFoldingHash> ClassIdToTypeMap;
+
+static ClassIdToTypeMap* createClassIdToTypeMap()
+{
+ ClassIdToTypeMap* map = new ClassIdToTypeMap;
+ map->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash");
+ map->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin");
+ map->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime");
+ map->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director");
+ map->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2");
+ map->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2");
+ return map;
+}
+
+static String serviceTypeForClassId(const String& classId)
+{
+ // Return early if classId is empty (since we won't do anything below).
+ // Furthermore, if classId is null, calling get() below will crash.
+ if (classId.isEmpty())
+ return String();
+
+ static ClassIdToTypeMap* map = createClassIdToTypeMap();
+ return map->get(classId);
+}
+
+static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues)
+{
+ // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP
+ // require "src" attribute).
+ int srcIndex = -1, dataIndex = -1;
+ for (unsigned int i = 0; i < paramNames->size(); ++i) {
+ if (equalIgnoringCase((*paramNames)[i], "src"))
+ srcIndex = i;
+ else if (equalIgnoringCase((*paramNames)[i], "data"))
+ dataIndex = i;
+ }
+
+ if (srcIndex == -1 && dataIndex != -1) {
+ paramNames->append("src");
+ paramValues->append((*paramValues)[dataIndex]);
+ }
+}
+
+void RenderEmbeddedObject::updateWidget(bool onlyCreateNonNetscapePlugins)
+{
+ String url;
+ String serviceType;
+ Vector<String> paramNames;
+ Vector<String> paramValues;
+ Frame* frame = frameView()->frame();
+
+ // The calls to FrameLoader::requestObject within this function can result in a plug-in being initialized.
+ // This can run cause arbitrary JavaScript to run and may result in this RenderObject being detached from
+ // the render tree and destroyed, causing a crash like <rdar://problem/6954546>. By extending our lifetime
+ // artifically to ensure that we remain alive for the duration of plug-in initialization.
+ RenderWidgetProtector protector(this);
+
+ if (node()->hasTagName(objectTag)) {
+ HTMLObjectElement* objectElement = static_cast<HTMLObjectElement*>(node());
+
+ objectElement->setNeedWidgetUpdate(false);
+ if (!objectElement->isFinishedParsingChildren())
+ return;
+
+ // Check for a child EMBED tag.
+ HTMLEmbedElement* embed = 0;
+ for (Node* child = objectElement->firstChild(); child; ) {
+ if (child->hasTagName(embedTag)) {
+ embed = static_cast<HTMLEmbedElement*>(child);
+ break;
+ }
+
+ if (child->hasTagName(objectTag))
+ child = child->nextSibling(); // Don't descend into nested OBJECT tags
+ else
+ child = child->traverseNextNode(objectElement); // Otherwise descend (EMBEDs may be inside COMMENT tags)
+ }
+
+ // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT.
+ HTMLElement* embedOrObject;
+ if (embed) {
+ embedOrObject = embed;
+ url = embed->url();
+ serviceType = embed->serviceType();
+ } else
+ embedOrObject = objectElement;
+
+ // If there was no URL or type defined in EMBED, try the OBJECT tag.
+ if (url.isEmpty())
+ url = objectElement->url();
+ if (serviceType.isEmpty())
+ serviceType = objectElement->serviceType();
+
+ HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
+
+ // Scan the PARAM children.
+ // Get the URL and type from the params if we don't already have them.
+ // Get the attributes from the params if there is no EMBED tag.
+ Node* child = objectElement->firstChild();
+ while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) {
+ if (child->hasTagName(paramTag)) {
+ HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
+ String name = p->name();
+ if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
+ url = p->value();
+ if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
+ serviceType = p->value();
+ int pos = serviceType.find(";");
+ if (pos != -1)
+ serviceType = serviceType.left(pos);
+ }
+ if (!embed && !name.isEmpty()) {
+ uniqueParamNames.add(name.impl());
+ paramNames.append(p->name());
+ paramValues.append(p->value());
+ }
+ }
+ child = child->nextSibling();
+ }
+
+ // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
+ // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
+ // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
+ // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
+ // else our Java plugin will misinterpret it. [4004531]
+ String codebase;
+ if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
+ codebase = "codebase";
+ uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
+ }
+
+ // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values.
+ NamedNodeMap* attributes = embedOrObject->attributes();
+ if (attributes) {
+ for (unsigned i = 0; i < attributes->length(); ++i) {
+ Attribute* it = attributes->attributeItem(i);
+ const AtomicString& name = it->name().localName();
+ if (embed || !uniqueParamNames.contains(name.impl())) {
+ paramNames.append(name.string());
+ paramValues.append(it->value().string());
+ }
+ }
+ }
+
+ mapDataParamToSrc(&paramNames, &paramValues);
+
+ // If we still don't have a type, try to map from a specific CLASSID to a type.
+ if (serviceType.isEmpty())
+ serviceType = serviceTypeForClassId(objectElement->classId());
+
+ if (!isURLAllowed(document(), url))
+ return;
+
+ // Find out if we support fallback content.
+ m_hasFallbackContent = false;
+ for (Node* child = objectElement->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) {
+ if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) // Discount <embed> and <param>
+ || (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace()))
+ m_hasFallbackContent = true;
+ }
+
+ if (onlyCreateNonNetscapePlugins) {
+ KURL completedURL;
+ if (!url.isEmpty())
+ completedURL = frame->loader()->completeURL(url);
+
+ if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
+ return;
+ }
+
+ bool success = objectElement->dispatchBeforeLoadEvent(url) && frame->loader()->requestObject(this, url, objectElement->getAttribute(nameAttr), serviceType, paramNames, paramValues);
+ if (!success && m_hasFallbackContent)
+ objectElement->renderFallbackContent();
+
+ } else if (node()->hasTagName(embedTag)) {
+ HTMLEmbedElement* embedElement = static_cast<HTMLEmbedElement*>(node());
+ embedElement->setNeedWidgetUpdate(false);
+ url = embedElement->url();
+ serviceType = embedElement->serviceType();
+
+ if (url.isEmpty() && serviceType.isEmpty())
+ return;
+ if (!isURLAllowed(document(), url))
+ return;
+
+ // add all attributes set on the embed object
+ NamedNodeMap* attributes = embedElement->attributes();
+ if (attributes) {
+ for (unsigned i = 0; i < attributes->length(); ++i) {
+ Attribute* it = attributes->attributeItem(i);
+ paramNames.append(it->name().localName().string());
+ paramValues.append(it->value().string());
+ }
+ }
+
+ if (onlyCreateNonNetscapePlugins) {
+ KURL completedURL;
+ if (!url.isEmpty())
+ completedURL = frame->loader()->completeURL(url);
+
+ if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
+ return;
+ }
+
+ if (embedElement->dispatchBeforeLoadEvent(url))
+ frame->loader()->requestObject(this, url, embedElement->getAttribute(nameAttr), serviceType, paramNames, paramValues);
+ }
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ else if (node()->hasTagName(videoTag) || node()->hasTagName(audioTag)) {
+ HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node());
+
+ mediaElement->setNeedWidgetUpdate(false);
+ if (node()->hasTagName(videoTag)) {
+ HTMLVideoElement* vid = static_cast<HTMLVideoElement*>(node());
+ String poster = vid->poster();
+ if (!poster.isEmpty()) {
+ paramNames.append("_media_element_poster_");
+ paramValues.append(poster);
+ }
+ }
+
+ url = mediaElement->initialURL();
+ if (!url.isEmpty()) {
+ paramNames.append("_media_element_src_");
+ paramValues.append(url);
+ }
+
+ serviceType = "application/x-media-element-proxy-plugin";
+
+ if (mediaElement->dispatchBeforeLoadEvent(url))
+ frame->loader()->requestObject(this, url, nullAtom, serviceType, paramNames, paramValues);
+ }
+#endif
+}
+
+void RenderEmbeddedObject::layout()
+{
+ ASSERT(needsLayout());
+
+ calcWidth();
+ calcHeight();
+
+ RenderPart::layout();
+
+ m_overflow.clear();
+ addShadowOverflow();
+
+ if (!widget() && frameView())
+ frameView()->addWidgetToUpdate(this);
+
+ setNeedsLayout(false);
+}
+
+}
diff --git a/WebCore/rendering/RenderEmbeddedObject.h b/WebCore/rendering/RenderEmbeddedObject.h
new file mode 100644
index 0000000..bdaea92
--- /dev/null
+++ b/WebCore/rendering/RenderEmbeddedObject.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 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
+ * 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 RenderEmbeddedObject_h
+#define RenderEmbeddedObject_h
+
+#include "RenderPartObject.h"
+
+namespace WebCore {
+
+// Renderer for embeds and objects.
+class RenderEmbeddedObject : public RenderPartObject {
+public:
+ RenderEmbeddedObject(Element*);
+ virtual ~RenderEmbeddedObject();
+
+ void updateWidget(bool onlyCreateNonNetscapePlugins);
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual bool allowsAcceleratedCompositing() const;
+#endif
+
+private:
+ virtual const char* renderName() const { return "RenderEmbeddedObject"; }
+ virtual bool isEmbeddedObject() const { return true; }
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual bool requiresLayer() const;
+#endif
+
+ virtual void layout();
+};
+
+inline RenderEmbeddedObject* toRenderEmbeddedObject(RenderObject* object)
+{
+ ASSERT(!object || !strcmp(object->renderName(), "RenderEmbeddedObject"));
+ return static_cast<RenderEmbeddedObject*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderEmbeddedObject(const RenderEmbeddedObject*);
+
+} // namespace WebCore
+
+#endif // RenderEmbeddedObject_h
diff --git a/WebCore/rendering/RenderFieldset.cpp b/WebCore/rendering/RenderFieldset.cpp
index 437991a..889b0bc 100644
--- a/WebCore/rendering/RenderFieldset.cpp
+++ b/WebCore/rendering/RenderFieldset.cpp
@@ -1,6 +1,4 @@
/*
- * This file is part of the DOM implementation for KDE.
- *
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
@@ -108,10 +106,11 @@ RenderBox* RenderFieldset::findLegend() const
{
for (RenderObject* legend = firstChild(); legend; legend = legend->nextSibling()) {
if (!legend->isFloatingOrPositioned() && legend->node() &&
- legend->node()->hasTagName(legendTag)
+ (legend->node()->hasTagName(legendTag)
#if ENABLE(WML)
|| legend->node()->hasTagName(WMLNames::insertedLegendTag)
#endif
+ )
)
return toRenderBox(legend);
}
@@ -120,6 +119,9 @@ RenderBox* RenderFieldset::findLegend() const
void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
{
+ if (!shouldPaintWithinRoot(paintInfo))
+ return;
+
int w = width();
int h = height();
RenderBox* legend = findLegend();
diff --git a/WebCore/rendering/RenderFileUploadControl.cpp b/WebCore/rendering/RenderFileUploadControl.cpp
index 9b5579c..59cbacf 100644
--- a/WebCore/rendering/RenderFileUploadControl.cpp
+++ b/WebCore/rendering/RenderFileUploadControl.cpp
@@ -21,6 +21,7 @@
#include "config.h"
#include "RenderFileUploadControl.h"
+#include "Chrome.h"
#include "FileList.h"
#include "Frame.h"
#include "FrameView.h"
@@ -63,8 +64,13 @@ private:
RenderFileUploadControl::RenderFileUploadControl(HTMLInputElement* input)
: RenderBlock(input)
, m_button(0)
- , m_fileChooser(FileChooser::create(this, input->value()))
{
+ FileList* list = input->files();
+ Vector<String> filenames;
+ unsigned length = list ? list->length() : 0;
+ for (unsigned i = 0; i < length; ++i)
+ filenames.append(list->item(i)->path());
+ m_fileChooser = FileChooser::create(this, filenames);
}
RenderFileUploadControl::~RenderFileUploadControl()
@@ -103,6 +109,11 @@ bool RenderFileUploadControl::allowsMultipleFiles()
return !input->getAttribute(multipleAttr).isNull();
}
+String RenderFileUploadControl::acceptTypes()
+{
+ return static_cast<HTMLInputElement*>(node())->accept();
+}
+
void RenderFileUploadControl::click()
{
Frame* frame = node()->document()->frame();
@@ -134,11 +145,7 @@ void RenderFileUploadControl::updateFromElement()
addChild(renderer);
}
-#ifndef ANDROID_DISABLE_UPLOAD
m_button->setDisabled(!theme()->isEnabled(this));
-#else
- m_button->setDisabled(true);
-#endif
// This only supports clearing out the files, but that's OK because for
// security reasons that's the only change the DOM is allowed to make.
@@ -188,7 +195,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty)
}
if (paintInfo.phase == PaintPhaseForeground) {
- const String& displayedFilename = m_fileChooser->basenameForWidth(style()->font(), maxFilenameWidth());
+ const String& displayedFilename = fileTextValue();
unsigned length = displayedFilename.length();
const UChar* string = displayedFilename.characters();
TextRun textRun(string, length, false, 0, 0, style()->direction() == RTL, style()->unicodeBidi() == Override);
@@ -208,7 +215,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty)
+ buttonRenderer->marginTop() + buttonRenderer->borderTop() + buttonRenderer->paddingTop()
+ buttonRenderer->baselinePosition(true, false);
- paintInfo.context->setFillColor(style()->color());
+ paintInfo.context->setFillColor(style()->color(), style()->colorSpace());
// Draw the filename
paintInfo.context->drawBidiText(style()->font(), textRun, IntPoint(textX, textY));
@@ -288,7 +295,7 @@ String RenderFileUploadControl::buttonValue()
return m_button->value();
}
-String RenderFileUploadControl::fileTextValue()
+String RenderFileUploadControl::fileTextValue() const
{
return m_fileChooser->basenameForWidth(style()->font(), maxFilenameWidth());
}
diff --git a/WebCore/rendering/RenderFileUploadControl.h b/WebCore/rendering/RenderFileUploadControl.h
index bd7d62a..dcdce4d 100644
--- a/WebCore/rendering/RenderFileUploadControl.h
+++ b/WebCore/rendering/RenderFileUploadControl.h
@@ -37,6 +37,8 @@ public:
RenderFileUploadControl(HTMLInputElement*);
virtual ~RenderFileUploadControl();
+ virtual bool isFileUploadControl() const { return true; }
+
void click();
void valueChanged();
@@ -44,9 +46,10 @@ public:
void receiveDroppedFiles(const Vector<String>&);
String buttonValue();
- String fileTextValue();
+ String fileTextValue() const;
bool allowsMultipleFiles();
+ String acceptTypes();
private:
virtual const char* renderName() const { return "RenderFileUploadControl"; }
@@ -66,10 +69,16 @@ private:
inline RenderFileUploadControl* toRenderFileUploadControl(RenderObject* object)
{
- ASSERT(!object || !strcmp(object->renderName(), "RenderFileUploadControl"));
+ ASSERT(!object || object->isFileUploadControl());
return static_cast<RenderFileUploadControl*>(object);
}
+inline const RenderFileUploadControl* toRenderFileUploadControl(const RenderObject* object)
+{
+ ASSERT(!object || object->isFileUploadControl());
+ return static_cast<const RenderFileUploadControl*>(object);
+}
+
// This will catch anyone doing an unnecessary cast.
void toRenderFileUploadControl(const RenderFileUploadControl*);
diff --git a/WebCore/rendering/RenderFlexibleBox.cpp b/WebCore/rendering/RenderFlexibleBox.cpp
index 6bbcc43..6882097 100644
--- a/WebCore/rendering/RenderFlexibleBox.cpp
+++ b/WebCore/rendering/RenderFlexibleBox.cpp
@@ -218,14 +218,15 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
int previousWidth = width();
int previousHeight = height();
-
+
#ifdef ANDROID_LAYOUT
int previousVisibleWidth = m_visibleWidth;
#endif
calcWidth();
calcHeight();
- m_overflowWidth = width();
+
+ m_overflow.clear();
if (previousWidth != width() || previousHeight != height() ||
(parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL &&
@@ -241,7 +242,6 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
#endif
setHeight(0);
- m_overflowHeight = 0;
m_flexingChildren = m_stretchingChildren = false;
initMaxMarginValues();
@@ -259,15 +259,8 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
else
layoutVerticalBox(relayoutChildren);
- int oldHeight = height();
calcHeight();
- if (oldHeight != height()) {
- // If the block got expanded in size, then increase our overflowheight to match.
- if (m_overflowHeight > height())
- m_overflowHeight -= (borderBottom() + paddingBottom() + horizontalScrollbarHeight());
- if (m_overflowHeight < height())
- m_overflowHeight = height();
- }
+
if (previousHeight != height())
relayoutChildren = true;
@@ -290,31 +283,14 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
setMaxTopMargins(pos, neg);
setMaxBottomMargins(0, 0);
}
+
+ // Add in the overflow from children.
+ FlexBoxIterator iterator(this);
+ for (RenderBox* child = iterator.first(); child; child = iterator.next())
+ addOverflowFromChild(child);
- // Always ensure our overflow width is at least as large as our width.
- if (m_overflowWidth < width())
- m_overflowWidth = width();
-
- if (!hasOverflowClip()) {
- int shadowLeft;
- int shadowRight;
- int shadowTop;
- int shadowBottom;
- style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
-
- m_overflowLeft = min(m_overflowLeft, shadowLeft);
- m_overflowWidth = max(m_overflowWidth, width() + shadowRight);
- m_overflowTop = min(m_overflowTop, shadowTop);
- m_overflowHeight = max(m_overflowHeight, height() + shadowBottom);
-
- if (hasReflection()) {
- IntRect reflection(reflectionBox());
- m_overflowTop = min(m_overflowTop, reflection.y());
- m_overflowHeight = max(m_overflowHeight, reflection.bottom());
- m_overflowLeft = min(m_overflowLeft, reflection.x());
- m_overflowHeight = max(m_overflowWidth, reflection.right());
- }
- }
+ // Add visual overflow from box-shadow and reflections.
+ addShadowOverflow();
statePusher.pop();
@@ -363,7 +339,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
int oldHeight = 0;
int remainingSpace = 0;
- m_overflowHeight = height();
+
FlexBoxIterator iterator(this);
unsigned int highestFlexGroup = 0;
@@ -380,7 +356,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
do {
// Reset our height.
setHeight(yPos);
- m_overflowHeight = height();
+
xPos = borderLeft() + paddingLeft();
// Our first pass is done without flexing. We simply lay the children
@@ -431,10 +407,6 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
setHeight(height() + lineHeight(true, true));
setHeight(height() + toAdd);
-
- // Always make sure our overflowheight is at least our height.
- if (m_overflowHeight < height())
- m_overflowHeight = height();
oldHeight = height();
calcHeight();
@@ -454,8 +426,13 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
child->layer()->setStaticX(xPos);
else child->layer()->setStaticX(width() - xPos);
}
- if (child->style()->hasStaticY())
- child->layer()->setStaticY(yPos);
+ if (child->style()->hasStaticY()) {
+ RenderLayer* childLayer = child->layer();
+ if (childLayer->staticY() != yPos) {
+ child->layer()->setStaticY(yPos);
+ child->setChildNeedsLayout(true, false);
+ }
+ }
child = iterator.next();
continue;
}
@@ -493,12 +470,6 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
}
placeChild(child, xPos, childY);
-
- if (child->isRenderBlock())
- toRenderBlock(child)->addVisualOverflow(toRenderBlock(child)->floatRect());
-
- m_overflowHeight = max(m_overflowHeight, childY + child->overflowHeight(false));
- m_overflowTop = min(m_overflowTop, child->y() + child->overflowTop(false));
xPos += child->width() + child->marginRight();
@@ -662,22 +633,6 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
}
}
- child = iterator.first();
- while (child && child->isPositioned()) {
- child = iterator.next();
- }
-
- if (child) {
- m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft);
-
- RenderBox* lastChild = child;
- while ((child = iterator.next())) {
- if (!child->isPositioned())
- lastChild = child;
- }
- m_overflowWidth = max(lastChild->x() + lastChild->overflowWidth(false), m_overflowWidth);
- }
-
// So that the calcHeight in layoutBlock() knows to relayout positioned objects because of
// a height change, we revert our height back to the intrinsic height before returning.
if (heightSpecified)
@@ -706,7 +661,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
// We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of
// mainstream block layout); this is not really part of the XUL box model.
- bool haveLineClamp = style()->lineClamp() >= 0 && style()->lineClamp() <= 100;
+ bool haveLineClamp = !style()->lineClamp().isNone();
if (haveLineClamp) {
int maxLineCount = 0;
child = iterator.first();
@@ -731,7 +686,8 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
// Get the # of lines and then alter all block flow children with auto height to use the
// specified height. We always try to leave room for at least one line.
- int numVisibleLines = max(1, static_cast<int>((maxLineCount + 1) * style()->lineClamp() / 100.0));
+ LineClampValue lineClamp = style()->lineClamp();
+ int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
if (numVisibleLines < maxLineCount) {
for (child = iterator.first(); child; child = iterator.next()) {
if (child->isPositioned() || !child->style()->height().isAuto() || !child->isBlockFlow())
@@ -762,28 +718,25 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
if (!lastLine)
continue;
- // See if the last item is an anchor
- InlineBox* anchorBox = lastLine->lastChild();
- if (!anchorBox)
- continue;
- if (!anchorBox->renderer()->node())
- continue;
- if (!anchorBox->renderer()->node()->isLink())
- continue;
-
RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines-1);
if (!lastVisibleLine)
continue;
const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
-
+ DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
const Font& font = style(numVisibleLines == 1)->font();
- int ellipsisAndSpaceWidth = font.width(TextRun(ellipsisAndSpace, 2));
- // Get ellipsis width + " " + anchor width
- int totalWidth = ellipsisAndSpaceWidth + anchorBox->width();
-
+ // Get ellipsis width, and if the last child is an anchor, it will go after the ellipsis, so add in a space and the anchor width too
+ int totalWidth;
+ InlineBox* anchorBox = lastLine->lastChild();
+ if (anchorBox && anchorBox->renderer()->node() && anchorBox->renderer()->node()->isLink())
+ totalWidth = anchorBox->width() + font.width(TextRun(ellipsisAndSpace, 2));
+ else {
+ anchorBox = 0;
+ totalWidth = font.width(TextRun(&horizontalEllipsis, 1));
+ }
+
// See if this width can be accommodated on the last visible line
RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer());
RenderBlock* srcBlock = toRenderBlock(lastLine->renderer());
@@ -805,7 +758,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
continue;
// Let the truncation code kick in.
- lastVisibleLine->placeEllipsis(ellipsisAndSpaceStr, ltr, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
+ lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, ltr, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
destBlock->setHasMarkupTruncation(true);
}
}
@@ -820,7 +773,6 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
do {
setHeight(borderTop() + paddingTop());
int minHeight = height() + toAdd;
- m_overflowHeight = height();
child = iterator.first();
while (child) {
@@ -828,8 +780,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))))
child->setChildNeedsLayout(true, false);
- if (child->isPositioned())
- {
+ if (child->isPositioned()) {
child->containingBlock()->insertPositionedObject(child);
if (child->style()->hasStaticX()) {
if (style()->direction() == LTR)
@@ -837,8 +788,13 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
else
child->layer()->setStaticX(borderRight()+paddingRight());
}
- if (child->style()->hasStaticY())
- child->layer()->setStaticY(height());
+ if (child->style()->hasStaticY()) {
+ RenderLayer* childLayer = child->layer();
+ if (childLayer->staticY() != height()) {
+ child->layer()->setStaticY(height());
+ child->setChildNeedsLayout(true, false);
+ }
+ }
child = iterator.next();
continue;
}
@@ -876,14 +832,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
// Place the child.
placeChild(child, childX, height());
setHeight(height() + child->height() + child->marginBottom());
-
- if (child->isRenderBlock())
- toRenderBlock(child)->addVisualOverflow(toRenderBlock(child)->floatRect());
- // See if this child has made our overflow need to grow.
- m_overflowWidth = max(child->x() + child->overflowWidth(false), m_overflowWidth);
- m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft);
-
child = iterator.next();
}
@@ -899,10 +848,6 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
if (height() < minHeight)
setHeight(minHeight);
- // Always make sure our overflowheight is at least our height.
- if (m_overflowHeight < height())
- m_overflowHeight = height();
-
// Now we have to calc our height, so we know how much space we have remaining.
oldHeight = height();
calcHeight();
@@ -1060,22 +1005,6 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
}
}
}
-
- child = iterator.first();
- while (child && child->isPositioned()) {
- child = iterator.next();
- }
-
- if (child) {
- m_overflowTop = min(child->y() + child->overflowTop(false), m_overflowTop);
-
- RenderBox* lastChild = child;
- while ((child = iterator.next())) {
- if (!child->isPositioned())
- lastChild = child;
- }
- m_overflowHeight = max(lastChild->y() + lastChild->overflowHeight(false), m_overflowHeight);
- }
// So that the calcHeight in layoutBlock() knows to relayout positioned objects because of
// a height change, we revert our height back to the intrinsic height before returning.
@@ -1161,6 +1090,8 @@ const char *RenderFlexibleBox::renderName() const
return "RenderFlexibleBox (floating)";
if (isPositioned())
return "RenderFlexibleBox (positioned)";
+ if (isAnonymous())
+ return "RenderFlexibleBox (generated)";
if (isRelPositioned())
return "RenderFlexibleBox (relative positioned)";
return "RenderFlexibleBox";
diff --git a/WebCore/rendering/RenderForeignObject.cpp b/WebCore/rendering/RenderForeignObject.cpp
index b15d55c..5bb4439 100644
--- a/WebCore/rendering/RenderForeignObject.cpp
+++ b/WebCore/rendering/RenderForeignObject.cpp
@@ -38,10 +38,10 @@ RenderForeignObject::RenderForeignObject(SVGForeignObjectElement* node)
{
}
-TransformationMatrix RenderForeignObject::translationForAttributes() const
+FloatPoint RenderForeignObject::translationForAttributes() const
{
SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(node());
- return TransformationMatrix().translate(foreign->x().value(foreign), foreign->y().value(foreign));
+ return FloatPoint(foreign->x().value(foreign), foreign->y().value(foreign));
}
void RenderForeignObject::paint(PaintInfo& paintInfo, int, int)
@@ -84,12 +84,15 @@ FloatRect RenderForeignObject::repaintRectInLocalCoordinates() const
void RenderForeignObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
{
rect = localToParentTransform().mapRect(rect);
+ style()->svgStyle()->inflateForShadow(rect);
RenderBlock::computeRectForRepaint(repaintContainer, rect, fixed);
}
-TransformationMatrix RenderForeignObject::localToParentTransform() const
+const AffineTransform& RenderForeignObject::localToParentTransform() const
{
- return localTransform() * translationForAttributes();
+ FloatPoint attributeTranslation(translationForAttributes());
+ m_localToParentTransform = localTransform().translateRight(attributeTranslation.x(), attributeTranslation.y());
+ return m_localToParentTransform;
}
void RenderForeignObject::layout()
@@ -118,6 +121,11 @@ bool RenderForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int
return false;
}
+void RenderForeignObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const
+{
+ SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState);
+}
+
} // namespace WebCore
#endif // ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT)
diff --git a/WebCore/rendering/RenderForeignObject.h b/WebCore/rendering/RenderForeignObject.h
index 8fdb816..f32069c 100644
--- a/WebCore/rendering/RenderForeignObject.h
+++ b/WebCore/rendering/RenderForeignObject.h
@@ -23,7 +23,8 @@
#define RenderForeignObject_h
#if ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT)
-#include "TransformationMatrix.h"
+#include "AffineTransform.h"
+#include "FloatPoint.h"
#include "RenderSVGBlock.h"
namespace WebCore {
@@ -38,24 +39,29 @@ public:
virtual void paint(PaintInfo&, int parentX, int parentY);
- virtual TransformationMatrix localToParentTransform() const;
+ virtual const AffineTransform& localToParentTransform() const;
virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false);
virtual bool requiresLayer() const { return false; }
virtual void layout();
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const { return borderBoxRect(); }
virtual FloatRect repaintRectInLocalCoordinates() const;
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+ virtual bool isSVGForeignObject() const { return true; }
+
+ virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const;
private:
- TransformationMatrix translationForAttributes() const;
+ FloatPoint translationForAttributes() const;
- virtual TransformationMatrix localTransform() const { return m_localTransform; }
+ virtual AffineTransform localTransform() const { return m_localTransform; }
- TransformationMatrix m_localTransform;
+ AffineTransform m_localTransform;
+ mutable AffineTransform m_localToParentTransform;
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderFrame.cpp b/WebCore/rendering/RenderFrame.cpp
index 54a73c7..ffe87c2 100644
--- a/WebCore/rendering/RenderFrame.cpp
+++ b/WebCore/rendering/RenderFrame.cpp
@@ -26,6 +26,7 @@
#include "FrameView.h"
#include "HTMLFrameElement.h"
+#include "RenderView.h"
#ifdef FLATTEN_FRAMESET
#include "Frame.h"
@@ -70,7 +71,7 @@ void RenderFrame::layout()
if (widget() && widget()->isFrameView()) {
FrameView* view = static_cast<FrameView*>(widget());
RenderView* root = NULL;
- if (view->frame() && view->frame()->document() &&
+ if (view->frame() && view->frame()->document() &&
view->frame()->document()->renderer() &&
view->frame()->document()->renderer()->isRenderView())
root = static_cast<RenderView*>(view->frame()->document()->renderer());
@@ -92,5 +93,56 @@ void RenderFrame::layout()
setNeedsLayout(false);
}
#endif
+void RenderFrame::layoutWithFlattening(bool fixedWidth, bool fixedHeight)
+{
+ // NOTE: The width and height have been set at this point by
+ // RenderFrameSet::positionFramesWithFlattening()
+
+ FrameView* childFrameView = static_cast<FrameView*>(widget());
+ RenderView* childRoot = childFrameView ? static_cast<RenderView*>(childFrameView->frame()->contentRenderer()) : 0;
+ HTMLFrameElement* element = static_cast<HTMLFrameElement*>(node());
+
+ // Do not expand framesets which has zero width or height
+ if (!width() || !height() || !childRoot) {
+ updateWidgetPosition();
+ if (childFrameView)
+ childFrameView->layout();
+ setNeedsLayout(false);
+ return;
+ }
+
+ // need to update to calculate min/max correctly
+ updateWidgetPosition();
+ if (childRoot->prefWidthsDirty())
+ childRoot->calcPrefWidths();
+
+ // if scrollbars are off, and the width or height are fixed
+ // we obey them and do not expand. With frame flattening
+ // no subframe much ever become scrollable.
+
+ bool isScrollable = element->scrollingMode() != ScrollbarAlwaysOff;
+
+ // make sure minimum preferred width is enforced
+ if (isScrollable || !fixedWidth || childRoot->isFrameSet())
+ setWidth(max(width(), childRoot->minPrefWidth()));
+
+ // update again to pass the width to the child frame
+ updateWidgetPosition();
+ childFrameView->layout();
+
+ // expand the frame by setting frame height = content height
+ if (isScrollable || !fixedHeight || childRoot->isFrameSet())
+ setHeight(max(height(), childFrameView->contentsHeight()));
+ if (isScrollable || !fixedWidth || childRoot->isFrameSet())
+ setWidth(max(width(), childFrameView->contentsWidth()));
+
+ updateWidgetPosition();
+
+ ASSERT(!childFrameView->layoutPending());
+ ASSERT(!childRoot->needsLayout());
+ ASSERT(!childRoot->firstChild() || !childRoot->firstChild()->firstChild() || !childRoot->firstChild()->firstChild()->needsLayout());
+
+ setNeedsLayout(false);
+}
} // namespace WebCore
diff --git a/WebCore/rendering/RenderFrame.h b/WebCore/rendering/RenderFrame.h
index 5b3b533..a66aa14 100644
--- a/WebCore/rendering/RenderFrame.h
+++ b/WebCore/rendering/RenderFrame.h
@@ -35,6 +35,7 @@ public:
RenderFrame(HTMLFrameElement*);
FrameEdgeInfo edgeInfo() const;
+ void layoutWithFlattening(bool fixedWidth, bool fixedHeight);
private:
virtual const char* renderName() const { return "RenderFrame"; }
diff --git a/WebCore/rendering/RenderFrameSet.cpp b/WebCore/rendering/RenderFrameSet.cpp
index 0838798..cf78b2b 100644
--- a/WebCore/rendering/RenderFrameSet.cpp
+++ b/WebCore/rendering/RenderFrameSet.cpp
@@ -1,6 +1,4 @@
/**
- * This file is part of the KDE project.
- *
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 2000 Simon Hausmann <hausmann@kde.org>
* (C) 2000 Stefan Schimanski (1Stein@gmx.de)
@@ -38,6 +36,7 @@
#include "MouseEvent.h"
#include "RenderFrame.h"
#include "RenderView.h"
+#include "Settings.h"
namespace WebCore {
@@ -90,13 +89,14 @@ void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect
// Fill first.
GraphicsContext* context = paintInfo.context;
- context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->borderLeftColor() : borderFillColor());
+ ColorSpace colorSpace = style()->colorSpace();
+ context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->borderLeftColor() : borderFillColor(), colorSpace);
// Now stroke the edges but only if we have enough room to paint both edges with a little
// bit of the fill color showing through.
if (borderRect.width() >= 3) {
- context->fillRect(IntRect(borderRect.topLeft(), IntSize(1, height())), borderStartEdgeColor());
- context->fillRect(IntRect(borderRect.topRight(), IntSize(1, height())), borderEndEdgeColor());
+ context->fillRect(IntRect(borderRect.topLeft(), IntSize(1, height())), borderStartEdgeColor(), colorSpace);
+ context->fillRect(IntRect(borderRect.topRight(), IntSize(1, height())), borderEndEdgeColor(), colorSpace);
}
}
@@ -109,13 +109,14 @@ void RenderFrameSet::paintRowBorder(const PaintInfo& paintInfo, const IntRect& b
// Fill first.
GraphicsContext* context = paintInfo.context;
- context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->borderLeftColor() : borderFillColor());
+ ColorSpace colorSpace = style()->colorSpace();
+ context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->borderLeftColor() : borderFillColor(), colorSpace);
// Now stroke the edges but only if we have enough room to paint both edges with a little
// bit of the fill color showing through.
if (borderRect.height() >= 3) {
- context->fillRect(IntRect(borderRect.topLeft(), IntSize(width(), 1)), borderStartEdgeColor());
- context->fillRect(IntRect(borderRect.bottomLeft(), IntSize(width(), 1)), borderEndEdgeColor());
+ context->fillRect(IntRect(borderRect.topLeft(), IntSize(width(), 1)), borderStartEdgeColor(), colorSpace);
+ context->fillRect(IntRect(borderRect.bottomLeft(), IntSize(width(), 1)), borderEndEdgeColor(), colorSpace);
}
}
@@ -496,7 +497,10 @@ void RenderFrameSet::layout()
}
#endif
- positionFrames();
+ if (flattenFrameSet())
+ positionFramesWithFlattening();
+ else
+ positionFrames();
RenderBox::layout();
@@ -520,7 +524,7 @@ void RenderFrameSet::positionFrames()
int rows = frameSet()->totalRows();
int cols = frameSet()->totalCols();
-
+
int yPos = 0;
int borderThickness = frameSet()->border();
#ifdef FLATTEN_FRAMESET
@@ -602,7 +606,7 @@ void RenderFrameSet::positionFrames()
child = (RenderBox*)firstChild();
yPos = 0;
#endif // FLATTEN_FRAMESET
-
+
for (int r = 0; r < rows; r++) {
int xPos = 0;
int height = m_rows.m_sizes[r];
@@ -635,6 +639,119 @@ void RenderFrameSet::positionFrames()
}
}
+void RenderFrameSet::positionFramesWithFlattening()
+{
+ RenderBox* child = firstChildBox();
+ if (!child)
+ return;
+
+ int rows = frameSet()->totalRows();
+ int cols = frameSet()->totalCols();
+
+ int borderThickness = frameSet()->border();
+ bool repaintNeeded = false;
+
+ // calculate frameset height based on actual content height to eliminate scrolling
+ bool out = false;
+ for (int r = 0; r < rows && !out; r++) {
+ int extra = 0;
+ int height = m_rows.m_sizes[r];
+
+ for (int c = 0; c < cols; c++) {
+ IntRect oldFrameRect = child->frameRect();
+
+ int width = m_cols.m_sizes[c];
+
+ bool fixedWidth = frameSet()->colLengths() && frameSet()->colLengths()[c].isFixed();
+ bool fixedHeight = frameSet()->rowLengths() && frameSet()->rowLengths()[r].isFixed();
+
+ // has to be resized and itself resize its contents
+ if (!fixedWidth)
+ child->setWidth(width ? width + extra / (cols - c) : 0);
+ else
+ child->setWidth(width);
+ child->setHeight(height);
+
+ child->setNeedsLayout(true);
+
+ if (child->isFrameSet())
+ toRenderFrameSet(child)->layout();
+ else
+ toRenderFrame(child)->layoutWithFlattening(fixedWidth, fixedHeight);
+
+ if (child->height() > m_rows.m_sizes[r])
+ m_rows.m_sizes[r] = child->height();
+ if (child->width() > m_cols.m_sizes[c])
+ m_cols.m_sizes[c] = child->width();
+
+ if (child->frameRect() != oldFrameRect)
+ repaintNeeded = true;
+
+ // difference between calculated frame width and the width it actually decides to have
+ extra += width - m_cols.m_sizes[c];
+
+ child = child->nextSiblingBox();
+ if (!child) {
+ out = true;
+ break;
+ }
+ }
+ }
+
+ int xPos = 0;
+ int yPos = 0;
+ out = false;
+ child = firstChildBox();
+ for (int r = 0; r < rows && !out; r++) {
+ xPos = 0;
+ for (int c = 0; c < cols; c++) {
+ // ensure the rows and columns are filled
+ IntRect oldRect = child->frameRect();
+
+ child->setLocation(xPos, yPos);
+ child->setHeight(m_rows.m_sizes[r]);
+ child->setWidth(m_cols.m_sizes[c]);
+
+ if (child->frameRect() != oldRect) {
+ repaintNeeded = true;
+
+ // update to final size
+ child->setNeedsLayout(true);
+ if (child->isFrameSet())
+ toRenderFrameSet(child)->layout();
+ else
+ toRenderFrame(child)->layoutWithFlattening(true, true);
+ }
+
+ xPos += m_cols.m_sizes[c] + borderThickness;
+ child = child->nextSiblingBox();
+ if (!child) {
+ out = true;
+ break;
+ }
+ }
+ yPos += m_rows.m_sizes[r] + borderThickness;
+ }
+
+ setWidth(xPos - borderThickness);
+ setHeight(yPos - borderThickness);
+
+ if (repaintNeeded)
+ repaint();
+
+ // all the remaining frames are hidden to avoid ugly spurious unflowed frames
+ for (; child; child = child->nextSiblingBox()) {
+ child->setWidth(0);
+ child->setHeight(0);
+ child->setNeedsLayout(false);
+ }
+}
+
+bool RenderFrameSet::flattenFrameSet() const
+{
+ return document()->frame() && document()->frame()->settings()->frameSetFlatteningEnabled();
+}
+
void RenderFrameSet::startResizing(GridAxis& axis, int position)
{
int split = hitTestSplit(axis, position);
@@ -663,6 +780,9 @@ void RenderFrameSet::continueResizing(GridAxis& axis, int position)
bool RenderFrameSet::userResize(MouseEvent* evt)
{
+ if (flattenFrameSet())
+ return false;
+
if (!m_isResizing) {
if (needsLayout())
return false;
diff --git a/WebCore/rendering/RenderFrameSet.h b/WebCore/rendering/RenderFrameSet.h
index aa3ac64..a4c8963 100644
--- a/WebCore/rendering/RenderFrameSet.h
+++ b/WebCore/rendering/RenderFrameSet.h
@@ -73,7 +73,8 @@ public:
#ifdef FLATTEN_FRAMESET
void setGridNeedsLayout() { m_gridCalculated = false; }
#endif
-
+ bool flattenFrameSet() const;
+
private:
static const int noSplit = -1;
@@ -108,6 +109,7 @@ private:
void computeEdgeInfo();
void fillFromEdgeInfo(const FrameEdgeInfo& edgeInfo, int r, int c);
void positionFrames();
+ void positionFramesWithFlattening();
int splitPosition(const GridAxis&, int split) const;
int hitTestSplit(const GridAxis&, int position) const;
diff --git a/WebCore/rendering/RenderHTMLCanvas.cpp b/WebCore/rendering/RenderHTMLCanvas.cpp
index 1fc07f0..8c17a0e 100644
--- a/WebCore/rendering/RenderHTMLCanvas.cpp
+++ b/WebCore/rendering/RenderHTMLCanvas.cpp
@@ -43,6 +43,19 @@ RenderHTMLCanvas::RenderHTMLCanvas(HTMLCanvasElement* element)
view()->frameView()->setIsVisuallyNonEmpty();
}
+bool RenderHTMLCanvas::requiresLayer() const
+{
+ if (RenderReplaced::requiresLayer())
+ return true;
+
+#if ENABLE(3D_CANVAS)
+ HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(node());
+ return canvas && canvas->is3D();
+#else
+ return false;
+#endif
+}
+
void RenderHTMLCanvas::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
{
IntRect rect = contentBoxRect();
@@ -55,10 +68,13 @@ void RenderHTMLCanvas::canvasSizeChanged()
IntSize canvasSize = static_cast<HTMLCanvasElement*>(node())->size();
IntSize zoomedSize(canvasSize.width() * style()->effectiveZoom(), canvasSize.height() * style()->effectiveZoom());
- if (canvasSize == intrinsicSize())
+ if (zoomedSize == intrinsicSize())
return;
- setIntrinsicSize(canvasSize);
+ setIntrinsicSize(zoomedSize);
+
+ if (!parent())
+ return;
if (!prefWidthsDirty())
setPrefWidthsDirty(true);
diff --git a/WebCore/rendering/RenderHTMLCanvas.h b/WebCore/rendering/RenderHTMLCanvas.h
index e82cf9a..473dad5 100644
--- a/WebCore/rendering/RenderHTMLCanvas.h
+++ b/WebCore/rendering/RenderHTMLCanvas.h
@@ -36,6 +36,9 @@ class RenderHTMLCanvas : public RenderReplaced {
public:
RenderHTMLCanvas(HTMLCanvasElement*);
+ virtual bool isCanvas() const { return true; }
+ virtual bool requiresLayer() const;
+
void canvasSizeChanged();
private:
diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp
index 91200bc..881d0b4 100644
--- a/WebCore/rendering/RenderImage.cpp
+++ b/WebCore/rendering/RenderImage.cpp
@@ -4,7 +4,7 @@
* (C) 2000 Dirk Mueller (mueller@kde.org)
* (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
* (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 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
@@ -26,14 +26,19 @@
#include "config.h"
#include "RenderImage.h"
+#include "Frame.h"
#include "GraphicsContext.h"
+#include "HTMLAreaElement.h"
+#include "HTMLCollection.h"
#include "HTMLImageElement.h"
#include "HTMLInputElement.h"
#include "HTMLMapElement.h"
#include "HTMLNames.h"
#include "HitTestResult.h"
#include "Page.h"
+#include "RenderTheme.h"
#include "RenderView.h"
+#include "SelectionController.h"
#include <wtf/CurrentTime.h>
#include <wtf/UnusedParam.h>
@@ -53,7 +58,7 @@ namespace WebCore {
static const double cInterpolationCutoff = 800. * 800.;
static const double cLowQualityTimeThreshold = 0.050; // 50 ms
-class RenderImageScaleData {
+class RenderImageScaleData : public Noncopyable {
public:
RenderImageScaleData(RenderImage* image, const IntSize& size, double time, bool lowQualityScale)
: m_size(size)
@@ -231,7 +236,7 @@ bool RenderImage::setImageSizeForAltText(CachedImage* newImage /* = 0 */)
imageHeight = paddingHeight;
}
- if (newImage) {
+ if (newImage && newImage->image()) {
// imageSize() returns 0 for the error image. We need the true size of the
// error image, so we have to get it by grabbing image() directly.
imageWidth += newImage->image()->width() * style()->effectiveZoom();
@@ -371,8 +376,8 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
context->save();
#endif
context->setStrokeStyle(SolidStroke);
- context->setStrokeColor(Color::lightGray);
- context->setFillColor(Color::transparent);
+ context->setStrokeColor(Color::lightGray, style()->colorSpace());
+ context->setFillColor(Color::transparent, style()->colorSpace());
context->drawRect(IntRect(tx + leftBorder + leftPad, ty + topBorder + topPad, cWidth, cHeight));
#ifdef ANDROID_FIX // see http://b/issue?id=2052757
context->restore();
@@ -396,13 +401,13 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
centerY = 0;
imageX = leftBorder + leftPad + centerX + 1;
imageY = topBorder + topPad + centerY + 1;
- context->drawImage(image(), IntPoint(tx + imageX, ty + imageY));
+ context->drawImage(image(), style()->colorSpace(), IntPoint(tx + imageX, ty + imageY));
errorPictureDrawn = true;
}
if (!m_altText.isEmpty()) {
String text = document()->displayStringModifiedByEncoding(m_altText);
- context->setFillColor(style()->color());
+ context->setFillColor(style()->color(), style()->colorSpace());
int ax = tx + leftBorder + leftPad;
int ay = ty + topBorder + topPad;
const Font& font = style()->font();
@@ -430,23 +435,80 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
#endif
IntSize contentSize(cWidth, cHeight);
- bool useLowQualityScaling = RenderImageScaleObserver::shouldImagePaintAtLowQuality(this, contentSize);
IntRect rect(IntPoint(tx + leftBorder + leftPad, ty + topBorder + topPad), contentSize);
- HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0;
- CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver;
- context->drawImage(image(cWidth, cHeight), rect, compositeOperator, useLowQualityScaling);
+ paintIntoRect(context, rect);
}
}
+void RenderImage::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ RenderReplaced::paint(paintInfo, tx, ty);
+
+ if (paintInfo.phase == PaintPhaseOutline)
+ paintFocusRings(paintInfo, style());
+}
+
+void RenderImage::paintFocusRings(PaintInfo& paintInfo, const RenderStyle* style)
+{
+ // Don't draw focus rings if printing.
+ if (document()->printing() || !document()->frame()->selection()->isFocusedAndActive())
+ return;
+
+ if (paintInfo.context->paintingDisabled() && !paintInfo.context->updatingControlTints())
+ return;
+
+ HTMLMapElement* mapElement = imageMap();
+ if (!mapElement)
+ return;
+
+ Document* document = mapElement->document();
+ if (!document)
+ return;
+
+ Node* focusedNode = document->focusedNode();
+ if (!focusedNode)
+ return;
+
+ RefPtr<HTMLCollection> areas = mapElement->areas();
+ unsigned numAreas = areas->length();
+
+ // FIXME: Clip the paths to the image bounding box.
+ for (unsigned k = 0; k < numAreas; ++k) {
+ HTMLAreaElement* areaElement = static_cast<HTMLAreaElement*>(areas->item(k));
+ if (focusedNode != areaElement)
+ continue;
+
+ Vector<Path> focusRingPaths;
+ focusRingPaths.append(areaElement->getPath(this));
+ paintInfo.context->drawFocusRing(focusRingPaths, style->outlineWidth(), style->outlineOffset(), style->outlineColor());
+ break;
+ }
+}
+
+void RenderImage::paintIntoRect(GraphicsContext* context, const IntRect& rect)
+{
+ if (!hasImage() || errorOccurred() || rect.width() <= 0 || rect.height() <= 0)
+ return;
+
+ Image* img = image(rect.width(), rect.height());
+ if (!img || img->isNull())
+ return;
+
+ HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0;
+ CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver;
+ bool useLowQualityScaling = RenderImageScaleObserver::shouldImagePaintAtLowQuality(this, rect.size());
+ context->drawImage(image(rect.width(), rect.height()), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling);
+}
+
int RenderImage::minimumReplacedHeight() const
{
return errorOccurred() ? intrinsicSize().height() : 0;
}
-HTMLMapElement* RenderImage::imageMap()
+HTMLMapElement* RenderImage::imageMap() const
{
HTMLImageElement* i = node() && node()->hasTagName(imgTag) ? static_cast<HTMLImageElement*>(node()) : 0;
- return i ? i->document()->getImageMap(i->useMap()) : 0;
+ return i ? i->document()->getImageMap(i->getAttribute(usemapAttr)) : 0;
}
bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
@@ -550,7 +612,7 @@ int RenderImage::calcReplacedWidth(bool includeMaxWidth) const
}
return width;
#else
- return max(minW, min(width, maxW));
+ return max(minW, min(width, maxW));
#endif
}
@@ -572,19 +634,19 @@ int RenderImage::calcReplacedHeight() const
#ifdef ANDROID_LAYOUT
height = max(minH, min(height, maxH));
// in SSR mode, we will fit the image to its container width
- if (height && document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
+ if (height && document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
int width;
if (isWidthSpecified())
width = calcReplacedWidthUsing(style()->width());
else
width = calcAspectRatioWidth();
int minW = calcReplacedWidthUsing(style()->minWidth());
- int maxW = style()->maxWidth().value() == undefinedLength ? width :
- calcReplacedWidthUsing(style()->maxWidth());
+ int maxW = style()->maxWidth().value() == undefinedLength ? width :
+ calcReplacedWidthUsing(style()->maxWidth());
width = max(minW, min(width, maxW));
int cw = containingBlockWidthForContent();
- if (cw && width && width>cw)
+ if (cw && width && width > cw)
height = cw * height / width; // preserve aspect ratio
}
return height;
diff --git a/WebCore/rendering/RenderImage.h b/WebCore/rendering/RenderImage.h
index 2224412..b89a652 100644
--- a/WebCore/rendering/RenderImage.h
+++ b/WebCore/rendering/RenderImage.h
@@ -3,7 +3,7 @@
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
* (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004, 2005, 2006, 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 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
@@ -43,7 +43,7 @@ public:
void setCachedImage(CachedImage*);
CachedImage* cachedImage() const { return m_cachedImage.get(); }
- HTMLMapElement* imageMap();
+ HTMLMapElement* imageMap() const;
void resetAnimation();
@@ -57,6 +57,15 @@ protected:
virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+ virtual void paintIntoRect(GraphicsContext*, const IntRect&);
+ void paintFocusRings(PaintInfo&, const RenderStyle*);
+ virtual void paint(PaintInfo&, int tx, int ty);
+
+ bool isWidthSpecified() const;
+ bool isHeightSpecified() const;
+
+ virtual void intrinsicSizeChanged() { imageChanged(imagePtr()); }
+
private:
virtual const char* renderName() const { return "RenderImage"; }
@@ -82,14 +91,9 @@ private:
virtual IntSize imageSize(float multiplier) const { return m_cachedImage ? m_cachedImage->imageSize(multiplier) : IntSize(); }
virtual WrappedImagePtr imagePtr() const { return m_cachedImage.get(); }
- virtual void intrinsicSizeChanged() { imageChanged(imagePtr()); }
-
int calcAspectRatioWidth() const;
int calcAspectRatioHeight() const;
- bool isWidthSpecified() const;
- bool isHeightSpecified() const;
-
protected:
// The image we are rendering.
CachedResourceHandle<CachedImage> m_cachedImage;
diff --git a/WebCore/rendering/RenderInline.cpp b/WebCore/rendering/RenderInline.cpp
index 223255e..9571751 100644
--- a/WebCore/rendering/RenderInline.cpp
+++ b/WebCore/rendering/RenderInline.cpp
@@ -23,6 +23,7 @@
#include "config.h"
#include "RenderInline.h"
+#include "Chrome.h"
#include "FloatQuad.h"
#include "GraphicsContext.h"
#include "HitTestResult.h"
@@ -30,6 +31,7 @@
#include "RenderArena.h"
#include "RenderBlock.h"
#include "RenderView.h"
+#include "TransformState.h"
#include "VisiblePosition.h"
#if ENABLE(DASHBOARD_SUPPORT)
@@ -55,14 +57,14 @@ void RenderInline::destroy()
// properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
children()->destroyLeftoverChildren();
- // Destroy our continuation before anything other than anonymous children.
- // The reason we don't destroy it before anonymous children is that they may
- // have continuations of their own that are anonymous children of our continuation.
- if (m_continuation) {
- m_continuation->destroy();
- m_continuation = 0;
- }
-
+ // Destroy our continuation before anything other than anonymous children.
+ // The reason we don't destroy it before anonymous children is that they may
+ // have continuations of their own that are anonymous children of our continuation.
+ if (m_continuation) {
+ m_continuation->destroy();
+ m_continuation = 0;
+ }
+
if (!documentBeingDestroyed()) {
if (firstLineBox()) {
// We can't wait for RenderBoxModelObject::destroy to clear the selection,
@@ -134,18 +136,6 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
}
}
-static inline bool isAfterContent(RenderObject* child)
-{
- if (!child)
- return false;
- if (child->style()->styleType() != AFTER)
- return false;
- // Text nodes don't have their own styles, so ignore the style on a text node.
- if (child->isText() && !child->isBR())
- return false;
- return true;
-}
-
void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
if (continuation())
@@ -559,6 +549,23 @@ IntRect RenderInline::linesBoundingBox() const
return result;
}
+IntRect RenderInline::linesVisibleOverflowBoundingBox() const
+{
+ if (!firstLineBox() || !lastLineBox())
+ return IntRect();
+
+ // Return the width of the minimal left side and the maximal right side.
+ int leftSide = numeric_limits<int>::max();
+ int rightSide = numeric_limits<int>::min();
+ for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) {
+ leftSide = min(leftSide, curr->leftVisibleOverflow());
+ rightSide = max(rightSide, curr->rightVisibleOverflow());
+ }
+
+ return IntRect(leftSide, firstLineBox()->topVisibleOverflow(), rightSide - leftSide,
+ lastLineBox()->bottomVisibleOverflow() - firstLineBox()->topVisibleOverflow());
+}
+
IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
{
// Only run-ins are allowed in here during layout.
@@ -568,7 +575,7 @@ IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repain
return IntRect();
// Find our leftmost position.
- IntRect boundingBox(linesBoundingBox());
+ IntRect boundingBox(linesVisibleOverflowBoundingBox());
int left = boundingBox.x();
int top = boundingBox.y();
@@ -650,7 +657,8 @@ void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer,
if (repaintContainer == this)
return;
- RenderObject* o = container();
+ bool containerSkipped;
+ RenderObject* o = container(repaintContainer, &containerSkipped);
if (!o)
return;
@@ -691,10 +699,103 @@ void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer,
return;
} else
rect.setLocation(topLeft);
+
+ if (containerSkipped) {
+ // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
+ IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
+ rect.move(-containerOffset);
+ return;
+ }
o->computeRectForRepaint(repaintContainer, rect, fixed);
}
+IntSize RenderInline::offsetFromContainer(RenderObject* container) const
+{
+ ASSERT(container == this->container());
+
+ IntSize offset;
+ if (isRelPositioned())
+ offset += relativePositionOffset();
+
+ if (!isInline() || isReplaced()) {
+ RenderBlock* cb;
+ if (container->isBlockFlow() && (cb = toRenderBlock(container))->hasColumns()) {
+ IntRect rect(0, 0, 1, 1);
+ cb->adjustRectForColumns(rect);
+ }
+ }
+
+ if (container->hasOverflowClip())
+ offset -= toRenderBox(container)->layer()->scrolledContentOffset();
+
+ return offset;
+}
+
+void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
+{
+ if (repaintContainer == this)
+ return;
+
+ if (RenderView *v = view()) {
+ if (v->layoutStateEnabled() && !repaintContainer) {
+ LayoutState* layoutState = v->layoutState();
+ IntSize offset = layoutState->m_offset;
+ if (style()->position() == RelativePosition && layer())
+ offset += layer()->relativePositionOffset();
+ transformState.move(offset);
+ return;
+ }
+ }
+
+ bool containerSkipped;
+ RenderObject* o = container(repaintContainer, &containerSkipped);
+ if (!o)
+ return;
+
+ IntSize containerOffset = offsetFromContainer(o);
+
+ bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
+ if (useTransforms && shouldUseTransformFromContainer(o)) {
+ TransformationMatrix t;
+ getTransformFromContainer(o, containerOffset, t);
+ transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
+ } else
+ transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
+
+ if (containerSkipped) {
+ // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
+ // to just subtract the delta between the repaintContainer and o.
+ IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
+ transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
+ return;
+ }
+
+ o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
+}
+
+void RenderInline::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
+{
+ // We don't expect this function to be called during layout.
+ ASSERT(!view() || !view()->layoutStateEnabled());
+
+ RenderObject* o = container();
+ if (!o)
+ return;
+
+ o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
+
+ IntSize containerOffset = offsetFromContainer(o);
+
+ bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
+ if (useTransforms && shouldUseTransformFromContainer(o)) {
+ TransformationMatrix t;
+ getTransformFromContainer(o, containerOffset, t);
+ transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
+ } else
+ transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
+}
+
void RenderInline::updateDragState(bool dragOn)
{
RenderBoxModelObject::updateDragState(dragOn);
@@ -831,10 +932,16 @@ void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
repaint();
}
-void RenderInline::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
{
- for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
- graphicsContext->addFocusRingRect(IntRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height()));
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
+ RootInlineBox* root = curr->root();
+ int top = max(root->lineTop(), curr->y());
+ int bottom = min(root->lineBottom(), curr->y() + curr->height());
+ IntRect rect(tx + curr->x(), ty + top, curr->width(), bottom - top);
+ if (!rect.isEmpty())
+ rects.append(rect);
+ }
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (!curr->isText() && !curr->isListMarker()) {
@@ -844,17 +951,17 @@ void RenderInline::addFocusRingRects(GraphicsContext* graphicsContext, int tx, i
pos = curr->localToAbsolute();
else if (curr->isBox())
pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y());
- curr->addFocusRingRects(graphicsContext, pos.x(), pos.y());
+ curr->addFocusRingRects(rects, pos.x(), pos.y());
}
}
if (continuation()) {
if (continuation()->isInline())
- continuation()->addFocusRingRects(graphicsContext,
+ continuation()->addFocusRingRects(rects,
tx - containingBlock()->x() + continuation()->containingBlock()->x(),
ty - containingBlock()->y() + continuation()->containingBlock()->y());
else
- continuation()->addFocusRingRects(graphicsContext,
+ continuation()->addFocusRingRects(rects,
tx - containingBlock()->x() + toRenderBox(continuation())->x(),
ty - containingBlock()->y() + toRenderBox(continuation())->y());
}
@@ -871,13 +978,12 @@ void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty
if (!oc.isValid())
oc = style()->color();
- graphicsContext->initFocusRing(ow, style()->outlineOffset());
- addFocusRingRects(graphicsContext, tx, ty);
+ Vector<IntRect> focusRingRects;
+ addFocusRingRects(focusRingRects, tx, ty);
if (style()->outlineStyleIsAuto())
- graphicsContext->drawFocusRing(oc);
+ graphicsContext->drawFocusRing(focusRingRects, ow, style()->outlineOffset(), oc);
else
- addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect());
- graphicsContext->clearFocusRing();
+ addPDFURLRect(graphicsContext, unionRect(focusRingRects));
}
if (style()->outlineStyleIsAuto() || style()->outlineStyle() == BNONE)
@@ -886,9 +992,12 @@ void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty
Vector<IntRect> rects;
rects.append(IntRect());
- for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
- rects.append(IntRect(curr->x(), curr->y(), curr->width(), curr->height()));
-
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
+ RootInlineBox* root = curr->root();
+ int top = max(root->lineTop(), curr->y());
+ int bottom = min(root->lineBottom(), curr->y() + curr->height());
+ rects.append(IntRect(curr->x(), top, curr->width(), bottom - top));
+ }
rects.append(IntRect());
for (unsigned i = 1; i < rects.size() - 1; i++)
diff --git a/WebCore/rendering/RenderInline.h b/WebCore/rendering/RenderInline.h
index 14d76ca..d35aa85 100644
--- a/WebCore/rendering/RenderInline.h
+++ b/WebCore/rendering/RenderInline.h
@@ -44,7 +44,10 @@ public:
virtual void absoluteRects(Vector<IntRect>&, int tx, int ty);
virtual void absoluteQuads(Vector<FloatQuad>&);
+ virtual IntSize offsetFromContainer(RenderObject*) const;
+
IntRect linesBoundingBox() const;
+ IntRect linesVisibleOverflowBoundingBox() const;
InlineFlowBox* createAndAppendInlineFlowBox();
@@ -62,7 +65,7 @@ public:
IntSize relativePositionedInlineOffset(const RenderBox* child) const;
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
void paintOutline(GraphicsContext*, int tx, int ty);
int verticalPositionFromCache(bool firstLine) const;
@@ -106,6 +109,9 @@ private:
virtual IntRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth);
virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed);
+ virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&) const;
+ virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const;
+
virtual VisiblePosition positionForPoint(const IntPoint&);
virtual IntRect borderBoundingBox() const
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index ab78f40..6dbb413 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -73,11 +73,13 @@
#include "RenderScrollbar.h"
#include "RenderScrollbarPart.h"
#include "RenderTheme.h"
+#include "RenderTreeAsText.h"
#include "RenderView.h"
#include "ScaleTransformOperation.h"
#include "Scrollbar.h"
#include "ScrollbarTheme.h"
#include "SelectionController.h"
+#include "TextStream.h"
#include "TransformationMatrix.h"
#include "TransformState.h"
#include "TranslateTransformOperation.h"
@@ -207,12 +209,8 @@ RenderLayer::~RenderLayer()
// Make sure we have no lingering clip rects.
ASSERT(!m_clipRects);
- if (m_reflection) {
- if (!m_reflection->documentBeingDestroyed())
- m_reflection->removeLayers(this);
- m_reflection->setParent(0);
- m_reflection->destroy();
- }
+ if (m_reflection)
+ removeReflection();
if (m_scrollCorner)
m_scrollCorner->destroy();
@@ -247,14 +245,6 @@ bool RenderLayer::hasAcceleratedCompositing() const
#endif
}
-void RenderLayer::setStaticY(int staticY)
-{
- if (m_staticY == staticY)
- return;
- m_staticY = staticY;
- renderer()->setChildNeedsLayout(true, false);
-}
-
void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags)
{
if (flags & DoFullRepaint) {
@@ -315,12 +305,19 @@ void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags)
if (m_reflection)
m_reflection->layout();
+#if USE(ACCELERATED_COMPOSITING)
+ // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
+ bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
+ if (isComposited())
+ flags &= ~IsCompositingUpdateRoot;
+#endif
+
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->updateLayerPositions(flags);
#if USE(ACCELERATED_COMPOSITING)
if ((flags & UpdateCompositingLayers) && isComposited())
- backing()->updateAfterLayout(RenderLayerBacking::CompositingChildren);
+ backing()->updateAfterLayout(RenderLayerBacking::CompositingChildren, isUpdateRoot);
#endif
// With all our children positioned, now update our marquee if we need to.
@@ -380,6 +377,20 @@ TransformationMatrix RenderLayer::currentTransform() const
return *m_transform;
}
+TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
+{
+ if (!m_transform)
+ return TransformationMatrix();
+
+ if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
+ TransformationMatrix matrix = *m_transform;
+ makeMatrixRenderable(matrix, false /* flatten 3d */);
+ return matrix;
+ }
+
+ return *m_transform;
+}
+
void RenderLayer::setHasVisibleContent(bool b)
{
if (m_hasVisibleContent == b && !m_visibleContentStatusDirty)
@@ -584,10 +595,10 @@ void RenderLayer::updateLayerPosition()
setHeight(box->height());
if (!box->hasOverflowClip()) {
- if (box->overflowWidth() > box->width())
- setWidth(box->overflowWidth());
- if (box->overflowHeight() > box->height())
- setHeight(box->overflowHeight());
+ if (box->rightLayoutOverflow() > box->width())
+ setWidth(box->rightLayoutOverflow());
+ if (box->bottomLayoutOverflow() > box->height())
+ setHeight(box->bottomLayoutOverflow());
}
}
}
@@ -637,48 +648,91 @@ FloatPoint RenderLayer::perspectiveOrigin() const
RenderLayer* RenderLayer::stackingContext() const
{
RenderLayer* layer = parent();
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ // When using composited fixed elements, they are turned into a stacking
+ // context and we thus need to return them.
+ // We can simplify the while loop by using isStackingContext(); with
+ // composited fixed elements turned on, this will return true for them,
+ // and is otherwise equivalent to the replaced statements.
+ while (layer && !layer->renderer()->isRoot() && !layer->isStackingContext())
+#else
while (layer && !layer->renderer()->isRenderView() && !layer->renderer()->isRoot() && layer->renderer()->style()->hasAutoZIndex())
+#endif
layer = layer->parent();
return layer;
}
+static inline bool isPositionedContainer(RenderLayer* layer)
+{
+ RenderObject* o = layer->renderer();
+ return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform();
+}
+
+static inline bool isFixedPositionedContainer(RenderLayer* layer)
+{
+ RenderObject* o = layer->renderer();
+ return o->isRenderView() || layer->hasTransform();
+}
+
RenderLayer* RenderLayer::enclosingPositionedAncestor() const
{
RenderLayer* curr = parent();
- for ( ; curr && !curr->renderer()->isRenderView() && !curr->renderer()->isPositioned() && !curr->renderer()->isRelPositioned() && !curr->hasTransform();
- curr = curr->parent()) { }
+ while (curr && !isPositionedContainer(curr))
+ curr = curr->parent();
+
return curr;
}
RenderLayer* RenderLayer::enclosingTransformedAncestor() const
{
RenderLayer* curr = parent();
- for ( ; curr && !curr->renderer()->isRenderView() && !curr->transform(); curr = curr->parent())
- { }
+ while (curr && !curr->renderer()->isRenderView() && !curr->transform())
+ curr = curr->parent();
+
return curr;
}
+static inline const RenderLayer* compositingContainer(const RenderLayer* layer)
+{
+ return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContext();
+}
+
#if USE(ACCELERATED_COMPOSITING)
RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const
{
if (includeSelf && isComposited())
return const_cast<RenderLayer*>(this);
- // Compositing layers are parented according to stacking order and overflow list,
- // so we have to check whether the parent is a stacking context, or whether
- // the child is overflow-only.
- bool inNormalFlowList = isNormalFlowOnly();
- for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
- if (curr->isComposited() && (inNormalFlowList || curr->isStackingContext()))
- return curr;
-
- inNormalFlowList = curr->isNormalFlowOnly();
+ for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
+ if (curr->isComposited())
+ return const_cast<RenderLayer*>(curr);
}
return 0;
}
#endif
+RenderLayer* RenderLayer::clippingRoot() const
+{
+ const RenderLayer* current = this;
+ while (current) {
+ if (current->renderer()->isRenderView())
+ return const_cast<RenderLayer*>(current);
+
+ current = compositingContainer(current);
+ ASSERT(current);
+ if (current->transform()
+#if USE(ACCELERATED_COMPOSITING)
+ || current->isComposited()
+#endif
+ )
+ return const_cast<RenderLayer*>(current);
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
IntPoint RenderLayer::absoluteToContents(const IntPoint& absolutePoint) const
{
// We don't use convertToLayerCoords because it doesn't know about transforms
@@ -717,13 +771,42 @@ RenderLayer* RenderLayer::transparentPaintingAncestor()
return 0;
}
-static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransform, const RenderLayer* l, const RenderLayer* rootLayer)
+static IntRect transparencyClipBox(const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior);
+
+static void expandClipRectForDescendantsAndReflection(IntRect& clipRect, const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
+{
+ // If we have a mask, then the clip is limited to the border box area (and there is
+ // no need to examine child layers).
+ if (!l->renderer()->hasMask()) {
+ // Note: we don't have to walk z-order lists since transparent elements always establish
+ // a stacking context. This means we can just walk the layer tree directly.
+ for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling()) {
+ if (!l->reflection() || l->reflectionLayer() != curr)
+ clipRect.unite(transparencyClipBox(curr, rootLayer, paintBehavior));
+ }
+ }
+
+ // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
+ // current transparencyClipBox to catch all child layers.
+ // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
+ // size into the parent layer.
+ if (l->renderer()->hasReflection()) {
+ int deltaX = 0;
+ int deltaY = 0;
+ l->convertToLayerCoords(rootLayer, deltaX, deltaY);
+ clipRect.move(-deltaX, -deltaY);
+ clipRect.unite(l->renderBox()->reflectedRect(clipRect));
+ clipRect.move(deltaX, deltaY);
+ }
+}
+
+static IntRect transparencyClipBox(const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
{
// FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
// paintDirtyRect, and that should cut down on the amount we have to paint. Still it
// would be better to respect clips.
- if (rootLayer != l && l->paintsWithTransform()) {
+ if (rootLayer != l && l->paintsWithTransform(paintBehavior)) {
// The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
// the transformed layer and all of its children.
int x = 0;
@@ -733,51 +816,36 @@ static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransfor
TransformationMatrix transform;
transform.translate(x, y);
transform = *l->transform() * transform;
- transform = transform * enclosingTransform;
- // We now have a transform that will produce a rectangle in our view's space.
- IntRect clipRect = transform.mapRect(l->boundingBox(l));
-
- // Now shift the root layer to be us and pass down the new enclosing transform.
- for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling()) {
- if (!l->reflection() || l->reflectionLayer() != curr)
- clipRect.unite(transparencyClipBox(transform, curr, l));
- }
-
- return clipRect;
+ IntRect clipRect = l->boundingBox(l);
+ expandClipRectForDescendantsAndReflection(clipRect, l, l, paintBehavior);
+ return transform.mapRect(clipRect);
}
- // Note: we don't have to walk z-order lists since transparent elements always establish
- // a stacking context. This means we can just walk the layer tree directly.
IntRect clipRect = l->boundingBox(rootLayer);
-
- // If we have a mask, then the clip is limited to the border box area (and there is
- // no need to examine child layers).
- if (!l->renderer()->hasMask()) {
- for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling()) {
- if (!l->reflection() || l->reflectionLayer() != curr)
- clipRect.unite(transparencyClipBox(enclosingTransform, curr, rootLayer));
- }
- }
-
- // Now map the clipRect via the enclosing transform
- return enclosingTransform.mapRect(clipRect);
+ expandClipRectForDescendantsAndReflection(clipRect, l, rootLayer, paintBehavior);
+ return clipRect;
}
-void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer)
+void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
{
- if (p->paintingDisabled() || (paintsWithTransparency() && m_usedTransparency))
+ if (p->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency))
return;
RenderLayer* ancestor = transparentPaintingAncestor();
if (ancestor)
- ancestor->beginTransparencyLayers(p, rootLayer);
+ ancestor->beginTransparencyLayers(p, rootLayer, paintBehavior);
- if (paintsWithTransparency()) {
+ if (paintsWithTransparency(paintBehavior)) {
m_usedTransparency = true;
p->save();
- p->clip(transparencyClipBox(TransformationMatrix(), this, rootLayer));
+ IntRect clipRect = transparencyClipBox(this, rootLayer, paintBehavior);
+ p->clip(clipRect);
p->beginTransparencyLayer(renderer()->opacity());
+#ifdef REVEAL_TRANSPARENCY_LAYERS
+ p->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), DeviceColorSpace);
+ p->fillRect(clipRect);
+#endif
}
}
@@ -935,9 +1003,10 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, i
{
if (ancestorLayer == this)
return;
-
- if (renderer()->style()->position() == FixedPosition) {
- // Add in the offset of the view. We can obtain this by calling
+
+ EPosition position = renderer()->style()->position();
+ if (position == FixedPosition && (!ancestorLayer || ancestorLayer == renderer()->view()->layer())) {
+ // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
// localToAbsolute() on the RenderView.
FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true);
xPos += absPos.x();
@@ -945,13 +1014,80 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, i
return;
}
+ if (position == FixedPosition) {
+ // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
+ // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
+ // so we should always find the ancestor at or before we find the fixed position container.
+ RenderLayer* fixedPositionContainerLayer = 0;
+ bool foundAncestor = false;
+ for (RenderLayer* currLayer = parent(); currLayer; currLayer = currLayer->parent()) {
+ if (currLayer == ancestorLayer)
+ foundAncestor = true;
+
+ if (isFixedPositionedContainer(currLayer)) {
+ fixedPositionContainerLayer = currLayer;
+ ASSERT(foundAncestor);
+ break;
+ }
+ }
+
+ ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
+
+ if (fixedPositionContainerLayer != ancestorLayer) {
+ int fixedContainerX = 0;
+ int fixedContainerY = 0;
+ convertToLayerCoords(fixedPositionContainerLayer, fixedContainerX, fixedContainerY);
+
+ int ancestorX = 0;
+ int ancestorY = 0;
+ ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorX, ancestorY);
+
+ xPos += (fixedContainerX - ancestorX);
+ yPos += (fixedContainerY - ancestorY);
+ return;
+ }
+ }
+
+
RenderLayer* parentLayer;
- if (renderer()->style()->position() == AbsolutePosition)
- parentLayer = enclosingPositionedAncestor();
- else
+ if (position == AbsolutePosition || position == FixedPosition) {
+ // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
+ parentLayer = parent();
+ bool foundAncestorFirst = false;
+ while (parentLayer) {
+ if (isPositionedContainer(parentLayer))
+ break;
+
+ if (parentLayer == ancestorLayer) {
+ foundAncestorFirst = true;
+ break;
+ }
+
+ parentLayer = parentLayer->parent();
+ }
+
+ if (foundAncestorFirst) {
+ // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
+ // to enclosingPositionedAncestor and subtract.
+ RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
+
+ int thisX = 0;
+ int thisY = 0;
+ convertToLayerCoords(positionedAncestor, thisX, thisY);
+
+ int ancestorX = 0;
+ int ancestorY = 0;
+ ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorX, ancestorY);
+
+ xPos += (thisX - ancestorX);
+ yPos += (thisY - ancestorY);
+ return;
+ }
+ } else
parentLayer = parent();
- if (!parentLayer) return;
+ if (!parentLayer)
+ return;
parentLayer->convertToLayerCoords(ancestorLayer, xPos, yPos);
@@ -959,12 +1095,22 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, i
yPos += y();
}
+static inline int adjustedScrollDelta(int beginningDelta) {
+ // This implemention matches Firefox's.
+ // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
+ const int speedReducer = 12;
+
+ int adjustedDelta = beginningDelta / speedReducer;
+ if (adjustedDelta > 1)
+ adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
+ else if (adjustedDelta < -1)
+ adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
+
+ return adjustedDelta;
+}
+
void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
{
- // We want to reduce the speed if we're close from the original point to improve the handleability of the scroll
- const int shortDistanceLimit = 100; // We delimit a 200 pixels long square enclosing the original point
- const int speedReducer = 2; // Within this square we divide the scrolling speed by 2
-
Frame* frame = renderer()->document()->frame();
if (!frame)
return;
@@ -981,42 +1127,52 @@ void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
int xDelta = currentMousePosition.x() - sourcePoint.x();
int yDelta = currentMousePosition.y() - sourcePoint.y();
- if (abs(xDelta) < ScrollView::noPanScrollRadius) // at the center we let the space for the icon
+ if (abs(xDelta) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
xDelta = 0;
- if (abs(yDelta) < ScrollView::noPanScrollRadius)
+ if (abs(yDelta) <= ScrollView::noPanScrollRadius)
yDelta = 0;
- // Let's attenuate the speed for the short distances
- if (abs(xDelta) < shortDistanceLimit)
- xDelta /= speedReducer;
- if (abs(yDelta) < shortDistanceLimit)
- yDelta /= speedReducer;
-
- scrollByRecursively(xDelta, yDelta);
+ scrollByRecursively(adjustedScrollDelta(xDelta), adjustedScrollDelta(yDelta));
}
void RenderLayer::scrollByRecursively(int xDelta, int yDelta)
{
+ if (!xDelta && !yDelta)
+ return;
+
bool restrictedByLineClamp = false;
if (renderer()->parent())
- restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0;
+ restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone();
if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
int newOffsetX = scrollXOffset() + xDelta;
int newOffsetY = scrollYOffset() + yDelta;
scrollToOffset(newOffsetX, newOffsetY);
- // If this layer can't do the scroll we ask its parent
+ // If this layer can't do the scroll we ask the next layer up that can scroll to try
int leftToScrollX = newOffsetX - scrollXOffset();
int leftToScrollY = newOffsetY - scrollYOffset();
if ((leftToScrollX || leftToScrollY) && renderer()->parent()) {
- renderer()->parent()->enclosingLayer()->scrollByRecursively(leftToScrollX, leftToScrollY);
+ RenderObject* nextRenderer = renderer()->parent();
+ while (nextRenderer) {
+ if (nextRenderer->isBox() && toRenderBox(nextRenderer)->canBeScrolledAndHasScrollableArea()) {
+ nextRenderer->enclosingLayer()->scrollByRecursively(leftToScrollX, leftToScrollY);
+ break;
+ }
+ nextRenderer = nextRenderer->parent();
+ }
+
Frame* frame = renderer()->document()->frame();
if (frame)
frame->eventHandler()->updateAutoscrollRenderer();
}
- } else if (renderer()->view()->frameView())
+ } else if (renderer()->view()->frameView()) {
+ // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
+ // have an overflow clip. Which means that it is a document node that can be scrolled.
renderer()->view()->frameView()->scrollBy(IntSize(xDelta, yDelta));
+ // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
+ // https://bugs.webkit.org/show_bug.cgi?id=28237
+ }
}
@@ -1071,8 +1227,10 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai
#if USE(ACCELERATED_COMPOSITING)
if (compositor()->inCompositingMode()) {
- if (RenderLayer* compositingAncestor = ancestorCompositingLayer())
- compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants);
+ if (RenderLayer* compositingAncestor = ancestorCompositingLayer()) {
+ bool isUpdateRoot = true;
+ compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot);
+ }
}
#endif
@@ -1093,7 +1251,7 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai
// The caret rect needs to be invalidated after scrolling
Frame* frame = renderer()->document()->frame();
if (frame)
- frame->invalidateSelection();
+ frame->selection()->setNeedsLayout();
// Just schedule a full repaint of our object.
if (repaint)
@@ -1128,7 +1286,7 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor,
bool restrictedByLineClamp = false;
if (renderer()->parent()) {
parentLayer = renderer()->parent()->enclosingLayer();
- restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0;
+ restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone();
}
if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
@@ -1275,7 +1433,9 @@ void RenderLayer::autoscroll()
if (!frameView)
return;
+#if ENABLE(DRAG_SUPPORT)
frame->eventHandler()->updateSelectionForMouseDrag();
+#endif
IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition());
scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
@@ -1594,6 +1754,11 @@ IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
return localPoint - bottomRight;
}
+bool RenderLayer::hasOverflowControls() const
+{
+ return m_hBar || m_vBar || m_scrollCorner || renderer()->style()->resize() != RESIZE_NONE;
+}
+
void RenderLayer::positionOverflowControls(int tx, int ty)
{
if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
@@ -1779,17 +1944,23 @@ RenderLayer::updateScrollInfoAfterLayout()
// Set up the range (and page step/line step).
if (m_hBar) {
int clientWidth = box->clientWidth();
- int pageStep = (clientWidth - cAmountToKeepWhenPaging);
- if (pageStep < 0) pageStep = clientWidth;
- m_hBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
+ int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
+ m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
m_hBar->setProportion(clientWidth, m_scrollWidth);
+ // Explicitly set the horizontal scroll value. This ensures that when a
+ // right-to-left scrollable area's width (or content width) changes, the
+ // top right corner of the content doesn't shift with respect to the top
+ // right corner of the area. Conceptually, right-to-left areas have
+ // their origin at the top-right, but RenderLayer is top-left oriented,
+ // so this is needed to keep everything working (see how scrollXOffset()
+ // differs from scrollYOffset() to get an idea of why the horizontal and
+ // vertical scrollbars need to be treated differently).
m_hBar->setValue(scrollXOffset());
}
if (m_vBar) {
int clientHeight = box->clientHeight();
- int pageStep = (clientHeight - cAmountToKeepWhenPaging);
- if (pageStep < 0) pageStep = clientHeight;
- m_vBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
+ int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
+ m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
m_vBar->setProportion(clientHeight, m_scrollHeight);
}
@@ -1842,7 +2013,7 @@ void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, co
return;
}
- context->fillRect(absRect, Color::white);
+ context->fillRect(absRect, Color::white, box->style()->colorSpace());
}
void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
@@ -1871,7 +2042,7 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I
// Paint the resizer control.
DEFINE_STATIC_LOCAL(RefPtr<Image>, resizeCornerImage, (Image::loadPlatformResource("textAreaResizeCorner")));
IntPoint imagePoint(absRect.right() - resizeCornerImage->width(), absRect.bottom() - resizeCornerImage->height());
- context->drawImage(resizeCornerImage.get(), imagePoint);
+ context->drawImage(resizeCornerImage.get(), box->style()->colorSpace(), imagePoint);
// Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
// Clipping will exclude the right and bottom edges of this frame.
@@ -1880,9 +2051,9 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I
context->clip(absRect);
IntRect largerCorner = absRect;
largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
- context->setStrokeColor(Color(makeRGB(217, 217, 217)));
+ context->setStrokeColor(Color(makeRGB(217, 217, 217)), DeviceColorSpace);
context->setStrokeThickness(1.0f);
- context->setFillColor(Color::transparent);
+ context->setFillColor(Color::transparent, DeviceColorSpace);
context->drawRect(largerCorner);
context->restore();
}
@@ -1965,10 +2136,10 @@ bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularit
return (didHorizontalScroll || didVerticalScroll);
}
-void RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintRestriction paintRestriction, RenderObject *paintingRoot)
+void RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintBehavior paintBehavior, RenderObject *paintingRoot)
{
RenderObject::OverlapTestRequestMap overlapTestRequests;
- paintLayer(this, p, damageRect, paintRestriction, paintingRoot, &overlapTestRequests);
+ paintLayer(this, p, damageRect, paintBehavior, paintingRoot, &overlapTestRequests);
RenderObject::OverlapTestRequestMap::iterator end = overlapTestRequests.end();
for (RenderObject::OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it)
it->first->setOverlapTestResult(false);
@@ -2012,7 +2183,7 @@ static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflect
#endif
void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
- const IntRect& paintDirtyRect, PaintRestriction paintRestriction,
+ const IntRect& paintDirtyRect, PaintBehavior paintBehavior,
RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* overlapTestRequests,
PaintLayerFlags paintFlags)
{
@@ -2020,7 +2191,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
if (isComposited()) {
// The updatingControlTints() painting pass goes through compositing layers,
// but we need to ensure that we don't cache clip rects computed with the wrong root in this case.
- if (p->updatingControlTints())
+ if (p->updatingControlTints() || (paintBehavior & PaintBehaviorFlattenCompositingLayers))
paintFlags |= PaintLayerTemporaryClipRects;
else if (!backing()->paintingGoesToWindow() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) {
// If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer().
@@ -2039,26 +2210,25 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
if (!renderer()->opacity())
return;
- if (paintsWithTransparency())
+ if (paintsWithTransparency(paintBehavior))
paintFlags |= PaintLayerHaveTransparency;
// Apply a transform if we have one. A reflection is considered to be a transform, since it is a flip and a translate.
- if (paintsWithTransform() && !(paintFlags & PaintLayerAppliedTransform)) {
+ if (paintsWithTransform(paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) {
+ TransformationMatrix layerTransform = renderableTransform(paintBehavior);
// If the transform can't be inverted, then don't paint anything.
- if (!m_transform->isInvertible())
+ if (!layerTransform.isInvertible())
return;
// If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency
// layer from the parent now.
if (paintFlags & PaintLayerHaveTransparency)
- parent()->beginTransparencyLayers(p, rootLayer);
+ parent()->beginTransparencyLayers(p, rootLayer, paintBehavior);
// Make sure the parent's clip rects have been calculated.
IntRect clipRect = paintDirtyRect;
if (parent()) {
- ClipRects parentRects;
- parentClipRects(rootLayer, parentRects, paintFlags & PaintLayerTemporaryClipRects);
- clipRect = parentRects.overflowClipRect();
+ clipRect = backgroundClipRect(rootLayer, paintFlags & PaintLayerTemporaryClipRects);
clipRect.intersect(paintDirtyRect);
}
@@ -2070,21 +2240,15 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
int x = 0;
int y = 0;
convertToLayerCoords(rootLayer, x, y);
-#ifdef ANDROID_FASTER_MATRIX
- TransformationMatrix transform(*m_transform);
+ TransformationMatrix transform(layerTransform);
transform.translateRight(x, y);
-#else
- TransformationMatrix transform;
- transform.translate(x, y);
- transform = *m_transform * transform;
-#endif
// Apply the transform.
p->save();
- p->concatCTM(transform);
+ p->concatCTM(transform.toAffineTransform());
// Now do a paint with the root layer shifted to be us.
- paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), paintRestriction, paintingRoot, overlapTestRequests, paintFlags | PaintLayerAppliedTransform);
+ paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), paintBehavior, paintingRoot, overlapTestRequests, paintFlags | PaintLayerAppliedTransform);
p->restore();
@@ -2101,7 +2265,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
if (m_reflection && !m_paintingInsideReflection) {
// Mark that we are now inside replica painting.
m_paintingInsideReflection = true;
- reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection);
+ reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection);
m_paintingInsideReflection = false;
}
@@ -2116,13 +2280,13 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
// Ensure our lists are up-to-date.
updateCompositingAndLayerListsIfNeeded();
- bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText;
- bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText;
+ bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText;
+ bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly;
// If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
// is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
// Else, our renderer tree may or may not contain the painting root, so we pass that root along
- // so it will be tested against as we decend through the renderers.
+ // so it will be tested against as we descend through the renderers.
RenderObject* paintingRootForRenderer = 0;
if (paintingRoot && !renderer()->isDescendantOf(paintingRoot))
paintingRootForRenderer = paintingRoot;
@@ -2135,7 +2299,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
if (shouldPaint && !selectionOnly && !damageRect.isEmpty()) {
// Begin transparency layers lazily now that we know we have to paint something.
if (haveTransparency)
- beginTransparencyLayers(p, rootLayer);
+ beginTransparencyLayers(p, rootLayer, paintBehavior);
// Paint our background first, before painting any child layers.
// Establish the clip used to paint our background.
@@ -2152,13 +2316,13 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
// Now walk the sorted list of children with negative z-indices.
if (m_negZOrderList)
for (Vector<RenderLayer*>::iterator it = m_negZOrderList->begin(); it != m_negZOrderList->end(); ++it)
- it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags);
+ it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
// Now establish the appropriate clip and paint our child RenderObjects.
if (shouldPaint && !clipRectToApply.isEmpty()) {
// Begin transparency layers lazily now that we know we have to paint something.
if (haveTransparency)
- beginTransparencyLayers(p, rootLayer);
+ beginTransparencyLayers(p, rootLayer, paintBehavior);
// Set up the clip used when painting our children.
setClip(p, paintDirtyRect, clipRectToApply);
@@ -2191,12 +2355,12 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
// Paint any child layers that have overflow.
if (m_normalFlowList)
for (Vector<RenderLayer*>::iterator it = m_normalFlowList->begin(); it != m_normalFlowList->end(); ++it)
- it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags);
+ it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
// Now walk the sorted list of children with positive z-indices.
if (m_posZOrderList)
for (Vector<RenderLayer*>::iterator it = m_posZOrderList->begin(); it != m_posZOrderList->end(); ++it)
- it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags);
+ it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty()) {
setClip(p, paintDirtyRect, damageRect);
@@ -2245,15 +2409,10 @@ bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
}
}
- // Now determine if the result is inside an anchor; make sure an image map wins if
- // it already set URLElement and only use the innermost.
+ // Now determine if the result is inside an anchor - if the urlElement isn't already set.
Node* node = result.innerNode();
- while (node) {
- // for imagemaps, URLElement is the associated area element not the image itself
- if (node->isLink() && !result.URLElement() && !node->hasTagName(imgTag))
- result.setURLElement(static_cast<Element*>(node));
- node = node->eventParentNode();
- }
+ if (node && !result.URLElement())
+ result.setURLElement(static_cast<Element*>(node->enclosingLinkEventParentOrSelf()));
// Next set up the correct :hover/:active state along the new chain.
updateHoverActiveState(request, result);
@@ -2368,9 +2527,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
if (transform() && !appliedTransform) {
// Make sure the parent's clip rects have been calculated.
if (parent()) {
- ClipRects parentRects;
- parentClipRects(rootLayer, parentRects, useTemporaryClipRects);
- IntRect clipRect = parentRects.overflowClipRect();
+ IntRect clipRect = backgroundClipRect(rootLayer, useTemporaryClipRects);
// Go ahead and test the enclosing clip now.
if (!clipRect.contains(hitTestPoint))
return 0;
@@ -2499,7 +2656,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
// Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
if (fgRect.contains(hitTestPoint) && isSelfPaintingLayer()) {
- // Hit test with a temporary HitTestResult, because we onlyl want to commit to 'result' if we know we're frontmost.
+ // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost.
HitTestResult tempResult(result.point());
if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) &&
isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
@@ -2668,10 +2825,10 @@ void RenderLayer::parentClipRects(const RenderLayer* rootLayer, ClipRects& clipR
clipRects = *parent()->clipRects();
}
-void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds,
- IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects) const
+IntRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, bool temporaryClipRects) const
{
- if (rootLayer != this && parent()) {
+ IntRect backgroundRect;
+ if (parent()) {
ClipRects parentRects;
parentClipRects(rootLayer, parentRects, temporaryClipRects);
backgroundRect = renderer()->style()->position() == FixedPosition ? parentRects.fixedClipRect() :
@@ -2681,7 +2838,15 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa
ASSERT(view);
if (view && parentRects.fixed() && rootLayer->renderer() == view)
backgroundRect.move(view->frameView()->scrollX(), view->frameView()->scrollY());
+ }
+ return backgroundRect;
+}
+void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds,
+ IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects) const
+{
+ if (rootLayer != this && parent()) {
+ backgroundRect = backgroundClipRect(rootLayer, temporaryClipRects);
backgroundRect.intersect(paintDirtyRect);
} else
backgroundRect = paintDirtyRect;
@@ -2730,17 +2895,49 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa
IntRect RenderLayer::childrenClipRect() const
{
RenderLayer* rootLayer = renderer()->view()->layer();
+ RenderLayer* clippingRootLayer = clippingRoot();
IntRect layerBounds, backgroundRect, foregroundRect, outlineRect;
- calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect);
- return foregroundRect;
+ calculateRects(clippingRootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect);
+ return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect)).enclosingBoundingBox();
}
IntRect RenderLayer::selfClipRect() const
{
RenderLayer* rootLayer = renderer()->view()->layer();
+ RenderLayer* clippingRootLayer = clippingRoot();
IntRect layerBounds, backgroundRect, foregroundRect, outlineRect;
- calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect);
- return backgroundRect;
+ calculateRects(clippingRootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect);
+ return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect)).enclosingBoundingBox();
+}
+
+void RenderLayer::addBlockSelectionGapsBounds(const IntRect& bounds)
+{
+ m_blockSelectionGapsBounds.unite(bounds);
+}
+
+void RenderLayer::clearBlockSelectionGapsBounds()
+{
+ m_blockSelectionGapsBounds = IntRect();
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+ child->clearBlockSelectionGapsBounds();
+}
+
+void RenderLayer::repaintBlockSelectionGaps()
+{
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+ child->repaintBlockSelectionGaps();
+
+ if (m_blockSelectionGapsBounds.isEmpty())
+ return;
+
+ IntRect rect = m_blockSelectionGapsBounds;
+ rect.move(-scrolledContentOffset());
+ if (renderer()->hasOverflowClip())
+ rect.intersect(toRenderBox(renderer())->overflowClipRect(0, 0));
+ if (renderer()->hasClip())
+ rect.intersect(toRenderBox(renderer())->clipRect(0, 0));
+ if (!rect.isEmpty())
+ renderer()->repaintRectangle(rect);
}
bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect& damageRect, const RenderLayer* rootLayer) const
@@ -2771,7 +2968,7 @@ IntRect RenderLayer::localBoundingBox() const
{
// There are three special cases we need to consider.
// (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the
- // inline. In other words, if some <span> wraps to three lines, we'll create a bounding box that fully encloses the root
+ // inline. In other words, if some <span> wraps to three lines, we'll create a bounding box that fully encloses the
// line boxes of all three lines (including overflow on those lines).
// (2) Left/Top Overflow. The width/height of layers already includes right/bottom overflow. However, in the case of left/top
// overflow, we have to create a bounding box that will extend to include this overflow.
@@ -2785,8 +2982,8 @@ IntRect RenderLayer::localBoundingBox() const
InlineFlowBox* firstBox = inlineFlow->firstLineBox();
if (!firstBox)
return result;
- int top = firstBox->root()->topOverflow();
- int bottom = inlineFlow->lastLineBox()->root()->bottomOverflow();
+ int top = firstBox->topVisibleOverflow();
+ int bottom = inlineFlow->lastLineBox()->bottomVisibleOverflow();
int left = firstBox->x();
for (InlineRunBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox())
left = min(left, curr->x());
@@ -2797,7 +2994,7 @@ IntRect RenderLayer::localBoundingBox() const
if (child->isTableCell()) {
IntRect bbox = toRenderBox(child)->borderBoxRect();
result.unite(bbox);
- IntRect overflowRect = renderBox()->overflowRect(false);
+ IntRect overflowRect = renderBox()->visibleOverflowRect();
if (bbox != overflowRect)
result.unite(overflowRect);
}
@@ -2810,7 +3007,7 @@ IntRect RenderLayer::localBoundingBox() const
else {
IntRect bbox = box->borderBoxRect();
result = bbox;
- IntRect overflowRect = box->overflowRect(false);
+ IntRect overflowRect = box->visibleOverflowRect();
if (bbox != overflowRect)
result.unite(overflowRect);
}
@@ -2873,6 +3070,11 @@ void RenderLayer::clearBacking()
{
m_backing.clear();
}
+
+bool RenderLayer::hasCompositedMask() const
+{
+ return m_backing && m_backing->hasMaskLayer();
+}
#endif
void RenderLayer::setParent(RenderLayer* parent)
@@ -3089,7 +3291,7 @@ void RenderLayer::updateCompositingAndLayerListsIfNeeded()
#if USE(ACCELERATED_COMPOSITING)
if (compositor()->inCompositingMode()) {
if ((isStackingContext() && m_zOrderListsDirty) || m_normalFlowListDirty)
- compositor()->updateCompositingLayers(this);
+ compositor()->updateCompositingLayers(CompositingUpdateOnPaitingOrHitTest, this);
return;
}
#endif
@@ -3150,7 +3352,7 @@ void RenderLayer::repaintIncludingNonCompositingDescendants(RenderBoxModelObject
bool RenderLayer::shouldBeNormalFlowOnly() const
{
- return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo()) &&
+ return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo() || renderer()->isEmbeddedObject()) &&
!renderer()->isPositioned() &&
!renderer()->isRelPositioned() &&
!renderer()->hasTransform() &&
@@ -3159,7 +3361,7 @@ bool RenderLayer::shouldBeNormalFlowOnly() const
bool RenderLayer::isSelfPaintingLayer() const
{
- return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo();
+ return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo() || renderer()->isEmbeddedObject();
}
void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*)
@@ -3173,7 +3375,7 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*)
dirtyStackingContextZOrderLists();
}
- if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE) {
+ if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE && renderer()->isBox()) {
if (!m_marquee)
m_marquee = new RenderMarquee(this);
m_marquee->updateMarqueeStyle();
@@ -3183,10 +3385,9 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*)
m_marquee = 0;
}
- if (!hasReflection() && m_reflection) {
- m_reflection->destroy();
- m_reflection = 0;
- } else if (hasReflection()) {
+ if (!hasReflection() && m_reflection)
+ removeReflection();
+ else if (hasReflection()) {
if (!m_reflection)
createReflection();
updateReflectionStyle();
@@ -3260,6 +3461,16 @@ void RenderLayer::createReflection()
m_reflection->setParent(renderer()); // We create a 1-way connection.
}
+void RenderLayer::removeReflection()
+{
+ if (!m_reflection->documentBeingDestroyed())
+ m_reflection->removeLayers(this);
+
+ m_reflection->setParent(0);
+ m_reflection->destroy();
+ m_reflection = 0;
+}
+
void RenderLayer::updateReflectionStyle()
{
RefPtr<RenderStyle> newStyle = RenderStyle::create();
@@ -3298,3 +3509,16 @@ void RenderLayer::updateReflectionStyle()
}
} // namespace WebCore
+
+#ifndef NDEBUG
+void showLayerTree(const WebCore::RenderLayer* layer)
+{
+ if (!layer)
+ return;
+
+ if (WebCore::Frame* frame = layer->renderer()->document()->frame()) {
+ WebCore::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers);
+ fprintf(stderr, "%s\n", output.utf8().data());
+ }
+}
+#endif
diff --git a/WebCore/rendering/RenderLayer.h b/WebCore/rendering/RenderLayer.h
index 1772c66..2c8d184 100644
--- a/WebCore/rendering/RenderLayer.h
+++ b/WebCore/rendering/RenderLayer.h
@@ -202,9 +202,10 @@ public:
bool isTransparent() const;
RenderLayer* transparentPaintingAncestor();
- void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer);
+ void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer, PaintBehavior);
bool hasReflection() const { return renderer()->hasReflection(); }
+ bool isReflection() const { return renderer()->isReplica(); }
RenderReplica* reflection() const { return m_reflection; }
RenderLayer* reflectionLayer() const;
@@ -262,6 +263,7 @@ public:
int verticalScrollbarWidth() const;
int horizontalScrollbarHeight() const;
+ bool hasOverflowControls() const;
void positionOverflowControls(int tx, int ty);
bool isPointInResizeControl(const IntPoint& absolutePoint) const;
bool hitTestOverflowControls(HitTestResult&, const IntPoint& localPoint);
@@ -298,10 +300,11 @@ public:
enum UpdateLayerPositionsFlag {
DoFullRepaint = 1,
CheckForRepaint = 1 << 1,
- UpdateCompositingLayers = 1 << 2,
+ IsCompositingUpdateRoot = 1 << 2,
+ UpdateCompositingLayers = 1 << 3,
};
typedef unsigned UpdateLayerPositionsFlags;
- void updateLayerPositions(UpdateLayerPositionsFlags = DoFullRepaint | UpdateCompositingLayers);
+ void updateLayerPositions(UpdateLayerPositionsFlags = DoFullRepaint | IsCompositingUpdateRoot | UpdateCompositingLayers);
void updateTransform();
@@ -311,10 +314,22 @@ public:
void clearClipRectsIncludingDescendants();
void clearClipRects();
+ void addBlockSelectionGapsBounds(const IntRect&);
+ void clearBlockSelectionGapsBounds();
+ void repaintBlockSelectionGaps();
+
// Get the enclosing stacking context for this layer. A stacking context is a layer
// that has a non-auto z-index.
RenderLayer* stackingContext() const;
- bool isStackingContext() const { return !hasAutoZIndex() || renderer()->isRenderView(); }
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ bool isFixed() const { return renderer()->isPositioned() && renderer()->style()->position() == FixedPosition; }
+ // If fixed elements are composited, they will be containing children
+ bool isStackingContext() const {
+ return !hasAutoZIndex() || renderer()->isRenderView() || (isComposited() && isFixed());
+ }
+#else
+ bool isStackingContext() const { return !hasAutoZIndex() || renderer()->isRenderView() ; }
+#endif
void dirtyZOrderLists();
void dirtyStackingContextZOrderLists();
@@ -327,6 +342,7 @@ public:
Vector<RenderLayer*>* normalFlowList() const { return m_normalFlowList; }
bool hasVisibleContent() const { return m_hasVisibleContent; }
+ bool hasVisibleDescendant() const { return m_hasVisibleDescendant; }
void setHasVisibleContent(bool);
void dirtyVisibleContentStatus();
@@ -334,6 +350,9 @@ public:
// the <html> layer and the root layer).
RenderLayer* enclosingPositionedAncestor() const;
+ // The layer relative to which clipping rects for this layer are computed.
+ RenderLayer* clippingRoot() const;
+
#if USE(ACCELERATED_COMPOSITING)
// Enclosing compositing layer; if includeSelf is true, may return this.
RenderLayer* enclosingCompositingLayer(bool includeSelf = true) const;
@@ -350,7 +369,7 @@ public:
// paints the layers that intersect the damage rect from back to
// front. The hitTest method looks for mouse events by walking
// layers that intersect the point from front to back.
- void paint(GraphicsContext*, const IntRect& damageRect, PaintRestriction = PaintRestrictionNone, RenderObject* paintingRoot = 0);
+ void paint(GraphicsContext*, const IntRect& damageRect, PaintBehavior = PaintBehaviorNormal, RenderObject* paintingRoot = 0);
bool hitTest(const HitTestRequest&, HitTestResult&);
// This method figures out our layerBounds in coordinates relative to
@@ -388,7 +407,7 @@ public:
int staticX() const { return m_staticX; }
int staticY() const { return m_staticY; }
void setStaticX(int staticX) { m_staticX = staticX; }
- void setStaticY(int staticY);
+ void setStaticY(int staticY) { m_staticY = staticY; }
bool hasTransform() const { return renderer()->hasTransform(); }
// Note that this transform has the transform-origin baked in.
@@ -397,6 +416,7 @@ public:
// resulting transform has transform-origin baked in. If the layer does not have a transform,
// returns the identity matrix.
TransformationMatrix currentTransform() const;
+ TransformationMatrix renderableTransform(PaintBehavior) const;
// Get the perspective transform, which is applied to transformed sublayers.
// Returns true if the layer has a -webkit-perspective.
@@ -415,21 +435,23 @@ public:
#if USE(ACCELERATED_COMPOSITING)
bool isComposited() const { return m_backing != 0; }
+ bool hasCompositedMask() const;
RenderLayerBacking* backing() const { return m_backing.get(); }
RenderLayerBacking* ensureBacking();
void clearBacking();
#else
bool isComposited() const { return false; }
+ bool hasCompositedMask() const { return false; }
#endif
- bool paintsWithTransparency() const
+ bool paintsWithTransparency(PaintBehavior paintBehavior) const
{
- return isTransparent() && !isComposited();
+ return isTransparent() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || !isComposited());
}
- bool paintsWithTransform() const
+ bool paintsWithTransform(PaintBehavior paintBehavior) const
{
- return transform() && !isComposited();
+ return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || !isComposited());
}
private:
@@ -461,7 +483,7 @@ private:
typedef unsigned PaintLayerFlags;
void paintLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect,
- PaintRestriction, RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* = 0,
+ PaintBehavior, RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* = 0,
PaintLayerFlags paintFlags = 0);
RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
@@ -507,11 +529,14 @@ private:
Node* enclosingElement() const;
void createReflection();
+ void removeReflection();
+
void updateReflectionStyle();
bool paintingInsideReflection() const { return m_paintingInsideReflection; }
void setPaintingInsideReflection(bool b) { m_paintingInsideReflection = b; }
void parentClipRects(const RenderLayer* rootLayer, ClipRects&, bool temporaryClipRects = false) const;
+ IntRect backgroundClipRect(const RenderLayer* rootLayer, bool temporaryClipRects) const;
RenderLayer* enclosingTransformedAncestor() const;
@@ -637,6 +662,9 @@ protected:
RenderScrollbarPart* m_scrollCorner;
RenderScrollbarPart* m_resizer;
+private:
+ IntRect m_blockSelectionGapsBounds;
+
#if USE(ACCELERATED_COMPOSITING)
OwnPtr<RenderLayerBacking> m_backing;
#endif
@@ -644,4 +672,9 @@ protected:
} // namespace WebCore
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showLayerTree(const WebCore::RenderLayer* layer);
+#endif
+
#endif // RenderLayer_h
diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp
index e98c458..3f60557 100644
--- a/WebCore/rendering/RenderLayerBacking.cpp
+++ b/WebCore/rendering/RenderLayerBacking.cpp
@@ -28,18 +28,27 @@
#if USE(ACCELERATED_COMPOSITING)
#include "AnimationController.h"
+#if ENABLE(3D_CANVAS)
+#include "WebGLRenderingContext.h"
+#endif
#include "CSSPropertyNames.h"
#include "CSSStyleSelector.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "GraphicsLayer.h"
+#include "HTMLCanvasElement.h"
#include "HTMLElement.h"
#include "HTMLNames.h"
+#include "InspectorTimelineAgent.h"
+#include "KeyframeList.h"
+#include "PluginWidget.h"
#include "RenderBox.h"
#include "RenderImage.h"
#include "RenderLayerCompositor.h"
+#include "RenderEmbeddedObject.h"
#include "RenderVideo.h"
#include "RenderView.h"
+#include "Settings.h"
#include "RenderLayerBacking.h"
@@ -47,17 +56,26 @@ using namespace std;
namespace WebCore {
+using namespace HTMLNames;
+
static bool hasBorderOutlineOrShadow(const RenderStyle*);
-static bool hasBoxDecorations(const RenderStyle*);
-static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle*);
+static bool hasBoxDecorationsOrBackground(const RenderStyle*);
+static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle*);
+
+static inline bool is3DCanvas(RenderObject* renderer)
+{
+#if ENABLE(3D_CANVAS)
+ if (renderer->isCanvas())
+ return static_cast<HTMLCanvasElement*>(renderer->node())->is3D();
+#else
+ UNUSED_PARAM(renderer);
+#endif
+ return false;
+}
RenderLayerBacking::RenderLayerBacking(RenderLayer* layer)
: m_owningLayer(layer)
- , m_ancestorClippingLayer(0)
- , m_graphicsLayer(0)
- , m_foregroundLayer(0)
- , m_clippingLayer(0)
- , m_hasDirectlyCompositedContent(false)
+ , m_artificiallyInflatedBounds(false)
{
createGraphicsLayer();
}
@@ -66,12 +84,13 @@ RenderLayerBacking::~RenderLayerBacking()
{
updateClippingLayers(false, false);
updateForegroundLayer(false);
+ updateMaskLayer(false);
destroyGraphicsLayer();
}
void RenderLayerBacking::createGraphicsLayer()
{
- m_graphicsLayer = GraphicsLayer::createGraphicsLayer(this);
+ m_graphicsLayer = GraphicsLayer::create(this);
#ifndef NDEBUG
if (renderer()->node()) {
@@ -79,16 +98,18 @@ void RenderLayerBacking::createGraphicsLayer()
m_graphicsLayer->setName("Document Node");
else {
if (renderer()->node()->isHTMLElement() && renderer()->node()->hasID())
- m_graphicsLayer->setName(renderer()->renderName() + String(" ") + static_cast<HTMLElement*>(renderer()->node())->id());
+ m_graphicsLayer->setName(renderer()->renderName() + String(" ") + static_cast<HTMLElement*>(renderer()->node())->getIDAttribute());
else
m_graphicsLayer->setName(renderer()->renderName());
}
- } else
+ } else if (m_owningLayer->isReflection())
+ m_graphicsLayer->setName("Reflection");
+ else
m_graphicsLayer->setName("Anonymous Node");
#endif // NDEBUG
- updateLayerOpacity();
- updateLayerTransform();
+ updateLayerOpacity(renderer()->style());
+ updateLayerTransform(renderer()->style());
}
void RenderLayerBacking::destroyGraphicsLayer()
@@ -96,25 +117,19 @@ void RenderLayerBacking::destroyGraphicsLayer()
if (m_graphicsLayer)
m_graphicsLayer->removeFromParent();
- delete m_graphicsLayer;
m_graphicsLayer = 0;
-
- delete m_foregroundLayer;
m_foregroundLayer = 0;
-
- delete m_clippingLayer;
m_clippingLayer = 0;
+ m_maskLayer = 0;
}
-void RenderLayerBacking::updateLayerOpacity()
+void RenderLayerBacking::updateLayerOpacity(const RenderStyle* style)
{
- m_graphicsLayer->setOpacity(compositingOpacity(renderer()->opacity()));
+ m_graphicsLayer->setOpacity(compositingOpacity(style->opacity()));
}
-void RenderLayerBacking::updateLayerTransform()
+void RenderLayerBacking::updateLayerTransform(const RenderStyle* style)
{
- RenderStyle* style = renderer()->style();
-
// FIXME: This could use m_owningLayer->transform(), but that currently has transform-origin
// baked into it, and we don't want that.
TransformationMatrix t;
@@ -126,7 +141,31 @@ void RenderLayerBacking::updateLayerTransform()
m_graphicsLayer->setTransform(t);
}
-void RenderLayerBacking::updateAfterLayout(UpdateDepth updateDepth)
+static bool hasNonZeroTransformOrigin(const RenderObject* renderer)
+{
+ RenderStyle* style = renderer->style();
+ return (style->transformOriginX().type() == Fixed && style->transformOriginX().value())
+ || (style->transformOriginY().type() == Fixed && style->transformOriginY().value());
+}
+
+void RenderLayerBacking::updateCompositedBounds()
+{
+ IntRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer);
+
+ // If the element has a transform-origin that has fixed lengths, and the renderer has zero size,
+ // then we need to ensure that the compositing layer has non-zero size so that we can apply
+ // the transform-origin via the GraphicsLayer anchorPoint (which is expressed as a fractional value).
+ if (layerBounds.isEmpty() && hasNonZeroTransformOrigin(renderer())) {
+ layerBounds.setWidth(1);
+ layerBounds.setHeight(1);
+ m_artificiallyInflatedBounds = true;
+ } else
+ m_artificiallyInflatedBounds = false;
+
+ setCompositedBounds(layerBounds);
+}
+
+void RenderLayerBacking::updateAfterLayout(UpdateDepth updateDepth, bool isUpdateRoot)
{
RenderLayerCompositor* layerCompositor = compositor();
if (!layerCompositor->compositingLayersNeedRebuild()) {
@@ -137,10 +176,10 @@ void RenderLayerBacking::updateAfterLayout(UpdateDepth updateDepth)
//
// The solution is to update compositing children of this layer here,
// via updateCompositingChildrenGeometry().
- setCompositedBounds(layerCompositor->calculateCompositedBounds(m_owningLayer, m_owningLayer));
+ updateCompositedBounds();
layerCompositor->updateCompositingDescendantGeometry(m_owningLayer, m_owningLayer, updateDepth);
- if (!m_owningLayer->parent()) {
+ if (isUpdateRoot) {
updateGraphicsLayerGeometry();
layerCompositor->updateRootLayerPosition();
}
@@ -158,19 +197,33 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration()
if (updateClippingLayers(compositor->clippedByAncestor(m_owningLayer), compositor->clipsCompositingDescendants(m_owningLayer)))
layerConfigChanged = true;
- m_hasDirectlyCompositedContent = false;
- if (canUseDirectCompositing()) {
- if (renderer()->isImage()) {
- updateImageContents();
- m_hasDirectlyCompositedContent = true;
- m_graphicsLayer->setDrawsContent(false);
+ if (updateMaskLayer(m_owningLayer->renderer()->hasMask()))
+ m_graphicsLayer->setMaskLayer(m_maskLayer.get());
+
+ if (m_owningLayer->hasReflection()) {
+ if (m_owningLayer->reflectionLayer()->backing()) {
+ GraphicsLayer* reflectionLayer = m_owningLayer->reflectionLayer()->backing()->graphicsLayer();
+ m_graphicsLayer->setReplicatedByLayer(reflectionLayer);
}
+ } else
+ m_graphicsLayer->setReplicatedByLayer(0);
+
+ if (isDirectlyCompositedImage())
+ updateImageContents();
+
+ if (renderer()->isEmbeddedObject() && toRenderEmbeddedObject(renderer())->allowsAcceleratedCompositing()) {
+ PluginWidget* pluginWidget = static_cast<PluginWidget*>(toRenderEmbeddedObject(renderer())->widget());
+ m_graphicsLayer->setContentsToMedia(pluginWidget->platformLayer());
+ }
- if (rendererHasBackground())
- m_graphicsLayer->setBackgroundColor(rendererBackgroundColor());
- else
- m_graphicsLayer->clearBackgroundColor();
+#if ENABLE(3D_CANVAS)
+ if (is3DCanvas(renderer())) {
+ HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node());
+ WebGLRenderingContext* context = static_cast<WebGLRenderingContext*>(canvas->renderingContext());
+ if (context->graphicsContext3D()->platformGraphicsContext3D())
+ m_graphicsLayer->setContentsToGraphicsContext3D(context->graphicsContext3D());
}
+#endif
return layerConfigChanged;
}
@@ -184,14 +237,14 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
// Set transform property, if it is not animating. We have to do this here because the transform
// is affected by the layer dimensions.
if (!renderer()->animation()->isAnimatingPropertyOnRenderer(renderer(), CSSPropertyWebkitTransform))
- updateLayerTransform();
+ updateLayerTransform(renderer()->style());
// Set opacity, if it is not animating.
if (!renderer()->animation()->isAnimatingPropertyOnRenderer(renderer(), CSSPropertyOpacity))
- updateLayerOpacity();
+ updateLayerOpacity(renderer()->style());
RenderStyle* style = renderer()->style();
- m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D);
+ m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection());
m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible);
RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer();
@@ -222,10 +275,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
// Call calculateRects to get the backgroundRect which is what is used to clip the contents of this
// layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects
// for a compositing layer, rootLayer is the layer itself.
- ClipRects parentRects;
- m_owningLayer->parentClipRects(compAncestor, parentRects, true);
- IntRect parentClipRect = parentRects.overflowClipRect();
-
+ IntRect parentClipRect = m_owningLayer->backgroundClipRect(compAncestor, true);
m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation));
m_ancestorClippingLayer->setSize(parentClipRect.size());
@@ -251,13 +301,19 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
}
// If we have a layer that clips children, position it.
+ IntRect clippingBox;
if (m_clippingLayer) {
- IntRect clippingBox = toRenderBox(renderer())->overflowClipRect(0, 0);
+ clippingBox = toRenderBox(renderer())->overflowClipRect(0, 0);
m_clippingLayer->setPosition(FloatPoint() + (clippingBox.location() - localCompositingBounds.location()));
m_clippingLayer->setSize(clippingBox.size());
m_clippingLayer->setOffsetFromRenderer(clippingBox.location() - IntPoint());
}
+ if (m_maskLayer) {
+ m_maskLayer->setSize(m_graphicsLayer->size());
+ m_maskLayer->setPosition(FloatPoint());
+ }
+
if (m_owningLayer->hasTransform()) {
const IntRect borderBox = toRenderBox(renderer())->borderBoxRect();
@@ -293,15 +349,35 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
}
if (m_foregroundLayer) {
- // The contents layer is always coincidental with the graphicsLayer for now.
- m_foregroundLayer->setPosition(IntPoint(0, 0));
- m_foregroundLayer->setSize(newSize);
- m_foregroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer());
+ FloatPoint foregroundPosition;
+ FloatSize foregroundSize = newSize;
+ IntSize foregroundOffset = m_graphicsLayer->offsetFromRenderer();
+ // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it,
+ // so that it gets correctly sorted with children. In that case, position relative to the clipping layer.
+ if (m_clippingLayer) {
+ foregroundPosition = FloatPoint() + (localCompositingBounds.location() - clippingBox.location());
+ foregroundSize = FloatSize(clippingBox.size());
+ foregroundOffset = clippingBox.location() - IntPoint();
+ }
+
+ m_foregroundLayer->setPosition(foregroundPosition);
+ m_foregroundLayer->setSize(foregroundSize);
+ m_foregroundLayer->setOffsetFromRenderer(foregroundOffset);
+ }
+
+ if (m_owningLayer->reflectionLayer() && m_owningLayer->reflectionLayer()->isComposited()) {
+ RenderLayerBacking* reflectionBacking = m_owningLayer->reflectionLayer()->backing();
+ reflectionBacking->updateGraphicsLayerGeometry();
+
+ // The reflection layer has the bounds of m_owningLayer->reflectionLayer(),
+ // but the reflected layer is the bounds of this layer, so we need to position it appropriately.
+ FloatRect layerBounds = compositedBounds();
+ FloatRect reflectionLayerBounds = reflectionBacking->compositedBounds();
+ reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint() + (layerBounds.location() - reflectionLayerBounds.location()));
}
m_graphicsLayer->setContentsRect(contentsBox());
- if (!m_hasDirectlyCompositedContent)
- m_graphicsLayer->setDrawsContent(!isSimpleContainerCompositingLayer() && !paintingGoesToWindow());
+ m_graphicsLayer->setDrawsContent(containsPaintedContent());
}
void RenderLayerBacking::updateInternalHierarchy()
@@ -311,12 +387,12 @@ void RenderLayerBacking::updateInternalHierarchy()
if (m_ancestorClippingLayer) {
m_ancestorClippingLayer->removeAllChildren();
m_graphicsLayer->removeFromParent();
- m_ancestorClippingLayer->addChild(m_graphicsLayer);
+ m_ancestorClippingLayer->addChild(m_graphicsLayer.get());
}
if (m_clippingLayer) {
m_clippingLayer->removeFromParent();
- m_graphicsLayer->addChild(m_clippingLayer);
+ m_graphicsLayer->addChild(m_clippingLayer.get());
}
}
@@ -327,7 +403,7 @@ bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needs
if (needsAncestorClip) {
if (!m_ancestorClippingLayer) {
- m_ancestorClippingLayer = GraphicsLayer::createGraphicsLayer(this);
+ m_ancestorClippingLayer = GraphicsLayer::create(this);
#ifndef NDEBUG
m_ancestorClippingLayer->setName("Ancestor clipping Layer");
#endif
@@ -336,14 +412,13 @@ bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needs
}
} else if (m_ancestorClippingLayer) {
m_ancestorClippingLayer->removeFromParent();
- delete m_ancestorClippingLayer;
m_ancestorClippingLayer = 0;
layersChanged = true;
}
if (needsDescendantClip) {
if (!m_clippingLayer) {
- m_clippingLayer = GraphicsLayer::createGraphicsLayer(0);
+ m_clippingLayer = GraphicsLayer::create(0);
#ifndef NDEBUG
m_clippingLayer->setName("Child clipping Layer");
#endif
@@ -352,7 +427,6 @@ bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needs
}
} else if (m_clippingLayer) {
m_clippingLayer->removeFromParent();
- delete m_clippingLayer;
m_clippingLayer = 0;
layersChanged = true;
}
@@ -368,25 +442,61 @@ bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer)
bool layerChanged = false;
if (needsForegroundLayer) {
if (!m_foregroundLayer) {
- m_foregroundLayer = GraphicsLayer::createGraphicsLayer(this);
+ m_foregroundLayer = GraphicsLayer::create(this);
#ifndef NDEBUG
- m_foregroundLayer->setName("Contents");
+ m_foregroundLayer->setName("Foreground");
#endif
m_foregroundLayer->setDrawsContent(true);
- m_foregroundLayer->setDrawingPhase(GraphicsLayerPaintForegroundMask);
- m_graphicsLayer->setDrawingPhase(GraphicsLayerPaintBackgroundMask);
+ m_foregroundLayer->setPaintingPhase(GraphicsLayerPaintForeground);
layerChanged = true;
}
} else if (m_foregroundLayer) {
m_foregroundLayer->removeFromParent();
- delete m_foregroundLayer;
m_foregroundLayer = 0;
- m_graphicsLayer->setDrawingPhase(GraphicsLayerPaintAllMask);
layerChanged = true;
}
+
+ if (layerChanged)
+ m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer());
+
+ return layerChanged;
+}
+
+bool RenderLayerBacking::updateMaskLayer(bool needsMaskLayer)
+{
+ bool layerChanged = false;
+ if (needsMaskLayer) {
+ if (!m_maskLayer) {
+ m_maskLayer = GraphicsLayer::create(this);
+#ifndef NDEBUG
+ m_maskLayer->setName("Mask");
+#endif
+ m_maskLayer->setDrawsContent(true);
+ m_maskLayer->setPaintingPhase(GraphicsLayerPaintMask);
+ layerChanged = true;
+ }
+ } else if (m_maskLayer) {
+ m_maskLayer = 0;
+ layerChanged = true;
+ }
+
+ if (layerChanged)
+ m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer());
+
return layerChanged;
}
+GraphicsLayerPaintingPhase RenderLayerBacking::paintingPhaseForPrimaryLayer() const
+{
+ unsigned phase = GraphicsLayerPaintBackground;
+ if (!m_foregroundLayer)
+ phase |= GraphicsLayerPaintForeground;
+ if (!m_maskLayer)
+ phase |= GraphicsLayerPaintMask;
+
+ return static_cast<GraphicsLayerPaintingPhase>(phase);
+}
+
float RenderLayerBacking::compositingOpacity(float rendererOpacity) const
{
float finalOpacity = rendererOpacity;
@@ -413,12 +523,12 @@ static bool hasBorderOutlineOrShadow(const RenderStyle* style)
return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow();
}
-static bool hasBoxDecorations(const RenderStyle* style)
+static bool hasBoxDecorationsOrBackground(const RenderStyle* style)
{
return hasBorderOutlineOrShadow(style) || style->hasBackground();
}
-static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle* style)
+static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle* style)
{
return hasBorderOutlineOrShadow(style) || style->hasBackgroundImage();
}
@@ -478,7 +588,7 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
// Reject anything that has a border, a border-radius or outline,
// or any background (color or image).
// FIXME: we could optimize layers for simple backgrounds.
- if (hasBoxDecorations(style))
+ if (hasBoxDecorationsOrBackground(style))
return false;
// If we have got this far and the renderer has no children, then we're ok.
@@ -495,18 +605,18 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
// Reject anything that has a border, a border-radius or outline,
// or is not a simple background (no background, or solid color).
- if (hasBoxDecorationsWithBackgroundImage(style))
+ if (hasBoxDecorationsOrBackgroundImage(style))
return false;
// Now look at the body's renderer.
HTMLElement* body = renderObject->document()->body();
- RenderObject* bodyObject = (body && body->hasLocalName(HTMLNames::bodyTag)) ? body->renderer() : 0;
+ RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
if (!bodyObject)
return false;
style = bodyObject->style();
- if (hasBoxDecorationsWithBackgroundImage(style))
+ if (hasBoxDecorationsOrBackgroundImage(style))
return false;
// Ceck to see if all the body's children are compositing layers.
@@ -523,9 +633,11 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
return true;
}
+// Conservative test for having no rendered children.
bool RenderLayerBacking::hasNonCompositingContent() const
{
- // Conservative test for having no rendered children.
+ if (m_owningLayer->hasOverflowControls())
+ return true;
// Some HTML can cause whitespace text nodes to have renderers, like:
// <div>
@@ -542,7 +654,6 @@ bool RenderLayerBacking::hasNonCompositingContent() const
}
}
- // FIXME: test for overflow controls.
if (m_owningLayer->isStackingContext()) {
// Use the m_hasCompositingDescendant bit to optimize?
if (Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList()) {
@@ -576,32 +687,43 @@ bool RenderLayerBacking::hasNonCompositingContent() const
return false;
}
-// A layer can use direct compositing if the render layer's object is a replaced object and has no children.
-// This allows the GraphicsLayer to display the RenderLayer contents directly; it's used for images.
-bool RenderLayerBacking::canUseDirectCompositing() const
+bool RenderLayerBacking::containsPaintedContent() const
{
- RenderObject* renderObject = renderer();
-
- // Reject anything that isn't an image
- if (!renderObject->isImage() && !renderObject->isVideo())
+ if (isSimpleContainerCompositingLayer() || paintingGoesToWindow() || m_artificiallyInflatedBounds || m_owningLayer->isReflection())
return false;
-
- if (renderObject->hasMask() || renderObject->hasReflection())
+
+ if (isDirectlyCompositedImage())
return false;
- // Video can use an inner layer even if it has box decorations; we draw those into another layer.
- if (renderObject->isVideo())
- return true;
-
- // Reject anything that would require the image to be drawn via the GraphicsContext,
- // like border, shadows etc. Solid background color is OK.
- return !hasBoxDecorationsWithBackgroundImage(renderObject->style());
+ // FIXME: we could optimize cases where the image, video or canvas is known to fill the border box entirely,
+ // and set background color on the layer in that case, instead of allocating backing store and painting.
+ if (renderer()->isVideo() || is3DCanvas(renderer()))
+ return hasBoxDecorationsOrBackground(renderer()->style());
+
+ return true;
}
-
+
+// An image can be directly compositing if it's the sole content of the layer, and has no box decorations
+// that require painting. Direct compositing saves backing store.
+bool RenderLayerBacking::isDirectlyCompositedImage() const
+{
+ RenderObject* renderObject = renderer();
+ return renderObject->isImage() && !hasBoxDecorationsOrBackground(renderObject->style());
+}
+
void RenderLayerBacking::rendererContentChanged()
{
- if (canUseDirectCompositing() && renderer()->isImage())
+ if (isDirectlyCompositedImage()) {
updateImageContents();
+ return;
+ }
+
+#if ENABLE(3D_CANVAS)
+ if (is3DCanvas(renderer())) {
+ m_graphicsLayer->setGraphicsContext3DNeedsDisplay();
+ return;
+ }
+#endif
}
void RenderLayerBacking::updateImageContents()
@@ -705,13 +827,16 @@ void RenderLayerBacking::setContentsNeedDisplay()
if (m_foregroundLayer && m_foregroundLayer->drawsContent())
m_foregroundLayer->setNeedsDisplay();
+
+ if (m_maskLayer && m_maskLayer->drawsContent())
+ m_maskLayer->setNeedsDisplay();
}
// r is in the coordinate space of the layer's render object
void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r)
{
if (m_graphicsLayer && m_graphicsLayer->drawsContent()) {
- FloatPoint dirtyOrigin = contentsToGraphicsLayerCoordinates(m_graphicsLayer, FloatPoint(r.x(), r.y()));
+ FloatPoint dirtyOrigin = contentsToGraphicsLayerCoordinates(m_graphicsLayer.get(), FloatPoint(r.x(), r.y()));
FloatRect dirtyRect(dirtyOrigin, r.size());
FloatRect bounds(FloatPoint(), m_graphicsLayer->size());
if (bounds.intersects(dirtyRect))
@@ -722,6 +847,11 @@ void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r)
// FIXME: do incremental repaint
m_foregroundLayer->setNeedsDisplay();
}
+
+ if (m_maskLayer && m_maskLayer->drawsContent()) {
+ // FIXME: do incremental repaint
+ m_maskLayer->setNeedsDisplay();
+ }
}
static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
@@ -742,7 +872,7 @@ static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const
// Share this with RenderLayer::paintLayer, which would have to be educated about GraphicsLayerPaintingPhase?
void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* context,
const IntRect& paintDirtyRect, // in the coords of rootLayer
- PaintRestriction paintRestriction, GraphicsLayerPaintingPhase paintingPhase,
+ PaintBehavior paintBehavior, GraphicsLayerPaintingPhase paintingPhase,
RenderObject* paintingRoot)
{
if (paintingGoesToWindow()) {
@@ -752,14 +882,6 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
m_owningLayer->updateLayerListsIfNeeded();
- // Paint the reflection first if we have one.
- if (m_owningLayer->hasReflection()) {
- // Mark that we are now inside replica painting.
- m_owningLayer->setPaintingInsideReflection(true);
- m_owningLayer->reflectionLayer()->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot, 0, RenderLayer::PaintLayerPaintingReflection);
- m_owningLayer->setPaintingInsideReflection(false);
- }
-
// Calculate the clip rects we should use.
IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
m_owningLayer->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect);
@@ -777,9 +899,9 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
if (paintingRoot && !renderer()->isDescendantOf(paintingRoot))
paintingRootForRenderer = paintingRoot;
- bool shouldPaint = m_owningLayer->hasVisibleContent() && m_owningLayer->isSelfPaintingLayer();
+ bool shouldPaint = (m_owningLayer->hasVisibleContent() || m_owningLayer->hasVisibleDescendant()) && m_owningLayer->isSelfPaintingLayer();
- if (shouldPaint && (paintingPhase & GraphicsLayerPaintBackgroundMask)) {
+ if (shouldPaint && (paintingPhase & GraphicsLayerPaintBackground)) {
// If this is the root then we need to send in a bigger bounding box
// because we'll be painting the background as well (see RenderBox::paintRootBoxDecorations()).
IntRect paintBox = clipRectToApply;
@@ -792,9 +914,9 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
int rw;
int rh;
- if (box->view()->frameView()) {
- rw = box->view()->frameView()->contentsWidth();
- rh = box->view()->frameView()->contentsHeight();
+ if (FrameView* frameView = box->view()->frameView()) {
+ rw = frameView->contentsWidth();
+ rh = frameView->contentsHeight();
} else {
rw = box->view()->width();
rh = box->view()->height();
@@ -823,18 +945,18 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
restoreClip(context, paintDirtyRect, damageRect);
}
- if (shouldPaint && (paintingPhase & GraphicsLayerPaintForegroundMask)) {
+ bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText;
+ bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly;
+
+ if (shouldPaint && (paintingPhase & GraphicsLayerPaintForeground)) {
// Now walk the sorted list of children with negative z-indices. Only RenderLayers without compositing layers will paint.
// FIXME: should these be painted as background?
Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList();
if (negZOrderList) {
for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it)
- it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot);
+ it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot);
}
- bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText;
- bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText;
-
// Set up the clip used when painting our children.
setClip(context, paintDirtyRect, clipRectToApply);
RenderObject::PaintInfo paintInfo(context, clipRectToApply,
@@ -868,16 +990,18 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList();
if (normalFlowList) {
for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it)
- it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot);
+ it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot);
}
// Now walk the sorted list of children with positive z-indices.
Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList();
if (posZOrderList) {
for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it)
- it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot);
+ it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot);
}
-
+ }
+
+ if (shouldPaint && (paintingPhase & GraphicsLayerPaintMask)) {
if (renderer()->hasMask() && !selectionOnly && !damageRect.isEmpty()) {
setClip(context, paintDirtyRect, damageRect);
@@ -893,9 +1017,27 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
ASSERT(!m_owningLayer->m_usedTransparency);
}
+#if ENABLE(INSPECTOR)
+static InspectorTimelineAgent* inspectorTimelineAgent(RenderObject* renderer)
+{
+ Frame* frame = renderer->document()->frame();
+ if (!frame)
+ return 0;
+ Page* page = frame->page();
+ if (!page)
+ return 0;
+ return page->inspectorTimelineAgent();
+}
+#endif
+
// Up-call from compositing layer drawing callback.
-void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase drawingPhase, const IntRect& clip)
+void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip)
{
+#if ENABLE(INSPECTOR)
+ if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(m_owningLayer->renderer()))
+ timelineAgent->willPaint(clip);
+#endif
+
// We have to use the same root as for hit testing, because both methods
// can compute and cache clipRects.
IntRect enclosingBBox = compositedBounds();
@@ -912,10 +1054,25 @@ void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& co
IntRect dirtyRect = enclosingBBox;
dirtyRect.intersect(clipRect);
- paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintRestrictionNone, drawingPhase, renderer());
+ paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase, renderer());
+
+#if ENABLE(INSPECTOR)
+ if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(m_owningLayer->renderer()))
+ timelineAgent->didPaint();
+#endif
}
-bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes)
+bool RenderLayerBacking::showDebugBorders() const
+{
+ return compositor() ? compositor()->showDebugBorders() : false;
+}
+
+bool RenderLayerBacking::showRepaintCounter() const
+{
+ return compositor() ? compositor()->showRepaintCounter() : false;
+}
+
+bool RenderLayerBacking::startAnimation(double timeOffset, const Animation* anim, const KeyframeList& keyframes)
{
bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity);
bool hasTransform = keyframes.containsProperty(CSSPropertyWebkitTransform);
@@ -946,10 +1103,10 @@ bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim,
bool didAnimateTransform = !hasTransform;
bool didAnimateOpacity = !hasOpacity;
- if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, keyframes.animationName(), beginTime))
+ if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, keyframes.animationName(), timeOffset))
didAnimateTransform = true;
- if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), beginTime))
+ if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), timeOffset))
didAnimateOpacity = true;
bool runningAcceleratedAnimation = didAnimateTransform && didAnimateOpacity;
@@ -959,7 +1116,7 @@ bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim,
return runningAcceleratedAnimation;
}
-bool RenderLayerBacking::startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle)
+bool RenderLayerBacking::startTransition(double timeOffset, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle)
{
bool didAnimate = false;
ASSERT(property != cAnimateAll);
@@ -970,8 +1127,12 @@ bool RenderLayerBacking::startTransition(double beginTime, int property, const R
KeyframeValueList opacityVector(AnimatedPropertyOpacity);
opacityVector.insert(new FloatAnimationValue(0, compositingOpacity(fromStyle->opacity())));
opacityVector.insert(new FloatAnimationValue(1, compositingOpacity(toStyle->opacity())));
- if (m_graphicsLayer->addAnimation(opacityVector, toRenderBox(renderer())->borderBoxRect().size(), opacityAnim, String(), beginTime))
+ // The boxSize param is only used for transform animations (which can only run on RenderBoxes), so we pass an empty size here.
+ if (m_graphicsLayer->addAnimation(opacityVector, IntSize(), opacityAnim, String(), timeOffset)) {
+ // To ensure that the correct opacity is visible when the animation ends, also set the final opacity.
+ updateLayerOpacity(toStyle);
didAnimate = true;
+ }
}
}
@@ -981,8 +1142,11 @@ bool RenderLayerBacking::startTransition(double beginTime, int property, const R
KeyframeValueList transformVector(AnimatedPropertyWebkitTransform);
transformVector.insert(new TransformAnimationValue(0, &fromStyle->transform()));
transformVector.insert(new TransformAnimationValue(1, &toStyle->transform()));
- if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, String(), beginTime))
+ if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, String(), timeOffset)) {
+ // To ensure that the correct transform is visible when the animation ends, also set the final opacity.
+ updateLayerTransform(toStyle);
didAnimate = true;
+ }
}
}
@@ -1008,9 +1172,9 @@ void RenderLayerBacking::animationFinished(const String& animationName)
m_graphicsLayer->removeAnimationsForKeyframes(animationName);
}
-void RenderLayerBacking::animationPaused(const String& animationName)
+void RenderLayerBacking::animationPaused(double timeOffset, const String& animationName)
{
- m_graphicsLayer->pauseAnimation(animationName);
+ m_graphicsLayer->pauseAnimation(animationName, timeOffset);
}
void RenderLayerBacking::transitionFinished(int property)
diff --git a/WebCore/rendering/RenderLayerBacking.h b/WebCore/rendering/RenderLayerBacking.h
index b027685..7aea926 100644
--- a/WebCore/rendering/RenderLayerBacking.h
+++ b/WebCore/rendering/RenderLayerBacking.h
@@ -54,7 +54,7 @@ public:
RenderLayer* owningLayer() const { return m_owningLayer; }
enum UpdateDepth { CompositingChildren, AllDescendants };
- void updateAfterLayout(UpdateDepth);
+ void updateAfterLayout(UpdateDepth, bool isUpdateRoot);
// Returns true if layer configuration changed.
bool updateGraphicsLayerConfiguration();
@@ -63,21 +63,23 @@ public:
// Update contents and clipping structure.
void updateInternalHierarchy(); // make private
- GraphicsLayer* graphicsLayer() const { return m_graphicsLayer; }
+ GraphicsLayer* graphicsLayer() const { return m_graphicsLayer.get(); }
// Layer to clip children
bool hasClippingLayer() const { return m_clippingLayer != 0; }
- GraphicsLayer* clippingLayer() const { return m_clippingLayer; }
+ GraphicsLayer* clippingLayer() const { return m_clippingLayer.get(); }
// Layer to get clipped by ancestor
bool hasAncestorClippingLayer() const { return m_ancestorClippingLayer != 0; }
- GraphicsLayer* ancestorClippingLayer() const { return m_ancestorClippingLayer; }
+ GraphicsLayer* ancestorClippingLayer() const { return m_ancestorClippingLayer.get(); }
bool hasContentsLayer() const { return m_foregroundLayer != 0; }
- GraphicsLayer* foregroundLayer() const { return m_foregroundLayer; }
+ GraphicsLayer* foregroundLayer() const { return m_foregroundLayer.get(); }
- GraphicsLayer* parentForSublayers() const { return m_clippingLayer ? m_clippingLayer : m_graphicsLayer; }
- GraphicsLayer* childForSuperlayers() const { return m_ancestorClippingLayer ? m_ancestorClippingLayer : m_graphicsLayer; }
+ bool hasMaskLayer() const { return m_maskLayer != 0; }
+
+ GraphicsLayer* parentForSublayers() const { return m_clippingLayer ? m_clippingLayer.get() : m_graphicsLayer.get(); }
+ GraphicsLayer* childForSuperlayers() const { return m_ancestorClippingLayer ? m_ancestorClippingLayer.get() : m_graphicsLayer.get(); }
// RenderLayers with backing normally short-circuit paintLayer() because
// their content is rendered via callbacks from GraphicsLayer. However, the document
@@ -95,10 +97,10 @@ public:
void rendererContentChanged();
// Interface to start, finish, suspend and resume animations and transitions
- bool startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes);
- bool startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle);
+ bool startAnimation(double timeOffset, const Animation* anim, const KeyframeList& keyframes);
+ bool startTransition(double timeOffset, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle);
void animationFinished(const String& name);
- void animationPaused(const String& name);
+ void animationPaused(double timeOffset, const String& name);
void transitionFinished(int property);
void suspendAnimations(double time = 0);
@@ -106,6 +108,7 @@ public:
IntRect compositedBounds() const;
void setCompositedBounds(const IntRect&);
+ void updateCompositedBounds();
FloatPoint graphicsLayerToContentsCoordinates(const GraphicsLayer*, const FloatPoint&);
FloatPoint contentsToGraphicsLayerCoordinates(const GraphicsLayer*, const FloatPoint&);
@@ -116,6 +119,9 @@ public:
virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& clip);
+ virtual bool showDebugBorders() const;
+ virtual bool showRepaintCounter() const;
+
IntRect contentsBox() const;
private:
@@ -127,25 +133,28 @@ private:
bool updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip);
bool updateForegroundLayer(bool needsForegroundLayer);
+ bool updateMaskLayer(bool needsMaskLayer);
+ GraphicsLayerPaintingPhase paintingPhaseForPrimaryLayer() const;
+
IntSize contentOffsetInCompostingLayer() const;
// Result is transform origin in pixels.
FloatPoint3D computeTransformOrigin(const IntRect& borderBox) const;
// Result is perspective origin in pixels.
FloatPoint computePerspectiveOrigin(const IntRect& borderBox) const;
- void updateLayerOpacity();
- void updateLayerTransform();
+ void updateLayerOpacity(const RenderStyle*);
+ void updateLayerTransform(const RenderStyle*);
// Return the opacity value that this layer should use for compositing.
float compositingOpacity(float rendererOpacity) const;
- // Returns true if this RenderLayer only has content that can be rendered directly
- // by the compositing layer, without drawing (e.g. solid background color).
+ // Returns true if this compositing layer has no visible content.
bool isSimpleContainerCompositingLayer() const;
- // Returns true if we can optimize the RenderLayer to draw the replaced content
- // directly into a compositing buffer
- bool canUseDirectCompositing() const;
+ // Returns true if this layer has content that needs to be rendered by painting into the backing store.
+ bool containsPaintedContent() const;
+ // Returns true if the RenderLayer just contains an image that we can composite directly.
+ bool isDirectlyCompositedImage() const;
void updateImageContents();
bool rendererHasBackground() const;
@@ -154,7 +163,7 @@ private:
bool hasNonCompositingContent() const;
void paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect,
- PaintRestriction paintRestriction, GraphicsLayerPaintingPhase, RenderObject* paintingRoot);
+ PaintBehavior paintBehavior, GraphicsLayerPaintingPhase, RenderObject* paintingRoot);
static int graphicsLayerToCSSProperty(AnimatedPropertyID);
static AnimatedPropertyID cssToGraphicsLayerProperty(int);
@@ -162,14 +171,15 @@ private:
private:
RenderLayer* m_owningLayer;
- GraphicsLayer* m_ancestorClippingLayer; // only used if we are clipped by an ancestor which is not a stacking context
- GraphicsLayer* m_graphicsLayer;
- GraphicsLayer* m_foregroundLayer; // only used in cases where we need to draw the foreground separately
- GraphicsLayer* m_clippingLayer; // only used if we have clipping on a stacking context, with compositing children
+ OwnPtr<GraphicsLayer> m_ancestorClippingLayer; // only used if we are clipped by an ancestor which is not a stacking context
+ OwnPtr<GraphicsLayer> m_graphicsLayer;
+ OwnPtr<GraphicsLayer> m_foregroundLayer; // only used in cases where we need to draw the foreground separately
+ OwnPtr<GraphicsLayer> m_clippingLayer; // only used if we have clipping on a stacking context, with compositing children
+ OwnPtr<GraphicsLayer> m_maskLayer; // only used if we have a mask
IntRect m_compositedBounds;
- bool m_hasDirectlyCompositedContent;
+ bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp
index fb15800..22118fe 100644
--- a/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/WebCore/rendering/RenderLayerCompositor.cpp
@@ -29,15 +29,18 @@
#include "RenderLayerCompositor.h"
#include "AnimationController.h"
+#include "Chrome.h"
#include "ChromeClient.h"
#include "CSSPropertyNames.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsLayer.h"
-#include "HitTestRequest.h"
#include "HitTestResult.h"
+#include "HTMLCanvasElement.h"
#include "Page.h"
+#include "RenderEmbeddedObject.h"
#include "RenderLayerBacking.h"
+#include "RenderReplica.h"
#include "RenderVideo.h"
#include "RenderView.h"
#include "Settings.h"
@@ -58,10 +61,15 @@ bool WebCoreHas3DRendering = true;
namespace WebCore {
+using namespace HTMLNames;
+
struct CompositingState {
CompositingState(RenderLayer* compAncestor)
: m_compositingAncestor(compAncestor)
, m_subtreeIsCompositing(false)
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ , m_fixedSibling(false)
+#endif
#ifndef NDEBUG
, m_depth(0)
#endif
@@ -70,6 +78,9 @@ struct CompositingState {
RenderLayer* m_compositingAncestor;
bool m_subtreeIsCompositing;
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ bool m_fixedSibling;
+#endif
#ifndef NDEBUG
int m_depth;
#endif
@@ -79,6 +90,8 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView)
: m_renderView(renderView)
, m_rootPlatformLayer(0)
, m_hasAcceleratedCompositing(true)
+ , m_showDebugBorders(false)
+ , m_showRepaintCounter(false)
, m_compositingConsultsOverlap(true)
, m_compositing(false)
, m_rootLayerAttached(false)
@@ -92,7 +105,6 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView)
RenderLayerCompositor::~RenderLayerCompositor()
{
ASSERT(!m_rootLayerAttached);
- delete m_rootPlatformLayer;
}
void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */)
@@ -110,16 +122,24 @@ void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */)
}
}
-void RenderLayerCompositor::cacheAcceleratedCompositingEnabledFlag()
+void RenderLayerCompositor::cacheAcceleratedCompositingFlags()
{
bool hasAcceleratedCompositing = false;
- if (Settings* settings = m_renderView->document()->settings())
+ bool showDebugBorders = false;
+ bool showRepaintCounter = false;
+
+ if (Settings* settings = m_renderView->document()->settings()) {
hasAcceleratedCompositing = settings->acceleratedCompositingEnabled();
+ showDebugBorders = settings->showDebugBorders();
+ showRepaintCounter = settings->showRepaintCounter();
+ }
- if (hasAcceleratedCompositing != m_hasAcceleratedCompositing)
+ if (hasAcceleratedCompositing != m_hasAcceleratedCompositing || showDebugBorders != m_showDebugBorders || showRepaintCounter != m_showRepaintCounter)
setCompositingLayersNeedRebuild();
m_hasAcceleratedCompositing = hasAcceleratedCompositing;
+ m_showDebugBorders = showDebugBorders;
+ m_showRepaintCounter = showRepaintCounter;
}
void RenderLayerCompositor::setCompositingLayersNeedRebuild(bool needRebuild)
@@ -138,16 +158,30 @@ void RenderLayerCompositor::scheduleSync()
page->chrome()->client()->scheduleCompositingLayerSync();
}
-void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot)
+void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType updateType, RenderLayer* updateRoot)
{
- // When m_compositingConsultsOverlap is true, then layer positions affect compositing,
- // so we can only bail here when we're not looking at overlap.
- if (!m_compositingLayersNeedRebuild && !m_compositingConsultsOverlap)
+ bool checkForHierarchyUpdate = false;
+ bool needGeometryUpdate = false;
+
+ switch (updateType) {
+ case CompositingUpdateAfterLayoutOrStyleChange:
+ case CompositingUpdateOnPaitingOrHitTest:
+ checkForHierarchyUpdate = true;
+ break;
+ case CompositingUpdateOnScroll:
+ if (m_compositingConsultsOverlap)
+ checkForHierarchyUpdate = true; // Overlap can change with scrolling, so need to check for hierarchy updates.
+
+ needGeometryUpdate = true;
+ break;
+ }
+
+ if (!checkForHierarchyUpdate && !needGeometryUpdate)
return;
ASSERT(inCompositingMode());
- bool needLayerRebuild = m_compositingLayersNeedRebuild;
+ bool needHierarchyUpdate = m_compositingLayersNeedRebuild;
if (!updateRoot) {
// Only clear the flag if we're updating the entire hierarchy.
m_compositingLayersNeedRebuild = false;
@@ -160,26 +194,33 @@ void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot)
double startTime = WTF::currentTime();
#endif
- // Go through the layers in presentation order, so that we can compute which
- // RLs need compositing layers.
- // FIXME: we could maybe do this in one pass, but the parenting logic would be more
- // complex.
- {
+ if (checkForHierarchyUpdate) {
+ // Go through the layers in presentation order, so that we can compute which RenderLayers need compositing layers.
+ // FIXME: we could maybe do this and the hierarchy udpate in one pass, but the parenting logic would be more complex.
CompositingState compState(updateRoot);
- bool layersChanged;
+ bool layersChanged = false;
if (m_compositingConsultsOverlap) {
OverlapMap overlapTestRequestMap;
computeCompositingRequirements(updateRoot, &overlapTestRequestMap, compState, layersChanged);
} else
computeCompositingRequirements(updateRoot, 0, compState, layersChanged);
- needLayerRebuild |= layersChanged;
+ needHierarchyUpdate |= layersChanged;
}
- // Now create and parent the compositing layers.
- {
+ if (needHierarchyUpdate) {
+ // Update the hierarchy of the compositing layers.
CompositingState compState(updateRoot);
- rebuildCompositingLayerTree(updateRoot, compState, needLayerRebuild);
+ Vector<GraphicsLayer*> childList;
+ rebuildCompositingLayerTree(updateRoot, compState, childList);
+
+ // Host the document layer in the RenderView's root layer.
+ if (updateRoot == rootRenderLayer() && !childList.isEmpty())
+ m_rootPlatformLayer->setChildren(childList);
+ } else if (needGeometryUpdate) {
+ // We just need to do a geometry update. This is only used for position:fixed scrolling;
+ // most of the time, geometry is updated via RenderLayer::styleChanged().
+ updateLayerTreeGeometry(updateRoot);
}
#if PROFILE_LAYER_REBUILD
@@ -216,6 +257,17 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR
}
} else {
if (layer->backing()) {
+ // If we're removing backing on a reflection, clear the source GraphicsLayer's pointer to
+ // its replica GraphicsLayer. In practice this should never happen because reflectee and reflection
+ // are both either composited, or not composited.
+ if (layer->isReflection()) {
+ RenderLayer* sourceLayer = toRenderBoxModelObject(layer->renderer()->parent())->layer();
+ if (RenderLayerBacking* backing = sourceLayer->backing()) {
+ ASSERT(backing->graphicsLayer()->replicaLayer() == layer->backing()->graphicsLayer());
+ backing->graphicsLayer()->setReplicatedByLayer(0);
+ }
+ }
+
layer->clearBacking();
layerChanged = true;
@@ -287,6 +339,13 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye
return boundingBoxRect;
}
+ if (RenderLayer* reflection = layer->reflectionLayer()) {
+ if (!reflection->isComposited()) {
+ IntRect childUnionBounds = calculateCompositedBounds(reflection, layer);
+ unionBounds.unite(childUnionBounds);
+ }
+ }
+
ASSERT(layer->isStackingContext() || (!layer->m_posZOrderList || layer->m_posZOrderList->size() == 0));
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) {
@@ -322,7 +381,7 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye
}
}
- if (layer->paintsWithTransform()) {
+ if (layer->paintsWithTransform(PaintBehaviorNormal)) {
TransformationMatrix* affineTrans = layer->transform();
boundingBoxRect = affineTrans->mapRect(boundingBoxRect);
unionBounds = affineTrans->mapRect(unionBounds);
@@ -425,11 +484,11 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
bool haveComputedBounds = false;
IntRect absBounds;
- if (overlapMap && mustOverlapCompositedLayers) {
+ if (overlapMap && !overlapMap->isEmpty()) {
// If we're testing for overlap, we only need to composite if we overlap something that is already composited.
absBounds = layer->renderer()->localToAbsoluteQuad(FloatRect(layer->localBoundingBox())).enclosingBoundingBox();
haveComputedBounds = true;
- mustOverlapCompositedLayers &= overlapsCompositedLayers(*overlapMap, absBounds);
+ mustOverlapCompositedLayers = overlapsCompositedLayers(*overlapMap, absBounds);
}
layer->setMustOverlapCompositedLayers(mustOverlapCompositedLayers);
@@ -443,7 +502,19 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
#endif
const bool willBeComposited = needsToBeComposited(layer);
+
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ // If we are a fixed layer, signal it to our siblings
+ if (layer->isFixed())
+ compositingState.m_fixedSibling = true;
+
+ if (!willBeComposited && compositingState.m_fixedSibling)
+ layer->setMustOverlapCompositedLayers(true);
+
+ if (willBeComposited || compositingState.m_fixedSibling) {
+#else
if (willBeComposited) {
+#endif
// Tell the parent it has compositing descendants.
compositingState.m_subtreeIsCompositing = true;
// This layer now acts as the ancestor for kids.
@@ -464,13 +535,32 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
ASSERT(!layer->m_zOrderListsDirty);
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) {
size_t listSize = negZOrderList->size();
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ childState.m_fixedSibling = false;
+
+ // For the negative z-order, if we have a fixed layer
+ // we need to make all the siblings composited layers.
+ // Otherwise a negative layer (below the fixed layer) could
+ // still be drawn onto a higher z-order layer (e.g. the body)
+ // if not immediately intersecting with our fixed layer.
+ // So it's not enough here to only set m_fixedSibling for
+ // subsequent siblings as we do for the normal flow
+ // and positive z-order.
+ for (size_t j = 0; j < listSize; ++j) {
+ if ((negZOrderList->at(j))->isFixed()) {
+ childState.m_fixedSibling = true;
+ break;
+ }
+ }
+#endif
+
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = negZOrderList->at(i);
computeCompositingRequirements(curLayer, overlapMap, childState, layersChanged);
// If we have to make a layer for this child, make one now so we can have a contents layer
// (since we need to ensure that the -ve z-order child renders underneath our contents).
- if (childState.m_subtreeIsCompositing) {
+ if (!willBeComposited && childState.m_subtreeIsCompositing) {
// make layer compositing
layer->setMustOverlapCompositedLayers(true);
childState.m_compositingAncestor = layer;
@@ -484,6 +574,9 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
ASSERT(!layer->m_normalFlowListDirty);
if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) {
size_t listSize = normalFlowList->size();
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ childState.m_fixedSibling = false;
+#endif
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = normalFlowList->at(i);
computeCompositingRequirements(curLayer, overlapMap, childState, layersChanged);
@@ -493,6 +586,9 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
if (layer->isStackingContext()) {
if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) {
size_t listSize = posZOrderList->size();
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ childState.m_fixedSibling = false;
+#endif
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = posZOrderList->at(i);
computeCompositingRequirements(curLayer, overlapMap, childState, layersChanged);
@@ -503,13 +599,15 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
// If we have a software transform, and we have layers under us, we need to also
// be composited. Also, if we have opacity < 1, then we need to be a layer so that
// the child layers are opaque, then rendered with opacity on this layer.
- if (childState.m_subtreeIsCompositing &&
- (layer->renderer()->hasTransform() || layer->renderer()->style()->opacity() < 1)) {
+ if (!willBeComposited && childState.m_subtreeIsCompositing && requiresCompositingWhenDescendantsAreCompositing(layer->renderer())) {
layer->setMustOverlapCompositedLayers(true);
if (overlapMap)
addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds);
}
+ if (layer->reflectionLayer())
+ layer->reflectionLayer()->setMustOverlapCompositedLayers(needsToBeComposited(layer));
+
// Subsequent layers in the parent stacking context also need to composite.
if (childState.m_subtreeIsCompositing)
compositingState.m_subtreeIsCompositing = true;
@@ -526,10 +624,14 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
// Update backing now, so that we can use isComposited() reliably during tree traversal in rebuildCompositingLayerTree().
if (updateBacking(layer, CompositingChangeRepaintNow))
layersChanged = true;
+
+ if (layer->reflectionLayer() && updateLayerCompositingState(layer->reflectionLayer(), CompositingChangeRepaintNow))
+ layersChanged = true;
}
void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer)
{
+ ASSERT(!parentLayer || childLayer->ancestorCompositingLayer() == parentLayer);
ASSERT(childLayer->isComposited());
// It's possible to be called with a parent that isn't yet composited when we're doing
@@ -571,40 +673,41 @@ void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer)
#if ENABLE(VIDEO)
bool RenderLayerCompositor::canAccelerateVideoRendering(RenderVideo* o) const
{
- // FIXME: ideally we need to look at all ancestors for mask or video. But for now,
- // just bail on the obvious cases.
- if (o->hasMask() || o->hasReflection() || !m_hasAcceleratedCompositing)
+ if (!m_hasAcceleratedCompositing)
return false;
return o->supportsAcceleratedRendering();
}
#endif
-void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState& compositingState, bool updateHierarchy)
+void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, const CompositingState& compositingState, Vector<GraphicsLayer*>& childLayersOfEnclosingLayer)
{
// Make the layer compositing if necessary, and set up clipping and content layers.
// Note that we can only do work here that is independent of whether the descendant layers
// have been processed. computeCompositingRequirements() will already have done the repaint if necessary.
+
RenderLayerBacking* layerBacking = layer->backing();
if (layerBacking) {
// The compositing state of all our children has been updated already, so now
// we can compute and cache the composited bounds for this layer.
- layerBacking->setCompositedBounds(calculateCompositedBounds(layer, layer));
+ layerBacking->updateCompositedBounds();
+
+ if (RenderLayer* reflection = layer->reflectionLayer()) {
+ if (reflection->backing())
+ reflection->backing()->updateCompositedBounds();
+ }
layerBacking->updateGraphicsLayerConfiguration();
layerBacking->updateGraphicsLayerGeometry();
if (!layer->parent())
updateRootLayerPosition();
-
- // FIXME: make this more incremental
- if (updateHierarchy)
- layerBacking->parentForSublayers()->removeAllChildren();
}
- // host the document layer in the RenderView's root layer
- if (updateHierarchy && layer->isRootLayer() && layer->isComposited())
- parentInRootLayer(layer);
+ // If this layer has backing, then we are collecting its children, otherwise appending
+ // to the compositing child list of an enclosing layer.
+ Vector<GraphicsLayer*> layerChildren;
+ Vector<GraphicsLayer*>& childList = layerBacking ? layerChildren : childLayersOfEnclosingLayer;
CompositingState childState = compositingState;
if (layer->isComposited())
@@ -625,19 +728,13 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, stru
size_t listSize = negZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = negZOrderList->at(i);
- rebuildCompositingLayerTree(curLayer, childState, updateHierarchy);
- if (updateHierarchy && curLayer->isComposited())
- setCompositingParent(curLayer, childState.m_compositingAncestor);
+ rebuildCompositingLayerTree(curLayer, childState, childList);
}
}
- if (updateHierarchy && layerBacking && layerBacking->foregroundLayer()) {
- // we only have a contents layer if we have an m_layer
- layerBacking->foregroundLayer()->removeFromParent();
-
- GraphicsLayer* hostingLayer = layerBacking->clippingLayer() ? layerBacking->clippingLayer() : layerBacking->graphicsLayer();
- hostingLayer->addChild(layerBacking->foregroundLayer());
- }
+ // If a negative z-order child is compositing, we get a foreground layer which needs to get parented.
+ if (layerBacking && layerBacking->foregroundLayer())
+ childList.append(layerBacking->foregroundLayer());
}
ASSERT(!layer->m_normalFlowListDirty);
@@ -645,38 +742,93 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, stru
size_t listSize = normalFlowList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = normalFlowList->at(i);
- rebuildCompositingLayerTree(curLayer, childState, updateHierarchy);
- if (updateHierarchy && curLayer->isComposited())
- setCompositingParent(curLayer, childState.m_compositingAncestor);
+ rebuildCompositingLayerTree(curLayer, childState, childList);
}
}
-
+
if (layer->isStackingContext()) {
if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) {
size_t listSize = posZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = posZOrderList->at(i);
- rebuildCompositingLayerTree(curLayer, childState, updateHierarchy);
- if (updateHierarchy && curLayer->isComposited())
- setCompositingParent(curLayer, childState.m_compositingAncestor);
+ rebuildCompositingLayerTree(curLayer, childState, childList);
}
}
}
+
+ if (layerBacking) {
+ layerBacking->parentForSublayers()->setChildren(layerChildren);
+ childLayersOfEnclosingLayer.append(layerBacking->childForSuperlayers());
+ }
}
+// This just updates layer geometry without changing the hierarchy.
+void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer)
+{
+ if (RenderLayerBacking* layerBacking = layer->backing()) {
+ // The compositing state of all our children has been updated already, so now
+ // we can compute and cache the composited bounds for this layer.
+ layerBacking->updateCompositedBounds();
+
+ if (RenderLayer* reflection = layer->reflectionLayer()) {
+ if (reflection->backing())
+ reflection->backing()->updateCompositedBounds();
+ }
+
+ layerBacking->updateGraphicsLayerConfiguration();
+ layerBacking->updateGraphicsLayerGeometry();
+
+ if (!layer->parent())
+ updateRootLayerPosition();
+ }
+
+ if (layer->isStackingContext()) {
+ ASSERT(!layer->m_zOrderListsDirty);
+
+ if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) {
+ size_t listSize = negZOrderList->size();
+ for (size_t i = 0; i < listSize; ++i)
+ updateLayerTreeGeometry(negZOrderList->at(i));
+ }
+ }
+
+ ASSERT(!layer->m_normalFlowListDirty);
+ if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) {
+ size_t listSize = normalFlowList->size();
+ for (size_t i = 0; i < listSize; ++i)
+ updateLayerTreeGeometry(normalFlowList->at(i));
+ }
+
+ if (layer->isStackingContext()) {
+ if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) {
+ size_t listSize = posZOrderList->size();
+ for (size_t i = 0; i < listSize; ++i)
+ updateLayerTreeGeometry(posZOrderList->at(i));
+ }
+ }
+}
// Recurs down the RenderLayer tree until its finds the compositing descendants of compositingAncestor and updates their geometry.
void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* compositingAncestor, RenderLayer* layer, RenderLayerBacking::UpdateDepth updateDepth)
{
if (layer != compositingAncestor) {
if (RenderLayerBacking* layerBacking = layer->backing()) {
- layerBacking->setCompositedBounds(calculateCompositedBounds(layer, layer));
+ layerBacking->updateCompositedBounds();
+
+ if (RenderLayer* reflection = layer->reflectionLayer()) {
+ if (reflection->backing())
+ reflection->backing()->updateCompositedBounds();
+ }
+
layerBacking->updateGraphicsLayerGeometry();
if (updateDepth == RenderLayerBacking::CompositingChildren)
return;
}
}
+ if (layer->reflectionLayer())
+ updateCompositingDescendantGeometry(compositingAncestor, layer->reflectionLayer(), updateDepth);
+
if (!layer->hasCompositingDescendant())
return;
@@ -711,6 +863,7 @@ void RenderLayerCompositor::repaintCompositedLayersAbsoluteRect(const IntRect& a
void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const IntRect& rect)
{
+ // FIXME: This method does not work correctly with transforms.
if (layer->isComposited())
layer->setBackingNeedsRepaintInRect(rect);
@@ -719,7 +872,8 @@ void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const
size_t listSize = negZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = negZOrderList->at(i);
- int x = 0, y = 0;
+ int x = 0;
+ int y = 0;
curLayer->convertToLayerCoords(layer, x, y);
IntRect childRect(rect);
childRect.move(-x, -y);
@@ -731,7 +885,8 @@ void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const
size_t listSize = posZOrderList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = posZOrderList->at(i);
- int x = 0, y = 0;
+ int x = 0;
+ int y = 0;
curLayer->convertToLayerCoords(layer, x, y);
IntRect childRect(rect);
childRect.move(-x, -y);
@@ -743,7 +898,8 @@ void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const
size_t listSize = normalFlowList->size();
for (size_t i = 0; i < listSize; ++i) {
RenderLayer* curLayer = normalFlowList->at(i);
- int x = 0, y = 0;
+ int x = 0;
+ int y = 0;
curLayer->convertToLayerCoords(layer, x, y);
IntRect childRect(rect);
childRect.move(-x, -y);
@@ -759,7 +915,7 @@ RenderLayer* RenderLayerCompositor::rootRenderLayer() const
GraphicsLayer* RenderLayerCompositor::rootPlatformLayer() const
{
- return m_rootPlatformLayer;
+ return m_rootPlatformLayer.get();
}
void RenderLayerCompositor::didMoveOnscreen()
@@ -772,7 +928,7 @@ void RenderLayerCompositor::didMoveOnscreen()
if (!page)
return;
- page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer);
+ page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer.get());
m_rootLayerAttached = true;
}
@@ -793,7 +949,7 @@ void RenderLayerCompositor::willMoveOffscreen()
void RenderLayerCompositor::updateRootLayerPosition()
{
if (m_rootPlatformLayer)
- m_rootPlatformLayer->setSize(FloatSize(m_renderView->overflowWidth(), m_renderView->overflowHeight()));
+ m_rootPlatformLayer->setSize(FloatSize(m_renderView->rightLayoutOverflow(), m_renderView->bottomLayoutOverflow()));
}
void RenderLayerCompositor::didStartAcceleratedAnimation()
@@ -814,21 +970,80 @@ bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const
if (!m_hasAcceleratedCompositing || !layer->isSelfPaintingLayer())
return false;
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ // if an ancestor is fixed positioned, we need to be composited...
+ const RenderLayer* currLayer = layer;
+ while ((currLayer = currLayer->parent())) {
+ if (currLayer->isComposited() && currLayer->isFixed())
+ return true;
+ }
+#endif
+
return requiresCompositingLayer(layer) || layer->mustOverlapCompositedLayers();
}
+#if PLATFORM(ANDROID)
+bool RenderLayerCompositor::requiresCompositingForMobileSites(const RenderLayer* layer) const
+{
+ // First, check if we are in an iframe, and if so bail out
+ if (m_renderView->document()->frame()->tree()->parent())
+ return false;
+
+ RenderObject* renderer = layer->renderer();
+ // Check for transforms
+ if (requiresCompositingForTransform(renderer))
+ return true;
+
+ // Check for animations
+ if (requiresCompositingForAnimation(renderer))
+ return true;
+
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ // For the moment, we want to only enable fixed composited layers on mobile websites.
+ // We can consider a website as being a 'mobile' site if all the
+ // following checks are true:
+ // 1) - the viewport width is either undefined (-1) or equal to device-width (0), and
+ // 2) - no scaling is allowed
+ if (!layer->isFixed())
+ return false;
+
+ Settings* settings = m_renderView->document()->settings();
+ if (!settings)
+ return false;
+
+ if ((settings->viewportWidth() == -1 || settings->viewportWidth() == 0) &&
+ !settings->viewportUserScalable())
+ return true;
+#endif
+
+ return false;
+}
+#endif
+
// Note: this specifies whether the RL needs a compositing layer for intrinsic reasons.
// Use needsToBeComposited() to determine if a RL actually needs a compositing layer.
// static
bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) const
{
+ RenderObject* renderer = layer->renderer();
+ // The compositing state of a reflection should match that of its reflected layer.
+ if (layer->isReflection()) {
+ renderer = renderer->parent(); // The RenderReplica's parent is the object being reflected.
+ layer = toRenderBoxModelObject(renderer)->layer();
+ }
// The root layer always has a compositing layer, but it may not have backing.
return (inCompositingMode() && layer->isRootLayer()) ||
- requiresCompositingForTransform(layer->renderer()) ||
- requiresCompositingForVideo(layer->renderer()) ||
- layer->renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden ||
- clipsCompositingDescendants(layer) ||
- requiresCompositingForAnimation(layer->renderer());
+#if PLATFORM(ANDROID)
+ requiresCompositingForMobileSites(layer) ||
+#else
+ requiresCompositingForTransform(renderer) ||
+ requiresCompositingForVideo(renderer) ||
+ requiresCompositingForCanvas(renderer) ||
+ requiresCompositingForPlugin(renderer) ||
+ requiresCompositingForAnimation(renderer) ||
+#endif
+ renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden ||
+ clipsCompositingDescendants(layer);
}
// Return true if the given layer has some ancestor in the RenderLayer hierarchy that clips,
@@ -862,10 +1077,8 @@ bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const
if (!computeClipRoot || computeClipRoot == layer)
return false;
- ClipRects parentRects;
- layer->parentClipRects(computeClipRoot, parentRects, true);
-
- return parentRects.overflowClipRect() != ClipRects::infiniteRect();
+ IntRect backgroundRect = layer->backgroundClipRect(computeClipRoot, true);
+ return backgroundRect != ClipRects::infiniteRect();
}
// Return true if the given layer is a stacking context and has compositing child
@@ -893,10 +1106,30 @@ bool RenderLayerCompositor::requiresCompositingForVideo(RenderObject* renderer)
RenderVideo* video = toRenderVideo(renderer);
return canAccelerateVideoRendering(video);
}
+#else
+ UNUSED_PARAM(renderer);
+#endif
+ return false;
+}
+
+bool RenderLayerCompositor::requiresCompositingForCanvas(RenderObject* renderer) const
+{
+#if ENABLE(3D_CANVAS)
+ if (renderer->isCanvas()) {
+ HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer->node());
+ return canvas->is3D();
+ }
+#else
+ UNUSED_PARAM(renderer);
#endif
return false;
}
+bool RenderLayerCompositor::requiresCompositingForPlugin(RenderObject* renderer) const
+{
+ return renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing();
+}
+
bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) const
{
if (AnimationController* animController = renderer->animation()) {
@@ -906,6 +1139,11 @@ bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* render
return false;
}
+bool RenderLayerCompositor::requiresCompositingWhenDescendantsAreCompositing(RenderObject* renderer) const
+{
+ return renderer->hasTransform() || renderer->isTransparent() || renderer->hasMask() || renderer->hasReflection();
+}
+
// If an element has negative z-index children, those children render in front of the
// layer background, so we need an extra 'contents' layer for the foreground of the layer
// object.
@@ -919,8 +1157,8 @@ void RenderLayerCompositor::ensureRootPlatformLayer()
if (m_rootPlatformLayer)
return;
- m_rootPlatformLayer = GraphicsLayer::createGraphicsLayer(0);
- m_rootPlatformLayer->setSize(FloatSize(m_renderView->overflowWidth(), m_renderView->overflowHeight()));
+ m_rootPlatformLayer = GraphicsLayer::create(0);
+ m_rootPlatformLayer->setSize(FloatSize(m_renderView->rightLayoutOverflow(), m_renderView->bottomLayoutOverflow()));
m_rootPlatformLayer->setPosition(FloatPoint(0, 0));
// The root layer does flipping if we need it on this platform.
m_rootPlatformLayer->setGeometryOrientation(GraphicsLayer::compositingCoordinatesOrientation());
@@ -937,7 +1175,6 @@ void RenderLayerCompositor::destroyRootPlatformLayer()
return;
willMoveOffscreen();
- delete m_rootPlatformLayer;
m_rootPlatformLayer = 0;
}
@@ -985,4 +1222,3 @@ bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const
} // namespace WebCore
#endif // USE(ACCELERATED_COMPOSITING)
-
diff --git a/WebCore/rendering/RenderLayerCompositor.h b/WebCore/rendering/RenderLayerCompositor.h
index 02929dc..eeacdf7 100644
--- a/WebCore/rendering/RenderLayerCompositor.h
+++ b/WebCore/rendering/RenderLayerCompositor.h
@@ -38,6 +38,12 @@ class GraphicsLayer;
class RenderVideo;
#endif
+enum CompositingUpdateType {
+ CompositingUpdateAfterLayoutOrStyleChange,
+ CompositingUpdateOnPaitingOrHitTest,
+ CompositingUpdateOnScroll
+};
+
// RenderLayerCompositor manages the hierarchy of
// composited RenderLayers. It determines which RenderLayers
// become compositing, and creates and maintains a hierarchy of
@@ -47,7 +53,6 @@ class RenderVideo;
class RenderLayerCompositor {
public:
-
RenderLayerCompositor(RenderView*);
~RenderLayerCompositor();
@@ -61,8 +66,11 @@ public:
// Returns true if the accelerated compositing is enabled
bool hasAcceleratedCompositing() const { return m_hasAcceleratedCompositing; }
- // Copy the acceleratedCompositingEnabledFlag from Settings
- void cacheAcceleratedCompositingEnabledFlag();
+ bool showDebugBorders() const { return m_showDebugBorders; }
+ bool showRepaintCounter() const { return m_showRepaintCounter; }
+
+ // Copy the accelerated compositing related flags from Settings
+ void cacheAcceleratedCompositingFlags();
// Called when the layer hierarchy needs to be updated (compositing layers have been
// created, destroyed or re-parented).
@@ -77,7 +85,7 @@ public:
void scheduleSync();
// Rebuild the tree of compositing layers
- void updateCompositingLayers(RenderLayer* updateRoot = 0);
+ void updateCompositingLayers(CompositingUpdateType = CompositingUpdateAfterLayoutOrStyleChange, RenderLayer* updateRoot = 0);
// Update the compositing state of the given layer. Returns true if that state changed.
enum CompositingChangeRepaint { CompositingChangeRepaintNow, CompositingChangeWillRepaintLater };
@@ -147,8 +155,13 @@ private:
// Returns true if any layer's compositing changed
void computeCompositingRequirements(RenderLayer*, OverlapMap*, struct CompositingState&, bool& layersChanged);
- void rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState&, bool updateHierarchy);
+
+ // Recurses down the tree, parenting descendant compositing layers and collecting an array of child layers for the current compositing layer.
+ void rebuildCompositingLayerTree(RenderLayer* layer, const struct CompositingState&, Vector<GraphicsLayer*>& childGraphicsLayersOfEnclosingLayer);
+ // Recurses down the tree, updating layer geometry only.
+ void updateLayerTreeGeometry(RenderLayer*);
+
// Hook compositing layers together
void setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer);
void removeCompositedChildren(RenderLayer*);
@@ -164,11 +177,21 @@ private:
bool requiresCompositingForAnimation(RenderObject*) const;
bool requiresCompositingForTransform(RenderObject*) const;
bool requiresCompositingForVideo(RenderObject*) const;
+ bool requiresCompositingForCanvas(RenderObject*) const;
+ bool requiresCompositingForPlugin(RenderObject*) const;
+ bool requiresCompositingWhenDescendantsAreCompositing(RenderObject*) const;
+
+#if PLATFORM(ANDROID)
+ // Whether we are on a mobile site
+ bool requiresCompositingForMobileSites(const RenderLayer* layer) const;
+#endif
private:
RenderView* m_renderView;
- GraphicsLayer* m_rootPlatformLayer;
+ OwnPtr<GraphicsLayer> m_rootPlatformLayer;
bool m_hasAcceleratedCompositing;
+ bool m_showDebugBorders;
+ bool m_showRepaintCounter;
bool m_compositingConsultsOverlap;
bool m_compositing;
bool m_rootLayerAttached;
diff --git a/WebCore/rendering/RenderLineBoxList.cpp b/WebCore/rendering/RenderLineBoxList.cpp
index 00566b8..57bc26c 100644
--- a/WebCore/rendering/RenderLineBoxList.cpp
+++ b/WebCore/rendering/RenderLineBoxList.cpp
@@ -162,8 +162,8 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, RenderObject::Pain
// intersect. This is a quick short-circuit that we can take to avoid walking any lines.
// FIXME: This check is flawed in the following extremely obscure way:
// if some line in the middle has a huge overflow, it might actually extend below the last line.
- int yPos = firstLineBox()->root()->topOverflow() - renderer->maximalOutlineSize(paintInfo.phase);
- int h = renderer->maximalOutlineSize(paintInfo.phase) + lastLineBox()->root()->bottomOverflow() - yPos;
+ int yPos = firstLineBox()->topVisibleOverflow() - renderer->maximalOutlineSize(paintInfo.phase);
+ int h = renderer->maximalOutlineSize(paintInfo.phase) + lastLineBox()->bottomVisibleOverflow() - yPos;
yPos += ty;
if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y())
return;
@@ -184,21 +184,22 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, RenderObject::Pain
// The whole way objects break across pages needs to be redone.
// Try to avoid splitting a line vertically, but only if it's less than the height
// of the entire page.
- if (curr->root()->bottomOverflow() - curr->root()->topOverflow() <= v->printRect().height()) {
- if (ty + curr->root()->bottomOverflow() > v->printRect().bottom()) {
- if (ty + curr->root()->topOverflow() < v->truncatedAt())
- v->setBestTruncatedAt(ty + curr->root()->topOverflow(), renderer);
+ if (curr->bottomVisibleOverflow() - curr->topVisibleOverflow() <= v->printRect().height()) {
+ if (ty + curr->bottomVisibleOverflow() > v->printRect().bottom()) {
+ if (ty + curr->topVisibleOverflow() < v->truncatedAt())
+ v->setBestTruncatedAt(ty + curr->root()->topVisibleOverflow(), renderer);
// If we were able to truncate, don't paint.
- if (ty + curr->root()->topOverflow() >= v->truncatedAt())
+ if (ty + curr->topVisibleOverflow() >= v->truncatedAt())
break;
}
}
}
- int top = min(curr->root()->topOverflow(), curr->root()->selectionTop()) - renderer->maximalOutlineSize(info.phase);
- int bottom = curr->root()->bottomOverflow() + renderer->maximalOutlineSize(info.phase);
+ int top = min(curr->topVisibleOverflow(), curr->root()->selectionTop()) - renderer->maximalOutlineSize(info.phase);
+ int bottom = curr->bottomVisibleOverflow() + renderer->maximalOutlineSize(info.phase);
h = bottom - top;
yPos = ty + top;
+ v->setMinimumColumnHeight(h);
if (yPos < info.rect.bottom() && yPos + h > info.rect.y())
curr->paint(info, tx, ty);
}
@@ -229,14 +230,14 @@ bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestReq
// contain the point. This is a quick short-circuit that we can take to avoid walking any lines.
// FIXME: This check is flawed in the following extremely obscure way:
// if some line in the middle has a huge overflow, it might actually extend below the last line.
- if ((y >= ty + lastLineBox()->root()->bottomOverflow()) || (y < ty + firstLineBox()->root()->topOverflow()))
+ if ((y >= ty + lastLineBox()->root()->bottomVisibleOverflow()) || (y < ty + firstLineBox()->root()->topVisibleOverflow()))
return false;
// See if our root lines contain the point. If so, then we hit test
// them further. Note that boxes can easily overlap, so we can't make any assumptions
// based off positions of our first line box or our last line box.
for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevFlowBox()) {
- if (y >= ty + curr->root()->topOverflow() && y < ty + curr->root()->bottomOverflow()) {
+ if (y >= ty + curr->root()->topVisibleOverflow() && y < ty + curr->root()->bottomVisibleOverflow()) {
bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty);
if (inside) {
renderer->updateHitTestResult(result, IntPoint(x - tx, y - ty));
diff --git a/WebCore/rendering/RenderListBox.cpp b/WebCore/rendering/RenderListBox.cpp
index e6c28f7..15c652c 100644
--- a/WebCore/rendering/RenderListBox.cpp
+++ b/WebCore/rendering/RenderListBox.cpp
@@ -321,7 +321,8 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in
textColor = theme()->inactiveListBoxSelectionForegroundColor();
}
- paintInfo.context->setFillColor(textColor);
+ ColorSpace colorSpace = itemStyle->colorSpace();
+ paintInfo.context->setFillColor(textColor, colorSpace);
Font itemFont = style()->font();
if (isOptionGroupElement(element)) {
@@ -358,9 +359,10 @@ void RenderListBox::paintItemBackground(PaintInfo& paintInfo, int tx, int ty, in
// Draw the background for this list box item
if (!element->renderStyle() || element->renderStyle()->visibility() != HIDDEN) {
+ ColorSpace colorSpace = element->renderStyle() ? element->renderStyle()->colorSpace() : style()->colorSpace();
IntRect itemRect = itemBoundingBoxRect(tx, ty, listIndex);
itemRect.intersect(controlClipRect(tx, ty));
- paintInfo.context->fillRect(itemRect, backColor);
+ paintInfo.context->fillRect(itemRect, backColor, colorSpace);
}
}
@@ -508,7 +510,7 @@ bool RenderListBox::listIndexIsVisible(int index)
return index >= m_indexOffset && index < m_indexOffset + numVisibleItems();
}
-bool RenderListBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
+bool RenderListBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node**)
{
return m_vBar && m_vBar->scroll(direction, granularity, multiplier);
}
@@ -527,8 +529,7 @@ void RenderListBox::valueChanged(Scrollbar*)
if (newOffset != m_indexOffset) {
m_indexOffset = newOffset;
repaint();
- // Fire the scroll DOM event.
- node()->dispatchEvent(eventNames().scrollEvent, false, false);
+ node()->dispatchEvent(Event::create(eventNames().scrollEvent, false, false));
}
}
diff --git a/WebCore/rendering/RenderListBox.h b/WebCore/rendering/RenderListBox.h
index e5454e5..aafb87e 100644
--- a/WebCore/rendering/RenderListBox.h
+++ b/WebCore/rendering/RenderListBox.h
@@ -68,7 +68,7 @@ private:
virtual bool isPointInOverflowControl(HitTestResult&, int x, int y, int tx, int ty);
- virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f);
+ virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f, Node** stopNode = 0);
virtual void calcPrefWidths();
virtual int baselinePosition(bool firstLine, bool isRootLineBox) const;
diff --git a/WebCore/rendering/RenderListItem.cpp b/WebCore/rendering/RenderListItem.cpp
index 374ef66..54a7dd2 100644
--- a/WebCore/rendering/RenderListItem.cpp
+++ b/WebCore/rendering/RenderListItem.cpp
@@ -1,9 +1,7 @@
/**
- * This file is part of the DOM implementation for KDE.
- *
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
- * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
*
* This library is free software; you can redistribute it and/or
@@ -53,8 +51,8 @@ void RenderListItem::styleDidChange(StyleDifference diff, const RenderStyle* old
{
RenderBlock::styleDidChange(diff, oldStyle);
- if (style()->listStyleType() != LNONE ||
- (style()->listStyleImage() && !style()->listStyleImage()->errorOccurred())) {
+ if (style()->listStyleType() != NoneListStyle
+ || (style()->listStyleImage() && !style()->listStyleImage()->errorOccurred())) {
RefPtr<RenderStyle> newStyle = RenderStyle::create();
// The marker always inherits from the list item, regardless of where it might end
// up (e.g., in some deeply nested line box). See CSS3 spec.
@@ -77,11 +75,16 @@ void RenderListItem::destroy()
RenderBlock::destroy();
}
+static bool isList(Node* node)
+{
+ return (node->hasTagName(ulTag) || node->hasTagName(olTag));
+}
+
static Node* enclosingList(Node* node)
{
Node* parent = node->parentNode();
for (Node* n = parent; n; n = n->parentNode())
- if (n->hasTagName(ulTag) || n->hasTagName(olTag))
+ if (isList(n))
return n;
// If there's no actual <ul> or <ol> list element, then our parent acts as
// our list for purposes of determining what other list items should be
@@ -89,22 +92,38 @@ static Node* enclosingList(Node* node)
return parent;
}
+static Node* enclosingList(const RenderObject* renderer)
+{
+ Node* node = renderer->node();
+ if (node)
+ return enclosingList(node);
+
+ renderer = renderer->parent();
+ while (renderer && !renderer->node())
+ renderer = renderer->parent();
+
+ node = renderer->node();
+ if (isList(node))
+ return node;
+
+ return enclosingList(node);
+}
+
static RenderListItem* previousListItem(Node* list, const RenderListItem* item)
{
- for (Node* node = item->node()->traversePreviousNode(); node != list; node = node->traversePreviousNode()) {
- RenderObject* renderer = node->renderer();
- if (!renderer || !renderer->isListItem())
+ for (RenderObject* renderer = item->previousInPreOrder(); renderer != list->renderer(); renderer = renderer->previousInPreOrder()) {
+ if (!renderer->isListItem())
continue;
- Node* otherList = enclosingList(node);
+ Node* otherList = enclosingList(renderer);
// This item is part of our current list, so it's what we're looking for.
if (list == otherList)
return toRenderListItem(renderer);
// We found ourself inside another list; lets skip the rest of it.
- // Use traverseNextNode() here because the other list itself may actually
+ // Use nextInPreOrder() here because the other list itself may actually
// be a list item itself. We need to examine it, so we do this to counteract
- // the traversePreviousNode() that will be done by the loop.
+ // the previousInPreOrder() that will be done by the loop.
if (otherList)
- node = otherList->traverseNextNode();
+ renderer = otherList->renderer()->nextInPreOrder();
}
return 0;
}
@@ -113,7 +132,7 @@ inline int RenderListItem::calcValue() const
{
if (m_hasExplicitValue)
return m_explicitValue;
- Node* list = enclosingList(node());
+ Node* list = enclosingList(this);
// FIXME: This recurses to a possible depth of the length of the list.
// That's not good -- we need to change this to an iterative algorithm.
if (RenderListItem* previousItem = previousListItem(list, this))
@@ -247,21 +266,30 @@ void RenderListItem::positionListMarker()
int markerXPos;
RootInlineBox* root = m_marker->inlineBoxWrapper()->root();
+ // FIXME: Inline flows in the line box hierarchy that have self-painting layers should act as cutoff points
+ // and really shouldn't keep propagating overflow up. This won't really break anything other than repainting
+ // not being as tight as it could be though.
if (style()->direction() == LTR) {
int leftLineOffset = leftRelOffset(yOffset, leftOffset(yOffset, false), false);
markerXPos = leftLineOffset - xOffset - paddingLeft() - borderLeft() + m_marker->marginLeft();
m_marker->inlineBoxWrapper()->adjustPosition(markerXPos - markerOldX, 0);
- if (markerXPos < root->leftOverflow()) {
- root->setHorizontalOverflowPositions(markerXPos, root->rightOverflow());
- adjustOverflow = true;
+ for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) {
+ if (markerXPos < box->leftLayoutOverflow()) {
+ box->setHorizontalOverflowPositions(markerXPos, box->rightLayoutOverflow(), box->leftVisualOverflow(), box->rightVisualOverflow());
+ if (box == root)
+ adjustOverflow = true;
+ }
}
} else {
int rightLineOffset = rightRelOffset(yOffset, rightOffset(yOffset, false), false);
markerXPos = rightLineOffset - xOffset + paddingRight() + borderRight() + m_marker->marginLeft();
m_marker->inlineBoxWrapper()->adjustPosition(markerXPos - markerOldX, 0);
- if (markerXPos + m_marker->width() > root->rightOverflow()) {
- root->setHorizontalOverflowPositions(root->leftOverflow(), markerXPos + m_marker->width());
- adjustOverflow = true;
+ for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) {
+ if (markerXPos + m_marker->width() > box->rightLayoutOverflow()) {
+ box->setHorizontalOverflowPositions(box->leftLayoutOverflow(), markerXPos + m_marker->width(), box->leftVisualOverflow(), box->rightVisualOverflow());
+ if (box == root)
+ adjustOverflow = true;
+ }
}
}
@@ -271,9 +299,9 @@ void RenderListItem::positionListMarker()
do {
o = o->parentBox();
if (o->isRenderBlock())
- toRenderBlock(o)->addVisualOverflow(markerRect);
+ toRenderBlock(o)->addLayoutOverflow(markerRect);
markerRect.move(-o->x(), -o->y());
- } while (o != this);
+ } while (o != this && !o->hasSelfPaintingLayer());
}
}
}
@@ -315,6 +343,8 @@ void RenderListItem::explicitValueChanged()
void RenderListItem::setExplicitValue(int value)
{
+ ASSERT(node());
+
if (m_hasExplicitValue && m_explicitValue == value)
return;
m_explicitValue = value;
@@ -325,6 +355,8 @@ void RenderListItem::setExplicitValue(int value)
void RenderListItem::clearExplicitValue()
{
+ ASSERT(node());
+
if (!m_hasExplicitValue)
return;
m_hasExplicitValue = false;
diff --git a/WebCore/rendering/RenderListItem.h b/WebCore/rendering/RenderListItem.h
index 21544f9..c4c41dc 100644
--- a/WebCore/rendering/RenderListItem.h
+++ b/WebCore/rendering/RenderListItem.h
@@ -44,6 +44,8 @@ public:
void setNotInList(bool notInList) { m_notInList = notInList; }
bool notInList() const { return m_notInList; }
+ const String& markerText() const;
+
private:
virtual const char* renderName() const { return "RenderListItem"; }
@@ -59,8 +61,6 @@ private:
virtual void positionListMarker();
- const String& markerText() const;
-
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
void updateMarkerLocation();
diff --git a/WebCore/rendering/RenderListMarker.cpp b/WebCore/rendering/RenderListMarker.cpp
index 9627711..d0353ee 100644
--- a/WebCore/rendering/RenderListMarker.cpp
+++ b/WebCore/rendering/RenderListMarker.cpp
@@ -3,6 +3,7 @@
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
+ * Copyright (C) 2010 Daniel Bates (dbates@intudata.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -40,6 +41,8 @@ namespace WebCore {
const int cMarkerPadding = 7;
+enum SequenceType { NumericSequence, AlphabeticSequence };
+
static String toRoman(int number, bool upper)
{
// FIXME: CSS3 describes how to make this work for much larger numbers,
@@ -48,7 +51,9 @@ static String toRoman(int number, bool upper)
if (number < 1 || number > 3999)
return String::number(number);
- const int lettersSize = 12; // big enough for three each of I, X, C, and M
+ // Big enough to store largest roman number less than 3999 which
+ // is 3888 (MMMDCCCLXXXVIII)
+ const int lettersSize = 15;
UChar letters[lettersSize];
int length = 0;
@@ -75,26 +80,63 @@ static String toRoman(int number, bool upper)
return String(&letters[lettersSize - length], length);
}
-static String toAlphabetic(int number, const UChar* alphabet, int alphabetSize)
+static inline String toAlphabeticOrNumeric(int number, const UChar* sequence, int sequenceSize, SequenceType type)
{
- ASSERT(alphabetSize >= 10);
+ ASSERT(sequenceSize >= 2);
- if (number < 1)
- return String::number(number);
+ const int lettersSize = sizeof(number) * 8 + 1; // Binary is the worst case; requires one character per bit plus a minus sign.
- const int lettersSize = 10; // big enough for a 32-bit int, with a 10-letter alphabet
UChar letters[lettersSize];
- --number;
- letters[lettersSize - 1] = alphabet[number % alphabetSize];
+ bool isNegativeNumber = false;
+ unsigned numberShadow = number;
+ if (type == AlphabeticSequence) {
+ ASSERT(number > 0);
+ --numberShadow;
+ } else if (number < 0) {
+ numberShadow = -number;
+ isNegativeNumber = true;
+ }
+ letters[lettersSize - 1] = sequence[numberShadow % sequenceSize];
int length = 1;
- while ((number /= alphabetSize) > 0)
- letters[lettersSize - ++length] = alphabet[number % alphabetSize - 1];
+
+ if (type == AlphabeticSequence) {
+ while ((numberShadow /= sequenceSize) > 0)
+ letters[lettersSize - ++length] = sequence[numberShadow % sequenceSize - 1];
+ } else {
+ while ((numberShadow /= sequenceSize) > 0)
+ letters[lettersSize - ++length] = sequence[numberShadow % sequenceSize];
+ }
+ if (isNegativeNumber)
+ letters[lettersSize - ++length] = hyphenMinus;
ASSERT(length <= lettersSize);
return String(&letters[lettersSize - length], length);
}
+static String toAlphabetic(int number, const UChar* alphabet, int alphabetSize)
+{
+ if (number < 1)
+ return String::number(number);
+
+ return toAlphabeticOrNumeric(number, alphabet, alphabetSize, AlphabeticSequence);
+}
+
+static String toNumeric(int number, const UChar* numerals, int numeralsSize)
+{
+ return toAlphabeticOrNumeric(number, numerals, numeralsSize, NumericSequence);
+}
+
+template <size_t size> static inline String toAlphabetic(int number, const UChar(&alphabet)[size])
+{
+ return toAlphabetic(number, alphabet, size);
+}
+
+template <size_t size> static inline String toNumeric(int number, const UChar(&alphabet)[size])
+{
+ return toNumeric(number, alphabet, size);
+}
+
static int toHebrewUnder1000(int number, UChar letters[5])
{
// FIXME: CSS3 mentions various refinements not implemented here.
@@ -335,58 +377,273 @@ static String toCJKIdeographic(int number, const UChar table[16])
return String(characters, length);
}
+static UChar listMarkerSuffix(EListStyleType type)
+{
+ // Note, the following switch statement has been explicitly
+ // grouped by list-style-type suffix.
+ switch (type) {
+ case NoneListStyle:
+ case Disc:
+ case Circle:
+ case Square:
+ ASSERT_NOT_REACHED();
+ return ' ';
+ case Afar:
+ case Amharic:
+ case AmharicAbegede:
+ case Ethiopic:
+ case EthiopicAbegede:
+ case EthiopicAbegedeAmEt:
+ case EthiopicAbegedeGez:
+ case EthiopicAbegedeTiEr:
+ case EthiopicAbegedeTiEt:
+ case EthiopicHalehameAaEr:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAmEt:
+ case EthiopicHalehameGez:
+ case EthiopicHalehameOmEt:
+ case EthiopicHalehameSidEt:
+ case EthiopicHalehameSoEt:
+ case EthiopicHalehameTiEr:
+ case EthiopicHalehameTiEt:
+ case EthiopicHalehameTig:
+ case Oromo:
+ case Sidama:
+ case Somali:
+ case Tigre:
+ case TigrinyaEr:
+ case TigrinyaErAbegede:
+ case TigrinyaEt:
+ case TigrinyaEtAbegede:
+ return ethiopicPrefaceColon;
+ case Armenian:
+ case ArabicIndic:
+ case Bengali:
+ case BinaryListStyle:
+ case Cambodian:
+ case CJKIdeographic:
+ case CjkEarthlyBranch:
+ case CjkHeavenlyStem:
+ case DecimalLeadingZero:
+ case DecimalListStyle:
+ case Devanagari:
+ case Georgian:
+ case Gujarati:
+ case Gurmukhi:
+ case Hangul:
+ case HangulConsonant:
+ case Hebrew:
+ case Hiragana:
+ case HiraganaIroha:
+ case Kannada:
+ case Katakana:
+ case KatakanaIroha:
+ case Khmer:
+ case Lao:
+ case LowerAlpha:
+ case LowerGreek:
+ case LowerHexadecimal:
+ case LowerLatin:
+ case LowerNorwegian:
+ case LowerRoman:
+ case Malayalam:
+ case Mongolian:
+ case Myanmar:
+ case Octal:
+ case Oriya:
+ case Persian:
+ case Telugu:
+ case Thai:
+ case Tibetan:
+ case UpperAlpha:
+ case UpperGreek:
+ case UpperHexadecimal:
+ case UpperLatin:
+ case UpperNorwegian:
+ case UpperRoman:
+ case Urdu:
+ return '.';
+ }
+
+ ASSERT_NOT_REACHED();
+ return '.';
+}
+
String listMarkerText(EListStyleType type, int value)
{
switch (type) {
- case LNONE:
+ case NoneListStyle:
return "";
// We use the same characters for text security.
// See RenderText::setInternalString.
- case CIRCLE:
+ case Circle:
return String(&whiteBullet, 1);
- case DISC:
+ case Disc:
return String(&bullet, 1);
- case SQUARE:
+ case Square:
// The CSS 2.1 test suite uses U+25EE BLACK MEDIUM SMALL SQUARE
// instead, but I think this looks better.
return String(&blackSquare, 1);
- case LDECIMAL:
+ case DecimalListStyle:
return String::number(value);
- case DECIMAL_LEADING_ZERO:
+ case DecimalLeadingZero:
if (value < -9 || value > 9)
return String::number(value);
if (value < 0)
return "-0" + String::number(-value); // -01 to -09
return "0" + String::number(value); // 00 to 09
- case LOWER_ALPHA:
- case LOWER_LATIN: {
+ case ArabicIndic: {
+ static const UChar arabicIndicNumerals[10] = {
+ 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669
+ };
+ return toNumeric(value, arabicIndicNumerals);
+ }
+ case BinaryListStyle: {
+ static const UChar binaryNumerals[2] = {
+ '0', '1'
+ };
+ return toNumeric(value, binaryNumerals);
+ }
+ case Bengali: {
+ static const UChar bengaliNumerals[10] = {
+ 0x09E6, 0x09E7, 0x09E8, 0x09E9, 0x09EA, 0x09EB, 0x09EC, 0x09ED, 0x09EE, 0x09EF
+ };
+ return toNumeric(value, bengaliNumerals);
+ }
+ case Cambodian:
+ case Khmer: {
+ static const UChar khmerNumerals[10] = {
+ 0x17E0, 0x17E1, 0x17E2, 0x17E3, 0x17E4, 0x17E5, 0x17E6, 0x17E7, 0x17E8, 0x17E9
+ };
+ return toNumeric(value, khmerNumerals);
+ }
+ case Devanagari: {
+ static const UChar devanagariNumerals[10] = {
+ 0x0966, 0x0967, 0x0968, 0x0969, 0x096A, 0x096B, 0x096C, 0x096D, 0x096E, 0x096F
+ };
+ return toNumeric(value, devanagariNumerals);
+ }
+ case Gujarati: {
+ static const UChar gujaratiNumerals[10] = {
+ 0x0AE6, 0x0AE7, 0x0AE8, 0x0AE9, 0x0AEA, 0x0AEB, 0x0AEC, 0x0AED, 0x0AEE, 0x0AEF
+ };
+ return toNumeric(value, gujaratiNumerals);
+ }
+ case Gurmukhi: {
+ static const UChar gurmukhiNumerals[10] = {
+ 0x0A66, 0x0A67, 0x0A68, 0x0A69, 0x0A6A, 0x0A6B, 0x0A6C, 0x0A6D, 0x0A6E, 0x0A6F
+ };
+ return toNumeric(value, gurmukhiNumerals);
+ }
+ case Kannada: {
+ static const UChar kannadaNumerals[10] = {
+ 0x0CE6, 0x0CE7, 0x0CE8, 0x0CE9, 0x0CEA, 0x0CEB, 0x0CEC, 0x0CED, 0x0CEE, 0x0CEF
+ };
+ return toNumeric(value, kannadaNumerals);
+ }
+ case LowerHexadecimal: {
+ static const UChar lowerHexadecimalNumerals[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+ return toNumeric(value, lowerHexadecimalNumerals);
+ }
+ case Lao: {
+ static const UChar laoNumerals[10] = {
+ 0x0ED0, 0x0ED1, 0x0ED2, 0x0ED3, 0x0ED4, 0x0ED5, 0x0ED6, 0x0ED7, 0x0ED8, 0x0ED9
+ };
+ return toNumeric(value, laoNumerals);
+ }
+ case Malayalam: {
+ static const UChar malayalamNumerals[10] = {
+ 0x0D66, 0x0D67, 0x0D68, 0x0D69, 0x0D6A, 0x0D6B, 0x0D6C, 0x0D6D, 0x0D6E, 0x0D6F
+ };
+ return toNumeric(value, malayalamNumerals);
+ }
+ case Mongolian: {
+ static const UChar mongolianNumerals[10] = {
+ 0x1810, 0x1811, 0x1812, 0x1813, 0x1814, 0x1815, 0x1816, 0x1817, 0x1818, 0x1819
+ };
+ return toNumeric(value, mongolianNumerals);
+ }
+ case Myanmar: {
+ static const UChar myanmarNumerals[10] = {
+ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, 0x1048, 0x1049
+ };
+ return toNumeric(value, myanmarNumerals);
+ }
+ case Octal: {
+ static const UChar octalNumerals[8] = {
+ '0', '1', '2', '3', '4', '5', '6', '7'
+ };
+ return toNumeric(value, octalNumerals);
+ }
+ case Oriya: {
+ static const UChar oriyaNumerals[10] = {
+ 0x0B66, 0x0B67, 0x0B68, 0x0B69, 0x0B6A, 0x0B6B, 0x0B6C, 0x0B6D, 0x0B6E, 0x0B6F
+ };
+ return toNumeric(value, oriyaNumerals);
+ }
+ case Persian:
+ case Urdu: {
+ static const UChar urduNumerals[10] = {
+ 0x06F0, 0x06F1, 0x06F2, 0x06F3, 0x06F4, 0x06F5, 0x06F6, 0x06F7, 0x06F8, 0x06F9
+ };
+ return toNumeric(value, urduNumerals);
+ }
+ case Telugu: {
+ static const UChar teluguNumerals[10] = {
+ 0x0C66, 0x0C67, 0x0C68, 0x0C69, 0x0C6A, 0x0C6B, 0x0C6C, 0x0C6D, 0x0C6E, 0x0C6F
+ };
+ return toNumeric(value, teluguNumerals);
+ }
+ case Tibetan: {
+ static const UChar tibetanNumerals[10] = {
+ 0x0F20, 0x0F21, 0x0F22, 0x0F23, 0x0F24, 0x0F25, 0x0F26, 0x0F27, 0x0F28, 0x0F29
+ };
+ return toNumeric(value, tibetanNumerals);
+ }
+ case Thai: {
+ static const UChar thaiNumerals[10] = {
+ 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, 0x0E58, 0x0E59
+ };
+ return toNumeric(value, thaiNumerals);
+ }
+ case UpperHexadecimal: {
+ static const UChar upperHexadecimalNumerals[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+ return toNumeric(value, upperHexadecimalNumerals);
+ }
+
+ case LowerAlpha:
+ case LowerLatin: {
static const UChar lowerLatinAlphabet[26] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
- return toAlphabetic(value, lowerLatinAlphabet, 26);
+ return toAlphabetic(value, lowerLatinAlphabet);
}
- case UPPER_ALPHA:
- case UPPER_LATIN: {
+ case UpperAlpha:
+ case UpperLatin: {
static const UChar upperLatinAlphabet[26] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
- return toAlphabetic(value, upperLatinAlphabet, 26);
+ return toAlphabetic(value, upperLatinAlphabet);
}
- case LOWER_GREEK: {
+ case LowerGreek: {
static const UChar lowerGreekAlphabet[24] = {
0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9
};
- return toAlphabetic(value, lowerGreekAlphabet, 24);
+ return toAlphabetic(value, lowerGreekAlphabet);
}
- case HIRAGANA: {
+ case Hiragana: {
// FIXME: This table comes from the CSS3 draft, and is probably
// incorrect, given the comments in that draft.
static const UChar hiraganaAlphabet[48] = {
@@ -397,9 +654,9 @@ String listMarkerText(EListStyleType type, int value)
0x3080, 0x3081, 0x3082, 0x3084, 0x3086, 0x3088, 0x3089, 0x308A,
0x308B, 0x308C, 0x308D, 0x308F, 0x3090, 0x3091, 0x3092, 0x3093
};
- return toAlphabetic(value, hiraganaAlphabet, 48);
+ return toAlphabetic(value, hiraganaAlphabet);
}
- case HIRAGANA_IROHA: {
+ case HiraganaIroha: {
// FIXME: This table comes from the CSS3 draft, and is probably
// incorrect, given the comments in that draft.
static const UChar hiraganaIrohaAlphabet[47] = {
@@ -410,9 +667,9 @@ String listMarkerText(EListStyleType type, int value)
0x3053, 0x3048, 0x3066, 0x3042, 0x3055, 0x304D, 0x3086, 0x3081,
0x307F, 0x3057, 0x3091, 0x3072, 0x3082, 0x305B, 0x3059
};
- return toAlphabetic(value, hiraganaIrohaAlphabet, 47);
+ return toAlphabetic(value, hiraganaIrohaAlphabet);
}
- case KATAKANA: {
+ case Katakana: {
// FIXME: This table comes from the CSS3 draft, and is probably
// incorrect, given the comments in that draft.
static const UChar katakanaAlphabet[48] = {
@@ -423,9 +680,9 @@ String listMarkerText(EListStyleType type, int value)
0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9, 0x30EA,
0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F0, 0x30F1, 0x30F2, 0x30F3
};
- return toAlphabetic(value, katakanaAlphabet, 48);
+ return toAlphabetic(value, katakanaAlphabet);
}
- case KATAKANA_IROHA: {
+ case KatakanaIroha: {
// FIXME: This table comes from the CSS3 draft, and is probably
// incorrect, given the comments in that draft.
static const UChar katakanaIrohaAlphabet[47] = {
@@ -436,10 +693,187 @@ String listMarkerText(EListStyleType type, int value)
0x30B3, 0x30A8, 0x30C6, 0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1,
0x30DF, 0x30B7, 0x30F1, 0x30D2, 0x30E2, 0x30BB, 0x30B9
};
- return toAlphabetic(value, katakanaIrohaAlphabet, 47);
+ return toAlphabetic(value, katakanaIrohaAlphabet);
}
- case CJK_IDEOGRAPHIC: {
+ case Afar:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAaEr: {
+ static const UChar ethiopicHalehameAaErAlphabet[18] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1260, 0x1270, 0x1290,
+ 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12E8, 0x12F0, 0x1308, 0x1338, 0x1348
+ };
+ return toAlphabetic(value, ethiopicHalehameAaErAlphabet);
+ }
+ case Amharic:
+ case EthiopicHalehameAmEt: {
+ static const UChar ethiopicHalehameAmEtAlphabet[33] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1238, 0x1240,
+ 0x1260, 0x1270, 0x1278, 0x1280, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12B8,
+ 0x12C8, 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308, 0x1320,
+ 0x1328, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350
+ };
+ return toAlphabetic(value, ethiopicHalehameAmEtAlphabet);
+ }
+ case AmharicAbegede:
+ case EthiopicAbegedeAmEt: {
+ static const UChar ethiopicAbegedeAmEtAlphabet[33] = {
+ 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0,
+ 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290,
+ 0x1298, 0x1220, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1228, 0x1230, 0x1238,
+ 0x1270, 0x1278, 0x1280, 0x1340, 0x1330, 0x1350
+ };
+ return toAlphabetic(value, ethiopicAbegedeAmEtAlphabet);
+ }
+ case CjkEarthlyBranch: {
+ static const UChar cjkEarthlyBranchAlphabet[12] = {
+ 0x5B50, 0x4E11, 0x5BC5, 0x536F, 0x8FB0, 0x5DF3, 0x5348, 0x672A, 0x7533,
+ 0x9149, 0x620C, 0x4EA5
+ };
+ return toAlphabetic(value, cjkEarthlyBranchAlphabet);
+ }
+ case CjkHeavenlyStem: {
+ static const UChar cjkHeavenlyStemAlphabet[10] = {
+ 0x7532, 0x4E59, 0x4E19, 0x4E01, 0x620A, 0x5DF1, 0x5E9A, 0x8F9B, 0x58EC,
+ 0x7678
+ };
+ return toAlphabetic(value, cjkHeavenlyStemAlphabet);
+ }
+ case Ethiopic:
+ case EthiopicHalehameGez: {
+ static const UChar ethiopicHalehameGezAlphabet[26] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1240, 0x1260,
+ 0x1270, 0x1280, 0x1290, 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12D8, 0x12E8,
+ 0x12F0, 0x1308, 0x1320, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350
+ };
+ return toAlphabetic(value, ethiopicHalehameGezAlphabet);
+ }
+ case EthiopicAbegede:
+ case EthiopicAbegedeGez: {
+ static const UChar ethiopicAbegedeGezAlphabet[26] = {
+ 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1200, 0x12C8, 0x12D8, 0x1210, 0x1320,
+ 0x12E8, 0x12A8, 0x1208, 0x1218, 0x1290, 0x1220, 0x12D0, 0x1348, 0x1338,
+ 0x1240, 0x1228, 0x1230, 0x1270, 0x1280, 0x1340, 0x1330, 0x1350
+ };
+ return toAlphabetic(value, ethiopicAbegedeGezAlphabet);
+ }
+ case HangulConsonant: {
+ static const UChar hangulConsonantAlphabet[14] = {
+ 0x3131, 0x3134, 0x3137, 0x3139, 0x3141, 0x3142, 0x3145, 0x3147, 0x3148,
+ 0x314A, 0x314B, 0x314C, 0x314D, 0x314E
+ };
+ return toAlphabetic(value, hangulConsonantAlphabet);
+ }
+ case Hangul: {
+ static const UChar hangulAlphabet[14] = {
+ 0xAC00, 0xB098, 0xB2E4, 0xB77C, 0xB9C8, 0xBC14, 0xC0AC, 0xC544, 0xC790,
+ 0xCC28, 0xCE74, 0xD0C0, 0xD30C, 0xD558
+ };
+ return toAlphabetic(value, hangulAlphabet);
+ }
+ case Oromo:
+ case EthiopicHalehameOmEt: {
+ static const UChar ethiopicHalehameOmEtAlphabet[25] = {
+ 0x1200, 0x1208, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260, 0x1270,
+ 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12C8, 0x12E8, 0x12F0, 0x12F8,
+ 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348
+ };
+ return toAlphabetic(value, ethiopicHalehameOmEtAlphabet);
+ }
+ case Sidama:
+ case EthiopicHalehameSidEt: {
+ static const UChar ethiopicHalehameSidEtAlphabet[26] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260,
+ 0x1270, 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12C8, 0x12E8, 0x12F0,
+ 0x12F8, 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348
+ };
+ return toAlphabetic(value, ethiopicHalehameSidEtAlphabet);
+ }
+ case Somali:
+ case EthiopicHalehameSoEt: {
+ static const UChar ethiopicHalehameSoEtAlphabet[22] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260,
+ 0x1270, 0x1290, 0x12A0, 0x12A8, 0x12B8, 0x12C8, 0x12D0, 0x12E8, 0x12F0,
+ 0x1300, 0x1308, 0x1338, 0x1348
+ };
+ return toAlphabetic(value, ethiopicHalehameSoEtAlphabet);
+ }
+ case Tigre:
+ case EthiopicHalehameTig: {
+ static const UChar ethiopicHalehameTigAlphabet[27] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260,
+ 0x1270, 0x1278, 0x1290, 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12D8, 0x12E8,
+ 0x12F0, 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348, 0x1350
+ };
+ return toAlphabetic(value, ethiopicHalehameTigAlphabet);
+ }
+ case TigrinyaEr:
+ case EthiopicHalehameTiEr: {
+ static const UChar ethiopicHalehameTiErAlphabet[31] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1250,
+ 0x1260, 0x1270, 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12B8, 0x12C8,
+ 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308, 0x1320, 0x1328,
+ 0x1330, 0x1338, 0x1348, 0x1350
+ };
+ return toAlphabetic(value, ethiopicHalehameTiErAlphabet);
+ }
+ case TigrinyaErAbegede:
+ case EthiopicAbegedeTiEr: {
+ static const UChar ethiopicAbegedeTiErAlphabet[31] = {
+ 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0,
+ 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290,
+ 0x1298, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1250, 0x1228, 0x1230, 0x1238,
+ 0x1270, 0x1278, 0x1330, 0x1350
+ };
+ return toAlphabetic(value, ethiopicAbegedeTiErAlphabet);
+ }
+ case TigrinyaEt:
+ case EthiopicHalehameTiEt: {
+ static const UChar ethiopicHalehameTiEtAlphabet[34] = {
+ 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1238, 0x1240,
+ 0x1250, 0x1260, 0x1270, 0x1278, 0x1280, 0x1290, 0x1298, 0x12A0, 0x12A8,
+ 0x12B8, 0x12C8, 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308,
+ 0x1320, 0x1328, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350
+ };
+ return toAlphabetic(value, ethiopicHalehameTiEtAlphabet);
+ }
+ case TigrinyaEtAbegede:
+ case EthiopicAbegedeTiEt: {
+ static const UChar ethiopicAbegedeTiEtAlphabet[34] = {
+ 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0,
+ 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290,
+ 0x1298, 0x1220, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1250, 0x1228, 0x1230,
+ 0x1238, 0x1270, 0x1278, 0x1280, 0x1340, 0x1330, 0x1350
+ };
+ return toAlphabetic(value, ethiopicAbegedeTiEtAlphabet);
+ }
+ case UpperGreek: {
+ static const UChar upperGreekAlphabet[24] = {
+ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399,
+ 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3,
+ 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9
+ };
+ return toAlphabetic(value, upperGreekAlphabet);
+ }
+ case LowerNorwegian: {
+ static const UChar lowerNorwegianAlphabet[29] = {
+ 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069,
+ 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072,
+ 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00E6,
+ 0x00F8, 0x00E5
+ };
+ return toAlphabetic(value, lowerNorwegianAlphabet);
+ }
+ case UpperNorwegian: {
+ static const UChar upperNorwegianAlphabet[29] = {
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049,
+ 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052,
+ 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00C6,
+ 0x00D8, 0x00C5
+ };
+ return toAlphabetic(value, upperNorwegianAlphabet);
+ }
+ case CJKIdeographic: {
static const UChar traditionalChineseInformalTable[16] = {
0x842C, 0x5104, 0x5146,
0x5341, 0x767E, 0x5343,
@@ -449,19 +883,19 @@ String listMarkerText(EListStyleType type, int value)
return toCJKIdeographic(value, traditionalChineseInformalTable);
}
- case LOWER_ROMAN:
+ case LowerRoman:
return toRoman(value, false);
- case UPPER_ROMAN:
+ case UpperRoman:
return toRoman(value, true);
- case ARMENIAN:
+ case Armenian:
// CSS3 says "armenian" means "lower-armenian".
// But the CSS2.1 test suite contains uppercase test results for "armenian",
// so we'll match the test suite.
return toArmenian(value, true);
- case GEORGIAN:
+ case Georgian:
return toGeorgian(value);
- case HEBREW:
+ case Hebrew:
return toHebrew(value);
}
@@ -517,6 +951,15 @@ bool RenderListMarker::isImage() const
return m_image && !m_image->errorOccurred();
}
+IntRect RenderListMarker::localSelectionRect()
+{
+ InlineBox* box = inlineBoxWrapper();
+ if (!box)
+ return IntRect();
+ RootInlineBox* root = box->root();
+ return IntRect(x(), root->selectionTop() - y(), width(), root->selectionHeight());
+}
+
void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
{
if (paintInfo.phase != PaintPhaseForeground)
@@ -543,10 +986,11 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
paintCustomHighlight(tx, ty, style()->highlight(), true);
#endif
- context->drawImage(m_image->image(this, marker.size()), marker.location());
+ context->drawImage(m_image->image(this, marker.size()), style()->colorSpace(), marker.location());
if (selectionState() != SelectionNone) {
- // FIXME: selectionRect() is in absolute, not painting coordinates.
- context->fillRect(selectionRect(), selectionBackgroundColor());
+ IntRect selRect = localSelectionRect();
+ selRect.move(tx, ty);
+ context->fillRect(selRect, selectionBackgroundColor(), style()->colorSpace());
}
return;
}
@@ -558,46 +1002,104 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
#endif
if (selectionState() != SelectionNone) {
- // FIXME: selectionRect() is in absolute, not painting coordinates.
- context->fillRect(selectionRect(), selectionBackgroundColor());
+ IntRect selRect = localSelectionRect();
+ selRect.move(tx, ty);
+ context->fillRect(selRect, selectionBackgroundColor(), style()->colorSpace());
}
const Color color(style()->color());
- context->setStrokeColor(color);
+ context->setStrokeColor(color, style()->colorSpace());
context->setStrokeStyle(SolidStroke);
context->setStrokeThickness(1.0f);
- context->setFillColor(color);
+ context->setFillColor(color, style()->colorSpace());
- switch (style()->listStyleType()) {
- case DISC:
+ EListStyleType type = style()->listStyleType();
+ switch (type) {
+ case Disc:
context->drawEllipse(marker);
return;
- case CIRCLE:
- context->setFillColor(Color::transparent);
+ case Circle:
+ context->setFillColor(Color::transparent, DeviceColorSpace);
context->drawEllipse(marker);
return;
- case SQUARE:
+ case Square:
context->drawRect(marker);
return;
- case LNONE:
+ case NoneListStyle:
return;
- case ARMENIAN:
- case CJK_IDEOGRAPHIC:
- case DECIMAL_LEADING_ZERO:
- case GEORGIAN:
- case HEBREW:
- case HIRAGANA:
- case HIRAGANA_IROHA:
- case KATAKANA:
- case KATAKANA_IROHA:
- case LDECIMAL:
- case LOWER_ALPHA:
- case LOWER_GREEK:
- case LOWER_LATIN:
- case LOWER_ROMAN:
- case UPPER_ALPHA:
- case UPPER_LATIN:
- case UPPER_ROMAN:
+ case Afar:
+ case Amharic:
+ case AmharicAbegede:
+ case ArabicIndic:
+ case Armenian:
+ case BinaryListStyle:
+ case Bengali:
+ case Cambodian:
+ case CJKIdeographic:
+ case CjkEarthlyBranch:
+ case CjkHeavenlyStem:
+ case DecimalLeadingZero:
+ case DecimalListStyle:
+ case Devanagari:
+ case Ethiopic:
+ case EthiopicAbegede:
+ case EthiopicAbegedeAmEt:
+ case EthiopicAbegedeGez:
+ case EthiopicAbegedeTiEr:
+ case EthiopicAbegedeTiEt:
+ case EthiopicHalehameAaEr:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAmEt:
+ case EthiopicHalehameGez:
+ case EthiopicHalehameOmEt:
+ case EthiopicHalehameSidEt:
+ case EthiopicHalehameSoEt:
+ case EthiopicHalehameTiEr:
+ case EthiopicHalehameTiEt:
+ case EthiopicHalehameTig:
+ case Georgian:
+ case Gujarati:
+ case Gurmukhi:
+ case Hangul:
+ case HangulConsonant:
+ case Hebrew:
+ case Hiragana:
+ case HiraganaIroha:
+ case Kannada:
+ case Katakana:
+ case KatakanaIroha:
+ case Khmer:
+ case Lao:
+ case LowerAlpha:
+ case LowerGreek:
+ case LowerHexadecimal:
+ case LowerLatin:
+ case LowerNorwegian:
+ case LowerRoman:
+ case Malayalam:
+ case Mongolian:
+ case Myanmar:
+ case Octal:
+ case Oriya:
+ case Oromo:
+ case Persian:
+ case Sidama:
+ case Somali:
+ case Telugu:
+ case Thai:
+ case Tibetan:
+ case Tigre:
+ case TigrinyaEr:
+ case TigrinyaErAbegede:
+ case TigrinyaEt:
+ case TigrinyaEtAbegede:
+ case UpperAlpha:
+ case UpperGreek:
+ case UpperHexadecimal:
+ case UpperLatin:
+ case UpperNorwegian:
+ case UpperRoman:
+ case Urdu:
break;
}
if (m_text.isEmpty())
@@ -618,16 +1120,17 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
}
const Font& font = style()->font();
+ const UChar suffix = listMarkerSuffix(type);
if (style()->direction() == LTR) {
int width = font.width(textRun);
context->drawText(style()->font(), textRun, marker.location());
- const UChar periodSpace[2] = { '.', ' ' };
- context->drawText(style()->font(), TextRun(periodSpace, 2), marker.location() + IntSize(width, 0));
+ UChar suffixSpace[2] = { suffix, ' ' };
+ context->drawText(style()->font(), TextRun(suffixSpace, 2), marker.location() + IntSize(width, 0));
} else {
- const UChar spacePeriod[2] = { ' ', '.' };
- TextRun spacePeriodRun(spacePeriod, 2);
- int width = font.width(spacePeriodRun);
- context->drawText(style()->font(), spacePeriodRun, marker.location());
+ UChar spaceSuffix[2] = { ' ', suffix };
+ TextRun spaceSuffixRun(spaceSuffix, 2);
+ int width = font.width(spaceSuffixRun);
+ context->drawText(style()->font(), spaceSuffixRun, marker.location());
context->drawText(style()->font(), textRun, marker.location() + IntSize(width, 0));
}
}
@@ -691,39 +1194,95 @@ void RenderListMarker::calcPrefWidths()
int width = 0;
EListStyleType type = style()->listStyleType();
switch (type) {
- case LNONE:
+ case NoneListStyle:
break;
- case CIRCLE:
- case DISC:
- case SQUARE:
+ case Circle:
+ case Disc:
+ case Square:
m_text = listMarkerText(type, 0); // value is ignored for these types
width = (font.ascent() * 2 / 3 + 1) / 2 + 2;
break;
- case ARMENIAN:
- case CJK_IDEOGRAPHIC:
- case DECIMAL_LEADING_ZERO:
- case GEORGIAN:
- case HEBREW:
- case HIRAGANA:
- case HIRAGANA_IROHA:
- case KATAKANA:
- case KATAKANA_IROHA:
- case LDECIMAL:
- case LOWER_ALPHA:
- case LOWER_GREEK:
- case LOWER_LATIN:
- case LOWER_ROMAN:
- case UPPER_ALPHA:
- case UPPER_LATIN:
- case UPPER_ROMAN:
+ case Afar:
+ case Amharic:
+ case AmharicAbegede:
+ case ArabicIndic:
+ case Armenian:
+ case BinaryListStyle:
+ case Bengali:
+ case Cambodian:
+ case CJKIdeographic:
+ case CjkEarthlyBranch:
+ case CjkHeavenlyStem:
+ case DecimalLeadingZero:
+ case DecimalListStyle:
+ case Devanagari:
+ case Ethiopic:
+ case EthiopicAbegede:
+ case EthiopicAbegedeAmEt:
+ case EthiopicAbegedeGez:
+ case EthiopicAbegedeTiEr:
+ case EthiopicAbegedeTiEt:
+ case EthiopicHalehameAaEr:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAmEt:
+ case EthiopicHalehameGez:
+ case EthiopicHalehameOmEt:
+ case EthiopicHalehameSidEt:
+ case EthiopicHalehameSoEt:
+ case EthiopicHalehameTiEr:
+ case EthiopicHalehameTiEt:
+ case EthiopicHalehameTig:
+ case Georgian:
+ case Gujarati:
+ case Gurmukhi:
+ case Hangul:
+ case HangulConsonant:
+ case Hebrew:
+ case Hiragana:
+ case HiraganaIroha:
+ case Kannada:
+ case Katakana:
+ case KatakanaIroha:
+ case Khmer:
+ case Lao:
+ case LowerAlpha:
+ case LowerGreek:
+ case LowerHexadecimal:
+ case LowerLatin:
+ case LowerNorwegian:
+ case LowerRoman:
+ case Malayalam:
+ case Mongolian:
+ case Myanmar:
+ case Octal:
+ case Oriya:
+ case Oromo:
+ case Persian:
+ case Sidama:
+ case Somali:
+ case Telugu:
+ case Thai:
+ case Tibetan:
+ case Tigre:
+ case TigrinyaEr:
+ case TigrinyaErAbegede:
+ case TigrinyaEt:
+ case TigrinyaEtAbegede:
+ case UpperAlpha:
+ case UpperGreek:
+ case UpperHexadecimal:
+ case UpperLatin:
+ case UpperNorwegian:
+ case UpperRoman:
+ case Urdu:
m_text = listMarkerText(type, m_listItem->value());
if (m_text.isEmpty())
width = 0;
else {
int itemWidth = font.width(m_text);
- const UChar periodSpace[2] = { '.', ' ' };
- int periodSpaceWidth = font.width(TextRun(periodSpace, 2));
- width = itemWidth + periodSpaceWidth;
+ UChar suffixSpace[2] = { listMarkerSuffix(type), ' ' };
+ int suffixSpaceWidth = font.width(TextRun(suffixSpace, 2));
+ width = itemWidth + suffixSpaceWidth;
}
break;
}
@@ -750,9 +1309,9 @@ void RenderListMarker::updateMargins()
else
marginLeft = cMarkerPadding;
} else switch (style()->listStyleType()) {
- case DISC:
- case CIRCLE:
- case SQUARE:
+ case Disc:
+ case Circle:
+ case Square:
if (style()->direction() == LTR) {
marginLeft = -1;
marginRight = font.ascent() - minPrefWidth() + 1;
@@ -771,12 +1330,12 @@ void RenderListMarker::updateMargins()
else {
int offset = font.ascent() * 2 / 3;
switch (style()->listStyleType()) {
- case DISC:
- case CIRCLE:
- case SQUARE:
+ case Disc:
+ case Circle:
+ case Square:
marginLeft = -offset - cMarkerPadding - 1;
break;
- case LNONE:
+ case NoneListStyle:
break;
default:
marginLeft = m_text.isEmpty() ? 0 : -minPrefWidth() - offset / 2;
@@ -788,12 +1347,12 @@ void RenderListMarker::updateMargins()
else {
int offset = font.ascent() * 2 / 3;
switch (style()->listStyleType()) {
- case DISC:
- case CIRCLE:
- case SQUARE:
+ case Disc:
+ case Circle:
+ case Square:
marginLeft = offset + cMarkerPadding + 1 - minPrefWidth();
break;
- case LNONE:
+ case NoneListStyle:
break;
default:
marginLeft = m_text.isEmpty() ? 0 : offset / 2;
@@ -833,42 +1392,99 @@ IntRect RenderListMarker::getRelativeMarkerRect()
if (isImage())
return IntRect(x(), y(), m_image->imageSize(this, style()->effectiveZoom()).width(), m_image->imageSize(this, style()->effectiveZoom()).height());
- switch (style()->listStyleType()) {
- case DISC:
- case CIRCLE:
- case SQUARE: {
+ EListStyleType type = style()->listStyleType();
+ switch (type) {
+ case Disc:
+ case Circle:
+ case Square: {
// FIXME: Are these particular rounding rules necessary?
const Font& font = style()->font();
int ascent = font.ascent();
int bulletWidth = (ascent * 2 / 3 + 1) / 2;
return IntRect(x() + 1, y() + 3 * (ascent - ascent * 2 / 3) / 2, bulletWidth, bulletWidth);
}
- case LNONE:
+ case NoneListStyle:
return IntRect();
- case ARMENIAN:
- case CJK_IDEOGRAPHIC:
- case DECIMAL_LEADING_ZERO:
- case GEORGIAN:
- case HEBREW:
- case HIRAGANA:
- case HIRAGANA_IROHA:
- case KATAKANA:
- case KATAKANA_IROHA:
- case LDECIMAL:
- case LOWER_ALPHA:
- case LOWER_GREEK:
- case LOWER_LATIN:
- case LOWER_ROMAN:
- case UPPER_ALPHA:
- case UPPER_LATIN:
- case UPPER_ROMAN:
+ case Afar:
+ case Amharic:
+ case AmharicAbegede:
+ case ArabicIndic:
+ case Armenian:
+ case BinaryListStyle:
+ case Bengali:
+ case Cambodian:
+ case CJKIdeographic:
+ case CjkEarthlyBranch:
+ case CjkHeavenlyStem:
+ case DecimalLeadingZero:
+ case DecimalListStyle:
+ case Devanagari:
+ case Ethiopic:
+ case EthiopicAbegede:
+ case EthiopicAbegedeAmEt:
+ case EthiopicAbegedeGez:
+ case EthiopicAbegedeTiEr:
+ case EthiopicAbegedeTiEt:
+ case EthiopicHalehameAaEr:
+ case EthiopicHalehameAaEt:
+ case EthiopicHalehameAmEt:
+ case EthiopicHalehameGez:
+ case EthiopicHalehameOmEt:
+ case EthiopicHalehameSidEt:
+ case EthiopicHalehameSoEt:
+ case EthiopicHalehameTiEr:
+ case EthiopicHalehameTiEt:
+ case EthiopicHalehameTig:
+ case Georgian:
+ case Gujarati:
+ case Gurmukhi:
+ case Hangul:
+ case HangulConsonant:
+ case Hebrew:
+ case Hiragana:
+ case HiraganaIroha:
+ case Kannada:
+ case Katakana:
+ case KatakanaIroha:
+ case Khmer:
+ case Lao:
+ case LowerAlpha:
+ case LowerGreek:
+ case LowerHexadecimal:
+ case LowerLatin:
+ case LowerNorwegian:
+ case LowerRoman:
+ case Malayalam:
+ case Mongolian:
+ case Myanmar:
+ case Octal:
+ case Oriya:
+ case Oromo:
+ case Persian:
+ case Sidama:
+ case Somali:
+ case Telugu:
+ case Thai:
+ case Tibetan:
+ case Tigre:
+ case TigrinyaEr:
+ case TigrinyaErAbegede:
+ case TigrinyaEt:
+ case TigrinyaEtAbegede:
+ case UpperAlpha:
+ case UpperGreek:
+ case UpperHexadecimal:
+ case UpperLatin:
+ case UpperNorwegian:
+ case UpperRoman:
+ case Urdu:
if (m_text.isEmpty())
return IntRect();
const Font& font = style()->font();
int itemWidth = font.width(m_text);
- const UChar periodSpace[2] = { '.', ' ' };
- int periodSpaceWidth = font.width(TextRun(periodSpace, 2));
- return IntRect(x(), y() + font.ascent(), itemWidth + periodSpaceWidth, font.height());
+ UChar suffixSpace[2] = { listMarkerSuffix(type), ' ' };
+ int suffixSpaceWidth = font.width(TextRun(suffixSpace, 2));
+ return IntRect(x(), y() + font.ascent(), itemWidth + suffixSpaceWidth, font.height());
}
return IntRect();
diff --git a/WebCore/rendering/RenderListMarker.h b/WebCore/rendering/RenderListMarker.h
index 5b46278..971877b 100644
--- a/WebCore/rendering/RenderListMarker.h
+++ b/WebCore/rendering/RenderListMarker.h
@@ -73,6 +73,7 @@ private:
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
IntRect getRelativeMarkerRect();
+ IntRect localSelectionRect();
String m_text;
RefPtr<StyleImage> m_image;
diff --git a/WebCore/rendering/RenderMarquee.cpp b/WebCore/rendering/RenderMarquee.cpp
index 31a8305..bb917f8 100644
--- a/WebCore/rendering/RenderMarquee.cpp
+++ b/WebCore/rendering/RenderMarquee.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* Portions are Copyright (C) 1998 Netscape Communications Corporation.
*
@@ -152,7 +153,11 @@ int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge
void RenderMarquee::start()
{
- if (m_timer.isActive() || m_layer->renderer()->style()->marqueeIncrement().isZero())
+ if (m_timer.isActive() || m_layer->renderer()->style()->marqueeIncrement().isZero()
+#if ENABLE(WCSS) && ENABLE(XHTMLMP)
+ || (m_layer->renderer()->document()->isXHTMLMPDocument() && !m_layer->renderer()->style()->marqueeLoopCount())
+#endif
+ )
return;
// We may end up propagating a scroll event. It is important that we suspend events until
diff --git a/WebCore/rendering/RenderMarquee.h b/WebCore/rendering/RenderMarquee.h
index 886c343..1651454 100644
--- a/WebCore/rendering/RenderMarquee.h
+++ b/WebCore/rendering/RenderMarquee.h
@@ -53,7 +53,7 @@ namespace WebCore {
class RenderLayer;
// This class handles the auto-scrolling of layers with overflow: marquee.
-class RenderMarquee {
+class RenderMarquee : public Noncopyable {
public:
RenderMarquee(RenderLayer*);
diff --git a/WebCore/rendering/RenderMedia.cpp b/WebCore/rendering/RenderMedia.cpp
index b87e99d..7100435 100644
--- a/WebCore/rendering/RenderMedia.cpp
+++ b/WebCore/rendering/RenderMedia.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,6 +33,7 @@
#include "HTMLNames.h"
#include "MediaControlElements.h"
#include "MouseEvent.h"
+#include "RenderTheme.h"
#include <wtf/CurrentTime.h>
#include <wtf/MathExtras.h>
@@ -44,32 +45,30 @@ using namespace HTMLNames;
static const double cTimeUpdateRepeatDelay = 0.2;
static const double cOpacityAnimationRepeatDelay = 0.05;
-// FIXME get this from style
-static const double cOpacityAnimationDurationFadeIn = 0.1;
-static const double cOpacityAnimationDurationFadeOut = 0.3;
RenderMedia::RenderMedia(HTMLMediaElement* video)
- : RenderReplaced(video)
+ : RenderImage(video)
, m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
, m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
, m_mouseOver(false)
, m_opacityAnimationStartTime(0)
- , m_opacityAnimationDuration(cOpacityAnimationDurationFadeIn)
+ , m_opacityAnimationDuration(0)
, m_opacityAnimationFrom(0)
, m_opacityAnimationTo(1.0f)
{
}
RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize)
- : RenderReplaced(video, intrinsicSize)
+ : RenderImage(video)
, m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
, m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
, m_mouseOver(false)
, m_opacityAnimationStartTime(0)
- , m_opacityAnimationDuration(cOpacityAnimationDurationFadeIn)
+ , m_opacityAnimationDuration(0)
, m_opacityAnimationFrom(0)
, m_opacityAnimationTo(1.0f)
{
+ setIntrinsicSize(intrinsicSize);
}
RenderMedia::~RenderMedia()
@@ -88,7 +87,7 @@ void RenderMedia::destroy()
m_controlsShadowRoot->detach();
m_controlsShadowRoot = 0;
}
- RenderReplaced::destroy();
+ RenderImage::destroy();
}
HTMLMediaElement* RenderMedia::mediaElement() const
@@ -103,7 +102,7 @@ MediaPlayer* RenderMedia::player() const
void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
- RenderReplaced::styleDidChange(diff, oldStyle);
+ RenderImage::styleDidChange(diff, oldStyle);
if (m_controlsShadowRoot) {
if (m_panel)
@@ -120,6 +119,8 @@ void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
m_rewindButton->updateStyle();
if (m_returnToRealtimeButton)
m_returnToRealtimeButton->updateStyle();
+ if (m_toggleClosedCaptionsButton)
+ m_toggleClosedCaptionsButton->updateStyle();
if (m_statusDisplay)
m_statusDisplay->updateStyle();
if (m_timelineContainer)
@@ -132,6 +133,10 @@ void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
m_currentTimeDisplay->updateStyle();
if (m_timeRemainingDisplay)
m_timeRemainingDisplay->updateStyle();
+ if (m_volumeSliderContainer)
+ m_volumeSliderContainer->updateStyle();
+ if (m_volumeSlider)
+ m_volumeSlider->updateStyle();
}
}
@@ -139,7 +144,7 @@ void RenderMedia::layout()
{
IntSize oldSize = contentBoxRect().size();
- RenderReplaced::layout();
+ RenderImage::layout();
RenderBox* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0;
if (!controlsRenderer)
@@ -218,6 +223,13 @@ void RenderMedia::createReturnToRealtimeButton()
m_returnToRealtimeButton->attachToParent(m_panel.get());
}
+void RenderMedia::createToggleClosedCaptionsButton()
+{
+ ASSERT(!m_toggleClosedCaptionsButton);
+ m_toggleClosedCaptionsButton = new MediaControlToggleClosedCaptionsButtonElement(document(), mediaElement());
+ m_toggleClosedCaptionsButton->attachToParent(m_panel.get());
+}
+
void RenderMedia::createStatusDisplay()
{
ASSERT(!m_statusDisplay);
@@ -240,6 +252,23 @@ void RenderMedia::createTimeline()
m_timeline->attachToParent(m_timelineContainer.get());
}
+void RenderMedia::createVolumeSliderContainer()
+{
+ ASSERT(!m_volumeSliderContainer);
+ m_volumeSliderContainer = new MediaControlVolumeSliderContainerElement(document(), mediaElement());
+ m_volumeSliderContainer->attachToParent(m_panel.get());
+}
+
+void RenderMedia::createVolumeSlider()
+{
+ ASSERT(!m_volumeSlider);
+ m_volumeSlider = new MediaControlVolumeSliderElement(document(), mediaElement());
+ m_volumeSlider->setAttribute(precisionAttr, "float");
+ m_volumeSlider->setAttribute(maxAttr, "1");
+ m_volumeSlider->setAttribute(valueAttr, String::number(mediaElement()->volume()));
+ m_volumeSlider->attachToParent(m_volumeSliderContainer.get());
+}
+
void RenderMedia::createCurrentTimeDisplay()
{
ASSERT(!m_currentTimeDisplay);
@@ -285,7 +314,10 @@ void RenderMedia::updateControls()
m_currentTimeDisplay = 0;
m_timeRemainingDisplay = 0;
m_fullscreenButton = 0;
+ m_volumeSliderContainer = 0;
+ m_volumeSlider = 0;
m_controlsShadowRoot = 0;
+ m_toggleClosedCaptionsButton = 0;
}
m_opacityAnimationTo = 1.0f;
m_opacityAnimationTimer.stop();
@@ -298,19 +330,23 @@ void RenderMedia::updateControls()
createPanel();
if (m_panel) {
createRewindButton();
- createMuteButton();
createPlayButton();
createReturnToRealtimeButton();
createStatusDisplay();
createTimelineContainer();
- createSeekBackButton();
- createSeekForwardButton();
- createFullscreenButton();
if (m_timelineContainer) {
createCurrentTimeDisplay();
createTimeline();
createTimeRemainingDisplay();
}
+ createSeekBackButton();
+ createSeekForwardButton();
+ createToggleClosedCaptionsButton();
+ createFullscreenButton();
+ createMuteButton();
+ createVolumeSliderContainer();
+ if (m_volumeSliderContainer)
+ createVolumeSlider();
m_panel->attach();
}
}
@@ -336,6 +372,8 @@ void RenderMedia::updateControls()
m_playButton->update();
if (m_timelineContainer)
m_timelineContainer->update();
+ if (m_volumeSliderContainer)
+ m_volumeSliderContainer->update();
if (m_timeline)
m_timeline->update();
if (m_currentTimeDisplay)
@@ -350,10 +388,14 @@ void RenderMedia::updateControls()
m_rewindButton->update();
if (m_returnToRealtimeButton)
m_returnToRealtimeButton->update();
+ if (m_toggleClosedCaptionsButton)
+ m_toggleClosedCaptionsButton->update();
if (m_statusDisplay)
m_statusDisplay->update();
if (m_fullscreenButton)
m_fullscreenButton->update();
+ if (m_volumeSlider)
+ m_volumeSlider->update();
updateTimeDisplay();
updateControlVisibility();
@@ -366,37 +408,20 @@ void RenderMedia::timeUpdateTimerFired(Timer<RenderMedia>*)
updateTimeDisplay();
}
-String RenderMedia::formatTime(float time)
-{
- if (!isfinite(time))
- time = 0;
- int seconds = (int)fabsf(time);
- int hours = seconds / (60 * 60);
- int minutes = (seconds / 60) % 60;
- seconds %= 60;
- if (hours) {
- if (hours > 9)
- return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
- else
- return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
- }
- else
- return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
-}
-
void RenderMedia::updateTimeDisplay()
{
if (!m_currentTimeDisplay || !m_currentTimeDisplay->renderer() || m_currentTimeDisplay->renderer()->style()->display() == NONE || style()->visibility() != VISIBLE)
return;
+
float now = mediaElement()->currentTime();
float duration = mediaElement()->duration();
- String timeString = formatTime(now);
+ // Allow the theme to format the time
ExceptionCode ec;
- m_currentTimeDisplay->setInnerText(timeString, ec);
-
- timeString = formatTime(now - duration);
- m_timeRemainingDisplay->setInnerText(timeString, ec);
+ m_currentTimeDisplay->setInnerText(theme()->formatMediaControlsCurrentTime(now, duration), ec);
+ m_currentTimeDisplay->setCurrentValue(now);
+ m_timeRemainingDisplay->setInnerText(theme()->formatMediaControlsRemainingTime(now, duration), ec);
+ m_timeRemainingDisplay->setCurrentValue(now - duration);
}
void RenderMedia::updateControlVisibility()
@@ -430,9 +455,9 @@ void RenderMedia::updateControlVisibility()
}
if (animateFrom < animateTo)
- m_opacityAnimationDuration = cOpacityAnimationDurationFadeIn;
+ m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeInDuration();
else
- m_opacityAnimationDuration = cOpacityAnimationDurationFadeOut;
+ m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeOutDuration();
m_opacityAnimationFrom = animateFrom;
m_opacityAnimationTo = animateTo;
@@ -463,13 +488,53 @@ void RenderMedia::opacityAnimationTimerFired(Timer<RenderMedia>*)
changeOpacity(m_panel.get(), opacity);
}
+void RenderMedia::updateVolumeSliderContainer(bool visible)
+{
+ if (!mediaElement()->hasAudio() || !m_volumeSliderContainer || !m_volumeSlider)
+ return;
+
+ if (visible && !m_volumeSliderContainer->isVisible()) {
+ if (!m_muteButton || !m_muteButton->renderer() || !m_muteButton->renderBox())
+ return;
+
+ RefPtr<RenderStyle> s = m_volumeSliderContainer->styleForElement();
+ int height = s->height().isPercent() ? 0 : s->height().value();
+ int x = m_muteButton->renderBox()->offsetLeft();
+ int y = m_muteButton->renderBox()->offsetTop() - height;
+ FloatPoint absPoint = m_muteButton->renderer()->localToAbsolute(FloatPoint(x, y), true, true);
+ if (absPoint.y() < 0)
+ y = m_muteButton->renderBox()->offsetTop() + m_muteButton->renderBox()->height();
+ m_volumeSliderContainer->setVisible(true);
+ m_volumeSliderContainer->setPosition(x, y);
+ m_volumeSliderContainer->update();
+ m_volumeSlider->update();
+ } else if (!visible && m_volumeSliderContainer->isVisible()) {
+ m_volumeSliderContainer->setVisible(false);
+ m_volumeSliderContainer->updateStyle();
+ }
+}
+
void RenderMedia::forwardEvent(Event* event)
{
if (event->isMouseEvent() && m_controlsShadowRoot) {
MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
IntPoint point(mouseEvent->absoluteLocation());
- if (m_muteButton && m_muteButton->hitTest(point))
+ bool showVolumeSlider = false;
+ if (m_muteButton && m_muteButton->hitTest(point)) {
m_muteButton->defaultEventHandler(event);
+ if (event->type() != eventNames().mouseoutEvent)
+ showVolumeSlider = true;
+ }
+
+ if (m_volumeSliderContainer && m_volumeSliderContainer->hitTest(point))
+ showVolumeSlider = true;
+
+ if (m_volumeSlider && m_volumeSlider->hitTest(point)) {
+ m_volumeSlider->defaultEventHandler(event);
+ showVolumeSlider = true;
+ }
+
+ updateVolumeSliderContainer(showVolumeSlider);
if (m_playButton && m_playButton->hitTest(point))
m_playButton->defaultEventHandler(event);
@@ -486,6 +551,9 @@ void RenderMedia::forwardEvent(Event* event)
if (m_returnToRealtimeButton && m_returnToRealtimeButton->hitTest(point))
m_returnToRealtimeButton->defaultEventHandler(event);
+ if (m_toggleClosedCaptionsButton && m_toggleClosedCaptionsButton->hitTest(point))
+ m_toggleClosedCaptionsButton->defaultEventHandler(event);
+
if (m_timeline && m_timeline->hitTest(point))
m_timeline->defaultEventHandler(event);
@@ -508,7 +576,7 @@ void RenderMedia::forwardEvent(Event* event)
int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
{
- int bottom = RenderReplaced::lowestPosition(includeOverflowInterior, includeSelf);
+ int bottom = RenderImage::lowestPosition(includeOverflowInterior, includeSelf);
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return bottom;
@@ -517,7 +585,7 @@ int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf)
int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
- int right = RenderReplaced::rightmostPosition(includeOverflowInterior, includeSelf);
+ int right = RenderImage::rightmostPosition(includeOverflowInterior, includeSelf);
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return right;
@@ -526,7 +594,7 @@ int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSel
int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
- int left = RenderReplaced::leftmostPosition(includeOverflowInterior, includeSelf);
+ int left = RenderImage::leftmostPosition(includeOverflowInterior, includeSelf);
if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
return left;
diff --git a/WebCore/rendering/RenderMedia.h b/WebCore/rendering/RenderMedia.h
index 5697bda..0d24c4c 100644
--- a/WebCore/rendering/RenderMedia.h
+++ b/WebCore/rendering/RenderMedia.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,7 +28,7 @@
#if ENABLE(VIDEO)
-#include "RenderReplaced.h"
+#include "RenderImage.h"
#include "Timer.h"
namespace WebCore {
@@ -40,28 +40,29 @@ class MediaControlPlayButtonElement;
class MediaControlSeekButtonElement;
class MediaControlRewindButtonElement;
class MediaControlReturnToRealtimeButtonElement;
+class MediaControlToggleClosedCaptionsButtonElement;
class MediaControlTimelineElement;
+class MediaControlVolumeSliderElement;
class MediaControlFullscreenButtonElement;
class MediaControlTimeDisplayElement;
class MediaControlStatusDisplayElement;
class MediaControlTimelineContainerElement;
+class MediaControlVolumeSliderContainerElement;
class MediaControlElement;
class MediaPlayer;
-class RenderMedia : public RenderReplaced {
+class RenderMedia : public RenderImage {
public:
RenderMedia(HTMLMediaElement*);
RenderMedia(HTMLMediaElement*, const IntSize& intrinsicSize);
virtual ~RenderMedia();
-
+
const RenderObjectChildList* children() const { return &m_children; }
RenderObjectChildList* children() { return &m_children; }
HTMLMediaElement* mediaElement() const;
MediaPlayer* player() const;
- static String formatTime(float time);
-
bool shouldShowTimeDisplayControls() const;
void updateFromElement();
@@ -82,6 +83,7 @@ private:
virtual const char* renderName() const { return "RenderMedia"; }
virtual bool isMedia() const { return true; }
+ virtual bool isImage() const { return false; }
virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const;
@@ -96,9 +98,12 @@ private:
void createSeekForwardButton();
void createRewindButton();
void createReturnToRealtimeButton();
+ void createToggleClosedCaptionsButton();
void createStatusDisplay();
void createTimelineContainer();
void createTimeline();
+ void createVolumeSliderContainer();
+ void createVolumeSlider();
void createCurrentTimeDisplay();
void createTimeRemainingDisplay();
void createFullscreenButton();
@@ -109,6 +114,8 @@ private:
void changeOpacity(HTMLElement*, float opacity);
void opacityAnimationTimerFired(Timer<RenderMedia>*);
+ void updateVolumeSliderContainer(bool visible);
+
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
RefPtr<HTMLElement> m_controlsShadowRoot;
@@ -119,9 +126,12 @@ private:
RefPtr<MediaControlSeekButtonElement> m_seekForwardButton;
RefPtr<MediaControlRewindButtonElement> m_rewindButton;
RefPtr<MediaControlReturnToRealtimeButtonElement> m_returnToRealtimeButton;
+ RefPtr<MediaControlToggleClosedCaptionsButtonElement> m_toggleClosedCaptionsButton;
RefPtr<MediaControlTimelineElement> m_timeline;
+ RefPtr<MediaControlVolumeSliderElement> m_volumeSlider;
RefPtr<MediaControlFullscreenButtonElement> m_fullscreenButton;
RefPtr<MediaControlTimelineContainerElement> m_timelineContainer;
+ RefPtr<MediaControlVolumeSliderContainerElement> m_volumeSliderContainer;
RefPtr<MediaControlTimeDisplayElement> m_currentTimeDisplay;
RefPtr<MediaControlTimeDisplayElement> m_timeRemainingDisplay;
RefPtr<MediaControlStatusDisplayElement> m_statusDisplay;
diff --git a/WebCore/rendering/RenderMediaControls.cpp b/WebCore/rendering/RenderMediaControls.cpp
index 06d901a..17576ae 100644
--- a/WebCore/rendering/RenderMediaControls.cpp
+++ b/WebCore/rendering/RenderMediaControls.cpp
@@ -37,7 +37,7 @@ using namespace std;
namespace WebCore {
-#if !defined(NDEBUG) && defined(USE_DEBUG_SAFARI_THEME)
+#ifdef DEBUG_ALL
SOFT_LINK_DEBUG_LIBRARY(SafariTheme)
#else
SOFT_LINK_LIBRARY(SafariTheme)
@@ -82,16 +82,6 @@ void RenderMediaControls::adjustMediaSliderThumbSize(RenderObject* o)
o->style()->setHeight(Length(static_cast<int>(mediaSliderThumbHeight * zoomLevel), Fixed));
}
-static HTMLMediaElement* parentMediaElement(RenderObject* o)
-{
- Node* node = o->node();
- Node* mediaNode = node ? node->shadowAncestorNode() : 0;
- if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag)))
- return 0;
-
- return static_cast<HTMLMediaElement*>(mediaNode);
-}
-
bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
ASSERT(SafariThemeLibrary());
@@ -100,6 +90,15 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R
case MediaFullscreenButton:
paintThemePart(SafariTheme::MediaFullscreenButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
break;
+ case MediaShowClosedCaptionsButton:
+ case MediaHideClosedCaptionsButton:
+#if SAFARI_THEME_VERSION >= 4
+ if (MediaControlToggleClosedCaptionsButtonElement* btn = static_cast<MediaControlToggleClosedCaptionsButtonElement*>(o->node())) {
+ bool captionsVisible = btn->displayType() == MediaHideClosedCaptionsButton;
+ paintThemePart(captionsVisible ? SafariTheme::MediaHideClosedCaptionsButtonPart : SafariTheme::MediaShowClosedCaptionsButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+ }
+#endif
+ break;
case MediaMuteButton:
case MediaUnMuteButton:
if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(o->node())) {
@@ -110,8 +109,8 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R
case MediaPauseButton:
case MediaPlayButton:
if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) {
- bool currentlyPlaying = btn->displayType() == MediaPlayButton;
- paintThemePart(currentlyPlaying ? SafariTheme::MediaPauseButtonPart : SafariTheme::MediaPlayButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+ bool canPlay = btn->displayType() == MediaPlayButton;
+ paintThemePart(canPlay ? SafariTheme::MediaPlayButtonPart : SafariTheme::MediaPauseButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
}
break;
case MediaSeekBackButton:
@@ -121,13 +120,25 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R
paintThemePart(SafariTheme::MediaSeekForwardButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
break;
case MediaSlider: {
- if (HTMLMediaElement* mediaElement = parentMediaElement(o))
+ if (HTMLMediaElement* mediaElement = toParentMediaElement(o))
STPaintProgressIndicator(SafariTheme::MediaType, paintInfo.context->platformContext(), r, NSRegularControlSize, 0, mediaElement->percentLoaded());
break;
}
case MediaSliderThumb:
paintThemePart(SafariTheme::MediaSliderThumbPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
break;
+ case MediaVolumeSliderContainer:
+ // FIXME: Implement volume slider.
+ ASSERT_NOT_REACHED();
+ break;
+ case MediaVolumeSlider:
+ // FIXME: Implement volume slider.
+ ASSERT_NOT_REACHED();
+ break;
+ case MediaVolumeSliderThumb:
+ // FIXME: Implement volume slider.
+ ASSERT_NOT_REACHED();
+ break;
case MediaTimelineContainer:
ASSERT_NOT_REACHED();
break;
@@ -147,4 +158,3 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R
#endif // #if ENABLE(VIDEO)
} // namespace WebCore
-
diff --git a/WebCore/rendering/RenderMediaControlsChromium.cpp b/WebCore/rendering/RenderMediaControlsChromium.cpp
new file mode 100644
index 0000000..50feb46
--- /dev/null
+++ b/WebCore/rendering/RenderMediaControlsChromium.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2009 Apple Inc.
+ * Copyright (C) 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:
+ * 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 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 "RenderMediaControlsChromium.h"
+
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "HTMLMediaElement.h"
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+#if ENABLE(VIDEO)
+
+typedef WTF::HashMap<const char*, Image*> MediaControlImageMap;
+static MediaControlImageMap* gMediaControlImageMap = 0;
+
+static Image* platformResource(const char* name)
+{
+ if (!gMediaControlImageMap)
+ gMediaControlImageMap = new MediaControlImageMap();
+ if (Image* image = gMediaControlImageMap->get(name))
+ return image;
+ if (Image* image = Image::loadPlatformResource(name).releaseRef()) {
+ gMediaControlImageMap->set(name, image);
+ return image;
+ }
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+static bool hasSource(const HTMLMediaElement* mediaElement)
+{
+ return mediaElement->networkState() != HTMLMediaElement::NETWORK_EMPTY
+ && mediaElement->networkState() != HTMLMediaElement::NETWORK_NO_SOURCE;
+}
+
+static bool paintMediaButton(GraphicsContext* context, const IntRect& rect, Image* image)
+{
+ IntRect imageRect = image->rect();
+ context->drawImage(image, DeviceColorSpace, rect);
+ return true;
+}
+
+static bool paintMediaMuteButton(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
+{
+ HTMLMediaElement* mediaElement = toParentMediaElement(object);
+ if (!mediaElement)
+ return false;
+
+ static Image* soundFull = platformResource("mediaSoundFull");
+ static Image* soundNone = platformResource("mediaSoundNone");
+ static Image* soundDisabled = platformResource("mediaSoundDisabled");
+
+ if (!hasSource(mediaElement) || !mediaElement->hasAudio())
+ return paintMediaButton(paintInfo.context, rect, soundDisabled);
+
+ return paintMediaButton(paintInfo.context, rect, mediaElement->muted() ? soundNone: soundFull);
+}
+
+static bool paintMediaPlayButton(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
+{
+ HTMLMediaElement* mediaElement = toParentMediaElement(object);
+ if (!mediaElement)
+ return false;
+
+ static Image* mediaPlay = platformResource("mediaPlay");
+ static Image* mediaPause = platformResource("mediaPause");
+ static Image* mediaPlayDisabled = platformResource("mediaPlayDisabled");
+
+ if (!hasSource(mediaElement))
+ return paintMediaButton(paintInfo.context, rect, mediaPlayDisabled);
+
+ return paintMediaButton(paintInfo.context, rect, mediaElement->paused() ? mediaPlay : mediaPause);
+}
+
+static bool paintMediaSlider(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
+{
+ HTMLMediaElement* mediaElement = toParentMediaElement(object);
+ if (!mediaElement)
+ return false;
+
+ RenderStyle* style = object->style();
+ GraphicsContext* context = paintInfo.context;
+
+ // Draw the border of the time bar.
+ // FIXME: this should be a rounded rect but need to fix GraphicsContextSkia first.
+ // https://bugs.webkit.org/show_bug.cgi?id=30143
+ context->save();
+ context->setShouldAntialias(true);
+ context->setStrokeStyle(SolidStroke);
+ context->setStrokeColor(style->borderLeftColor(), DeviceColorSpace);
+ context->setStrokeThickness(style->borderLeftWidth());
+ context->setFillColor(style->backgroundColor(), DeviceColorSpace);
+ context->drawRect(rect);
+ context->restore();
+
+ // Draw the buffered ranges.
+ // FIXME: Draw multiple ranges if there are multiple buffered ranges.
+ IntRect bufferedRect = rect;
+ bufferedRect.inflate(-style->borderLeftWidth());
+ bufferedRect.setWidth((bufferedRect.width() * mediaElement->percentLoaded()));
+
+ // Don't bother drawing an empty area.
+ if (!bufferedRect.isEmpty()) {
+ IntPoint sliderTopLeft = bufferedRect.location();
+ IntPoint sliderTopRight = sliderTopLeft;
+ sliderTopRight.move(0, bufferedRect.height());
+
+ RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight);
+ Color startColor = object->style()->color();
+ gradient->addColorStop(0.0, startColor);
+ gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha()));
+
+ context->save();
+ context->setStrokeStyle(NoStroke);
+ context->setFillGradient(gradient);
+ context->fillRect(bufferedRect);
+ context->restore();
+ }
+
+ return true;
+}
+
+static bool paintMediaSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
+{
+ if (!object->parent()->isSlider())
+ return false;
+
+ HTMLMediaElement* mediaElement = toParentMediaElement(object->parent());
+ if (!mediaElement)
+ return false;
+
+ if (!hasSource(mediaElement))
+ return true;
+
+ static Image* mediaSliderThumb = platformResource("mediaSliderThumb");
+ return paintMediaButton(paintInfo.context, rect, mediaSliderThumb);
+}
+
+static bool paintMediaVolumeSlider(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
+{
+ HTMLMediaElement* mediaElement = toParentMediaElement(object);
+ if (!mediaElement)
+ return false;
+
+ GraphicsContext* context = paintInfo.context;
+ Color originalColor = context->strokeColor();
+ if (originalColor != Color::white)
+ context->setStrokeColor(Color::white, DeviceColorSpace);
+
+ int x = rect.x() + rect.width() / 2;
+ context->drawLine(IntPoint(x, rect.y()), IntPoint(x, rect.y() + rect.height()));
+
+ if (originalColor != Color::white)
+ context->setStrokeColor(originalColor, DeviceColorSpace);
+ return true;
+}
+
+static bool paintMediaVolumeSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
+{
+ if (!object->parent()->isSlider())
+ return false;
+
+ static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb");
+ return paintMediaButton(paintInfo.context, rect, mediaVolumeSliderThumb);
+}
+
+static bool paintMediaTimelineContainer(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
+{
+ HTMLMediaElement* mediaElement = toParentMediaElement(object);
+ if (!mediaElement)
+ return false;
+
+ if (!rect.isEmpty()) {
+ GraphicsContext* context = paintInfo.context;
+ Color originalColor = context->strokeColor();
+ float originalThickness = context->strokeThickness();
+ StrokeStyle originalStyle = context->strokeStyle();
+
+ context->setStrokeStyle(SolidStroke);
+
+ // Draw the left border using CSS defined width and color.
+ context->setStrokeThickness(object->style()->borderLeftWidth());
+ context->setStrokeColor(object->style()->borderLeftColor().rgb(), DeviceColorSpace);
+ context->drawLine(IntPoint(rect.x() + 1, rect.y()),
+ IntPoint(rect.x() + 1, rect.y() + rect.height()));
+
+ // Draw the right border using CSS defined width and color.
+ context->setStrokeThickness(object->style()->borderRightWidth());
+ context->setStrokeColor(object->style()->borderRightColor().rgb(), DeviceColorSpace);
+ context->drawLine(IntPoint(rect.x() + rect.width() - 1, rect.y()),
+ IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height()));
+
+ context->setStrokeColor(originalColor, DeviceColorSpace);
+ context->setStrokeThickness(originalThickness);
+ context->setStrokeStyle(originalStyle);
+ }
+ return true;
+}
+
+bool RenderMediaControlsChromium::shouldRenderMediaControlPart(ControlPart part, Element* e)
+{
+ UNUSED_PARAM(e);
+
+ switch (part) {
+ case MediaMuteButtonPart:
+ case MediaPlayButtonPart:
+ case MediaSliderPart:
+ case MediaSliderThumbPart:
+ case MediaVolumeSliderContainerPart:
+ case MediaVolumeSliderPart:
+ case MediaVolumeSliderThumbPart:
+ case MediaControlsBackgroundPart:
+ case MediaCurrentTimePart:
+ case MediaTimeRemainingPart:
+ return true;
+ default:
+ ;
+ }
+ return false;
+}
+
+bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
+{
+ switch (part) {
+ case MediaMuteButton:
+ case MediaUnMuteButton:
+ return paintMediaMuteButton(object, paintInfo, rect);
+ case MediaPauseButton:
+ case MediaPlayButton:
+ return paintMediaPlayButton(object, paintInfo, rect);
+ case MediaSlider:
+ return paintMediaSlider(object, paintInfo, rect);
+ case MediaSliderThumb:
+ return paintMediaSliderThumb(object, paintInfo, rect);
+ case MediaVolumeSlider:
+ return paintMediaVolumeSlider(object, paintInfo, rect);
+ case MediaVolumeSliderThumb:
+ return paintMediaVolumeSliderThumb(object, paintInfo, rect);
+ case MediaTimelineContainer:
+ return paintMediaTimelineContainer(object, paintInfo, rect);
+ case MediaFullscreenButton:
+ case MediaSeekBackButton:
+ case MediaSeekForwardButton:
+ case MediaVolumeSliderContainer:
+ case MediaCurrentTimeDisplay:
+ case MediaTimeRemainingDisplay:
+ case MediaControlsPanel:
+ case MediaRewindButton:
+ case MediaReturnToRealtimeButton:
+ case MediaStatusDisplay:
+ case MediaShowClosedCaptionsButton:
+ case MediaHideClosedCaptionsButton:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ return false;
+}
+
+void RenderMediaControlsChromium::adjustMediaSliderThumbSize(RenderObject* object)
+{
+ static Image* mediaSliderThumb = platformResource("mediaSliderThumb");
+ static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb");
+
+ Image* thumbImage = 0;
+ if (object->style()->appearance() == MediaSliderThumbPart)
+ thumbImage = mediaSliderThumb;
+ else if (object->style()->appearance() == MediaVolumeSliderThumbPart)
+ thumbImage = mediaVolumeSliderThumb;
+
+ float zoomLevel = object->style()->effectiveZoom();
+ if (thumbImage) {
+ object->style()->setWidth(Length(static_cast<int>(thumbImage->width() * zoomLevel), Fixed));
+ object->style()->setHeight(Length(static_cast<int>(thumbImage->height() * zoomLevel), Fixed));
+ }
+}
+
+#endif // #if ENABLE(VIDEO)
+
+} // namespace WebCore
diff --git a/WebCore/rendering/RenderMediaControlsChromium.h b/WebCore/rendering/RenderMediaControlsChromium.h
new file mode 100644
index 0000000..d6d986c
--- /dev/null
+++ b/WebCore/rendering/RenderMediaControlsChromium.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009 Apple Inc.
+ * Copyright (C) 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:
+ * 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 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 RenderMediaControlsChromium_h
+#define RenderMediaControlsChromium_h
+
+#include "RenderObject.h"
+#include "MediaControlElements.h"
+
+namespace WebCore {
+
+class HTMLMediaElement;
+class RenderMediaControlsChromium {
+public:
+ static bool shouldRenderMediaControlPart(ControlPart, Element*);
+ static bool paintMediaControlsPart(MediaControlElementType, RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ static void adjustMediaSliderThumbSize(RenderObject*);
+};
+
+} // namespace WebCore
+
+#endif // RenderMediaControlsChromium_h
diff --git a/WebCore/rendering/RenderMenuList.cpp b/WebCore/rendering/RenderMenuList.cpp
index 9d2e7e0..05a9873 100644
--- a/WebCore/rendering/RenderMenuList.cpp
+++ b/WebCore/rendering/RenderMenuList.cpp
@@ -1,7 +1,7 @@
/*
* This file is part of the select element renderer in WebCore.
*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
* 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* This library is free software; you can redistribute it and/or
@@ -24,6 +24,7 @@
#include "config.h"
#include "RenderMenuList.h"
+#include "AXObjectCache.h"
#include "CSSStyleSelector.h"
#include "Frame.h"
#include "FrameView.h"
@@ -50,6 +51,7 @@ RenderMenuList::RenderMenuList(Element* element)
, m_innerBlock(0)
, m_optionsChanged(true)
, m_optionsWidth(0)
+ , m_lastSelectedIndex(-1)
, m_popup(0)
, m_popupIsVisible(false)
{
@@ -292,7 +294,6 @@ void RenderMenuList::hidePopup()
{
if (m_popup)
m_popup->hide();
- m_popupIsVisible = false;
}
void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange)
@@ -307,10 +308,25 @@ void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange)
select->setSelectedIndexByUser(select->listToOptionIndex(listIndex), true, fireOnChange);
}
+void RenderMenuList::didSetSelectedIndex()
+{
+ int index = selectedIndex();
+ if (m_lastSelectedIndex == index)
+ return;
+
+ m_lastSelectedIndex = index;
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->postNotification(this, AXObjectCache::AXMenuListValueChanged, true, PostSynchronously);
+}
+
String RenderMenuList::itemText(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return String();
+ Element* element = listItems[listIndex];
if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element))
return optionGroupElement->groupLabelText();
else if (OptionElement* optionElement = toOptionElement(element))
@@ -321,14 +337,20 @@ String RenderMenuList::itemText(unsigned listIndex) const
String RenderMenuList::itemToolTip(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return String();
+ Element* element = listItems[listIndex];
return element->title();
}
bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return false;
+ Element* element = listItems[listIndex];
if (!isOptionElement(element))
return false;
@@ -346,7 +368,18 @@ bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size()) {
+ // If we are making an out of bounds access, then we want to use the style
+ // of a different option element (index 0). However, if there isn't an option element
+ // before at index 0, we fall back to the menu's style.
+ if (!listIndex)
+ return menuStyle();
+
+ // Try to retrieve the style of an option element we know exists (index 0).
+ listIndex = 0;
+ }
+ Element* element = listItems[listIndex];
RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle();
return style ? PopupMenuStyle(style->color(), itemBackgroundColor(listIndex), style->font(), style->visibility() == VISIBLE, style->textIndent(), style->direction()) : menuStyle();
@@ -355,7 +388,10 @@ PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return style()->backgroundColor();
+ Element* element = listItems[listIndex];
Color backgroundColor;
if (element->renderStyle())
@@ -375,7 +411,6 @@ Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const
PopupMenuStyle RenderMenuList::menuStyle() const
{
-
RenderStyle* s = m_innerBlock ? m_innerBlock->style() : style();
return PopupMenuStyle(s->color(), s->backgroundColor(), s->font(), s->visibility() == VISIBLE, s->textIndent(), s->direction());
}
@@ -411,8 +446,19 @@ int RenderMenuList::clientPaddingLeft() const
return paddingLeft();
}
+const int endOfLinePadding = 2;
int RenderMenuList::clientPaddingRight() const
{
+ if (style()->appearance() == MenulistPart || style()->appearance() == MenulistButtonPart) {
+ // For these appearance values, the theme applies padding to leave room for the
+ // drop-down button. But leaving room for the button inside the popup menu itself
+ // looks strange, so we return a small default padding to avoid having a large empty
+ // space appear on the side of the popup menu.
+ return endOfLinePadding;
+ }
+
+ // If the appearance isn't MenulistPart, then the select is styled (non-native), so
+ // we want to return the user specified padding.
return paddingRight();
}
@@ -428,24 +474,38 @@ int RenderMenuList::selectedIndex() const
return select->optionToListIndex(select->selectedIndex());
}
+void RenderMenuList::popupDidHide()
+{
+ m_popupIsVisible = false;
+}
+
bool RenderMenuList::itemIsSeparator(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return false;
+ Element* element = listItems[listIndex];
return element->hasTagName(hrTag);
}
bool RenderMenuList::itemIsLabel(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return false;
+ Element* element = listItems[listIndex];
return isOptionGroupElement(element);
}
bool RenderMenuList::itemIsSelected(unsigned listIndex) const
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
- Element* element = select->listItems()[listIndex];
+ const Vector<Element*>& listItems = select->listItems();
+ if (listIndex >= listItems.size())
+ return false;
+ Element* element = listItems[listIndex];
if (OptionElement* optionElement = toOptionElement(element))
return optionElement->selected();
return false;
diff --git a/WebCore/rendering/RenderMenuList.h b/WebCore/rendering/RenderMenuList.h
index 5c18e9e..a5aa041 100644
--- a/WebCore/rendering/RenderMenuList.h
+++ b/WebCore/rendering/RenderMenuList.h
@@ -1,7 +1,7 @@
/*
* This file is part of the select element renderer in WebCore.
*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 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
@@ -49,6 +49,8 @@ public:
void setOptionsChanged(bool changed) { m_optionsChanged = changed; }
+ void didSetSelectedIndex();
+
String text() const;
private:
@@ -82,6 +84,7 @@ private:
virtual int clientPaddingRight() const;
virtual int listSize() const;
virtual int selectedIndex() const;
+ virtual void popupDidHide();
virtual bool itemIsSeparator(unsigned listIndex) const;
virtual bool itemIsLabel(unsigned listIndex) const;
virtual bool itemIsSelected(unsigned listIndex) const;
@@ -109,6 +112,8 @@ private:
bool m_optionsChanged;
int m_optionsWidth;
+ int m_lastSelectedIndex;
+
RefPtr<PopupMenu> m_popup;
bool m_popupIsVisible;
};
diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp
index 5137338..1d1e7c2 100644
--- a/WebCore/rendering/RenderObject.cpp
+++ b/WebCore/rendering/RenderObject.cpp
@@ -4,6 +4,8 @@
* (C) 2000 Dirk Mueller (mueller@kde.org)
* (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -26,6 +28,7 @@
#include "RenderObject.h"
#include "AXObjectCache.h"
+#include "Chrome.h"
#include "CSSStyleSelector.h"
#include "FloatQuad.h"
#include "Frame.h"
@@ -40,12 +43,15 @@
#include "RenderImageGeneratedContent.h"
#include "RenderInline.h"
#include "RenderListItem.h"
+#include "RenderRuby.h"
+#include "RenderRubyText.h"
#include "RenderTableCell.h"
#include "RenderTableCol.h"
#include "RenderTableRow.h"
#include "RenderTheme.h"
#include "RenderView.h"
#include "TransformState.h"
+#include "htmlediting.h"
#include <algorithm>
#ifdef ANDROID_LAYOUT
#include "Settings.h"
@@ -62,6 +68,10 @@
#include "WMLNames.h"
#endif
+#if ENABLE(SVG)
+#include "SVGRenderSupport.h"
+#endif
+
using namespace std;
namespace WebCore {
@@ -104,56 +114,58 @@ RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
return image;
}
- RenderObject* o = 0;
+#if ENABLE(RUBY)
+ if (node->hasTagName(rubyTag)) {
+ if (style->display() == INLINE)
+ return new (arena) RenderRubyAsInline(node);
+ else
+ return new (arena) RenderRubyAsBlock(node);
+ }
+ // treat <rt> as ruby text ONLY if it still has its default treatment of block
+ if (node->hasTagName(rtTag) && style->display() == BLOCK)
+ return new (arena) RenderRubyText(node);
+#endif
switch (style->display()) {
case NONE:
- break;
+ return 0;
case INLINE:
- o = new (arena) RenderInline(node);
- break;
+ return new (arena) RenderInline(node);
case BLOCK:
- o = new (arena) RenderBlock(node);
- break;
case INLINE_BLOCK:
- o = new (arena) RenderBlock(node);
- break;
- case LIST_ITEM:
- o = new (arena) RenderListItem(node);
- break;
case RUN_IN:
case COMPACT:
- o = new (arena) RenderBlock(node);
- break;
+ return new (arena) RenderBlock(node);
+ case LIST_ITEM:
+ return new (arena) RenderListItem(node);
case TABLE:
case INLINE_TABLE:
- o = new (arena) RenderTable(node);
- break;
+ return new (arena) RenderTable(node);
case TABLE_ROW_GROUP:
case TABLE_HEADER_GROUP:
case TABLE_FOOTER_GROUP:
- o = new (arena) RenderTableSection(node);
- break;
+ return new (arena) RenderTableSection(node);
case TABLE_ROW:
- o = new (arena) RenderTableRow(node);
- break;
+ return new (arena) RenderTableRow(node);
case TABLE_COLUMN_GROUP:
case TABLE_COLUMN:
- o = new (arena) RenderTableCol(node);
- break;
+ return new (arena) RenderTableCol(node);
case TABLE_CELL:
- o = new (arena) RenderTableCell(node);
- break;
+ return new (arena) RenderTableCell(node);
case TABLE_CAPTION:
- o = new (arena) RenderBlock(node);
- break;
+#if ENABLE(WCSS)
+ // As per the section 17.1 of the spec WAP-239-WCSS-20011026-a.pdf,
+ // the marquee box inherits and extends the characteristics of the
+ // principal block box ([CSS2] section 9.2.1).
+ case WAP_MARQUEE:
+#endif
+ return new (arena) RenderBlock(node);
case BOX:
case INLINE_BOX:
- o = new (arena) RenderFlexibleBox(node);
- break;
+ return new (arena) RenderFlexibleBox(node);
}
- return o;
+ return 0;
}
#ifndef NDEBUG
@@ -200,7 +212,6 @@ RenderObject::RenderObject(Node* node)
, m_selectionState(SelectionNone)
, m_hasColumns(false)
, m_cellWidthChanged(false)
- , m_replacedHasOverflow(false)
{
#ifndef NDEBUG
renderObjectCounter.increment();
@@ -303,7 +314,7 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild)
// Just add it...
children->insertChildNode(this, newChild, beforeChild);
}
-
+ RenderCounter::rendererSubtreeAttached(newChild);
if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) {
RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalText();
if (textToTransform)
@@ -362,19 +373,14 @@ RenderObject* RenderObject::nextInPreOrderAfterChildren(RenderObject* stayWithin
if (this == stayWithin)
return 0;
- RenderObject* o;
- if (!(o = nextSibling())) {
- o = parent();
- while (o && !o->nextSibling()) {
- if (o == stayWithin)
- return 0;
- o = o->parent();
- }
- if (o)
- o = o->nextSibling();
+ const RenderObject* current = this;
+ RenderObject* next;
+ while (!(next = current->nextSibling())) {
+ current = current->parent();
+ if (!current || current == stayWithin)
+ return 0;
}
-
- return o;
+ return next;
}
RenderObject* RenderObject::previousInPreOrder() const
@@ -621,6 +627,11 @@ RenderBlock* RenderObject::containingBlock() const
// inline directly.
if (o->style()->position() == RelativePosition && o->isInline() && !o->isReplaced())
return o->containingBlock();
+#if ENABLE(SVG)
+ if (o->isSVGForeignObject()) //foreignObject is the containing block for contents inside it
+ break;
+#endif
+
o = o->parent();
}
} else {
@@ -634,7 +645,7 @@ RenderBlock* RenderObject::containingBlock() const
}
if (!o || !o->isRenderBlock())
- return 0; // Probably doesn't happen any more, but leave just in case. -dwh
+ return 0; // This can still happen in case of an orphaned tree
return toRenderBlock(o);
}
@@ -653,10 +664,10 @@ static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer*
if (!layer->xPosition().isZero() || !layer->yPosition().isZero())
return true;
- if (layer->isSizeSet()) {
- if (layer->size().width().isPercent() || layer->size().height().isPercent())
+ if (layer->size().type == SizeLength) {
+ if (layer->size().size.width().isPercent() || layer->size().size.height().isPercent())
return true;
- } else if (img->usesImageContainerSize())
+ } else if (layer->size().type == Contain || layer->size().type == Cover || img->usesImageContainerSize())
return true;
return false;
@@ -710,7 +721,7 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1,
return;
case DOTTED:
case DASHED:
- graphicsContext->setStrokeColor(c);
+ graphicsContext->setStrokeColor(c, m_style->colorSpace());
graphicsContext->setStrokeThickness(width);
graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke);
@@ -731,7 +742,7 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1,
if (adjbw1 == 0 && adjbw2 == 0) {
graphicsContext->setStrokeStyle(NoStroke);
- graphicsContext->setFillColor(c);
+ graphicsContext->setFillColor(c, m_style->colorSpace());
switch (s) {
case BSTop:
case BSBottom:
@@ -844,7 +855,7 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1,
// fall through
case SOLID: {
graphicsContext->setStrokeStyle(NoStroke);
- graphicsContext->setFillColor(c);
+ graphicsContext->setFillColor(c, m_style->colorSpace());
ASSERT(x2 >= x1);
ASSERT(y2 >= y1);
if (!adjbw1 && !adjbw2) {
@@ -904,7 +915,7 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in
return;
case DOTTED:
case DASHED:
- graphicsContext->setStrokeColor(c);
+ graphicsContext->setStrokeColor(c, m_style->colorSpace());
graphicsContext->setStrokeStyle(style == DOTTED ? DottedStroke : DashedStroke);
graphicsContext->setStrokeThickness(thickness);
graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan);
@@ -926,7 +937,7 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in
}
graphicsContext->setStrokeStyle(SolidStroke);
- graphicsContext->setStrokeColor(c);
+ graphicsContext->setStrokeColor(c, m_style->colorSpace());
graphicsContext->setStrokeThickness(third);
graphicsContext->strokeArc(IntRect(x, outerY, radius.width() * 2, outerHeight), angleStart, angleSpan);
graphicsContext->setStrokeThickness(innerThird > 2 ? innerThird - 1 : innerThird);
@@ -945,13 +956,13 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in
}
graphicsContext->setStrokeStyle(SolidStroke);
- graphicsContext->setStrokeColor(c);
+ graphicsContext->setStrokeColor(c, m_style->colorSpace());
graphicsContext->setStrokeThickness(thickness);
graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan);
float halfThickness = (thickness + 1.0f) / 4.0f;
int shiftForInner = static_cast<int>(halfThickness * 1.5f);
- graphicsContext->setStrokeColor(c2);
+ graphicsContext->setStrokeColor(c2, m_style->colorSpace());
graphicsContext->setStrokeThickness(halfThickness > 2 ? halfThickness - 1 : halfThickness);
graphicsContext->strokeArc(IntRect(x + shiftForInner, y + shiftForInner, (radius.width() - shiftForInner) * 2,
(radius.height() - shiftForInner) * 2), angleStart, angleSpan);
@@ -965,7 +976,7 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in
c = c.dark();
case SOLID:
graphicsContext->setStrokeStyle(SolidStroke);
- graphicsContext->setStrokeColor(c);
+ graphicsContext->setStrokeColor(c, m_style->colorSpace());
graphicsContext->setStrokeThickness(thickness);
graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan);
break;
@@ -1002,13 +1013,12 @@ void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty
if (style->outlineStyleIsAuto() || hasOutlineAnnotation()) {
if (!theme()->supportsFocusRing(style)) {
// Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
- graphicsContext->initFocusRing(ow, offset);
- addFocusRingRects(graphicsContext, tx, ty);
+ Vector<IntRect> focusRingRects;
+ addFocusRingRects(focusRingRects, tx, ty);
if (style->outlineStyleIsAuto())
- graphicsContext->drawFocusRing(oc);
+ graphicsContext->drawFocusRing(focusRingRects, ow, offset, oc);
else
- addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect());
- graphicsContext->clearFocusRing();
+ addPDFURLRect(graphicsContext, unionRect(focusRingRects));
}
}
@@ -1066,6 +1076,23 @@ IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms)
return result;
}
+void RenderObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads)
+{
+ Vector<IntRect> rects;
+ // FIXME: addFocusRingRects() needs to be passed this transform-unaware
+ // localToAbsolute() offset here because RenderInline::addFocusRingRects()
+ // implicitly assumes that. This doesn't work correctly with transformed
+ // descendants.
+ FloatPoint absolutePoint = localToAbsolute();
+ addFocusRingRects(rects, absolutePoint.x(), absolutePoint.y());
+ size_t count = rects.size();
+ for (size_t i = 0; i < count; ++i) {
+ IntRect rect = rects[i];
+ rect.move(-absolutePoint.x(), -absolutePoint.y());
+ quads.append(localToAbsoluteQuad(FloatQuad(rect)));
+ }
+}
+
void RenderObject::addAbsoluteRectForLayer(IntRect& result)
{
if (hasLayer())
@@ -1329,6 +1356,50 @@ void RenderObject::showTreeForThis() const
node()->showTreeForThis();
}
+void RenderObject::showRenderObject() const
+{
+ showRenderObject(0);
+}
+
+void RenderObject::showRenderObject(int printedCharacters) const
+{
+ // As this function is intended to be used when debugging, the
+ // this pointer may be 0.
+ if (!this) {
+ fputs("(null)\n", stderr);
+ return;
+ }
+
+ printedCharacters += fprintf(stderr, "%s %p", renderName(), this);
+
+ if (node()) {
+ if (printedCharacters)
+ for (; printedCharacters < 39; printedCharacters++)
+ fputc(' ', stderr);
+ fputc('\t', stderr);
+ node()->showNode();
+ } else
+ fputc('\n', stderr);
+}
+
+void RenderObject::showRenderTreeAndMark(const RenderObject* markedObject1, const char* markedLabel1, const RenderObject* markedObject2, const char* markedLabel2, int depth) const
+{
+ int printedCharacters = 0;
+ if (markedObject1 == this && markedLabel1)
+ printedCharacters += fprintf(stderr, "%s", markedLabel1);
+ if (markedObject2 == this && markedLabel2)
+ printedCharacters += fprintf(stderr, "%s", markedLabel2);
+ for (; printedCharacters < depth * 2; printedCharacters++)
+ fputc(' ', stderr);
+
+ showRenderObject(printedCharacters);
+ if (!this)
+ return;
+
+ for (const RenderObject* child = firstChild(); child; child = child->nextSibling())
+ child->showRenderTreeAndMark(markedObject1, markedLabel1, markedObject2, markedLabel2, depth + 1);
+}
+
#endif // NDEBUG
Color RenderObject::selectionBackgroundColor() const
@@ -1365,6 +1436,7 @@ Color RenderObject::selectionForegroundColor() const
return color;
}
+#if ENABLE(DRAG_SUPPORT)
Node* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
{
if (!dhtmlOK && !uaOK)
@@ -1399,6 +1471,7 @@ Node* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& d
}
return 0;
}
+#endif // ENABLE(DRAG_SUPPORT)
void RenderObject::selectionStartEnd(int& spos, int& epos) const
{
@@ -1557,7 +1630,7 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
// For changes in float styles, we need to conceivably remove ourselves
// from the floating objects list.
toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists();
- else if (isPositioned() && (newStyle->position() != AbsolutePosition && newStyle->position() != FixedPosition))
+ else if (isPositioned() && (m_style->position() != newStyle->position()))
// For changes in positioning styles, we need to conceivably remove ourselves
// from the positioned objects list.
toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists();
@@ -1582,8 +1655,20 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
if (view()->frameView()) {
// FIXME: A better solution would be to only invalidate the fixed regions when scrolling. It's overkill to
// prevent the entire view from blitting on a scroll.
- bool newStyleSlowScroll = newStyle && (newStyle->position() == FixedPosition || newStyle->hasFixedBackgroundImage());
- bool oldStyleSlowScroll = m_style && (m_style->position() == FixedPosition || m_style->hasFixedBackgroundImage());
+
+ bool shouldBlitOnFixedBackgroundImage = false;
+#if ENABLE(FAST_MOBILE_SCROLLING)
+ // On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays
+ // when scrolling a page with a fixed background image. As an optimization, assuming there are
+ // no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we
+ // ignore the CSS property "background-attachment: fixed".
+ shouldBlitOnFixedBackgroundImage = true;
+#endif
+
+ bool newStyleSlowScroll = newStyle && (newStyle->position() == FixedPosition
+ || (!shouldBlitOnFixedBackgroundImage && newStyle->hasFixedBackgroundImage()));
+ bool oldStyleSlowScroll = m_style && (m_style->position() == FixedPosition
+ || (!shouldBlitOnFixedBackgroundImage && m_style->hasFixedBackgroundImage()));
if (oldStyleSlowScroll != newStyleSlowScroll) {
if (oldStyleSlowScroll)
view()->frameView()->removeSlowRepaintObject();
@@ -1593,7 +1678,7 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
}
}
-void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle*)
+void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
if (s_affectsParentBlock)
handleDynamicFloatPositionChange();
@@ -1601,9 +1686,19 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle*)
if (!m_parent)
return;
- if (diff == StyleDifferenceLayout)
+ if (diff == StyleDifferenceLayout) {
+ RenderCounter::rendererStyleChanged(this, oldStyle, m_style.get());
+
+ // If the object already needs layout, then setNeedsLayout won't do
+ // any work. But if the containing block has changed, then we may need
+ // to mark the new containing blocks for layout. The change that can
+ // directly affect the containing block of this object is a change to
+ // the position style.
+ if (m_needsLayout && oldStyle->position() != m_style->position())
+ markContainingBlocksForLayout();
+
setNeedsLayoutAndPrefWidthsRecalc();
- else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
+ } else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
setNeedsPositionedMovementLayout();
// Don't check for repaint here; we need to wait until the layer has been
@@ -1612,15 +1707,20 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle*)
void RenderObject::updateFillImages(const FillLayer* oldLayers, const FillLayer* newLayers)
{
- // FIXME: This will be slow when a large number of images is used. Fix by using a dict.
- for (const FillLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
- if (currOld->image() && (!newLayers || !newLayers->containsImage(currOld->image())))
- currOld->image()->removeClient(this);
- }
+ // Optimize the common case
+ if (oldLayers && !oldLayers->next() && newLayers && !newLayers->next() && (oldLayers->image() == newLayers->image()))
+ return;
+
+ // Go through the new layers and addClients first, to avoid removing all clients of an image.
for (const FillLayer* currNew = newLayers; currNew; currNew = currNew->next()) {
- if (currNew->image() && (!oldLayers || !oldLayers->containsImage(currNew->image())))
+ if (currNew->image())
currNew->image()->addClient(this);
}
+
+ for (const FillLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
+ if (currOld->image())
+ currOld->image()->removeClient(this);
+ }
}
void RenderObject::updateImage(StyleImage* oldImage, StyleImage* newImage)
@@ -1739,6 +1839,23 @@ IntSize RenderObject::offsetFromContainer(RenderObject* o) const
return offset;
}
+IntSize RenderObject::offsetFromAncestorContainer(RenderObject* container) const
+{
+ IntSize offset;
+ const RenderObject* currContainer = this;
+ do {
+ RenderObject* nextContainer = currContainer->container();
+ ASSERT(nextContainer); // This means we reached the top without finding container.
+ if (!nextContainer)
+ break;
+ ASSERT(!currContainer->hasTransform());
+ offset += currContainer->offsetFromContainer(nextContainer);
+ currContainer = nextContainer;
+ } while (currContainer != container);
+
+ return offset;
+}
+
IntRect RenderObject::localCaretRect(InlineBox*, int, int* extraWidthToEndOfLine)
{
if (extraWidthToEndOfLine)
@@ -1772,8 +1889,11 @@ bool RenderObject::hasOutlineAnnotation() const
return node() && node()->isLink() && document()->printing();
}
-RenderObject* RenderObject::container() const
+RenderObject* RenderObject::container(RenderBoxModelObject* repaintContainer, bool* repaintContainerSkipped) const
{
+ if (repaintContainerSkipped)
+ *repaintContainerSkipped = false;
+
// This method is extremely similar to containingBlock(), but with a few notable
// exceptions.
// (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
@@ -1798,14 +1918,20 @@ RenderObject* RenderObject::container() const
// we'll just return 0).
// FIXME: The definition of view() has changed to not crawl up the render tree. It might
// be safe now to use it.
- while (o && o->parent() && !(o->hasTransform() && o->isRenderBlock()))
+ while (o && o->parent() && !(o->hasTransform() && o->isRenderBlock())) {
+ if (repaintContainerSkipped && o == repaintContainer)
+ *repaintContainerSkipped = true;
o = o->parent();
+ }
} else if (pos == AbsolutePosition) {
// Same goes here. We technically just want our containing block, but
// we may not have one if we're part of an uninstalled subtree. We'll
// climb as high as we can though.
- while (o && o->style()->position() == StaticPosition && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock()))
+ while (o && o->style()->position() == StaticPosition && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock())) {
+ if (repaintContainerSkipped && o == repaintContainer)
+ *repaintContainerSkipped = true;
o = o->parent();
+ }
}
return o;
@@ -1825,7 +1951,12 @@ void RenderObject::destroy()
children->destroyLeftoverChildren();
// If this renderer is being autoscrolled, stop the autoscroll timer
- if (document()->frame()->eventHandler()->autoscrollRenderer() == this)
+
+ // FIXME: RenderObject::destroy should not get called with a renderer whose document
+ // has a null frame, so we assert this. However, we don't want release builds to crash which is why we
+ // check that the frame is not null.
+ ASSERT(document()->frame());
+ if (document()->frame() && document()->frame()->eventHandler()->autoscrollRenderer() == this)
document()->frame()->eventHandler()->stopAutoscrollTimer(true);
if (m_hasCounterNodeMap)
@@ -2322,9 +2453,20 @@ RenderBoxModelObject* RenderObject::offsetParent() const
VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity)
{
- // If this is a non-anonymous renderer, then it's simple.
- if (Node* node = this->node())
+ // If this is a non-anonymous renderer in an editable area, then it's simple.
+ if (Node* node = this->node()) {
+ if (!node->isContentEditable()) {
+ // If it can be found, we prefer a visually equivalent position that is editable.
+ Position position(node, offset);
+ Position candidate = position.downstream(Position::CanCrossEditingBoundary);
+ if (candidate.node()->isContentEditable())
+ return VisiblePosition(candidate, affinity);
+ candidate = position.upstream(Position::CanCrossEditingBoundary);
+ if (candidate.node()->isContentEditable())
+ return VisiblePosition(candidate, affinity);
+ }
return VisiblePosition(node, offset, affinity);
+ }
// We don't want to cross the boundary between editable and non-editable
// regions of the document, but that is either impossible or at least
@@ -2372,6 +2514,11 @@ VisiblePosition RenderObject::createVisiblePosition(const Position& position)
}
#if ENABLE(SVG)
+const SVGRenderBase* RenderObject::toSVGRenderBase() const
+{
+ ASSERT_NOT_REACHED();
+ return 0;
+}
FloatRect RenderObject::objectBoundingBox() const
{
@@ -2387,25 +2534,16 @@ FloatRect RenderObject::repaintRectInLocalCoordinates() const
return FloatRect();
}
-TransformationMatrix RenderObject::localTransform() const
-{
- return TransformationMatrix();
-}
-
-TransformationMatrix RenderObject::localToParentTransform() const
+AffineTransform RenderObject::localTransform() const
{
- // FIXME: This double virtual call indirection is temporary until I can land the
- // rest of the of the localToParentTransform() support for SVG.
- return localTransform();
+ static const AffineTransform identity;
+ return identity;
}
-TransformationMatrix RenderObject::absoluteTransform() const
+const AffineTransform& RenderObject::localToParentTransform() const
{
- // FIXME: This should use localToParentTransform(), but much of the SVG code
- // depends on RenderBox::absoluteTransform() being the sum of the localTransform()s of all parent renderers.
- if (parent())
- return localTransform() * parent()->absoluteTransform();
- return localTransform();
+ static const AffineTransform identity;
+ return identity;
}
bool RenderObject::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction)
@@ -2426,4 +2564,19 @@ void showTree(const WebCore::RenderObject* ro)
ro->showTreeForThis();
}
+void showRenderTree(const WebCore::RenderObject* object1)
+{
+ showRenderTree(object1, 0);
+}
+
+void showRenderTree(const WebCore::RenderObject* object1, const WebCore::RenderObject* object2)
+{
+ if (object1) {
+ const WebCore::RenderObject* root = object1;
+ while (root->parent())
+ root = root->parent();
+ root->showRenderTreeAndMark(object1, "*", object2, "-", 0);
+ }
+}
+
#endif
diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h
index 911169d..6764818 100644
--- a/WebCore/rendering/RenderObject.h
+++ b/WebCore/rendering/RenderObject.h
@@ -4,6 +4,7 @@
* (C) 2000 Dirk Mueller (mueller@kde.org)
* (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google 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
@@ -25,6 +26,7 @@
#ifndef RenderObject_h
#define RenderObject_h
+#include "AffineTransform.h"
#include "CachedResourceClient.h"
#include "Document.h"
#include "Element.h"
@@ -51,6 +53,9 @@ class RenderLayer;
class RenderTheme;
class TransformState;
class VisiblePosition;
+#if ENABLE(SVG)
+class SVGRenderBase;
+#endif
/*
* The painting of a layer occurs in three distinct phases. Each phase involves
@@ -76,11 +81,13 @@ enum PaintPhase {
PaintPhaseMask
};
-enum PaintRestriction {
- PaintRestrictionNone,
- PaintRestrictionSelectionOnly,
- PaintRestrictionSelectionOnlyBlackText
+enum PaintBehaviorFlags {
+ PaintBehaviorNormal = 0,
+ PaintBehaviorSelectionOnly = 1 << 0,
+ PaintBehaviorForceBlackText = 1 << 1,
+ PaintBehaviorFlattenCompositingLayers = 1 << 2
};
+typedef unsigned PaintBehavior;
enum HitTestFilter {
HitTestAll,
@@ -228,6 +235,12 @@ private:
public:
#ifndef NDEBUG
void showTreeForThis() const;
+
+ void showRenderObject() const;
+ // We don't make printedCharacters an optional parameter so that
+ // showRenderObject can be called from gdb easily.
+ void showRenderObject(int printedCharacters) const;
+ void showRenderTreeAndMark(const RenderObject* markedObject1 = 0, const char* markedLabel1 = 0, const RenderObject* markedObject2 = 0, const char* markedLabel2 = 0, int depth = 0) const;
#endif
static RenderObject* createObject(Node*, RenderStyle*);
@@ -251,7 +264,9 @@ public:
virtual bool isBlockFlow() const { return false; }
virtual bool isBoxModelObject() const { return false; }
virtual bool isCounter() const { return false; }
+ virtual bool isEmbeddedObject() const { return false; }
virtual bool isFieldset() const { return false; }
+ virtual bool isFileUploadControl() const { return false; }
virtual bool isFrame() const { return false; }
virtual bool isFrameSet() const { return false; }
virtual bool isImage() const { return false; }
@@ -267,6 +282,13 @@ public:
virtual bool isRenderInline() const { return false; }
virtual bool isRenderPart() const { return false; }
virtual bool isRenderView() const { return false; }
+ virtual bool isReplica() const { return false; }
+#if ENABLE(RUBY)
+ virtual bool isRuby() const { return false; }
+ virtual bool isRubyBase() const { return false; }
+ virtual bool isRubyRun() const { return false; }
+ virtual bool isRubyText() const { return false; }
+#endif
virtual bool isSlider() const { return false; }
virtual bool isTable() const { return false; }
virtual bool isTableCell() const { return false; }
@@ -278,6 +300,7 @@ public:
virtual bool isTextField() const { return false; }
virtual bool isVideo() const { return false; }
virtual bool isWidget() const { return false; }
+ virtual bool isCanvas() const { return false; }
bool isRoot() const { return document()->documentElement() == m_node; }
bool isBody() const;
@@ -285,6 +308,9 @@ public:
bool isHTMLMarquee() const;
+ inline bool isAfterContent() const;
+ static inline bool isAfterContent(const RenderObject* obj) { return obj && obj->isAfterContent(); }
+
bool childrenInline() const { return m_childrenInline; }
void setChildrenInline(bool b = true) { m_childrenInline = b; }
bool hasColumns() const { return m_hasColumns; }
@@ -292,6 +318,10 @@ public:
bool cellWidthChanged() const { return m_cellWidthChanged; }
void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; }
+#if ENABLE(MATHML)
+ virtual bool isRenderMathMLBlock() const { return false; }
+#endif // ENABLE(MATHML)
+
#if ENABLE(SVG)
// FIXME: Until all SVG renders can be subclasses of RenderSVGModelObject we have
// to add SVG renderer methods to RenderObject with an ASSERT_NOT_REACHED() default implementation.
@@ -301,6 +331,9 @@ public:
virtual bool isRenderPath() const { return false; }
virtual bool isSVGText() const { return false; }
virtual bool isSVGImage() const { return false; }
+ virtual bool isSVGForeignObject() const { return false; }
+
+ virtual const SVGRenderBase* toSVGRenderBase() const;
// Per SVG 1.1 objectBoundingBox ignores clipping, masking, filter effects, opacity and stroke-width.
// This is used for all computation of objectBoundingBox relative units and by SVGLocateable::getBBox().
@@ -317,16 +350,11 @@ public:
// FIXME: This accessor is deprecated and mostly around for SVGRenderTreeAsText.
// This only returns the transform="" value from the element
// most callsites want localToParentTransform() instead.
- virtual TransformationMatrix localTransform() const;
+ virtual AffineTransform localTransform() const;
// Returns the full transform mapping from local coordinates to local coords for the parent SVG renderer
// This includes any viewport transforms and x/y offsets as well as the transform="" value off the element.
- virtual TransformationMatrix localToParentTransform() const;
-
- // Walks up the parent chain to create a transform which maps from local to document coords
- // NOTE: This method is deprecated! It doesn't respect scroll offsets or repaint containers.
- // FIXME: This is only virtual so that RenderSVGHiddenContainer can override it to match old LayoutTest results.
- virtual TransformationMatrix absoluteTransform() const;
+ virtual const AffineTransform& localToParentTransform() const;
// SVG uses FloatPoint precise hit testing, and passes the point in parent
// coordinates instead of in repaint container coordinates. Eventually the
@@ -398,11 +426,11 @@ public:
bool hasOutlineAnnotation() const;
bool hasOutline() const { return style()->hasOutline() || hasOutlineAnnotation(); }
- /**
- * returns the object containing this one. can be different from parent for
- * positioned elements
- */
- RenderObject* container() const;
+ // Returns the object containing this one. Can be different from parent for positioned elements.
+ // If repaintContainer and repaintContainerSkipped are not null, on return *repaintContainerSkipped
+ // is true if the renderer returned is an ancestor of repaintContainer.
+ RenderObject* container(RenderBoxModelObject* repaintContainer = 0, bool* repaintContainerSkipped = 0) const;
+
virtual RenderObject* hoverAncestor() const { return parent(); }
// IE Extension that can be called on any RenderObject. See the implementation for the details.
@@ -536,6 +564,8 @@ public:
// Return the offset from the container() renderer (excluding transforms)
virtual IntSize offsetFromContainer(RenderObject*) const;
+ // Return the offset from an object up the container() chain. Asserts that none of the intermediate objects have transforms.
+ IntSize offsetFromAncestorContainer(RenderObject*) const;
virtual void absoluteRects(Vector<IntRect>&, int, int) { }
// FIXME: useTransforms should go away eventually
@@ -544,6 +574,8 @@ public:
// Build an array of quads in absolute coords for line boxes
virtual void absoluteQuads(Vector<FloatQuad>&) { }
+ void absoluteFocusRingQuads(Vector<FloatQuad>&);
+
// the rect that will be painted if this object is passed as the paintingRoot
IntRect paintingRootRect(IntRect& topLevelRect);
@@ -658,7 +690,9 @@ public:
// Whether or not a given block needs to paint selection gaps.
virtual bool shouldPaintSelectionGaps() const { return false; }
+#if ENABLE(DRAG_SUPPORT)
Node* draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const;
+#endif
/**
* Returns the local coordinates of the caret within this render object.
@@ -727,16 +761,13 @@ public:
bool shouldUseTransformFromContainer(const RenderObject* container) const;
void getTransformFromContainer(const RenderObject* container, const IntSize& offsetInContainer, TransformationMatrix&) const;
- virtual void addFocusRingRects(GraphicsContext*, int /*tx*/, int /*ty*/) { };
+ virtual void addFocusRingRects(Vector<IntRect>&, int /*tx*/, int /*ty*/) { };
IntRect absoluteOutlineBounds() const
{
return outlineBoundsForRepaint(0);
}
- bool replacedHasOverflow() const { return m_replacedHasOverflow; }
- void setReplacedHasOverflow(bool b = true) { m_replacedHasOverflow = b; }
-
protected:
// Overrides should call the superclass at the end
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
@@ -845,9 +876,6 @@ private:
// from RenderTableCell
bool m_cellWidthChanged : 1;
- // from RenderReplaced
- bool m_replacedHasOverflow : 1;
-
private:
// Store state between styleWillChange and styleDidChange
static bool s_affectsParentBlock;
@@ -858,6 +886,16 @@ inline bool RenderObject::documentBeingDestroyed() const
return !document()->renderer();
}
+inline bool RenderObject::isAfterContent() const
+{
+ if (style()->styleType() != AFTER)
+ return false;
+ // Text nodes don't have their own styles, so ignore the style on a text node.
+ if (isText() && !isBR())
+ return false;
+ return true;
+}
+
inline void RenderObject::setNeedsLayout(bool b, bool markParents)
{
bool alreadyNeededLayout = m_needsLayout;
@@ -974,11 +1012,51 @@ inline void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRenderi
#endif
}
+inline int adjustForAbsoluteZoom(int value, RenderObject* renderer)
+{
+ float zoomFactor = renderer->style()->effectiveZoom();
+ if (zoomFactor == 1)
+ return value;
+ // Needed because computeLengthInt truncates (rather than rounds) when scaling up.
+ if (zoomFactor > 1)
+ value++;
+ return static_cast<int>(value / zoomFactor);
+}
+
+inline void adjustIntRectForAbsoluteZoom(IntRect& rect, RenderObject* renderer)
+{
+ rect.setX(adjustForAbsoluteZoom(rect.x(), renderer));
+ rect.setY(adjustForAbsoluteZoom(rect.y(), renderer));
+ rect.setWidth(adjustForAbsoluteZoom(rect.width(), renderer));
+ rect.setHeight(adjustForAbsoluteZoom(rect.height(), renderer));
+}
+
+inline FloatPoint adjustFloatPointForAbsoluteZoom(const FloatPoint& point, RenderObject* renderer)
+{
+ // The result here is in floats, so we don't need the truncation hack from the integer version above.
+ float zoomFactor = renderer->style()->effectiveZoom();
+ if (zoomFactor == 1)
+ return point;
+ return FloatPoint(point.x() / zoomFactor, point.y() / zoomFactor);
+}
+
+inline void adjustFloatQuadForAbsoluteZoom(FloatQuad& quad, RenderObject* renderer)
+{
+ quad.setP1(adjustFloatPointForAbsoluteZoom(quad.p1(), renderer));
+ quad.setP2(adjustFloatPointForAbsoluteZoom(quad.p2(), renderer));
+ quad.setP3(adjustFloatPointForAbsoluteZoom(quad.p3(), renderer));
+ quad.setP4(adjustFloatPointForAbsoluteZoom(quad.p4(), renderer));
+}
+
} // namespace WebCore
#ifndef NDEBUG
// Outside the WebCore namespace for ease of invocation from gdb.
void showTree(const WebCore::RenderObject*);
+void showRenderTree(const WebCore::RenderObject* object1);
+// We don't make object2 an optional parameter so that showRenderTree
+// can be called from gdb easily.
+void showRenderTree(const WebCore::RenderObject* object1, const WebCore::RenderObject* object2);
#endif
#endif // RenderObject_h
diff --git a/WebCore/rendering/RenderObjectChildList.cpp b/WebCore/rendering/RenderObjectChildList.cpp
index 23ab98f..d56a015 100644
--- a/WebCore/rendering/RenderObjectChildList.cpp
+++ b/WebCore/rendering/RenderObjectChildList.cpp
@@ -271,24 +271,29 @@ static RenderObject* findBeforeAfterParent(RenderObject* object)
return beforeAfterParent;
}
-static void invalidateCountersInContainer(RenderObject* container)
+static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier)
{
if (!container)
return;
container = findBeforeAfterParent(container);
if (!container)
return;
+ // Sometimes the counter is attached directly on the container.
+ if (container->isCounter()) {
+ toRenderCounter(container)->invalidate(identifier);
+ return;
+ }
for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
if (content->isCounter())
- toRenderCounter(content)->invalidate();
+ toRenderCounter(content)->invalidate(identifier);
}
}
-void RenderObjectChildList::invalidateCounters(RenderObject* owner)
+void RenderObjectChildList::invalidateCounters(RenderObject* owner, const AtomicString& identifier)
{
ASSERT(!owner->documentBeingDestroyed());
- invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE));
- invalidateCountersInContainer(beforeAfterContainer(owner, AFTER));
+ invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE), identifier);
+ invalidateCountersInContainer(beforeAfterContainer(owner, AFTER), identifier);
}
void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject)
@@ -369,9 +374,11 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo
RefPtr<RenderStyle> style = RenderStyle::create();
style->inheritFrom(pseudoElementStyle);
genChild->setStyle(style.release());
- } else
- // Must be a first-letter container. updateFirstLetter() will take care of it.
- ASSERT(genChild->style()->styleType() == FIRST_LETTER);
+ } else {
+ // RenderListItem may insert a list marker here. We do not need to care about this case.
+ // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
+ ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
+ }
}
}
return; // We've updated the generated content. That's all we needed to do.
diff --git a/WebCore/rendering/RenderObjectChildList.h b/WebCore/rendering/RenderObjectChildList.h
index bf8800a..ba73c50 100644
--- a/WebCore/rendering/RenderObjectChildList.h
+++ b/WebCore/rendering/RenderObjectChildList.h
@@ -30,6 +30,7 @@
namespace WebCore {
+class AtomicString;
class RenderObject;
class RenderObjectChildList {
@@ -55,7 +56,7 @@ public:
void insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* before, bool fullInsert = true);
void updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject = 0);
- void invalidateCounters(RenderObject* owner);
+ void invalidateCounters(RenderObject* owner, const AtomicString& identifier);
private:
RenderObject* m_firstChild;
diff --git a/WebCore/rendering/RenderOverflow.h b/WebCore/rendering/RenderOverflow.h
new file mode 100644
index 0000000..253a672
--- /dev/null
+++ b/WebCore/rendering/RenderOverflow.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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
+ * 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 RenderOverflow_h
+#define RenderOverflow_h
+
+#include "IntRect.h"
+
+namespace WebCore
+{
+// RenderOverflow is a class for tracking content that spills out of a box. This class is used by RenderBox and
+// InlineFlowBox.
+//
+// There are two types of overflow: layout overflow (which is expected to be reachable via scrolling mechanisms) and
+// visual overflow (which is not expected to be reachable via scrolling mechanisms).
+//
+// Layout overflow examples include other boxes that spill out of our box, For example, in the inline case a tall image
+// could spill out of a line box.
+
+// Examples of visual overflow are shadows, text stroke (and eventually outline and border-image).
+
+// This object is allocated only when some of these fields have non-default values in the owning box.
+class RenderOverflow : public Noncopyable {
+public:
+ RenderOverflow(const IntRect& defaultRect = IntRect())
+ : m_topLayoutOverflow(defaultRect.y())
+ , m_bottomLayoutOverflow(defaultRect.bottom())
+ , m_leftLayoutOverflow(defaultRect.x())
+ , m_rightLayoutOverflow(defaultRect.right())
+ , m_topVisualOverflow(defaultRect.y())
+ , m_bottomVisualOverflow(defaultRect.bottom())
+ , m_leftVisualOverflow(defaultRect.x())
+ , m_rightVisualOverflow(defaultRect.right())
+ {
+ }
+
+ int topLayoutOverflow() const { return m_topLayoutOverflow; }
+ int bottomLayoutOverflow() const { return m_bottomLayoutOverflow; }
+ int leftLayoutOverflow() const { return m_leftLayoutOverflow; }
+ int rightLayoutOverflow() const { return m_rightLayoutOverflow; }
+ IntRect layoutOverflowRect() const;
+
+ int topVisualOverflow() const { return m_topVisualOverflow; }
+ int bottomVisualOverflow() const { return m_bottomVisualOverflow; }
+ int leftVisualOverflow() const { return m_leftVisualOverflow; }
+ int rightVisualOverflow() const { return m_rightVisualOverflow; }
+ IntRect visualOverflowRect() const;
+
+ IntRect visibleOverflowRect() const;
+
+ void setTopLayoutOverflow(int overflow) { m_topLayoutOverflow = overflow; }
+ void setBottomLayoutOverflow(int overflow) { m_bottomLayoutOverflow = overflow; }
+ void setLeftLayoutOverflow(int overflow) { m_leftLayoutOverflow = overflow; }
+ void setRightLayoutOverflow(int overflow) { m_rightLayoutOverflow = overflow; }
+
+ void setTopVisualOverflow(int overflow) { m_topVisualOverflow = overflow; }
+ void setBottomVisualOverflow(int overflow) { m_bottomVisualOverflow = overflow; }
+ void setLeftVisualOverflow(int overflow) { m_leftVisualOverflow = overflow; }
+ void setRightVisualOverflow(int overflow) { m_rightVisualOverflow = overflow; }
+
+ void move(int dx, int dy);
+
+ void addLayoutOverflow(const IntRect&);
+ void addVisualOverflow(const IntRect&);
+
+ void resetLayoutOverflow(const IntRect& defaultRect);
+
+private:
+ int m_topLayoutOverflow;
+ int m_bottomLayoutOverflow;
+ int m_leftLayoutOverflow;
+ int m_rightLayoutOverflow;
+
+ int m_topVisualOverflow;
+ int m_bottomVisualOverflow;
+ int m_leftVisualOverflow;
+ int m_rightVisualOverflow;
+};
+
+inline IntRect RenderOverflow::layoutOverflowRect() const
+{
+ return IntRect(m_leftLayoutOverflow, m_topLayoutOverflow, m_rightLayoutOverflow - m_leftLayoutOverflow, m_bottomLayoutOverflow - m_topLayoutOverflow);
+}
+
+inline IntRect RenderOverflow::visualOverflowRect() const
+{
+ return IntRect(m_leftVisualOverflow, m_topVisualOverflow, m_rightVisualOverflow - m_leftVisualOverflow, m_bottomVisualOverflow - m_topVisualOverflow);
+}
+
+inline IntRect RenderOverflow::visibleOverflowRect() const
+{
+ IntRect combinedRect(layoutOverflowRect());
+ combinedRect.unite(visualOverflowRect());
+ return combinedRect;
+}
+
+inline void RenderOverflow::move(int dx, int dy)
+{
+ m_topLayoutOverflow += dy;
+ m_bottomLayoutOverflow += dy;
+ m_leftLayoutOverflow += dx;
+ m_rightLayoutOverflow += dx;
+
+ m_topVisualOverflow += dy;
+ m_bottomVisualOverflow += dy;
+ m_leftVisualOverflow += dx;
+ m_rightVisualOverflow += dx;
+}
+
+inline void RenderOverflow::addLayoutOverflow(const IntRect& rect)
+{
+ m_topLayoutOverflow = std::min(rect.y(), m_topLayoutOverflow);
+ m_bottomLayoutOverflow = std::max(rect.bottom(), m_bottomLayoutOverflow);
+ m_leftLayoutOverflow = std::min(rect.x(), m_leftLayoutOverflow);
+ m_rightLayoutOverflow = std::max(rect.right(), m_rightLayoutOverflow);
+}
+
+inline void RenderOverflow::addVisualOverflow(const IntRect& rect)
+{
+ m_topVisualOverflow = std::min(rect.y(), m_topVisualOverflow);
+ m_bottomVisualOverflow = std::max(rect.bottom(), m_bottomVisualOverflow);
+ m_leftVisualOverflow = std::min(rect.x(), m_leftVisualOverflow);
+ m_rightVisualOverflow = std::max(rect.right(), m_rightVisualOverflow);
+}
+
+inline void RenderOverflow::resetLayoutOverflow(const IntRect& rect)
+{
+ m_topLayoutOverflow = rect.y();
+ m_bottomLayoutOverflow = rect.bottom();
+ m_leftLayoutOverflow = rect.x();
+ m_rightLayoutOverflow = rect.right();
+}
+
+} // namespace WebCore
+
+#endif // RenderOverflow_h
diff --git a/WebCore/rendering/RenderPart.cpp b/WebCore/rendering/RenderPart.cpp
index cb56c0c..5c4a6ec 100644
--- a/WebCore/rendering/RenderPart.cpp
+++ b/WebCore/rendering/RenderPart.cpp
@@ -31,6 +31,7 @@ namespace WebCore {
RenderPart::RenderPart(Element* node)
: RenderWidget(node)
+ , m_hasFallbackContent(false)
{
// init RenderObject attributes
setInline(false);
diff --git a/WebCore/rendering/RenderPart.h b/WebCore/rendering/RenderPart.h
index 08abf99..8303543 100644
--- a/WebCore/rendering/RenderPart.h
+++ b/WebCore/rendering/RenderPart.h
@@ -27,6 +27,10 @@
namespace WebCore {
+// Renderer for frames via RenderPartObject, and plug-ins via RenderEmbeddedObject.
+
+// FIXME: This class is subclassed in RenderPartObject for iframes, which is in turn
+// subclassed in RenderEmbeddedObject for object and embed. This class itself could be removed.
class RenderPart : public RenderWidget {
public:
RenderPart(Element*);
diff --git a/WebCore/rendering/RenderPartObject.cpp b/WebCore/rendering/RenderPartObject.cpp
index 72298c6..617c8bf 100644
--- a/WebCore/rendering/RenderPartObject.cpp
+++ b/WebCore/rendering/RenderPartObject.cpp
@@ -33,8 +33,8 @@
#include "HTMLParamElement.h"
#include "MIMETypeRegistry.h"
#include "Page.h"
-#include "PluginData.h"
#include "RenderView.h"
+#include "RenderWidgetProtector.h"
#include "Text.h"
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
@@ -48,300 +48,6 @@ using namespace HTMLNames;
RenderPartObject::RenderPartObject(Element* element)
: RenderPart(element)
{
- // init RenderObject attributes
- setInline(true);
- m_hasFallbackContent = false;
-
- if (element->hasTagName(embedTag) || element->hasTagName(objectTag))
- view()->frameView()->setIsVisuallyNonEmpty();
-}
-
-RenderPartObject::~RenderPartObject()
-{
- if (frameView())
- frameView()->removeWidgetToUpdate(this);
-}
-
-static bool isURLAllowed(Document* doc, const String& url)
-{
- if (doc->frame()->page()->frameCount() >= 200)
- return false;
-
- // We allow one level of self-reference because some sites depend on that.
- // But we don't allow more than one.
- KURL completeURL = doc->completeURL(url);
- bool foundSelfReference = false;
- for (Frame* frame = doc->frame(); frame; frame = frame->tree()->parent()) {
- if (equalIgnoringFragmentIdentifier(frame->loader()->url(), completeURL)) {
- if (foundSelfReference)
- return false;
- foundSelfReference = true;
- }
- }
- return true;
-}
-
-typedef HashMap<String, String, CaseFoldingHash> ClassIdToTypeMap;
-
-static ClassIdToTypeMap* createClassIdToTypeMap()
-{
- ClassIdToTypeMap* map = new ClassIdToTypeMap;
- map->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash");
- map->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin");
- map->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime");
- map->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director");
-#if ENABLE(ACTIVEX_TYPE_CONVERSION_WMPLAYER)
- map->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2");
- map->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2");
-#endif
- return map;
-}
-
-static const String& activeXType()
-{
- DEFINE_STATIC_LOCAL(String, activeXType, ("application/x-oleobject"));
- return activeXType;
-}
-
-static inline bool havePlugin(const PluginData* pluginData, const String& type)
-{
- return pluginData && !type.isEmpty() && pluginData->supportsMimeType(type);
-}
-
-static String serviceTypeForClassId(const String& classId, const PluginData* pluginData)
-{
- // Return early if classId is empty (since we won't do anything below).
- // Furthermore, if classId is null, calling get() below will crash.
- if (classId.isEmpty())
- return String();
-
- static ClassIdToTypeMap* map = createClassIdToTypeMap();
- String type = map->get(classId);
-
- // If we do have a plug-in that supports generic ActiveX content and don't have a plug-in
- // for the MIME type we came up with, ignore the MIME type we came up with and just use
- // the ActiveX type.
- if (havePlugin(pluginData, activeXType()) && !havePlugin(pluginData, type))
- return activeXType();
-
- return type;
-}
-
-static inline bool shouldUseEmbedDescendant(HTMLObjectElement* objectElement, const PluginData* pluginData)
-{
-#if PLATFORM(MAC)
- UNUSED_PARAM(objectElement);
- UNUSED_PARAM(pluginData);
- // On Mac, we always want to use the embed descendant.
- return true;
-#else
- // If we have both an <object> and <embed>, we always want to use the <embed> except when we have
- // an ActiveX plug-in and plan to use it.
- return !(havePlugin(pluginData, activeXType())
- && serviceTypeForClassId(objectElement->classId(), pluginData) == activeXType());
-#endif
-}
-
-static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues)
-{
- // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP
- // require "src" attribute).
- int srcIndex = -1, dataIndex = -1;
- for (unsigned int i = 0; i < paramNames->size(); ++i) {
- if (equalIgnoringCase((*paramNames)[i], "src"))
- srcIndex = i;
- else if (equalIgnoringCase((*paramNames)[i], "data"))
- dataIndex = i;
- }
-
- if (srcIndex == -1 && dataIndex != -1) {
- paramNames->append("src");
- paramValues->append((*paramValues)[dataIndex]);
- }
-}
-
-void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins)
-{
- String url;
- String serviceType;
- Vector<String> paramNames;
- Vector<String> paramValues;
- Frame* frame = frameView()->frame();
-
- if (node()->hasTagName(objectTag)) {
- HTMLObjectElement* o = static_cast<HTMLObjectElement*>(node());
-
- o->setNeedWidgetUpdate(false);
- if (!o->isFinishedParsingChildren())
- return;
-
- // Check for a child EMBED tag.
- HTMLEmbedElement* embed = 0;
- const PluginData* pluginData = frame->page()->pluginData();
- if (shouldUseEmbedDescendant(o, pluginData)) {
- for (Node* child = o->firstChild(); child; ) {
- if (child->hasTagName(embedTag)) {
- embed = static_cast<HTMLEmbedElement*>(child);
- break;
- } else if (child->hasTagName(objectTag))
- child = child->nextSibling(); // Don't descend into nested OBJECT tags
- else
- child = child->traverseNextNode(o); // Otherwise descend (EMBEDs may be inside COMMENT tags)
- }
- }
-
- // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT.
- HTMLElement *embedOrObject;
- if (embed) {
- embedOrObject = (HTMLElement *)embed;
- url = embed->url();
- serviceType = embed->serviceType();
- } else
- embedOrObject = (HTMLElement *)o;
-
- // If there was no URL or type defined in EMBED, try the OBJECT tag.
- if (url.isEmpty())
- url = o->url();
- if (serviceType.isEmpty())
- serviceType = o->serviceType();
-
- HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
-
- // Scan the PARAM children.
- // Get the URL and type from the params if we don't already have them.
- // Get the attributes from the params if there is no EMBED tag.
- Node *child = o->firstChild();
- while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) {
- if (child->hasTagName(paramTag)) {
- HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
- String name = p->name();
- if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
- url = p->value();
- if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
- serviceType = p->value();
- int pos = serviceType.find(";");
- if (pos != -1)
- serviceType = serviceType.left(pos);
- }
- if (!embed && !name.isEmpty()) {
- uniqueParamNames.add(name.impl());
- paramNames.append(p->name());
- paramValues.append(p->value());
- }
- }
- child = child->nextSibling();
- }
-
- // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
- // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
- // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
- // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
- // else our Java plugin will misinterpret it. [4004531]
- String codebase;
- if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
- codebase = "codebase";
- uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
- }
-
- // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values.
- NamedNodeMap* attributes = embedOrObject->attributes();
- if (attributes) {
- for (unsigned i = 0; i < attributes->length(); ++i) {
- Attribute* it = attributes->attributeItem(i);
- const AtomicString& name = it->name().localName();
- if (embed || !uniqueParamNames.contains(name.impl())) {
- paramNames.append(name.string());
- paramValues.append(it->value().string());
- }
- }
- }
-
- mapDataParamToSrc(&paramNames, &paramValues);
-
- // If we still don't have a type, try to map from a specific CLASSID to a type.
- if (serviceType.isEmpty())
- serviceType = serviceTypeForClassId(o->classId(), pluginData);
-
- if (!isURLAllowed(document(), url))
- return;
-
- // Find out if we support fallback content.
- m_hasFallbackContent = false;
- for (Node *child = o->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) {
- if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) || // Discount <embed> and <param>
- (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace()))
- m_hasFallbackContent = true;
- }
-
- if (onlyCreateNonNetscapePlugins) {
- KURL completedURL;
- if (!url.isEmpty())
- completedURL = frame->loader()->completeURL(url);
-
- if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
- return;
- }
-
- bool success = frame->loader()->requestObject(this, url, AtomicString(o->name()), serviceType, paramNames, paramValues);
- if (!success && m_hasFallbackContent)
- o->renderFallbackContent();
- } else if (node()->hasTagName(embedTag)) {
- HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(node());
- o->setNeedWidgetUpdate(false);
- url = o->url();
- serviceType = o->serviceType();
-
- if (url.isEmpty() && serviceType.isEmpty())
- return;
- if (!isURLAllowed(document(), url))
- return;
-
- // add all attributes set on the embed object
- NamedNodeMap* a = o->attributes();
- if (a) {
- for (unsigned i = 0; i < a->length(); ++i) {
- Attribute* it = a->attributeItem(i);
- paramNames.append(it->name().localName().string());
- paramValues.append(it->value().string());
- }
- }
-
- if (onlyCreateNonNetscapePlugins) {
- KURL completedURL;
- if (!url.isEmpty())
- completedURL = frame->loader()->completeURL(url);
-
- if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
- return;
-
- }
-
- frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues);
- }
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- else if (node()->hasTagName(videoTag) || node()->hasTagName(audioTag)) {
- HTMLMediaElement* o = static_cast<HTMLMediaElement*>(node());
-
- o->setNeedWidgetUpdate(false);
- if (node()->hasTagName(videoTag)) {
- HTMLVideoElement* vid = static_cast<HTMLVideoElement*>(node());
- String poster = vid->poster();
- if (!poster.isEmpty()) {
- paramNames.append("_media_element_poster_");
- paramValues.append(poster);
- }
- }
-
- url = o->initialURL();
- if (!url.isEmpty()) {
- paramNames.append("_media_element_src_");
- paramValues.append(url);
- }
-
- serviceType = "application/x-media-element-proxy-plugin";
- frame->loader()->requestObject(this, url, nullAtom, serviceType, paramNames, paramValues);
- }
-#endif
}
void RenderPartObject::layout()
@@ -351,10 +57,15 @@ void RenderPartObject::layout()
#ifdef FLATTEN_IFRAME
RenderPart::calcWidth();
RenderPart::calcHeight();
+ // Calculate the styled dimensions by subtracting the border and padding.
+ int extraWidth = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+ int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom();
+ int styleWidth = width() - extraWidth;
+ int styleHeight = height() - extraHeight;
// Some IFrames have a width and/or height of 1 when they are meant to be
// hidden. If that is the case, do not try to expand.
- if (node()->hasTagName(iframeTag) && widget() && widget()->isFrameView()
- && width() > 1 && height() > 1) {
+ if (node()->hasTagName(iframeTag) && widget() && widget()->isFrameView() &&
+ styleWidth > 1 && styleHeight > 1) {
HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(node());
bool scrolling = element->scrollingMode() != ScrollbarAlwaysOff;
bool widthIsFixed = style()->width().isFixed();
@@ -365,15 +76,11 @@ void RenderPartObject::layout()
if (scrolling || !widthIsFixed || !heightIsFixed) {
FrameView* view = static_cast<FrameView*>(widget());
RenderView* root = view ? view->frame()->contentRenderer() : NULL;
- RenderPart* owner = view->frame()->ownerRenderer();
- if (root && style()->visibility() != HIDDEN
- && (!owner || owner->style()->visibility() != HIDDEN)) {
+ if (root && style()->visibility() != HIDDEN) {
// Update the dimensions to get the correct minimum preferred
// width
updateWidgetPosition();
- int extraWidth = paddingLeft() + paddingRight() + borderLeft() + borderRight();
- int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom();
// Use the preferred width if it is larger and only if
// scrollbars are visible or the width style is not fixed.
if (scrolling || !widthIsFixed)
@@ -406,6 +113,10 @@ void RenderPartObject::layout()
// Update one last time
updateWidgetPosition();
+ // Layout one more time to ensure all objects have the correct
+ // height.
+ view->layout();
+
#if !ASSERT_DISABLED
ASSERT(!view->layoutPending());
ASSERT(!root->needsLayout());
@@ -415,9 +126,6 @@ void RenderPartObject::layout()
ASSERT(!c->needsLayout());
c = c->nextInPreOrder();
}
- Node* body = document()->body();
- if (body)
- ASSERT(!body->renderer()->needsLayout());
#endif
}
}
@@ -427,12 +135,10 @@ void RenderPartObject::layout()
calcHeight();
#endif
- adjustOverflowForBoxShadowAndReflect();
-
RenderPart::layout();
- if (!widget() && frameView())
- frameView()->addWidgetToUpdate(this);
+ m_overflow.clear();
+ addShadowOverflow();
setNeedsLayout(false);
}
diff --git a/WebCore/rendering/RenderPartObject.h b/WebCore/rendering/RenderPartObject.h
index 092395d..1175a31 100644
--- a/WebCore/rendering/RenderPartObject.h
+++ b/WebCore/rendering/RenderPartObject.h
@@ -27,20 +27,20 @@
namespace WebCore {
+// Renderer for iframes. Is subclassed in RenderEmbeddedObject for object and embed.
class RenderPartObject : public RenderPart {
public:
RenderPartObject(Element*);
- virtual ~RenderPartObject();
-
- void updateWidget(bool onlyCreateNonNetscapePlugins);
-
-private:
- virtual const char* renderName() const { return "RenderPartObject"; }
#ifdef FLATTEN_IFRAME
+protected:
virtual void calcWidth();
virtual void calcHeight();
#endif
+
+private:
+ virtual const char* renderName() const { return "RenderPartObject"; }
+
virtual void layout();
virtual void viewCleared();
diff --git a/WebCore/rendering/RenderPath.cpp b/WebCore/rendering/RenderPath.cpp
index 4a7662f..7dbde42 100644
--- a/WebCore/rendering/RenderPath.cpp
+++ b/WebCore/rendering/RenderPath.cpp
@@ -3,6 +3,7 @@
2004, 2005, 2008 Rob Buis <buis@kde.org>
2005, 2007 Eric Seidel <eric@webkit.org>
2009 Google, Inc.
+ 2009 Dirk Schulze <krit@webkit.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -68,12 +69,12 @@ RenderPath::RenderPath(SVGStyledTransformableElement* node)
{
}
-TransformationMatrix RenderPath::localToParentTransform() const
+const AffineTransform& RenderPath::localToParentTransform() const
{
return m_localTransform;
}
-TransformationMatrix RenderPath::localTransform() const
+AffineTransform RenderPath::localTransform() const
{
return m_localTransform;
}
@@ -112,6 +113,34 @@ FloatRect RenderPath::objectBoundingBox() const
return m_cachedLocalFillBBox;
}
+FloatRect RenderPath::strokeBoundingBox() const
+{
+ if (m_path.isEmpty())
+ return FloatRect();
+
+ if (!m_cachedLocalStrokeBBox.isEmpty())
+ return m_cachedLocalStrokeBBox;
+
+ m_cachedLocalStrokeBBox = objectBoundingBox();
+ if (style()->svgStyle()->hasStroke()) {
+ BoundingRectStrokeStyleApplier strokeStyle(this, style());
+ m_cachedLocalStrokeBBox.unite(m_path.strokeBoundingRect(&strokeStyle));
+ }
+
+ return m_cachedLocalStrokeBBox;
+}
+
+FloatRect RenderPath::markerBoundingBox() const
+{
+ if (m_path.isEmpty())
+ return FloatRect();
+
+ if (m_cachedLocalMarkerBBox.isEmpty())
+ calculateMarkerBoundsIfNeeded();
+
+ return m_cachedLocalMarkerBBox;
+}
+
FloatRect RenderPath::repaintRectInLocalCoordinates() const
{
if (m_path.isEmpty())
@@ -121,16 +150,25 @@ FloatRect RenderPath::repaintRectInLocalCoordinates() const
if (!m_cachedLocalRepaintRect.isEmpty())
return m_cachedLocalRepaintRect;
- if (!style()->svgStyle()->hasStroke())
- m_cachedLocalRepaintRect = objectBoundingBox();
+ // FIXME: We need to be careful here. We assume that there is no filter,
+ // clipper, marker or masker if the rects are empty.
+ FloatRect rect = filterBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect = rect;
else {
- BoundingRectStrokeStyleApplier strokeStyle(this, style());
- m_cachedLocalRepaintRect = m_path.strokeBoundingRect(&strokeStyle);
+ m_cachedLocalRepaintRect = strokeBoundingBox();
+ m_cachedLocalRepaintRect.unite(markerBoundingBox());
}
- // Markers and filters can paint outside of the stroke path
- m_cachedLocalRepaintRect.unite(m_markerBounds);
- m_cachedLocalRepaintRect.unite(filterBoundingBoxForRenderer(this));
+ rect = clipperBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect.intersect(rect);
+
+ rect = maskerBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect.intersect(rect);
+
+ style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect);
return m_cachedLocalRepaintRect;
}
@@ -139,12 +177,9 @@ void RenderPath::setPath(const Path& newPath)
{
m_path = newPath;
m_cachedLocalRepaintRect = FloatRect();
+ m_cachedLocalStrokeBBox = FloatRect();
m_cachedLocalFillBBox = FloatRect();
-}
-
-const Path& RenderPath::path() const
-{
- return m_path;
+ m_cachedLocalMarkerBBox = FloatRect();
}
void RenderPath::layout()
@@ -180,39 +215,48 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int)
{
if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || m_path.isEmpty())
return;
-
- paintInfo.context->save();
- paintInfo.context->concatCTM(localToParentTransform());
-
- SVGResourceFilter* filter = 0;
FloatRect boundingBox = repaintRectInLocalCoordinates();
- if (paintInfo.phase == PaintPhaseForeground) {
- PaintInfo savedInfo(paintInfo);
+ FloatRect nonLocalBoundingBox = m_localTransform.mapRect(boundingBox);
+ // FIXME: The empty rect check is to deal with incorrect initial clip in renderSubtreeToImage
+ // unfortunately fixing that problem is fairly complex unless we were willing to just futz the
+ // rect to something "close enough"
+ if (!nonLocalBoundingBox.intersects(paintInfo.rect) && !paintInfo.rect.isEmpty())
+ return;
+
+ PaintInfo childPaintInfo(paintInfo);
+ childPaintInfo.context->save();
+ applyTransformToPaintInfo(childPaintInfo, m_localTransform);
+ SVGResourceFilter* filter = 0;
- prepareToRenderSVGContent(this, paintInfo, boundingBox, filter);
- if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES)
- paintInfo.context->setShouldAntialias(false);
- fillAndStrokePath(m_path, paintInfo.context, style(), this);
+ if (childPaintInfo.phase == PaintPhaseForeground) {
+ PaintInfo savedInfo(childPaintInfo);
- if (static_cast<SVGStyledElement*>(node())->supportsMarkers())
- m_markerBounds = drawMarkersIfNeeded(paintInfo.context, paintInfo.rect, m_path);
+ if (prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter)) {
+ if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES)
+ childPaintInfo.context->setShouldAntialias(false);
+ fillAndStrokePath(m_path, childPaintInfo.context, style(), this);
- finishRenderSVGContent(this, paintInfo, filter, savedInfo.context);
+ if (static_cast<SVGStyledElement*>(node())->supportsMarkers())
+ m_markerLayoutInfo.drawMarkers(childPaintInfo);
+ }
+ finishRenderSVGContent(this, childPaintInfo, filter, savedInfo.context);
}
- if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth())
- paintOutline(paintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()),
+ if ((childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth())
+ paintOutline(childPaintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()),
static_cast<int>(boundingBox.width()), static_cast<int>(boundingBox.height()), style());
- paintInfo.context->restore();
+ childPaintInfo.context->restore();
}
// This method is called from inside paintOutline() since we call paintOutline()
// while transformed to our coord system, return local coords
-void RenderPath::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+void RenderPath::addFocusRingRects(Vector<IntRect>& rects, int, int)
{
- graphicsContext->addFocusRingRect(enclosingIntRect(repaintRectInLocalCoordinates()));
+ IntRect rect = enclosingIntRect(repaintRectInLocalCoordinates());
+ if (!rect.isEmpty())
+ rects.append(rect);
}
bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
@@ -221,7 +265,7 @@ bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result,
if (hitTestAction != HitTestForeground)
return false;
- FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
+ FloatPoint localPoint = m_localTransform.inverse().mapPoint(pointInParent);
PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_PATH_HITTESTING, style()->pointerEvents());
@@ -237,143 +281,27 @@ bool RenderPath::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result,
return false;
}
-enum MarkerType {
- Start,
- Mid,
- End
-};
-
-struct MarkerData {
- FloatPoint origin;
- FloatPoint subpathStart;
- double strokeWidth;
- FloatPoint inslopePoints[2];
- FloatPoint outslopePoints[2];
- MarkerType type;
- SVGResourceMarker* marker;
-};
-
-struct DrawMarkersData {
- DrawMarkersData(GraphicsContext*, SVGResourceMarker* startMarker, SVGResourceMarker* midMarker, double strokeWidth);
- GraphicsContext* context;
- int elementIndex;
- MarkerData previousMarkerData;
- SVGResourceMarker* midMarker;
-};
-
-DrawMarkersData::DrawMarkersData(GraphicsContext* c, SVGResourceMarker *start, SVGResourceMarker *mid, double strokeWidth)
- : context(c)
- , elementIndex(0)
- , midMarker(mid)
-{
- previousMarkerData.origin = FloatPoint();
- previousMarkerData.subpathStart = FloatPoint();
- previousMarkerData.strokeWidth = strokeWidth;
- previousMarkerData.marker = start;
- previousMarkerData.type = Start;
-}
-
-static void drawMarkerWithData(GraphicsContext* context, MarkerData &data)
-{
- if (!data.marker)
- return;
-
- FloatPoint inslopeChange = data.inslopePoints[1] - FloatSize(data.inslopePoints[0].x(), data.inslopePoints[0].y());
- FloatPoint outslopeChange = data.outslopePoints[1] - FloatSize(data.outslopePoints[0].x(), data.outslopePoints[0].y());
-
- double inslope = rad2deg(atan2(inslopeChange.y(), inslopeChange.x()));
- double outslope = rad2deg(atan2(outslopeChange.y(), outslopeChange.x()));
-
- double angle = 0.0;
- switch (data.type) {
- case Start:
- angle = outslope;
- break;
- case Mid:
- angle = (inslope + outslope) / 2;
- break;
- case End:
- angle = inslope;
- }
-
- data.marker->draw(context, FloatRect(), data.origin.x(), data.origin.y(), data.strokeWidth, angle);
-}
-
-static inline void updateMarkerDataForElement(MarkerData& previousMarkerData, const PathElement* element)
-{
- FloatPoint* points = element->points;
-
- switch (element->type) {
- case PathElementAddQuadCurveToPoint:
- // TODO
- previousMarkerData.origin = points[1];
- break;
- case PathElementAddCurveToPoint:
- previousMarkerData.inslopePoints[0] = points[1];
- previousMarkerData.inslopePoints[1] = points[2];
- previousMarkerData.origin = points[2];
- break;
- case PathElementMoveToPoint:
- previousMarkerData.subpathStart = points[0];
- case PathElementAddLineToPoint:
- previousMarkerData.inslopePoints[0] = previousMarkerData.origin;
- previousMarkerData.inslopePoints[1] = points[0];
- previousMarkerData.origin = points[0];
- break;
- case PathElementCloseSubpath:
- previousMarkerData.inslopePoints[0] = previousMarkerData.origin;
- previousMarkerData.inslopePoints[1] = points[0];
- previousMarkerData.origin = previousMarkerData.subpathStart;
- previousMarkerData.subpathStart = FloatPoint();
- }
-}
-
-static void drawStartAndMidMarkers(void* info, const PathElement* element)
-{
- DrawMarkersData& data = *reinterpret_cast<DrawMarkersData*>(info);
-
- int elementIndex = data.elementIndex;
- MarkerData& previousMarkerData = data.previousMarkerData;
-
- FloatPoint* points = element->points;
-
- // First update the outslope for the previous element
- previousMarkerData.outslopePoints[0] = previousMarkerData.origin;
- previousMarkerData.outslopePoints[1] = points[0];
-
- // Draw the marker for the previous element
- if (elementIndex != 0)
- drawMarkerWithData(data.context, previousMarkerData);
-
- // Update our marker data for this element
- updateMarkerDataForElement(previousMarkerData, element);
-
- if (elementIndex == 1) {
- // After drawing the start marker, switch to drawing mid markers
- previousMarkerData.marker = data.midMarker;
- previousMarkerData.type = Mid;
- }
-
- data.elementIndex++;
-}
-
-FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatRect&, const Path& path) const
+void RenderPath::calculateMarkerBoundsIfNeeded() const
{
Document* doc = document();
SVGElement* svgElement = static_cast<SVGElement*>(node());
- ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
+ ASSERT(svgElement && svgElement->document());
+ if (!svgElement->isStyled())
+ return;
SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement);
- const SVGRenderStyle* svgStyle = style()->svgStyle();
+ if (!styledElement->supportsMarkers())
+ return;
+ const SVGRenderStyle* svgStyle = style()->svgStyle();
AtomicString startMarkerId(svgStyle->startMarker());
AtomicString midMarkerId(svgStyle->midMarker());
AtomicString endMarkerId(svgStyle->endMarker());
- SVGResourceMarker* startMarker = getMarkerById(doc, startMarkerId);
- SVGResourceMarker* midMarker = getMarkerById(doc, midMarkerId);
- SVGResourceMarker* endMarker = getMarkerById(doc, endMarkerId);
+ SVGResourceMarker* startMarker = getMarkerById(doc, startMarkerId, this);
+ SVGResourceMarker* midMarker = getMarkerById(doc, midMarkerId, this);
+ SVGResourceMarker* endMarker = getMarkerById(doc, endMarkerId, this);
if (!startMarker && !startMarkerId.isEmpty())
svgElement->document()->accessSVGExtensions()->addPendingResource(startMarkerId, styledElement);
@@ -391,32 +319,10 @@ FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatR
endMarker->addClient(styledElement);
if (!startMarker && !midMarker && !endMarker)
- return FloatRect();
-
- double strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f);
- DrawMarkersData data(context, startMarker, midMarker, strokeWidth);
-
- path.apply(&data, drawStartAndMidMarkers);
-
- data.previousMarkerData.marker = endMarker;
- data.previousMarkerData.type = End;
- drawMarkerWithData(context, data.previousMarkerData);
-
- // We know the marker boundaries, only after they're drawn!
- // Otherwhise we'd need to do all the marker calculation twice
- // once here (through paint()) and once in absoluteClippedOverflowRect().
- FloatRect bounds;
-
- if (startMarker)
- bounds.unite(startMarker->cachedBounds());
-
- if (midMarker)
- bounds.unite(midMarker->cachedBounds());
-
- if (endMarker)
- bounds.unite(endMarker->cachedBounds());
+ return;
- return bounds;
+ float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f);
+ m_cachedLocalMarkerBBox = m_markerLayoutInfo.calculateBoundaries(startMarker, midMarker, endMarker, strokeWidth, m_path);
}
}
diff --git a/WebCore/rendering/RenderPath.h b/WebCore/rendering/RenderPath.h
index 2ff179e..d530f3c 100644
--- a/WebCore/rendering/RenderPath.h
+++ b/WebCore/rendering/RenderPath.h
@@ -25,10 +25,10 @@
#define RenderPath_h
#if ENABLE(SVG)
-
+#include "AffineTransform.h"
#include "FloatRect.h"
#include "RenderSVGModelObject.h"
-#include "TransformationMatrix.h"
+#include "SVGMarkerLayoutInfo.h"
namespace WebCore {
@@ -40,7 +40,7 @@ class RenderPath : public RenderSVGModelObject {
public:
RenderPath(SVGStyledTransformableElement*);
- const Path& path() const;
+ const Path& path() const { return m_path; }
private:
// Hit-detection seperated for the fill and the stroke
@@ -48,9 +48,11 @@ private:
bool strokeContains(const FloatPoint&, bool requiresStroke = true) const;
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const;
+ virtual FloatRect markerBoundingBox() const;
virtual FloatRect repaintRectInLocalCoordinates() const;
- virtual TransformationMatrix localToParentTransform() const;
+ virtual const AffineTransform& localToParentTransform() const;
void setPath(const Path&);
@@ -59,20 +61,22 @@ private:
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
- FloatRect drawMarkersIfNeeded(GraphicsContext*, const FloatRect&, const Path&) const;
+ void calculateMarkerBoundsIfNeeded() const;
private:
- virtual TransformationMatrix localTransform() const;
+ virtual AffineTransform localTransform() const;
mutable Path m_path;
mutable FloatRect m_cachedLocalFillBBox;
+ mutable FloatRect m_cachedLocalStrokeBBox;
mutable FloatRect m_cachedLocalRepaintRect;
- FloatRect m_markerBounds;
- TransformationMatrix m_localTransform;
+ mutable FloatRect m_cachedLocalMarkerBBox;
+ mutable SVGMarkerLayoutInfo m_markerLayoutInfo;
+ AffineTransform m_localTransform;
};
inline RenderPath* toRenderPath(RenderObject* object)
@@ -94,5 +98,3 @@ void toRenderPath(const RenderPath*);
#endif // ENABLE(SVG)
#endif
-
-// vim:ts=4:noet
diff --git a/WebCore/rendering/RenderReplaced.cpp b/WebCore/rendering/RenderReplaced.cpp
index 692a66e..ba579df 100644
--- a/WebCore/rendering/RenderReplaced.cpp
+++ b/WebCore/rendering/RenderReplaced.cpp
@@ -34,9 +34,6 @@ using namespace std;
namespace WebCore {
-typedef WTF::HashMap<const RenderReplaced*, IntRect> OverflowRectMap;
-static OverflowRectMap* gOverflowRectMap = 0;
-
const int cDefaultWidth = 300;
const int cDefaultHeight = 150;
@@ -56,8 +53,6 @@ RenderReplaced::RenderReplaced(Node* node, const IntSize& intrinsicSize)
RenderReplaced::~RenderReplaced()
{
- if (replacedHasOverflow())
- gOverflowRectMap->remove(this);
}
void RenderReplaced::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
@@ -66,7 +61,7 @@ void RenderReplaced::styleDidChange(StyleDifference diff, const RenderStyle* old
bool hadStyle = (oldStyle != 0);
float oldZoom = hadStyle ? oldStyle->effectiveZoom() : RenderStyle::initialZoom();
- if (hadStyle && style() && style()->effectiveZoom() != oldZoom)
+ if (style() && style()->effectiveZoom() != oldZoom)
intrinsicSizeChanged();
}
@@ -77,10 +72,12 @@ void RenderReplaced::layout()
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
setHeight(minimumReplacedHeight());
-
+
calcWidth();
calcHeight();
- adjustOverflowForBoxShadowAndReflect();
+
+ m_overflow.clear();
+ addShadowOverflow();
repainter.repaintAfterLayout();
@@ -127,28 +124,36 @@ void RenderReplaced::paint(PaintInfo& paintInfo, int tx, int ty)
drawSelectionTint = false;
}
+ bool completelyClippedOut = false;
if (style()->hasBorderRadius()) {
- // Push a clip if we have a border radius, since we want to round the foreground content that gets painted.
- paintInfo.context->save();
-
- IntSize topLeft, topRight, bottomLeft, bottomRight;
IntRect borderRect = IntRect(tx, ty, width(), height());
- style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight);
- paintInfo.context->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight);
+ if (borderRect.isEmpty())
+ completelyClippedOut = true;
+ else {
+ // Push a clip if we have a border radius, since we want to round the foreground content that gets painted.
+ paintInfo.context->save();
+
+ IntSize topLeft, topRight, bottomLeft, bottomRight;
+ style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight);
+
+ paintInfo.context->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight);
+ }
}
- paintReplaced(paintInfo, tx, ty);
+ if (!completelyClippedOut) {
+ paintReplaced(paintInfo, tx, ty);
- if (style()->hasBorderRadius())
- paintInfo.context->restore();
+ if (style()->hasBorderRadius())
+ paintInfo.context->restore();
+ }
// The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of
// surrounding content.
if (drawSelectionTint) {
IntRect selectionPaintingRect = localSelectionRect();
selectionPaintingRect.move(tx, ty);
- paintInfo.context->fillRect(selectionPaintingRect, selectionBackgroundColor());
+ paintInfo.context->fillRect(selectionPaintingRect, selectionBackgroundColor(), style()->colorSpace());
}
}
@@ -169,8 +174,8 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, int& tx, int& ty)
int currentTY = ty + y();
// Early exit if the element touches the edges.
- int top = currentTY + overflowTop();
- int bottom = currentTY + overflowHeight();
+ int top = currentTY + topVisibleOverflow();
+ int bottom = currentTY + bottomVisibleOverflow();
if (isSelected() && m_inlineBoxWrapper) {
int selTop = ty + m_inlineBoxWrapper->root()->selectionTop();
int selBottom = ty + selTop + m_inlineBoxWrapper->root()->selectionHeight();
@@ -179,7 +184,7 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, int& tx, int& ty)
}
int os = 2 * maximalOutlineSize(paintInfo.phase);
- if (currentTX + overflowLeft() >= paintInfo.rect.right() + os || currentTX + overflowWidth() <= paintInfo.rect.x() - os)
+ if (currentTX + leftVisibleOverflow() >= paintInfo.rect.right() + os || currentTX + rightVisibleOverflow() <= paintInfo.rect.x() - os)
return false;
if (top >= paintInfo.rect.bottom() + os || bottom <= paintInfo.rect.y() - os)
return false;
@@ -231,8 +236,8 @@ VisiblePosition RenderReplaced::positionForPoint(const IntPoint& point)
RootInlineBox* root = box->root();
- int top = root->topOverflow();
- int bottom = root->nextRootBox() ? root->nextRootBox()->topOverflow() : root->bottomOverflow();
+ int top = root->lineTop();
+ int bottom = root->nextRootBox() ? root->nextRootBox()->lineTop() : root->lineBottom();
if (point.y() + y() < top)
return createVisiblePosition(caretMinOffset(), DOWNSTREAM); // coordinates are above
@@ -327,82 +332,6 @@ void RenderReplaced::setIntrinsicSize(const IntSize& size)
m_intrinsicSize = size;
}
-void RenderReplaced::adjustOverflowForBoxShadowAndReflect()
-{
- IntRect overflow;
- for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
- if (boxShadow->style == Inset)
- continue;
- IntRect shadow = borderBoxRect();
- shadow.move(boxShadow->x, boxShadow->y);
- shadow.inflate(boxShadow->blur + boxShadow->spread);
- overflow.unite(shadow);
- }
-
- // Now that we have an overflow rect including shadow, let's make sure that
- // the reflection (which can also include the shadow) is also included.
- if (hasReflection()) {
- if (overflow.isEmpty())
- overflow = borderBoxRect();
- overflow.unite(reflectedRect(overflow));
- }
-
- if (!overflow.isEmpty()) {
- if (!gOverflowRectMap)
- gOverflowRectMap = new OverflowRectMap();
- overflow.unite(borderBoxRect());
- gOverflowRectMap->set(this, overflow);
- setReplacedHasOverflow(true);
- } else if (replacedHasOverflow()) {
- gOverflowRectMap->remove(this);
- setReplacedHasOverflow(false);
- }
-}
-
-int RenderReplaced::overflowHeight(bool) const
-{
- if (replacedHasOverflow()) {
- IntRect *r = &gOverflowRectMap->find(this)->second;
- return r->height() + r->y();
- }
-
- return height();
-}
-
-int RenderReplaced::overflowWidth(bool) const
-{
- if (replacedHasOverflow()) {
- IntRect *r = &gOverflowRectMap->find(this)->second;
- return r->width() + r->x();
- }
-
- return width();
-}
-
-int RenderReplaced::overflowLeft(bool) const
-{
- if (replacedHasOverflow())
- return gOverflowRectMap->get(this).x();
-
- return 0;
-}
-
-int RenderReplaced::overflowTop(bool) const
-{
- if (replacedHasOverflow())
- return gOverflowRectMap->get(this).y();
-
- return 0;
-}
-
-IntRect RenderReplaced::overflowRect(bool) const
-{
- if (replacedHasOverflow())
- return gOverflowRectMap->find(this)->second;
-
- return borderBoxRect();
-}
-
IntRect RenderReplaced::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
{
if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
@@ -410,7 +339,7 @@ IntRect RenderReplaced::clippedOverflowRectForRepaint(RenderBoxModelObject* repa
// The selectionRect can project outside of the overflowRect, so take their union
// for repainting to avoid selection painting glitches.
- IntRect r = unionRect(localSelectionRect(false), overflowRect(false));
+ IntRect r = unionRect(localSelectionRect(false), visibleOverflowRect());
RenderView* v = view();
if (v) {
diff --git a/WebCore/rendering/RenderReplaced.h b/WebCore/rendering/RenderReplaced.h
index 70ad4f2..bcf565d 100644
--- a/WebCore/rendering/RenderReplaced.h
+++ b/WebCore/rendering/RenderReplaced.h
@@ -46,6 +46,7 @@ protected:
void setIntrinsicSize(const IntSize&);
virtual void intrinsicSizeChanged();
+ virtual void paint(PaintInfo&, int tx, int ty);
bool shouldPaint(PaintInfo&, int& tx, int& ty);
void adjustOverflowForBoxShadowAndReflect();
IntRect localSelectionRect(bool checkWhetherSelected = true) const;
@@ -62,15 +63,8 @@ private:
virtual int minimumReplacedHeight() const { return 0; }
- virtual void paint(PaintInfo&, int tx, int ty);
virtual void paintReplaced(PaintInfo&, int /*tx*/, int /*ty*/) { }
- virtual int overflowHeight(bool includeInterior = true) const;
- virtual int overflowWidth(bool includeInterior = true) const;
- virtual int overflowLeft(bool includeInterior = true) const;
- virtual int overflowTop(bool includeInterior = true) const;
- virtual IntRect overflowRect(bool includeInterior = true) const;
-
virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
virtual unsigned caretMaxRenderedOffset() const;
diff --git a/WebCore/rendering/RenderReplica.cpp b/WebCore/rendering/RenderReplica.cpp
index 5fa3c62..1d589ae 100644
--- a/WebCore/rendering/RenderReplica.cpp
+++ b/WebCore/rendering/RenderReplica.cpp
@@ -72,7 +72,7 @@ void RenderReplica::paint(PaintInfo& paintInfo, int tx, int ty)
// computing using the wrong rootLayer
layer()->parent()->paintLayer(layer()->transform() ? layer()->parent() : layer()->enclosingTransformedAncestor(),
paintInfo.context, paintInfo.rect,
- PaintRestrictionNone, 0, 0,
+ PaintBehaviorNormal, 0, 0,
RenderLayer::PaintLayerHaveTransparency | RenderLayer::PaintLayerAppliedTransform | RenderLayer::PaintLayerTemporaryClipRects | RenderLayer::PaintLayerPaintingReflection);
else if (paintInfo.phase == PaintPhaseMask)
paintMask(paintInfo, tx, ty);
diff --git a/WebCore/rendering/RenderReplica.h b/WebCore/rendering/RenderReplica.h
index d5db3b7..48c64e4 100644
--- a/WebCore/rendering/RenderReplica.h
+++ b/WebCore/rendering/RenderReplica.h
@@ -46,6 +46,10 @@ public:
virtual void calcPrefWidths();
virtual void paint(PaintInfo&, int tx, int ty);
+
+private:
+ virtual bool isReplica() const { return true; }
+
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderRuby.cpp b/WebCore/rendering/RenderRuby.cpp
new file mode 100644
index 0000000..f13e2b4
--- /dev/null
+++ b/WebCore/rendering/RenderRuby.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 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"
+
+#if ENABLE(RUBY)
+#include "RenderRuby.h"
+
+#include "RenderRubyRun.h"
+
+namespace WebCore {
+
+//=== generic helper functions to avoid excessive code duplication ===
+
+static RenderRubyRun* lastRubyRun(const RenderObject* ruby)
+{
+ RenderObject* child = ruby->lastChild();
+ if (child && ruby->isAfterContent(child))
+ child = child->previousSibling();
+ ASSERT(!child || child->isRubyRun());
+ return static_cast<RenderRubyRun*>(child);
+}
+
+static inline RenderRubyRun* findRubyRunParent(RenderObject* child)
+{
+ while (child && !child->isRubyRun())
+ child = child->parent();
+ return static_cast<RenderRubyRun*>(child);
+}
+
+//=== ruby as inline object ===
+
+RenderRubyAsInline::RenderRubyAsInline(Node* node)
+ : RenderInline(node)
+{
+}
+
+RenderRubyAsInline::~RenderRubyAsInline()
+{
+}
+
+bool RenderRubyAsInline::isChildAllowed(RenderObject* child, RenderStyle*) const
+{
+ return child->isRubyText()
+ || child->isRubyRun()
+ || child->isInline();
+}
+
+void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild)
+{
+ // Note: ':after' content is handled implicitely below
+
+ // if child is a ruby run, just add it normally
+ if (child->isRubyRun()) {
+ RenderInline::addChild(child, beforeChild);
+ return;
+ }
+
+ if (beforeChild && !isAfterContent(beforeChild)) {
+ // insert child into run
+ ASSERT(!beforeChild->isRubyRun());
+ RenderRubyRun* run = findRubyRunParent(beforeChild);
+ ASSERT(run); // beforeChild should always have a run as parent
+ if (run) {
+ run->addChild(child, beforeChild);
+ return;
+ }
+ ASSERT(false); // beforeChild should always have a run as parent!
+ // Emergency fallback: fall through and just append.
+ }
+
+ // If the new child would be appended, try to add the child to the previous run
+ // if possible, or create a new run otherwise.
+ // (The RenderRubyRun object will handle the details)
+ RenderRubyRun* lastRun = lastRubyRun(this);
+ if (!lastRun || lastRun->hasRubyText()) {
+ lastRun = RenderRubyRun::staticCreateRubyRun(this);
+ RenderInline::addChild(lastRun);
+ }
+ lastRun->addChild(child);
+}
+
+void RenderRubyAsInline::removeChild(RenderObject* child)
+{
+ // If the child's parent is *this, i.e. a ruby run or ':after' content,
+ // just use the normal remove method.
+ if (child->parent() == this) {
+ ASSERT(child->isRubyRun() || child->isAfterContent());
+ RenderInline::removeChild(child);
+ return;
+ }
+
+ // Find the containing run
+ RenderRubyRun* run = findRubyRunParent(child);
+ ASSERT(run);
+ run->removeChild(child);
+}
+
+
+//=== ruby as block object ===
+
+RenderRubyAsBlock::RenderRubyAsBlock(Node* node)
+ : RenderBlock(node)
+{
+}
+
+RenderRubyAsBlock::~RenderRubyAsBlock()
+{
+}
+
+bool RenderRubyAsBlock::isChildAllowed(RenderObject* child, RenderStyle*) const
+{
+ return child->isRubyText()
+ || child->isRubyRun()
+ || child->isInline();
+}
+
+void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild)
+{
+ // Note: ':after' content is handled implicitely below
+
+ // if child is a ruby run, just add it normally
+ if (child->isRubyRun()) {
+ RenderBlock::addChild(child, beforeChild);
+ return;
+ }
+
+ if (beforeChild && !isAfterContent(beforeChild)) {
+ // insert child into run
+ ASSERT(!beforeChild->isRubyRun());
+ RenderObject* run = beforeChild;
+ while (run && !run->isRubyRun())
+ run = run->parent();
+ if (run) {
+ run->addChild(child, beforeChild);
+ return;
+ }
+ ASSERT(false); // beforeChild should always have a run as parent!
+ // Emergency fallback: fall through and just append.
+ }
+
+ // If the new child would be appended, try to add the child to the previous run
+ // if possible, or create a new run otherwise.
+ // (The RenderRubyRun object will handle the details)
+ RenderRubyRun* lastRun = lastRubyRun(this);
+ if (!lastRun || lastRun->hasRubyText()) {
+ lastRun = RenderRubyRun::staticCreateRubyRun(this);
+ RenderBlock::addChild(lastRun);
+ }
+ lastRun->addChild(child);
+}
+
+void RenderRubyAsBlock::removeChild(RenderObject* child)
+{
+ // If the child's parent is *this, just use the normal remove method.
+ if (child->parent() == this) {
+ // This should happen only during destruction of the whole ruby element, though.
+ RenderBlock::removeChild(child);
+ return;
+ }
+
+ // Find the containing run
+ RenderRubyRun* run = findRubyRunParent(child);
+ ASSERT(run);
+ run->removeChild(child);
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/rendering/RenderRuby.h b/WebCore/rendering/RenderRuby.h
new file mode 100644
index 0000000..a5dafe9
--- /dev/null
+++ b/WebCore/rendering/RenderRuby.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef RenderRuby_h
+#define RenderRuby_h
+
+#if ENABLE(RUBY)
+
+#include "RenderBlock.h"
+#include "RenderInline.h"
+
+namespace WebCore {
+
+// Following the HTML 5 spec, the box object model for a <ruby> element allows several runs of ruby
+// bases with their respective ruby texts looks as follows:
+//
+// 1 RenderRuby object, corresponding to the whole <ruby> HTML element
+// 1+ RenderRubyRun (anonymous)
+// 0 or 1 RenderRubyText - shuffled to the front in order to re-use existing block layouting
+// 0-n inline object(s)
+// 0 or 1 RenderRubyBase - contains the inline objects that make up the ruby base
+// 1-n inline object(s)
+//
+// Note: <rp> elements are defined as having 'display:none' and thus normally are not assigned a renderer.
+
+// <ruby> when used as 'display:inline'
+class RenderRubyAsInline : public RenderInline {
+public:
+ RenderRubyAsInline(Node*);
+ virtual ~RenderRubyAsInline();
+
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
+ virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
+ virtual void removeChild(RenderObject* child);
+
+private:
+ virtual bool isRuby() const { return true; }
+ virtual const char* renderName() const { return "RenderRuby (inline)"; }
+ virtual bool createsAnonymousWrapper() const { return true; }
+ virtual void removeLeftoverAnonymousBlock(RenderBlock*) { ASSERT_NOT_REACHED(); }
+};
+
+// <ruby> when used as 'display:block' or 'display:inline-block'
+class RenderRubyAsBlock : public RenderBlock {
+public:
+ RenderRubyAsBlock(Node*);
+ virtual ~RenderRubyAsBlock();
+
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
+ virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
+ virtual void removeChild(RenderObject* child);
+
+private:
+ virtual bool isRuby() const { return true; }
+ virtual const char* renderName() const { return "RenderRuby (block)"; }
+ virtual bool createsAnonymousWrapper() const { return true; }
+ virtual void removeLeftoverAnonymousBlock(RenderBlock*) { ASSERT_NOT_REACHED(); }
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // RenderRuby_h
diff --git a/WebCore/rendering/RenderRubyBase.cpp b/WebCore/rendering/RenderRubyBase.cpp
new file mode 100644
index 0000000..65f9bc0
--- /dev/null
+++ b/WebCore/rendering/RenderRubyBase.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 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"
+
+#if ENABLE(RUBY)
+#include "RenderRubyBase.h"
+
+namespace WebCore {
+
+RenderRubyBase::RenderRubyBase(Node* node)
+ : RenderBlock(node)
+{
+ setInline(false);
+}
+
+RenderRubyBase::~RenderRubyBase()
+{
+}
+
+bool RenderRubyBase::isChildAllowed(RenderObject* child, RenderStyle*) const
+{
+ return child->isInline();
+}
+
+bool RenderRubyBase::hasOnlyWrappedInlineChildren(RenderObject* beforeChild) const
+{
+ // Tests whether all children in the base before beforeChild are either floated/positioned,
+ // or inline objects wrapped in anonymous blocks.
+ // Note that beforeChild may be 0, in which case all children are looked at.
+ for (RenderObject* child = firstChild(); child != beforeChild; child = child->nextSibling()) {
+ if (!child->isFloatingOrPositioned() && !(child->isAnonymousBlock() && child->childrenInline()))
+ return false;
+ }
+ return true;
+}
+
+void RenderRubyBase::moveChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
+{
+ // This function removes all children that are before (!) beforeChild
+ // and appends them to toBase.
+ ASSERT(toBase);
+
+ // First make sure that beforeChild (if set) is indeed a direct child of this.
+ // Inline children might be wrapped in an anonymous block if there's a continuation.
+ // Theoretically, in ruby bases, this can happen with only the first such a child,
+ // so it should be OK to just climb the tree.
+ while (fromBeforeChild && fromBeforeChild->parent() != this)
+ fromBeforeChild = fromBeforeChild->parent();
+
+ if (childrenInline())
+ moveInlineChildren(toBase, fromBeforeChild);
+ else
+ moveBlockChildren(toBase, fromBeforeChild);
+
+ setNeedsLayoutAndPrefWidthsRecalc();
+ toBase->setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+void RenderRubyBase::moveInlineChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
+{
+ RenderBlock* toBlock;
+
+ if (toBase->childrenInline()) {
+ // The standard and easy case: move the children into the target base
+ toBlock = toBase;
+ } else {
+ // We need to wrap the inline objects into an anonymous block.
+ // If toBase has a suitable block, we re-use it, otherwise create a new one.
+ RenderObject* lastChild = toBase->lastChild();
+ if (lastChild && lastChild->isAnonymousBlock() && lastChild->childrenInline())
+ toBlock = toRenderBlock(lastChild);
+ else {
+ toBlock = toBase->createAnonymousBlock();
+ toBase->children()->appendChildNode(toBase, toBlock);
+ }
+ }
+ // Move our inline children into the target block we determined above.
+ for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild())
+ moveChildTo(toBlock, toBlock->children(), child);
+}
+
+void RenderRubyBase::moveBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
+{
+ if (toBase->childrenInline()) {
+ // First check whether we move only wrapped inline objects.
+ if (hasOnlyWrappedInlineChildren(fromBeforeChild)) {
+ // The reason why the base is in block flow must be after beforeChild.
+ // We therefore can extract the inline objects and move them to toBase.
+ for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild()) {
+ if (child->isAnonymousBlock()) {
+ RenderBlock* anonBlock = toRenderBlock(child);
+ ASSERT(anonBlock->childrenInline());
+ ASSERT(!anonBlock->inlineContinuation());
+ anonBlock->moveAllChildrenTo(toBase, toBase->children());
+ anonBlock->deleteLineBoxTree();
+ anonBlock->destroy();
+ } else {
+ ASSERT(child->isFloatingOrPositioned());
+ moveChildTo(toBase, toBase->children(), child);
+ }
+ }
+ } else {
+ // Moving block children -> have to set toBase as block flow
+ toBase->makeChildrenNonInline();
+ // Move children, potentially collapsing anonymous block wrappers.
+ mergeBlockChildren(toBase, fromBeforeChild);
+
+ // Now we need to check if the leftover children are all inline.
+ // If so, make this base inline again.
+ if (hasOnlyWrappedInlineChildren()) {
+ RenderObject* next = 0;
+ for (RenderObject* child = firstChild(); child; child = next) {
+ next = child->nextSibling();
+ if (child->isFloatingOrPositioned())
+ continue;
+ ASSERT(child->isAnonymousBlock());
+
+ RenderBlock* anonBlock = toRenderBlock(child);
+ ASSERT(anonBlock->childrenInline());
+ ASSERT(!anonBlock->inlineContinuation());
+ // Move inline children out of anonymous block.
+ anonBlock->moveAllChildrenTo(this, children(), anonBlock);
+ anonBlock->deleteLineBoxTree();
+ anonBlock->destroy();
+ }
+ setChildrenInline(true);
+ }
+ }
+ } else
+ mergeBlockChildren(toBase, fromBeforeChild);
+}
+
+void RenderRubyBase::mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
+{
+ // This function removes all children that are before fromBeforeChild and appends them to toBase.
+ ASSERT(!childrenInline());
+ ASSERT(toBase);
+ ASSERT(!toBase->childrenInline());
+
+ // Quick check whether we have anything to do, to simplify the following code.
+ if (fromBeforeChild != firstChild())
+ return;
+
+ // If an anonymous block would be put next to another such block, then merge those.
+ RenderObject* firstChildHere = firstChild();
+ RenderObject* lastChildThere = toBase->lastChild();
+ if (firstChildHere && firstChildHere->isAnonymousBlock() && firstChildHere->childrenInline()
+ && lastChildThere && lastChildThere->isAnonymousBlock() && lastChildThere->childrenInline()) {
+ RenderBlock* anonBlockHere = toRenderBlock(firstChildHere);
+ RenderBlock* anonBlockThere = toRenderBlock(lastChildThere);
+ anonBlockHere->moveAllChildrenTo(anonBlockThere, anonBlockThere->children());
+ anonBlockHere->deleteLineBoxTree();
+ anonBlockHere->destroy();
+ }
+ // Move all remaining children normally.
+ for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild())
+ moveChildTo(toBase, toBase->children(), child);
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/rendering/RenderRubyBase.h b/WebCore/rendering/RenderRubyBase.h
new file mode 100644
index 0000000..29c4858
--- /dev/null
+++ b/WebCore/rendering/RenderRubyBase.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef RenderRubyBase_h
+#define RenderRubyBase_h
+
+#if ENABLE(RUBY)
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class RenderRubyBase : public RenderBlock {
+public:
+ RenderRubyBase(Node*);
+ virtual ~RenderRubyBase();
+
+ virtual const char* renderName() const { return "RenderRubyBase (anonymous)"; }
+
+ virtual bool isRubyBase() const { return true; }
+
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
+
+private:
+ bool hasOnlyWrappedInlineChildren(RenderObject* beforeChild = 0) const;
+
+ void moveChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0);
+ void moveInlineChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0);
+ void moveBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0);
+ void mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0);
+
+ // Allow RenderRubyRun to manipulate the children within ruby bases.
+ friend class RenderRubyRun;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // RenderRubyBase_h
diff --git a/WebCore/rendering/RenderRubyRun.cpp b/WebCore/rendering/RenderRubyRun.cpp
new file mode 100644
index 0000000..61be455
--- /dev/null
+++ b/WebCore/rendering/RenderRubyRun.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 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"
+
+#if ENABLE(RUBY)
+#include "RenderRubyRun.h"
+
+#include "RenderRubyBase.h"
+#include "RenderRubyText.h"
+#include "RenderView.h"
+
+using namespace std;
+
+namespace WebCore {
+
+RenderRubyRun::RenderRubyRun(Node* node)
+ : RenderBlock(node)
+ , m_beingDestroyed(false)
+{
+ setReplaced(true);
+ setInline(true);
+}
+
+RenderRubyRun::~RenderRubyRun()
+{
+}
+
+void RenderRubyRun::destroy()
+{
+ // Mark if the run is being destroyed to avoid trouble in removeChild().
+ m_beingDestroyed = true;
+ RenderBlock::destroy();
+}
+
+bool RenderRubyRun::hasRubyText() const
+{
+ // The only place where a ruby text can be is in the first position
+ // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
+ return firstChild() && firstChild()->isRubyText();
+}
+
+bool RenderRubyRun::hasRubyBase() const
+{
+ // The only place where a ruby base can be is in the last position
+ // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
+ return lastChild() && lastChild()->isRubyBase();
+}
+
+bool RenderRubyRun::isEmpty() const
+{
+ return !hasRubyText() && !hasRubyBase();
+}
+
+RenderRubyText* RenderRubyRun::rubyText() const
+{
+ RenderObject* child = firstChild();
+ return child && child->isRubyText() ? static_cast<RenderRubyText*>(child) : 0;
+}
+
+RenderRubyBase* RenderRubyRun::rubyBase() const
+{
+ RenderObject* child = lastChild();
+ return child && child->isRubyBase() ? static_cast<RenderRubyBase*>(child) : 0;
+}
+
+RenderRubyBase* RenderRubyRun::rubyBaseSafe()
+{
+ RenderRubyBase* base = rubyBase();
+ if (!base) {
+ base = createRubyBase();
+ RenderBlock::addChild(base);
+ }
+ return base;
+}
+
+RenderBlock* RenderRubyRun::firstLineBlock() const
+{
+ return 0;
+}
+
+void RenderRubyRun::updateFirstLetter()
+{
+}
+
+bool RenderRubyRun::isChildAllowed(RenderObject* child, RenderStyle*) const
+{
+ return child->isRubyText() || child->isInline();
+}
+
+void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild)
+{
+ ASSERT(child);
+
+ // If child is a ruby text
+ if (child->isRubyText()) {
+ if (!beforeChild) {
+ // RenderRuby has already ascertained that we can add the child here.
+ ASSERT(!hasRubyText());
+ // prepend ruby texts as first child
+ RenderBlock::addChild(child, firstChild());
+ } else if (beforeChild->isRubyText()) {
+ // New text is inserted just before another.
+ // In this case the new text takes the place of the old one, and
+ // the old text goes into a new run that is inserted as next sibling.
+ ASSERT(beforeChild->parent() == this);
+ RenderObject* ruby = parent();
+ ASSERT(ruby->isRuby());
+ RenderBlock* newRun = staticCreateRubyRun(ruby);
+ ruby->addChild(newRun, nextSibling());
+ // Add the new ruby text and move the old one to the new run
+ // Note: Doing it in this order and not using RenderRubyRun's methods,
+ // in order to avoid automatic removal of the ruby run in case there is no
+ // other child besides the old ruby text.
+ RenderBlock::addChild(child, beforeChild);
+ RenderBlock::removeChild(beforeChild);
+ newRun->addChild(beforeChild);
+ } else {
+ ASSERT(hasRubyBase()); // Otherwise beforeChild would be borked.
+ // Insertion before a ruby base object.
+ // In this case we need insert a new run before the current one and split the base.
+ RenderObject* ruby = parent();
+ RenderRubyRun* newRun = staticCreateRubyRun(ruby);
+ ruby->addChild(newRun, this);
+ newRun->addChild(child);
+ rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild);
+ }
+ } else {
+ // child is not a text -> insert it into the base
+ // (append it instead if beforeChild is the ruby text)
+ if (beforeChild && beforeChild->isRubyText())
+ beforeChild = 0;
+ rubyBaseSafe()->addChild(child, beforeChild);
+ }
+}
+
+void RenderRubyRun::removeChild(RenderObject* child)
+{
+ // If the child is a ruby text, then merge the ruby base with the base of
+ // the right sibling run, if possible.
+ if (!m_beingDestroyed && !documentBeingDestroyed() && child->isRubyText()) {
+ RenderRubyBase* base = rubyBase();
+ RenderObject* rightNeighbour = nextSibling();
+ if (base && rightNeighbour && rightNeighbour->isRubyRun()) {
+ // Ruby run without a base can happen only at the first run.
+ RenderRubyRun* rightRun = static_cast<RenderRubyRun*>(rightNeighbour);
+ ASSERT(rightRun->hasRubyBase());
+ RenderRubyBase* rightBase = rightRun->rubyBaseSafe();
+ // Collect all children in a single base, then swap the bases.
+ rightBase->moveChildren(base);
+ moveChildTo(rightRun, rightRun->children(), base);
+ rightRun->moveChildTo(this, children(), rightBase);
+ // The now empty ruby base will be removed below.
+ }
+ }
+
+ RenderBlock::removeChild(child);
+
+ if (!m_beingDestroyed && !documentBeingDestroyed()) {
+ // Check if our base (if any) is now empty. If so, destroy it.
+ RenderBlock* base = rubyBase();
+ if (base && !base->firstChild()) {
+ RenderBlock::removeChild(base);
+ base->deleteLineBoxTree();
+ base->destroy();
+ }
+
+ // If any of the above leaves the run empty, destroy it as well.
+ if (isEmpty()) {
+ parent()->removeChild(this);
+ deleteLineBoxTree();
+ destroy();
+ }
+ }
+}
+
+RenderRubyBase* RenderRubyRun::createRubyBase() const
+{
+ RenderRubyBase* rb = new (renderArena()) RenderRubyBase(document() /* anonymous */);
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(style());
+ newStyle->setDisplay(BLOCK);
+ newStyle->setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
+ rb->setStyle(newStyle.release());
+ return rb;
+}
+
+RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby)
+{
+ ASSERT(parentRuby && parentRuby->isRuby());
+ RenderRubyRun* rr = new (parentRuby->renderArena()) RenderRubyRun(parentRuby->document() /* anonymous */);
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(parentRuby->style());
+ newStyle->setDisplay(INLINE_BLOCK);
+ rr->setStyle(newStyle.release());
+ return rr;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/rendering/RenderRubyRun.h b/WebCore/rendering/RenderRubyRun.h
new file mode 100644
index 0000000..acf359b
--- /dev/null
+++ b/WebCore/rendering/RenderRubyRun.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef RenderRubyRun_h
+#define RenderRubyRun_h
+
+#if ENABLE(RUBY)
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class RenderRubyBase;
+class RenderRubyText;
+
+// RenderRubyRun are 'inline-block/table' like objects,and wrap a single pairing of a ruby base with its ruby text(s).
+// See RenderRuby.h for further comments on the structure
+
+class RenderRubyRun : public RenderBlock {
+public:
+ RenderRubyRun(Node*);
+ virtual ~RenderRubyRun();
+
+ virtual void destroy();
+
+ bool hasRubyText() const;
+ bool hasRubyBase() const;
+ bool isEmpty() const;
+ RenderRubyText* rubyText() const;
+ RenderRubyBase* rubyBase() const;
+ RenderRubyBase* rubyBaseSafe(); // creates the base if it doesn't already exist
+
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
+ virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
+ virtual void removeChild(RenderObject* child);
+
+ virtual RenderBlock* firstLineBlock() const;
+ virtual void updateFirstLetter();
+
+ static RenderRubyRun* staticCreateRubyRun(const RenderObject* parentRuby);
+
+protected:
+ RenderRubyBase* createRubyBase() const;
+
+private:
+ virtual bool isRubyRun() const { return true; }
+ virtual const char* renderName() const { return "RenderRubyRun (anonymous)"; }
+ virtual bool createsAnonymousWrapper() const { return true; }
+ virtual void removeLeftoverAnonymousBlock(RenderBlock*) { }
+
+ bool m_beingDestroyed;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // RenderRubyRun_h
diff --git a/WebCore/rendering/RenderRubyText.cpp b/WebCore/rendering/RenderRubyText.cpp
new file mode 100644
index 0000000..1cf2b9e
--- /dev/null
+++ b/WebCore/rendering/RenderRubyText.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 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"
+
+#if ENABLE(RUBY)
+#include "RenderRubyText.h"
+
+namespace WebCore {
+
+RenderRubyText::RenderRubyText(Node* node)
+ : RenderBlock(node)
+{
+}
+
+RenderRubyText::~RenderRubyText()
+{
+}
+
+bool RenderRubyText::isChildAllowed(RenderObject* child, RenderStyle*) const
+{
+ return child->isInline();
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/rendering/RenderRubyText.h b/WebCore/rendering/RenderRubyText.h
new file mode 100644
index 0000000..865d179
--- /dev/null
+++ b/WebCore/rendering/RenderRubyText.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef RenderRubyText_h
+#define RenderRubyText_h
+
+#if ENABLE(RUBY)
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class RenderRubyText : public RenderBlock {
+public:
+ RenderRubyText(Node*);
+ virtual ~RenderRubyText();
+
+ virtual const char* renderName() const { return "RenderRubyText"; }
+
+ virtual bool isRubyText() const { return true; }
+
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // RenderRubyText_h
diff --git a/WebCore/rendering/RenderSVGBlock.h b/WebCore/rendering/RenderSVGBlock.h
index a4ececb..0b0d107 100644
--- a/WebCore/rendering/RenderSVGBlock.h
+++ b/WebCore/rendering/RenderSVGBlock.h
@@ -35,6 +35,8 @@ class RenderSVGBlock : public RenderBlock, protected SVGRenderBase {
public:
RenderSVGBlock(SVGElement*);
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
+
private:
virtual void setStyle(PassRefPtr<RenderStyle>);
};
diff --git a/WebCore/rendering/RenderSVGContainer.cpp b/WebCore/rendering/RenderSVGContainer.cpp
index d7aec99..6d1b965 100644
--- a/WebCore/rendering/RenderSVGContainer.cpp
+++ b/WebCore/rendering/RenderSVGContainer.cpp
@@ -3,6 +3,7 @@
2004, 2005, 2007, 2008 Rob Buis <buis@kde.org>
2007 Eric Seidel <eric@webkit.org>
Copyright (C) 2009 Google, Inc. All rights reserved.
+ 2009 Dirk Schulze <krit@webkit.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -25,14 +26,11 @@
#if ENABLE(SVG)
#include "RenderSVGContainer.h"
-#include "AXObjectCache.h"
-#include "FloatQuad.h"
#include "GraphicsContext.h"
#include "RenderView.h"
#include "SVGRenderSupport.h"
#include "SVGResourceFilter.h"
#include "SVGStyledElement.h"
-#include "SVGURIReference.h"
namespace WebCore {
@@ -62,17 +60,7 @@ void RenderSVGContainer::layout()
LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint());
calculateLocalTransform(); // Allow RenderSVGTransformableContainer to update its transform
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- // Only force our kids to layout if we're being asked to relayout as a result of a parent changing
- // FIXME: We should be able to skip relayout of non-relative kids when only bounds size has changed
- // that's a possible future optimization using LayoutState
- // http://bugs.webkit.org/show_bug.cgi?id=15391
- if (selfNeedsLayout())
- child->setNeedsLayout(true);
-
- child->layoutIfNeeded();
- ASSERT(!child->needsLayout());
- }
+ layoutChildren(this, selfNeedsLayout());
repainter.repaintAfterLayout();
setNeedsLayout(false);
@@ -82,7 +70,7 @@ bool RenderSVGContainer::selfWillPaint() const
{
#if ENABLE(FILTERS)
const SVGRenderStyle* svgStyle = style()->svgStyle();
- SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
+ SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter(), this);
if (filter)
return true;
#endif
@@ -94,7 +82,7 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int)
if (paintInfo.context->paintingDisabled() || !drawsContents())
return;
- // Spec: groups w/o children still may render filter content.
+ // Spec: groups w/o children still may render filter content.
if (!firstChild() && !selfWillPaint())
return;
@@ -109,12 +97,16 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int)
SVGResourceFilter* filter = 0;
FloatRect boundingBox = repaintRectInLocalCoordinates();
+
+ bool continueRendering = true;
if (childPaintInfo.phase == PaintPhaseForeground)
- prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
+ continueRendering = prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
- childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo);
- for (RenderObject* child = firstChild(); child; child = child->nextSibling())
- child->paint(childPaintInfo, 0, 0);
+ if (continueRendering) {
+ childPaintInfo.paintingRoot = paintingRootForChildren(childPaintInfo);
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling())
+ child->paint(childPaintInfo, 0, 0);
+ }
if (paintInfo.phase == PaintPhaseForeground)
finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
@@ -132,10 +124,11 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int)
}
// addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call
-void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, int, int)
{
IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates()));
- graphicsContext->addFocusRingRect(paintRectInParent);
+ if (!paintRectInParent.isEmpty())
+ rects.append(paintRectInParent);
}
FloatRect RenderSVGContainer::objectBoundingBox() const
@@ -143,14 +136,30 @@ FloatRect RenderSVGContainer::objectBoundingBox() const
return computeContainerBoundingBox(this, false);
}
+FloatRect RenderSVGContainer::strokeBoundingBox() const
+{
+ return computeContainerBoundingBox(this, true);
+}
+
// RenderSVGContainer is used for <g> elements which do not themselves have a
// width or height, so we union all of our child rects as our repaint rect.
FloatRect RenderSVGContainer::repaintRectInLocalCoordinates() const
{
FloatRect repaintRect = computeContainerBoundingBox(this, true);
- // A filter on this container can paint outside of the union of the child repaint rects
- repaintRect.unite(filterBoundingBoxForRenderer(this));
+ FloatRect rect = filterBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect = rect;
+
+ rect = clipperBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect.intersect(rect);
+
+ rect = maskerBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect.intersect(rect);
+
+ style()->svgStyle()->inflateForShadow(repaintRect);
return repaintRect;
}
@@ -178,5 +187,3 @@ bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTest
}
#endif // ENABLE(SVG)
-
-// vim:ts=4:noet
diff --git a/WebCore/rendering/RenderSVGContainer.h b/WebCore/rendering/RenderSVGContainer.h
index f2195e3..f681e50 100644
--- a/WebCore/rendering/RenderSVGContainer.h
+++ b/WebCore/rendering/RenderSVGContainer.h
@@ -42,10 +42,9 @@ public:
void setDrawsContents(bool);
bool drawsContents() const;
-protected:
virtual void paint(PaintInfo&, int parentX, int parentY);
-private:
+protected:
virtual RenderObjectChildList* virtualChildren() { return children(); }
virtual const RenderObjectChildList* virtualChildren() const { return children(); }
@@ -54,9 +53,10 @@ private:
virtual void layout();
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const;
virtual FloatRect repaintRectInLocalCoordinates() const;
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
@@ -71,6 +71,7 @@ private:
bool selfWillPaint() const;
+private:
RenderObjectChildList m_children;
bool m_drawsContents : 1;
};
@@ -78,14 +79,14 @@ private:
inline RenderSVGContainer* toRenderSVGContainer(RenderObject* object)
{
// Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this.
- ASSERT(!object || object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer"));
+ ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer")));
return static_cast<RenderSVGContainer*>(object);
}
inline const RenderSVGContainer* toRenderSVGContainer(const RenderObject* object)
{
// Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this.
- ASSERT(!object || object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer"));
+ ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer")));
return static_cast<const RenderSVGContainer*>(object);
}
diff --git a/WebCore/rendering/RenderSVGGradientStop.cpp b/WebCore/rendering/RenderSVGGradientStop.cpp
index b81e7f4..66391c8 100644
--- a/WebCore/rendering/RenderSVGGradientStop.cpp
+++ b/WebCore/rendering/RenderSVGGradientStop.cpp
@@ -49,7 +49,7 @@ void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderSty
// <stop> elements should only be allowed to make renderers under gradient elements
// but I can imagine a few cases we might not be catching, so let's not crash if our parent isn't a gradient.
if (SVGGradientElement* gradient = gradientElement()) {
- if (SVGResource* resource = gradient->canvasResource())
+ if (SVGResource* resource = gradient->canvasResource(this))
resource->invalidate();
}
}
diff --git a/WebCore/rendering/RenderSVGHiddenContainer.cpp b/WebCore/rendering/RenderSVGHiddenContainer.cpp
index d4b39d3..bb0a15d 100644
--- a/WebCore/rendering/RenderSVGHiddenContainer.cpp
+++ b/WebCore/rendering/RenderSVGHiddenContainer.cpp
@@ -38,17 +38,7 @@ RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGStyledElement* element)
void RenderSVGHiddenContainer::layout()
{
ASSERT(needsLayout());
-
- // Layout our kids to prevent a kid from being marked as needing layout
- // then never being asked to layout.
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (selfNeedsLayout())
- child->setNeedsLayout(true);
-
- child->layoutIfNeeded();
- ASSERT(!child->needsLayout());
- }
-
+ layoutChildren(this, selfNeedsLayout());
setNeedsLayout(false);
}
diff --git a/WebCore/rendering/RenderSVGHiddenContainer.h b/WebCore/rendering/RenderSVGHiddenContainer.h
index 0ef0a43..fdbd2bc 100644
--- a/WebCore/rendering/RenderSVGHiddenContainer.h
+++ b/WebCore/rendering/RenderSVGHiddenContainer.h
@@ -51,9 +51,6 @@ namespace WebCore {
virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty);
virtual void absoluteQuads(Vector<FloatQuad>&);
- // FIXME: This override only exists to match existing LayoutTest results.
- virtual TransformationMatrix absoluteTransform() const { return TransformationMatrix(); }
-
virtual FloatRect objectBoundingBox() const;
virtual FloatRect repaintRectInLocalCoordinates() const;
diff --git a/WebCore/rendering/RenderSVGImage.cpp b/WebCore/rendering/RenderSVGImage.cpp
index 7e0b40d..96eeaf9 100644
--- a/WebCore/rendering/RenderSVGImage.cpp
+++ b/WebCore/rendering/RenderSVGImage.cpp
@@ -4,6 +4,7 @@
Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
Copyright (C) 2007, 2008, 2009 Rob Buis <buis@kde.org>
Copyright (C) 2009, Google, Inc.
+ Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -47,81 +48,6 @@ RenderSVGImage::RenderSVGImage(SVGImageElement* impl)
{
}
-void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& srcRect, SVGPreserveAspectRatio* aspectRatio)
-{
- float origDestWidth = destRect.width();
- float origDestHeight = destRect.height();
- if (aspectRatio->meetOrSlice() == SVGPreserveAspectRatio::SVG_MEETORSLICE_MEET) {
- float widthToHeightMultiplier = srcRect.height() / srcRect.width();
- if (origDestHeight > (origDestWidth * widthToHeightMultiplier)) {
- destRect.setHeight(origDestWidth * widthToHeightMultiplier);
- switch (aspectRatio->align()) {
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
- destRect.setY(destRect.y() + origDestHeight / 2.0f - destRect.height() / 2.0f);
- break;
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
- destRect.setY(destRect.y() + origDestHeight - destRect.height());
- break;
- }
- }
- if (origDestWidth > (origDestHeight / widthToHeightMultiplier)) {
- destRect.setWidth(origDestHeight / widthToHeightMultiplier);
- switch (aspectRatio->align()) {
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
- destRect.setX(destRect.x() + origDestWidth / 2.0f - destRect.width() / 2.0f);
- break;
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
- destRect.setX(destRect.x() + origDestWidth - destRect.width());
- break;
- }
- }
- } else if (aspectRatio->meetOrSlice() == SVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE) {
- float widthToHeightMultiplier = srcRect.height() / srcRect.width();
- // if the destination height is less than the height of the image we'll be drawing
- if (origDestHeight < (origDestWidth * widthToHeightMultiplier)) {
- float destToSrcMultiplier = srcRect.width() / destRect.width();
- srcRect.setHeight(destRect.height() * destToSrcMultiplier);
- switch (aspectRatio->align()) {
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
- srcRect.setY(destRect.y() + image()->height() / 2.0f - srcRect.height() / 2.0f);
- break;
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
- srcRect.setY(destRect.y() + image()->height() - srcRect.height());
- break;
- }
- }
- // if the destination width is less than the width of the image we'll be drawing
- if (origDestWidth < (origDestHeight / widthToHeightMultiplier)) {
- float destToSrcMultiplier = srcRect.height() / destRect.height();
- srcRect.setWidth(destRect.width() * destToSrcMultiplier);
- switch (aspectRatio->align()) {
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
- srcRect.setX(destRect.x() + image()->width() / 2.0f - srcRect.width() / 2.0f);
- break;
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
- case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
- srcRect.setX(destRect.x() + image()->width() - srcRect.width());
- break;
- }
- }
- }
-}
-
void RenderSVGImage::layout()
{
ASSERT(needsLayout());
@@ -138,6 +64,7 @@ void RenderSVGImage::layout()
calcHeight();
m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image));
+ m_cachedLocalRepaintRect = FloatRect();
repainter.repaintAfterLayout();
@@ -157,16 +84,16 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int)
PaintInfo savedInfo(paintInfo);
- prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter);
+ if (prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter)) {
+ FloatRect destRect = m_localBounds;
+ FloatRect srcRect(0, 0, image()->width(), image()->height());
- FloatRect destRect = m_localBounds;
- FloatRect srcRect(0, 0, image()->width(), image()->height());
+ SVGImageElement* imageElt = static_cast<SVGImageElement*>(node());
+ if (imageElt->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE)
+ imageElt->preserveAspectRatio().transformRect(destRect, srcRect);
- SVGImageElement* imageElt = static_cast<SVGImageElement*>(node());
- if (imageElt->preserveAspectRatio()->align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE)
- adjustRectsForAspectRatio(destRect, srcRect, imageElt->preserveAspectRatio());
-
- paintInfo.context->drawImage(image(), destRect, srcRect);
+ paintInfo.context->drawImage(image(), DeviceColorSpace, destRect, srcRect);
+ }
finishRenderSVGContent(this, paintInfo, filter, savedInfo.context);
}
@@ -212,12 +139,29 @@ FloatRect RenderSVGImage::objectBoundingBox() const
FloatRect RenderSVGImage::repaintRectInLocalCoordinates() const
{
- FloatRect repaintRect = m_localBounds;
+ // If we already have a cached repaint rect, return that
+ if (!m_cachedLocalRepaintRect.isEmpty())
+ return m_cachedLocalRepaintRect;
+
+ m_cachedLocalRepaintRect = m_localBounds;
+
+ // FIXME: We need to be careful here. We assume that there is no filter,
+ // clipper or masker if the rects are empty.
+ FloatRect rect = filterBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect = rect;
+
+ rect = clipperBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect.intersect(rect);
+
+ rect = maskerBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ m_cachedLocalRepaintRect.intersect(rect);
- // Filters can paint outside the image content
- repaintRect.unite(filterBoundingBoxForRenderer(this));
+ style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect);
- return repaintRect;
+ return m_cachedLocalRepaintRect;
}
void RenderSVGImage::imageChanged(WrappedImagePtr image, const IntRect* rect)
@@ -241,11 +185,12 @@ void RenderSVGImage::mapLocalToContainer(RenderBoxModelObject* repaintContainer,
SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState);
}
-void RenderSVGImage::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, int, int)
{
// this is called from paint() after the localTransform has already been applied
IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates());
- graphicsContext->addFocusRingRect(contentRect);
+ if (!contentRect.isEmpty())
+ rects.append(contentRect);
}
void RenderSVGImage::absoluteRects(Vector<IntRect>& rects, int, int)
diff --git a/WebCore/rendering/RenderSVGImage.h b/WebCore/rendering/RenderSVGImage.h
index ef11719..8ed9146 100644
--- a/WebCore/rendering/RenderSVGImage.h
+++ b/WebCore/rendering/RenderSVGImage.h
@@ -24,28 +24,29 @@
#define RenderSVGImage_h
#if ENABLE(SVG)
-
-#include "TransformationMatrix.h"
+#include "AffineTransform.h"
#include "FloatRect.h"
#include "RenderImage.h"
+#include "SVGPreserveAspectRatio.h"
#include "SVGRenderSupport.h"
namespace WebCore {
class SVGImageElement;
- class SVGPreserveAspectRatio;
- class RenderSVGImage : public RenderImage, SVGRenderBase {
+ class RenderSVGImage : public RenderImage, protected SVGRenderBase {
public:
RenderSVGImage(SVGImageElement*);
private:
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
virtual const char* renderName() const { return "RenderSVGImage"; }
virtual bool isSVGImage() const { return true; }
- virtual TransformationMatrix localToParentTransform() const { return m_localTransform; }
+ virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const { return m_localBounds; }
virtual FloatRect repaintRectInLocalCoordinates() const;
virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
@@ -55,10 +56,9 @@ namespace WebCore {
virtual void absoluteRects(Vector<IntRect>&, int tx, int ty);
virtual void absoluteQuads(Vector<FloatQuad>&);
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
- void adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& srcRect, SVGPreserveAspectRatio*);
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
@@ -68,10 +68,11 @@ namespace WebCore {
virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
- virtual TransformationMatrix localTransform() const { return m_localTransform; }
+ virtual AffineTransform localTransform() const { return m_localTransform; }
- TransformationMatrix m_localTransform;
+ AffineTransform m_localTransform;
FloatRect m_localBounds;
+ mutable FloatRect m_cachedLocalRepaintRect;
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderSVGInline.h b/WebCore/rendering/RenderSVGInline.h
index 9f9f3f5..53fd4b7 100644
--- a/WebCore/rendering/RenderSVGInline.h
+++ b/WebCore/rendering/RenderSVGInline.h
@@ -27,6 +27,8 @@
#if ENABLE(SVG)
#include "RenderInline.h"
+#include "SVGRenderSupport.h"
+
namespace WebCore {
class RenderSVGInline : public RenderInline {
@@ -38,6 +40,9 @@ public:
// These are shared between RenderSVGTSpan and RenderSVGTextPath
virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty);
virtual void absoluteQuads(Vector<FloatQuad>&);
+
+ virtual FloatRect objectBoundingBox() const { return FloatRect(); }
+ virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); }
private:
virtual InlineFlowBox* createInlineFlowBox();
diff --git a/WebCore/rendering/RenderSVGModelObject.h b/WebCore/rendering/RenderSVGModelObject.h
index 0aa13ad..4c50734 100644
--- a/WebCore/rendering/RenderSVGModelObject.h
+++ b/WebCore/rendering/RenderSVGModelObject.h
@@ -49,6 +49,8 @@ class RenderSVGModelObject : public RenderObject, protected SVGRenderBase {
public:
RenderSVGModelObject(SVGStyledElement*);
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
+
virtual bool requiresLayer() const { return false; }
virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
diff --git a/WebCore/rendering/RenderSVGRoot.cpp b/WebCore/rendering/RenderSVGRoot.cpp
index 0a39bf4..74172fc 100644
--- a/WebCore/rendering/RenderSVGRoot.cpp
+++ b/WebCore/rendering/RenderSVGRoot.cpp
@@ -86,23 +86,20 @@ void RenderSVGRoot::layout()
LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout());
+ int oldWidth = width();
calcWidth();
+
+ int oldHeight = height();
calcHeight();
SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
setWidth(static_cast<int>(width() * svg->currentScale()));
setHeight(static_cast<int>(height() * svg->currentScale()));
-
calcViewport();
-
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (selfNeedsLayout()) // either bounds or transform changed, force kids to relayout
- child->setNeedsLayout(true, false);
-
- child->layoutIfNeeded();
- ASSERT(!child->needsLayout());
- }
+ // RenderSVGRoot needs to take special care to propagate window size changes to the children,
+ // if the outermost <svg> is using relative x/y/width/height values. Hence the additonal parameters.
+ layoutChildren(this, selfNeedsLayout() || (svg->hasRelativeValues() && (width() != oldWidth || height() != oldHeight)));
repainter.repaintAfterLayout();
view()->enableLayoutState();
@@ -113,7 +110,7 @@ bool RenderSVGRoot::selfWillPaint() const
{
#if ENABLE(FILTERS)
const SVGRenderStyle* svgStyle = style()->svgStyle();
- SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
+ SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter(), this);
if (filter)
return true;
#endif
@@ -132,7 +129,7 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
paintBoxDecorations(paintInfo, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y());
// An empty viewport disables rendering. FIXME: Should we still render filters?
- if (viewportSize().isEmpty())
+ if (m_viewportSize.isEmpty())
return;
// Don't paint if we don't have kids, except if we have filters we should paint those.
@@ -143,9 +140,8 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
RenderObject::PaintInfo childPaintInfo(paintInfo);
childPaintInfo.context->save();
- // SVG does not support independent x/y clipping
- if (style()->overflowX() != OVISIBLE)
- childPaintInfo.context->clip(overflowClipRect(borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y()));
+ // Apply initial viewport clip - not affected by overflow handling
+ childPaintInfo.context->clip(overflowClipRect(borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y()));
// Convert from container offsets (html renderers) to a relative transform (svg renderers).
// Transform from our paint container's coordinate system to our local coords.
@@ -153,10 +149,13 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
SVGResourceFilter* filter = 0;
FloatRect boundingBox = repaintRectInLocalCoordinates();
+
+ bool continueRendering = true;
if (childPaintInfo.phase == PaintPhaseForeground)
- prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
+ continueRendering = prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
- RenderBox::paint(childPaintInfo, 0, 0);
+ if (continueRendering)
+ RenderBox::paint(childPaintInfo, 0, 0);
if (childPaintInfo.phase == PaintPhaseForeground)
finishRenderSVGContent(this, childPaintInfo, filter, paintInfo.context);
@@ -167,11 +166,6 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
paintOutline(paintInfo.context, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y(), width(), height(), style());
}
-const FloatSize& RenderSVGRoot::viewportSize() const
-{
- return m_viewportSize;
-}
-
void RenderSVGRoot::calcViewport()
{
SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
@@ -196,13 +190,12 @@ void RenderSVGRoot::calcViewport()
// RenderBox methods will expect coordinates w/o any transforms in coordinates
// relative to our borderBox origin. This method gives us exactly that.
-TransformationMatrix RenderSVGRoot::localToBorderBoxTransform() const
+AffineTransform RenderSVGRoot::localToBorderBoxTransform() const
{
- TransformationMatrix ctm;
IntSize borderAndPadding = borderOriginToContentBox();
- ctm.translate(borderAndPadding.width(), borderAndPadding.height());
SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
- ctm.scale(svg->currentScale());
+ float scale = svg->currentScale();
+ AffineTransform ctm(scale, 0, 0, scale, borderAndPadding.width(), borderAndPadding.height());
ctm.translate(svg->currentTranslate().x(), svg->currentTranslate().y());
return svg->viewBoxToViewTransform(width(), height()) * ctm;
}
@@ -217,28 +210,21 @@ IntSize RenderSVGRoot::borderOriginToContentBox() const
return IntSize(borderLeft() + paddingLeft(), borderTop() + paddingTop());
}
-TransformationMatrix RenderSVGRoot::localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const
+AffineTransform RenderSVGRoot::localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const
{
- TransformationMatrix parentToContainer;
- parentToContainer.translate(parentOriginInContainer.x(), parentOriginInContainer.y());
- return localToParentTransform() * parentToContainer;
+ AffineTransform parentToContainer(localToParentTransform());
+ return parentToContainer.translateRight(parentOriginInContainer.x(), parentOriginInContainer.y());
}
-TransformationMatrix RenderSVGRoot::localToParentTransform() const
+const AffineTransform& RenderSVGRoot::localToParentTransform() const
{
IntSize parentToBorderBoxOffset = parentOriginToBorderBox();
- TransformationMatrix borderBoxOriginToParentOrigin;
- borderBoxOriginToParentOrigin.translate(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height());
+ AffineTransform borderBoxOriginToParentOrigin(localToBorderBoxTransform());
+ borderBoxOriginToParentOrigin.translateRight(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height());
- return localToBorderBoxTransform() * borderBoxOriginToParentOrigin;
-}
-
-// FIXME: This method should be removed as soon as callers to RenderBox::absoluteTransform() can be removed.
-TransformationMatrix RenderSVGRoot::absoluteTransform() const
-{
- // This would apply localTransform() twice if localTransform() were not the identity.
- return localToParentTransform() * RenderBox::absoluteTransform();
+ m_localToParentTransform = borderBoxOriginToParentOrigin;
+ return m_localToParentTransform;
}
FloatRect RenderSVGRoot::objectBoundingBox() const
@@ -249,18 +235,26 @@ FloatRect RenderSVGRoot::objectBoundingBox() const
FloatRect RenderSVGRoot::repaintRectInLocalCoordinates() const
{
// FIXME: This does not include the border but it should!
- return computeContainerBoundingBox(this, true);
+ FloatRect repaintRect = computeContainerBoundingBox(this, true);
+ style()->svgStyle()->inflateForShadow(repaintRect);
+ return repaintRect;
}
-TransformationMatrix RenderSVGRoot::localTransform() const
+AffineTransform RenderSVGRoot::localTransform() const
{
- return TransformationMatrix();
+ return AffineTransform();
}
void RenderSVGRoot::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
{
- // Apply our local transforms (except for x/y translation) and call RenderBox's method to handle all the normal CSS Box model bits
+ // Apply our local transforms (except for x/y translation), then our shadow,
+ // and then call RenderBox's method to handle all the normal CSS Box model bits
repaintRect = localToBorderBoxTransform().mapRect(repaintRect);
+
+ // Apply initial viewport clip - not affected by overflow settings
+ repaintRect.intersect(enclosingIntRect(FloatRect(FloatPoint(), m_viewportSize)));
+
+ style()->svgStyle()->inflateForShadow(repaintRect);
RenderBox::computeRectForRepaint(repaintContainer, repaintRect, fixed);
}
@@ -283,14 +277,9 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
IntPoint pointInBorderBox = pointInParent - parentOriginToBorderBox();
// Note: For now, we're ignoring hits to border and padding for <svg>
-
- if (style()->overflowX() == OHIDDEN) {
- // SVG doesn't support independent x/y overflow
- ASSERT(style()->overflowY() == OHIDDEN);
- IntPoint pointInContentBox = pointInBorderBox - borderOriginToContentBox();
- if (!contentBoxRect().contains(pointInContentBox))
- return false;
- }
+ IntPoint pointInContentBox = pointInBorderBox - borderOriginToContentBox();
+ if (!contentBoxRect().contains(pointInContentBox))
+ return false;
IntPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
@@ -310,5 +299,3 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
}
#endif // ENABLE(SVG)
-
-// vim:ts=4:noet
diff --git a/WebCore/rendering/RenderSVGRoot.h b/WebCore/rendering/RenderSVGRoot.h
index 08c3058..8ad5e40 100644
--- a/WebCore/rendering/RenderSVGRoot.h
+++ b/WebCore/rendering/RenderSVGRoot.h
@@ -31,9 +31,9 @@
namespace WebCore {
class SVGStyledElement;
-class TransformationMatrix;
+class AffineTransform;
-class RenderSVGRoot : public RenderBox, SVGRenderBase {
+class RenderSVGRoot : public RenderBox, protected SVGRenderBase {
public:
RenderSVGRoot(SVGStyledElement*);
@@ -54,17 +54,17 @@ private:
virtual void layout();
virtual void paint(PaintInfo&, int parentX, int parentY);
- virtual TransformationMatrix localToParentTransform() const;
+ virtual const AffineTransform& localToParentTransform() const;
bool fillContains(const FloatPoint&) const;
bool strokeContains(const FloatPoint&) const;
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const { return computeContainerBoundingBox(this, true); }
virtual FloatRect repaintRectInLocalCoordinates() const;
- // FIXME: Both of these overrides should be removed.
- virtual TransformationMatrix localTransform() const;
- virtual TransformationMatrix absoluteTransform() const;
+ // FIXME: This override should be removed.
+ virtual AffineTransform localTransform() const;
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
@@ -73,17 +73,17 @@ private:
virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const;
void calcViewport();
- const FloatSize& viewportSize() const;
bool selfWillPaint() const;
IntSize parentOriginToBorderBox() const;
IntSize borderOriginToContentBox() const;
- TransformationMatrix localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const;
- TransformationMatrix localToBorderBoxTransform() const;
+ AffineTransform localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const;
+ AffineTransform localToBorderBoxTransform() const;
RenderObjectChildList m_children;
FloatSize m_viewportSize;
+ mutable AffineTransform m_localToParentTransform;
};
inline RenderSVGRoot* toRenderSVGRoot(RenderObject* object)
diff --git a/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp b/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp
new file mode 100644
index 0000000..9d3d26f
--- /dev/null
+++ b/WebCore/rendering/RenderSVGShadowTreeRootContainer.cpp
@@ -0,0 +1,101 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. 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
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGShadowTreeRootContainer.h"
+
+#include "MouseEvent.h"
+#include "SVGShadowTreeElements.h"
+#include "SVGUseElement.h"
+
+namespace WebCore {
+
+RenderSVGShadowTreeRootContainer::RenderSVGShadowTreeRootContainer(SVGUseElement* node)
+ : RenderSVGTransformableContainer(node)
+ , m_recreateTree(false)
+{
+}
+
+RenderSVGShadowTreeRootContainer::~RenderSVGShadowTreeRootContainer()
+{
+ if (m_shadowRoot && m_shadowRoot->attached())
+ m_shadowRoot->detach();
+}
+
+void RenderSVGShadowTreeRootContainer::updateStyle(Node::StyleChange change)
+{
+ if (m_shadowRoot && m_shadowRoot->attached())
+ m_shadowRoot->recalcStyle(change);
+}
+
+void RenderSVGShadowTreeRootContainer::updateFromElement()
+{
+ bool hadExistingTree = m_shadowRoot;
+
+ SVGUseElement* useElement = static_cast<SVGUseElement*>(node());
+ if (!m_shadowRoot) {
+ ASSERT(!m_recreateTree);
+ m_shadowRoot = new SVGShadowTreeRootElement(document(), useElement);
+ useElement->buildPendingResource();
+ }
+
+ ASSERT(m_shadowRoot->shadowParentNode() == useElement);
+
+ bool shouldRecreateTree = m_recreateTree;
+ if (m_recreateTree) {
+ ASSERT(hadExistingTree);
+
+ if (m_shadowRoot->attached())
+ m_shadowRoot->detach();
+
+ m_shadowRoot->removeAllChildren();
+ m_recreateTree = false;
+ }
+
+ // Only rebuild the shadow tree, if we a) never had a tree or b) we were specifically asked to do so
+ // If the use element is a pending resource, and a) or b) is true, do nothing, and wait for the use
+ // element to be asked to buildPendingResource(), this will call us again, with m_recreateTrue=true.
+ if ((shouldRecreateTree || !hadExistingTree) && !useElement->isPendingResource()) {
+ useElement->buildShadowAndInstanceTree(m_shadowRoot.get());
+
+ // Attach shadow root element
+ m_shadowRoot->attachElement(style(), renderArena());
+
+ // Attach subtree, as if it was a regular non-shadow tree
+ for (Node* child = m_shadowRoot->firstChild(); child; child = child->nextSibling())
+ child->attach();
+ }
+
+ ASSERT(!m_recreateTree);
+ RenderSVGTransformableContainer::updateFromElement();
+}
+
+void RenderSVGShadowTreeRootContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderSVGTransformableContainer::styleDidChange(diff, oldStyle);
+
+ if (RenderObject* shadowRootRenderer = m_shadowRoot ? m_shadowRoot->renderer() : 0)
+ shadowRootRenderer->setStyle(style());
+}
+
+}
+
+#endif
diff --git a/WebCore/rendering/RenderSVGShadowTreeRootContainer.h b/WebCore/rendering/RenderSVGShadowTreeRootContainer.h
new file mode 100644
index 0000000..01cd427
--- /dev/null
+++ b/WebCore/rendering/RenderSVGShadowTreeRootContainer.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. 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
+ aint 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 RenderSVGShadowTreeRootContainer_h
+#define RenderSVGShadowTreeRootContainer_h
+
+#if ENABLE(SVG)
+#include "RenderSVGTransformableContainer.h"
+
+namespace WebCore {
+
+class SVGUseElement;
+class SVGShadowTreeRootElement;
+
+class RenderSVGShadowTreeRootContainer : public RenderSVGTransformableContainer {
+public:
+ RenderSVGShadowTreeRootContainer(SVGUseElement*);
+ virtual ~RenderSVGShadowTreeRootContainer();
+
+ void markShadowTreeForRecreation() { m_recreateTree = true; }
+ void updateStyle(Node::StyleChange);
+ virtual void updateFromElement();
+
+private:
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+
+ bool m_recreateTree;
+ RefPtr<SVGShadowTreeRootElement> m_shadowRoot;
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/rendering/RenderSVGText.cpp b/WebCore/rendering/RenderSVGText.cpp
index 3919d7f..e332c85 100644
--- a/WebCore/rendering/RenderSVGText.cpp
+++ b/WebCore/rendering/RenderSVGText.cpp
@@ -6,6 +6,7 @@
* 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
* 2007 Nikolas Zimmermann <zimmermann@kde.org>
* 2008 Rob Buis <buis@kde.org>
+ * 2009 Dirk Schulze <krit@webkit.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -69,10 +70,6 @@ void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer,
void RenderSVGText::layout()
{
ASSERT(needsLayout());
-
- // FIXME: This is a hack to avoid the RenderBlock::layout() partial repainting code which is not (yet) SVG aware
- setNeedsLayout(true);
-
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
// Best guess for a relative starting point
@@ -184,13 +181,13 @@ FloatRect RenderSVGText::objectBoundingBox() const
return boundingBox;
}
-FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
+FloatRect RenderSVGText::strokeBoundingBox() const
{
FloatRect repaintRect = objectBoundingBox();
// SVG needs to include the strokeWidth(), not the textStrokeWidth().
if (style()->svgStyle()->hasStroke()) {
- float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, style()->svgStyle()->strokeWidth(), 0.0f);
+ float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, style()->svgStyle()->strokeWidth(), 1.0f);
#if ENABLE(SVG_FONTS)
const Font& font = style()->font();
@@ -205,7 +202,28 @@ FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
repaintRect.inflate(strokeWidth);
}
- repaintRect.unite(filterBoundingBoxForRenderer(this));
+ return repaintRect;
+}
+
+FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
+{
+ FloatRect repaintRect = strokeBoundingBox();
+
+ // FIXME: We need to be careful here. We assume that there is no filter,
+ // clipper or masker if the rects are empty.
+ FloatRect rect = filterBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect = rect;
+
+ rect = clipperBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect.intersect(rect);
+
+ rect = maskerBoundingBoxForRenderer(this);
+ if (!rect.isEmpty())
+ repaintRect.intersect(rect);
+
+ style()->svgStyle()->inflateForShadow(repaintRect);
return repaintRect;
}
diff --git a/WebCore/rendering/RenderSVGText.h b/WebCore/rendering/RenderSVGText.h
index 9a2770b..9ae96a0 100644
--- a/WebCore/rendering/RenderSVGText.h
+++ b/WebCore/rendering/RenderSVGText.h
@@ -26,7 +26,7 @@
#if ENABLE(SVG)
-#include "TransformationMatrix.h"
+#include "AffineTransform.h"
#include "RenderSVGBlock.h"
namespace WebCore {
@@ -40,9 +40,11 @@ public:
private:
virtual const char* renderName() const { return "RenderSVGText"; }
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
+
virtual bool isSVGText() const { return true; }
- virtual TransformationMatrix localToParentTransform() const { return m_localTransform; }
+ virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
virtual void paint(PaintInfo&, int tx, int ty);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
@@ -60,14 +62,15 @@ private:
virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const;
virtual FloatRect objectBoundingBox() const;
+ virtual FloatRect strokeBoundingBox() const;
virtual FloatRect repaintRectInLocalCoordinates() const;
// FIXME: This can be removed when localTransform() is removed from RenderObject
- virtual TransformationMatrix localTransform() const { return m_localTransform; }
+ virtual AffineTransform localTransform() const { return m_localTransform; }
virtual RootInlineBox* createRootInlineBox();
- TransformationMatrix m_localTransform;
+ AffineTransform m_localTransform;
};
}
diff --git a/WebCore/rendering/RenderSVGTransformableContainer.cpp b/WebCore/rendering/RenderSVGTransformableContainer.cpp
index 2324eee..4bec7a7 100644
--- a/WebCore/rendering/RenderSVGTransformableContainer.cpp
+++ b/WebCore/rendering/RenderSVGTransformableContainer.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
+ Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
2004, 2005, 2006 Rob Buis <buis@kde.org>
2009 Google, Inc.
@@ -20,12 +20,12 @@
*/
#include "config.h"
-#if ENABLE(SVG)
+#if ENABLE(SVG)
#include "RenderSVGTransformableContainer.h"
+#include "SVGShadowTreeElements.h"
#include "SVGStyledTransformableElement.h"
-#include "SVGTransformList.h"
namespace WebCore {
@@ -34,12 +34,12 @@ RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransf
{
}
-TransformationMatrix RenderSVGTransformableContainer::localToParentTransform() const
+const AffineTransform& RenderSVGTransformableContainer::localToParentTransform() const
{
return m_localTransform;
}
-TransformationMatrix RenderSVGTransformableContainer::localTransform() const
+AffineTransform RenderSVGTransformableContainer::localTransform() const
{
return m_localTransform;
}
@@ -47,6 +47,14 @@ TransformationMatrix RenderSVGTransformableContainer::localTransform() const
void RenderSVGTransformableContainer::calculateLocalTransform()
{
m_localTransform = static_cast<SVGStyledTransformableElement*>(node())->animatedLocalTransform();
+ if (!node()->hasTagName(SVGNames::gTag) || !static_cast<SVGGElement*>(node())->isShadowTreeContainerElement())
+ return;
+
+ FloatSize translation = static_cast<SVGShadowTreeContainerElement*>(node())->containerTranslation();
+ if (translation.width() == 0 && translation.height() == 0)
+ return;
+
+ m_localTransform.translate(translation.width(), translation.height());
}
}
diff --git a/WebCore/rendering/RenderSVGTransformableContainer.h b/WebCore/rendering/RenderSVGTransformableContainer.h
index c929761..1de0b19 100644
--- a/WebCore/rendering/RenderSVGTransformableContainer.h
+++ b/WebCore/rendering/RenderSVGTransformableContainer.h
@@ -31,14 +31,14 @@ namespace WebCore {
public:
RenderSVGTransformableContainer(SVGStyledTransformableElement*);
- virtual TransformationMatrix localToParentTransform() const;
+ virtual const AffineTransform& localToParentTransform() const;
private:
virtual void calculateLocalTransform();
// FIXME: This can be made non-virtual once SVGRenderTreeAsText stops using localTransform()
- virtual TransformationMatrix localTransform() const;
+ virtual AffineTransform localTransform() const;
- TransformationMatrix m_localTransform;
+ AffineTransform m_localTransform;
};
}
diff --git a/WebCore/rendering/RenderSVGViewportContainer.cpp b/WebCore/rendering/RenderSVGViewportContainer.cpp
index a432ef3..103d9d2 100644
--- a/WebCore/rendering/RenderSVGViewportContainer.cpp
+++ b/WebCore/rendering/RenderSVGViewportContainer.cpp
@@ -38,23 +38,33 @@ RenderSVGViewportContainer::RenderSVGViewportContainer(SVGStyledElement* node)
{
}
-void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, int parentX, int parentY)
+FloatRect RenderSVGViewportContainer::markerBoundaries(const AffineTransform& markerTransformation) const
{
- // FIXME: The if statement here evaluates to false. isEmpty() is exactly the same
- // as what is on the right side, so it's basically !isEmpty && isEmpty. So this
- // function does nothing.
+ FloatRect coordinates = repaintRectInLocalCoordinates();
- // A value of zero disables rendering of the element.
- if (!m_viewport.isEmpty() && (m_viewport.width() <= 0. || m_viewport.height() <= 0.))
- return;
+ // Map repaint rect into parent coordinate space, in which the marker boundaries have to be evaluated
+ coordinates = localToParentTransform().mapRect(coordinates);
- RenderSVGContainer::paint(paintInfo, parentX, parentY);
+ return markerTransformation.mapRect(coordinates);
+}
+
+AffineTransform RenderSVGViewportContainer::markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth) const
+{
+ // The 'origin' coordinate maps to SVGs refX/refY, given in coordinates relative to the viewport established by the marker
+ FloatPoint mappedOrigin = viewportTransform().mapPoint(origin);
+
+ AffineTransform transformation = contentTransformation;
+ if (strokeWidth != -1)
+ transformation.scaleNonUniform(strokeWidth, strokeWidth);
+
+ transformation.translate(-mappedOrigin.x(), -mappedOrigin.y());
+ return transformation;
}
void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo)
{
- if (style()->overflowX() != OVISIBLE)
- paintInfo.context->clip(enclosingIntRect(m_viewport)); // FIXME: Eventually we'll want float-precision clipping
+ if (SVGRenderBase::isOverflowHidden(this))
+ paintInfo.context->clip(m_viewport);
}
void RenderSVGViewportContainer::calcViewport()
@@ -82,7 +92,7 @@ void RenderSVGViewportContainer::calcViewport()
}
}
-TransformationMatrix RenderSVGViewportContainer::viewportTransform() const
+AffineTransform RenderSVGViewportContainer::viewportTransform() const
{
if (node()->hasTagName(SVGNames::svgTag)) {
SVGSVGElement* svg = static_cast<SVGSVGElement*>(node());
@@ -92,38 +102,27 @@ TransformationMatrix RenderSVGViewportContainer::viewportTransform() const
return marker->viewBoxToViewTransform(m_viewport.width(), m_viewport.height());
}
- return TransformationMatrix();
+ return AffineTransform();
}
-TransformationMatrix RenderSVGViewportContainer::localToParentTransform() const
+const AffineTransform& RenderSVGViewportContainer::localToParentTransform() const
{
- TransformationMatrix viewportTranslation;
- viewportTranslation.translate(m_viewport.x(), m_viewport.y());
- return viewportTransform() * viewportTranslation;
+ AffineTransform viewportTranslation(viewportTransform());
+ m_localToParentTransform = viewportTranslation.translateRight(m_viewport.x(), m_viewport.y());
+ return m_localToParentTransform;
// If this class were ever given a localTransform(), then the above would read:
// return viewportTransform() * localTransform() * viewportTranslation;
}
-// FIXME: This method should be removed as soon as callers to RenderBox::absoluteTransform() can be removed.
-TransformationMatrix RenderSVGViewportContainer::absoluteTransform() const
-{
- // This would apply localTransform() twice if localTransform() were not the identity.
- return localToParentTransform() * RenderSVGContainer::absoluteTransform();
-}
-
bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& pointInParent)
{
- // Respect the viewport clip (which is in parent coords). SVG does not support separate x/y overflow rules.
- if (style()->overflowX() == OHIDDEN) {
- ASSERT(style()->overflowY() == OHIDDEN);
- if (!m_viewport.contains(pointInParent))
- return false;
- }
- return true;
+ // Respect the viewport clip (which is in parent coords)
+ if (!SVGRenderBase::isOverflowHidden(this))
+ return true;
+
+ return m_viewport.contains(pointInParent);
}
}
#endif // ENABLE(SVG)
-
-// vim:ts=4:noet
diff --git a/WebCore/rendering/RenderSVGViewportContainer.h b/WebCore/rendering/RenderSVGViewportContainer.h
index b8b30b5..c4043ec 100644
--- a/WebCore/rendering/RenderSVGViewportContainer.h
+++ b/WebCore/rendering/RenderSVGViewportContainer.h
@@ -24,7 +24,6 @@
#define RenderSVGViewportContainer_h
#if ENABLE(SVG)
-
#include "RenderSVGContainer.h"
namespace WebCore {
@@ -35,19 +34,19 @@ class RenderSVGViewportContainer : public RenderSVGContainer {
public:
RenderSVGViewportContainer(SVGStyledElement*);
- // FIXME: This is only public for SVGResourceMarker::draw, likely the callsite should be changed.
- TransformationMatrix viewportTransform() const;
+ // Calculates marker boundaries, mapped to the target element's coordinate space
+ FloatRect markerBoundaries(const AffineTransform& markerTransformation) const;
- virtual void paint(PaintInfo&, int parentX, int parentY);
+ // Generates a transformation matrix usable to render marker content. Handles scaling the marker content
+ // acording to SVGs markerUnits="strokeWidth" concept, when a strokeWidth value != -1 is passed in.
+ AffineTransform markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth = -1) const;
private:
virtual bool isSVGContainer() const { return true; }
virtual const char* renderName() const { return "RenderSVGViewportContainer"; }
- virtual TransformationMatrix localToParentTransform() const;
-
- // FIXME: This override should be removed once callers of RenderBox::absoluteTransform() can be removed.
- virtual TransformationMatrix absoluteTransform() const;
+ AffineTransform viewportTransform() const;
+ virtual const AffineTransform& localToParentTransform() const;
virtual void calcViewport();
@@ -55,6 +54,7 @@ private:
virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent);
FloatRect m_viewport;
+ mutable AffineTransform m_localToParentTransform;
};
inline RenderSVGViewportContainer* toRenderSVGViewportContainer(RenderObject* object)
@@ -70,5 +70,3 @@ void toRenderSVGViewportContainer(const RenderSVGViewportContainer*);
#endif // ENABLE(SVG)
#endif // RenderSVGViewportContainer_h
-
-// vim:ts=4:noet
diff --git a/WebCore/rendering/RenderScrollbar.cpp b/WebCore/rendering/RenderScrollbar.cpp
index b3c5369..63fce8d 100644
--- a/WebCore/rendering/RenderScrollbar.cpp
+++ b/WebCore/rendering/RenderScrollbar.cpp
@@ -40,6 +40,16 @@ RenderScrollbar::RenderScrollbar(ScrollbarClient* client, ScrollbarOrientation o
: Scrollbar(client, orientation, RegularScrollbar, RenderScrollbarTheme::renderScrollbarTheme())
, m_owner(renderer)
{
+ // FIXME: We need to do this because RenderScrollbar::styleChanged is called as soon as the scrollbar is created.
+
+ // Update the scrollbar size.
+ updateScrollbarPart(ScrollbarBGPart);
+ RenderScrollbarPart* part = m_parts.get(ScrollbarBGPart);
+ if (!part)
+ return;
+
+ part->layout();
+ setFrameRect(IntRect(0, 0, part->width(), part->height()));
}
RenderScrollbar::~RenderScrollbar()
diff --git a/WebCore/rendering/RenderScrollbarPart.cpp b/WebCore/rendering/RenderScrollbarPart.cpp
index 0f29aeb..c83248a 100644
--- a/WebCore/rendering/RenderScrollbarPart.cpp
+++ b/WebCore/rendering/RenderScrollbarPart.cpp
@@ -27,6 +27,7 @@
#include "RenderScrollbarPart.h"
#include "RenderScrollbar.h"
#include "RenderScrollbarTheme.h"
+#include "RenderView.h"
using namespace std;
@@ -51,9 +52,6 @@ void RenderScrollbarPart::layout()
else
layoutVerticalPart();
- m_overflowWidth = max(width(), m_overflowWidth);
- m_overflowHeight = max(height(), m_overflowHeight);
-
setNeedsLayout(false);
}
@@ -143,8 +141,16 @@ void RenderScrollbarPart::imageChanged(WrappedImagePtr image, const IntRect* rec
{
if (m_scrollbar && m_part != NoPart)
m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part);
- else
+ else {
+ if (FrameView* frameView = view()->frameView()) {
+ if (frameView->isFrameViewScrollCorner(this)) {
+ frameView->invalidateScrollCorner();
+ return;
+ }
+ }
+
RenderBlock::imageChanged(image, rect);
+ }
}
void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, int tx, int ty, const IntRect& rect)
@@ -153,8 +159,6 @@ void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, int tx
setLocation(rect.x() - tx, rect.y() - ty);
setWidth(rect.width());
setHeight(rect.height());
- setOverflowWidth(max(rect.width(), overflowWidth()));
- setOverflowHeight(max(rect.height(), overflowHeight()));
if (graphicsContext->paintingDisabled())
return;
diff --git a/WebCore/rendering/RenderScrollbarTheme.cpp b/WebCore/rendering/RenderScrollbarTheme.cpp
index 06ca32a..19143cc 100644
--- a/WebCore/rendering/RenderScrollbarTheme.cpp
+++ b/WebCore/rendering/RenderScrollbarTheme.cpp
@@ -109,7 +109,7 @@ IntRect RenderScrollbarTheme::constrainTrackRectToTrackPieces(Scrollbar* scrollb
void RenderScrollbarTheme::paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect)
{
// FIXME: Implement.
- context->fillRect(cornerRect, Color::white);
+ context->fillRect(cornerRect, Color::white, DeviceColorSpace);
}
void RenderScrollbarTheme::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar)
diff --git a/WebCore/rendering/RenderSelectionInfo.h b/WebCore/rendering/RenderSelectionInfo.h
index e7b7b78..c06a9ae 100644
--- a/WebCore/rendering/RenderSelectionInfo.h
+++ b/WebCore/rendering/RenderSelectionInfo.h
@@ -30,7 +30,7 @@
namespace WebCore {
-class RenderSelectionInfoBase {
+class RenderSelectionInfoBase : public Noncopyable {
public:
RenderSelectionInfoBase()
: m_object(0)
diff --git a/WebCore/rendering/RenderSlider.cpp b/WebCore/rendering/RenderSlider.cpp
index 8a19d97..7398a2f 100644
--- a/WebCore/rendering/RenderSlider.cpp
+++ b/WebCore/rendering/RenderSlider.cpp
@@ -52,9 +52,10 @@ static const int defaultTrackLength = 129;
// FIXME: The SliderRange class and functions are entirely based on the DOM,
// and could be put with HTMLInputElement (possibly with a new name) instead of here.
struct SliderRange {
- bool isIntegral;
+ bool hasStep;
+ double step;
double minimum;
- double maximum;
+ double maximum; // maximum must be >= minimum.
explicit SliderRange(HTMLInputElement*);
double clampValue(double value);
@@ -79,33 +80,40 @@ struct SliderRange {
SliderRange::SliderRange(HTMLInputElement* element)
{
- // FIXME: What's the right way to handle an integral range with non-integral minimum and maximum?
- // Currently values are guaranteed to be integral but could be outside the range in that case.
-
- isIntegral = !equalIgnoringCase(element->getAttribute(precisionAttr), "float");
-
- // FIXME: This treats maximum strings that can't be parsed as 0, but perhaps 100 would be more appropriate.
- const AtomicString& maxString = element->getAttribute(maxAttr);
- maximum = maxString.isNull() ? 100.0 : maxString.toDouble();
-
- // If the maximum is smaller, use it as the minimum.
- minimum = min(element->getAttribute(minAttr).toDouble(), maximum);
+ if (element->hasAttribute(precisionAttr)) {
+ step = 1.0;
+ hasStep = !equalIgnoringCase(element->getAttribute(precisionAttr), "float");
+ } else
+ hasStep = element->getAllowedValueStep(&step);
+
+ maximum = element->maximum();
+ minimum = element->minimum();
}
double SliderRange::clampValue(double value)
{
double clampedValue = max(minimum, min(value, maximum));
- return isIntegral ? round(clampedValue) : clampedValue;
+ if (!hasStep)
+ return clampedValue;
+ // Rounds clampedValue to minimum + N * step.
+ clampedValue = minimum + round((clampedValue - minimum) / step) * step;
+ if (clampedValue > maximum)
+ clampedValue -= step;
+ ASSERT(clampedValue >= minimum);
+ ASSERT(clampedValue <= maximum);
+ return clampedValue;
}
double SliderRange::valueFromElement(HTMLInputElement* element, bool* wasClamped)
{
- String valueString = element->value();
- double oldValue = valueString.isNull() ? (minimum + maximum) / 2 : valueString.toDouble();
+ double oldValue;
+ bool parseSuccess = HTMLInputElement::formStringToDouble(element->value(), &oldValue);
+ if (!parseSuccess)
+ oldValue = (minimum + maximum) / 2;
double newValue = clampValue(oldValue);
if (wasClamped)
- *wasClamped = valueString.isNull() || newValue != oldValue;
+ *wasClamped = !parseSuccess || newValue != oldValue;
return newValue;
}
@@ -285,6 +293,8 @@ PassRefPtr<RenderStyle> RenderSlider::createThumbStyle(const RenderStyle* parent
style->setAppearance(SliderThumbHorizontalPart);
else if (parentStyle->appearance() == MediaSliderPart)
style->setAppearance(MediaSliderThumbPart);
+ else if (parentStyle->appearance() == MediaVolumeSliderPart)
+ style->setAppearance(MediaVolumeSliderThumbPart);
return style.release();
}
@@ -302,7 +312,7 @@ IntRect RenderSlider::thumbRect()
double fraction = sliderPosition(static_cast<HTMLInputElement*>(node()));
IntRect contentRect = contentBoxRect();
- if (style()->appearance() == SliderVerticalPart) {
+ if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart) {
thumbRect.setX(contentRect.x() + (contentRect.width() - thumbRect.width()) / 2);
thumbRect.setY(contentRect.y() + static_cast<int>(nextafter((contentRect.height() - thumbRect.height()) + 1, 0) * (1 - fraction)));
} else {
@@ -340,8 +350,6 @@ void RenderSlider::layout()
calcWidth();
calcHeight();
- IntRect overflowRect(IntPoint(), size());
-
if (thumb) {
if (oldSize != size())
thumb->setChildNeedsLayout(true, false);
@@ -358,19 +366,9 @@ void RenderSlider::layout()
thumb->repaintDuringLayoutIfMoved(oldThumbRect);
statePusher.pop();
-
- IntRect thumbOverflowRect = thumb->overflowRect();
- thumbOverflowRect.move(thumb->x(), thumb->y());
- overflowRect.unite(thumbOverflowRect);
+ addOverflowFromChild(thumb);
}
- // FIXME: m_overflowWidth and m_overflowHeight should be renamed
- // m_overflowRight and m_overflowBottom.
- m_overflowLeft = overflowRect.x();
- m_overflowTop = overflowRect.y();
- m_overflowWidth = overflowRect.right();
- m_overflowHeight = overflowRect.bottom();
-
repainter.repaintAfterLayout();
setNeedsLayout(false);
@@ -385,7 +383,7 @@ void RenderSlider::updateFromElement()
bool clamped;
double value = range.valueFromElement(element, &clamped);
if (clamped)
- element->setValueFromRenderer(String::number(value));
+ element->setValueFromRenderer(HTMLInputElement::formStringFromDouble(value));
// Layout will take care of the thumb's size and position.
if (!m_thumb) {
@@ -406,7 +404,7 @@ bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt)
return false;
#if ENABLE(VIDEO)
- if (style()->appearance() == MediaSliderPart) {
+ if (style()->appearance() == MediaSliderPart || style()->appearance() == MediaVolumeSliderPart) {
MediaControlInputElement *sliderThumb = static_cast<MediaControlInputElement*>(m_thumb->renderer()->node());
return sliderThumb->hitTest(evt->absoluteLocation());
}
@@ -438,10 +436,10 @@ void RenderSlider::setValueForPosition(int position)
// Calculate the new value based on the position, and send it to the element.
SliderRange range(element);
double fraction = static_cast<double>(position) / trackSize();
- if (style()->appearance() == SliderVerticalPart)
+ if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart)
fraction = 1 - fraction;
double value = range.clampValue(range.valueFromProportion(fraction));
- element->setValueFromRenderer(String::number(value));
+ element->setValueFromRenderer(HTMLInputElement::formStringFromDouble(value));
// Also update the position if appropriate.
if (position != currentPosition()) {
@@ -459,7 +457,7 @@ int RenderSlider::positionForOffset(const IntPoint& p)
return 0;
int position;
- if (style()->appearance() == SliderVerticalPart)
+ if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart)
position = p.y() - m_thumb->renderBox()->height() / 2;
else
position = p.x() - m_thumb->renderBox()->width() / 2;
@@ -472,7 +470,7 @@ int RenderSlider::currentPosition()
ASSERT(m_thumb);
ASSERT(m_thumb->renderer());
- if (style()->appearance() == SliderVerticalPart)
+ if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart)
return toRenderBox(m_thumb->renderer())->y() - contentBoxRect().y();
return toRenderBox(m_thumb->renderer())->x() - contentBoxRect().x();
}
@@ -482,7 +480,7 @@ int RenderSlider::trackSize()
ASSERT(m_thumb);
ASSERT(m_thumb->renderer());
- if (style()->appearance() == SliderVerticalPart)
+ if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart)
return contentHeight() - m_thumb->renderBox()->height();
return contentWidth() - m_thumb->renderBox()->width();
}
diff --git a/WebCore/rendering/RenderTable.cpp b/WebCore/rendering/RenderTable.cpp
index 7599999..61e05ad 100644
--- a/WebCore/rendering/RenderTable.cpp
+++ b/WebCore/rendering/RenderTable.cpp
@@ -62,8 +62,8 @@ RenderTable::RenderTable(Node* node)
, m_borderRight(0)
{
#ifdef ANDROID_LAYOUT
- m_singleColumn = false;
-#endif
+ m_singleColumn = false;
+#endif
m_columnPos.fill(0, 2);
m_columns.fill(ColumnStruct(), 1);
}
@@ -208,7 +208,7 @@ void RenderTable::calcWidth()
}
}
#endif
-
+
if (isPositioned())
calcAbsoluteHorizontal();
@@ -248,7 +248,7 @@ void RenderTable::calcWidth()
// in SSR mode, we ignore left/right margin for table
if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR)
return;
-#endif
+#endif
calcHorizontalMargins(style()->marginLeft(), style()->marginRight(), availableWidth);
}
@@ -265,21 +265,21 @@ void RenderTable::layout()
LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));
setHeight(0);
- m_overflowHeight = 0;
- m_overflowTop = 0;
+ m_overflow.clear();
+
initMaxMarginValues();
#ifdef ANDROID_LAYOUT
bool relayoutChildren = false;
int oldVisibleWidth = m_visibleWidth;
#endif
-
+
int oldWidth = width();
calcWidth();
#ifdef ANDROID_LAYOUT
if (oldVisibleWidth != m_visibleWidth
- && document()->settings()->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen)
+ && document()->settings()->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen)
relayoutChildren = true;
else if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
// if the width of a table is wider than its container width, or it has a nested table,
@@ -298,7 +298,7 @@ void RenderTable::layout()
}
if (shouldRenderAsSingleColumn) {
- m_singleColumn = true;
+ m_singleColumn = true;
if (width() > cw)
setWidth(cw);
if (m_minPrefWidth > cw)
@@ -354,9 +354,6 @@ void RenderTable::layout()
if (m_caption)
m_caption->layoutIfNeeded();
- m_overflowWidth = width() + (collapsing ? outerBorderRight() - borderRight() : 0);
- m_overflowLeft = collapsing ? borderLeft() - outerBorderLeft() : 0;
-
// If any table section moved vertically, we will just repaint everything from that
// section down (it is quite unlikely that any of the following sections
// did not shift).
@@ -372,10 +369,6 @@ void RenderTable::layout()
m_caption->repaintDuringLayoutIfMoved(captionRect);
setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom());
- m_overflowLeft = min(m_overflowLeft, m_caption->x() + m_caption->overflowLeft(false));
- m_overflowWidth = max(m_overflowWidth, m_caption->x() + m_caption->overflowWidth(false));
- m_overflowTop = min(m_overflowTop, m_caption->y() + m_caption->overflowTop(false));
- m_overflowHeight = max(m_overflowHeight, m_caption->y() + m_caption->overflowHeight(false));
if (height() != oldTableTop) {
sectionMoved = true;
@@ -421,15 +414,11 @@ void RenderTable::layout()
while (section) {
if (!sectionMoved && section->y() != height()) {
sectionMoved = true;
- movedSectionTop = min(height(), section->y()) + section->overflowTop(false);
+ movedSectionTop = min(height(), section->y()) + section->topVisibleOverflow();
}
section->setLocation(bl, height());
setHeight(height() + section->height());
- m_overflowLeft = min(m_overflowLeft, section->x() + section->overflowLeft(false));
- m_overflowWidth = max(m_overflowWidth, section->x() + section->overflowWidth(false));
- m_overflowTop = min(m_overflowTop, section->y() + section->overflowTop(false));
- m_overflowHeight = max(m_overflowHeight, section->y() + section->overflowHeight(false));
section = sectionBelow(section);
}
@@ -443,37 +432,34 @@ void RenderTable::layout()
m_caption->repaintDuringLayoutIfMoved(captionRect);
setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom());
- m_overflowLeft = min(m_overflowLeft, m_caption->x() + m_caption->overflowLeft(false));
- m_overflowWidth = max(m_overflowWidth, m_caption->x() + m_caption->overflowWidth(false));
}
if (isPositioned())
calcHeight();
- m_overflowHeight = max(m_overflowHeight, height());
-
// table can be containing block of positioned elements.
// FIXME: Only pass true if width or height changed.
layoutPositionedObjects(true);
- if (!hasOverflowClip()) {
- int shadowLeft;
- int shadowRight;
- int shadowTop;
- int shadowBottom;
- style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
-
- m_overflowLeft = min(m_overflowLeft, shadowLeft);
- m_overflowWidth = max(m_overflowWidth, width() + shadowRight);
- m_overflowTop = min(m_overflowTop, shadowTop);
- m_overflowHeight = max(m_overflowHeight, height() + shadowBottom);
-
- if (hasReflection()) {
- IntRect reflection(reflectionBox());
- m_overflowTop = min(m_overflowTop, reflection.y());
- m_overflowHeight = max(m_overflowHeight, reflection.bottom());
- m_overflowLeft = min(m_overflowLeft, reflection.x());
- m_overflowHeight = max(m_overflowWidth, reflection.right());
+ // Add overflow from borders.
+ int rightBorderOverflow = width() + (collapsing ? outerBorderRight() - borderRight() : 0);
+ int leftBorderOverflow = collapsing ? borderLeft() - outerBorderLeft() : 0;
+ int bottomBorderOverflow = height() + (collapsing ? outerBorderBottom() - borderBottom() : 0);
+ int topBorderOverflow = collapsing ? borderTop() - outerBorderTop() : 0;
+ addLayoutOverflow(IntRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow));
+
+ // Add visual overflow from box-shadow and reflections.
+ addShadowOverflow();
+
+ // Add overflow from our caption.
+ if (m_caption)
+ addOverflowFromChild(m_caption);
+
+ // Add overflow from our sections.
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isTableSection()) {
+ RenderTableSection* section = toRenderTableSection(child);
+ addOverflowFromChild(section);
}
}
@@ -482,7 +468,7 @@ void RenderTable::layout()
bool didFullRepaint = repainter.repaintAfterLayout();
// Repaint with our new bounds if they are different from our old bounds.
if (!didFullRepaint && sectionMoved)
- repaintRectangle(IntRect(m_overflowLeft, movedSectionTop, m_overflowWidth - m_overflowLeft, m_overflowHeight - movedSectionTop));
+ repaintRectangle(IntRect(leftVisibleOverflow(), movedSectionTop, rightVisibleOverflow() - leftVisibleOverflow(), bottomVisibleOverflow() - movedSectionTop));
setNeedsLayout(false);
}
@@ -503,9 +489,9 @@ void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty)
PaintPhase paintPhase = paintInfo.phase;
int os = 2 * maximalOutlineSize(paintPhase);
- if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + overflowHeight(false) <= paintInfo.rect.y() - os)
+ if (ty + topVisibleOverflow() >= paintInfo.rect.bottom() + os || ty + bottomVisibleOverflow() <= paintInfo.rect.y() - os)
return;
- if (tx + overflowLeft(false) >= paintInfo.rect.right() + os || tx + overflowWidth(false) <= paintInfo.rect.x() - os)
+ if (tx + leftVisibleOverflow() >= paintInfo.rect.right() + os || tx + rightVisibleOverflow() <= paintInfo.rect.x() - os)
return;
bool pushedClip = pushContentsClip(paintInfo, tx, ty);
@@ -566,6 +552,9 @@ void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty)
void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
{
+ if (!shouldPaintWithinRoot(paintInfo))
+ return;
+
int w = width();
int h = height();
diff --git a/WebCore/rendering/RenderTableCell.cpp b/WebCore/rendering/RenderTableCell.cpp
index 8b7a068..d97ae6e 100644
--- a/WebCore/rendering/RenderTableCell.cpp
+++ b/WebCore/rendering/RenderTableCell.cpp
@@ -168,6 +168,17 @@ void RenderTableCell::setOverrideSize(int size)
RenderBlock::setOverrideSize(size);
}
+IntSize RenderTableCell::offsetFromContainer(RenderObject* o) const
+{
+ ASSERT(o == container());
+
+ IntSize offset = RenderBlock::offsetFromContainer(o);
+ if (parent())
+ offset.expand(-parentBox()->x(), -parentBox()->y());
+
+ return offset;
+}
+
IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
{
// If the table grid is dirty, we cannot get reliable information about adjoining cells,
@@ -207,9 +218,9 @@ IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBoxModelObject* rep
right = max(right, below->borderHalfRight(true));
}
}
- left = max(left, -overflowLeft(false));
- top = max(top, -overflowTop(false));
- IntRect r(-left, - top, left + max(width() + right, overflowWidth(false)), top + max(height() + bottom, overflowHeight(false)));
+ left = max(left, -leftVisibleOverflow());
+ top = max(top, -topVisibleOverflow());
+ IntRect r(-left, - top, left + max(width() + right, rightVisibleOverflow()), top + max(height() + bottom, bottomVisibleOverflow()));
if (RenderView* v = view()) {
// FIXME: layoutDelta needs to be applied in parts before/after transforms and
@@ -226,35 +237,11 @@ void RenderTableCell::computeRectForRepaint(RenderBoxModelObject* repaintContain
return;
r.setY(r.y());
RenderView* v = view();
- if ((!v || !v->layoutStateEnabled()) && parent())
+ if ((!v || !v->layoutStateEnabled() || repaintContainer) && parent())
r.move(-parentBox()->x(), -parentBox()->y()); // Rows are in the same coordinate space, so don't add their offset in.
RenderBlock::computeRectForRepaint(repaintContainer, r, fixed);
}
-void RenderTableCell::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
-{
- if (repaintContainer == this)
- return;
-
- RenderView* v = view();
- if ((!v || !v->layoutStateEnabled()) && parent()) {
- // Rows are in the same coordinate space, so don't add their offset in.
- // FIXME: this is wrong with transforms
- transformState.move(-parentBox()->x(), -parentBox()->y());
- }
- RenderBlock::mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
-}
-
-void RenderTableCell::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
-{
- RenderBlock::mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
- if (parent()) {
- // Rows are in the same coordinate space, so add their offset back in.
- // FIXME: this is wrong with transforms
- transformState.move(parentBox()->x(), parentBox()->y());
- }
-}
-
int RenderTableCell::baselinePosition(bool firstLine, bool isRootLineBox) const
{
if (isRootLineBox)
@@ -656,6 +643,9 @@ int RenderTableCell::borderHalfBottom(bool outer) const
void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty)
{
if (paintInfo.phase == PaintPhaseCollapsedTableBorders && style()->visibility() == VISIBLE) {
+ if (!shouldPaintWithinRoot(paintInfo))
+ return;
+
tx += x();
ty += y();
int os = 2 * maximalOutlineSize(paintInfo.phase);
@@ -827,6 +817,9 @@ void RenderTableCell::paintCollapsedBorder(GraphicsContext* graphicsContext, int
void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, int ty, RenderObject* backgroundObject)
{
+ if (!shouldPaintWithinRoot(paintInfo))
+ return;
+
if (!backgroundObject)
return;
@@ -858,7 +851,7 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, i
paintInfo.context->save();
paintInfo.context->clip(clipRect);
}
- paintFillLayers(paintInfo, c, bgLayer, tx, ty, w, h);
+ paintFillLayers(paintInfo, c, bgLayer, tx, ty, w, h, CompositeSourceOver, backgroundObject);
if (shouldClip)
paintInfo.context->restore();
}
@@ -866,6 +859,9 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, i
void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
{
+ if (!shouldPaintWithinRoot(paintInfo))
+ return;
+
RenderTable* tableElt = table();
if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
return;
diff --git a/WebCore/rendering/RenderTableCell.h b/WebCore/rendering/RenderTableCell.h
index 9532bb6..0f8580d 100644
--- a/WebCore/rendering/RenderTableCell.h
+++ b/WebCore/rendering/RenderTableCell.h
@@ -106,13 +106,12 @@ public:
virtual void setOverrideSize(int);
+ bool hasVisibleOverflow() const { return m_overflow; }
+
protected:
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
- virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const;
- virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const;
-
private:
virtual const char* renderName() const { return isAnonymous() ? "RenderTableCell (anonymous)" : "RenderTableCell"; }
@@ -127,6 +126,7 @@ private:
virtual void paintBoxDecorations(PaintInfo&, int tx, int ty);
virtual void paintMask(PaintInfo&, int tx, int ty);
+ virtual IntSize offsetFromContainer(RenderObject*) const;
virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer);
virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false);
diff --git a/WebCore/rendering/RenderTableRow.cpp b/WebCore/rendering/RenderTableRow.cpp
index bafadfc..a11a14b 100644
--- a/WebCore/rendering/RenderTableRow.cpp
+++ b/WebCore/rendering/RenderTableRow.cpp
@@ -1,6 +1,4 @@
/**
- * This file is part of the DOM implementation for KDE.
- *
* Copyright (C) 1997 Martin Jones (mjones@kde.org)
* (C) 1997 Torben Weis (weis@kde.org)
* (C) 1998 Waldo Bastian (bastian@kde.org)
diff --git a/WebCore/rendering/RenderTableSection.cpp b/WebCore/rendering/RenderTableSection.cpp
index 5d47357..a2457e1 100644
--- a/WebCore/rendering/RenderTableSection.cpp
+++ b/WebCore/rendering/RenderTableSection.cpp
@@ -46,6 +46,14 @@ namespace WebCore {
using namespace HTMLNames;
+static inline void setRowHeightToRowStyleHeightIfNotRelative(RenderTableSection::RowStruct* row)
+{
+ ASSERT(row && row->rowRenderer);
+ row->height = row->rowRenderer->style()->height();
+ if (row->height.isRelative())
+ row->height = Length();
+}
+
RenderTableSection::RenderTableSection(Node* node)
: RenderBox(node)
, m_gridRows(0)
@@ -55,10 +63,6 @@ RenderTableSection::RenderTableSection(Node* node)
, m_outerBorderRight(0)
, m_outerBorderTop(0)
, m_outerBorderBottom(0)
- , m_overflowLeft(0)
- , m_overflowWidth(0)
- , m_overflowTop(0)
- , m_overflowHeight(0)
, m_needsCellRecalc(false)
, m_hasOverflowingCell(false)
{
@@ -130,11 +134,8 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild
m_grid[m_cRow].rowRenderer = toRenderTableRow(child);
- if (!beforeChild) {
- m_grid[m_cRow].height = child->style()->height();
- if (m_grid[m_cRow].height.isRelative())
- m_grid[m_cRow].height = Length();
- }
+ if (!beforeChild)
+ setRowHeightToRowStyleHeightIfNotRelative(&m_grid[m_cRow]);
// If the next renderer is actually wrapped in an anonymous table row, we need to go up and find that.
while (beforeChild && beforeChild->parent() != this)
@@ -266,12 +267,11 @@ void RenderTableSection::setCellWidths()
if (view()->frameView()) {
const Settings* settings = document()->settings();
ASSERT(settings);
- if (settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) {
+ if (settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen)
visibleWidth = view()->frameView()->screenWidth();
- }
}
#endif
-
+
for (int i = 0; i < m_gridRows; i++) {
Row& row = *m_grid[i].row;
int cols = row.size();
@@ -288,12 +288,13 @@ void RenderTableSection::setCellWidths()
endCol++;
}
int w = columnPos[endCol] - columnPos[j] - table()->hBorderSpacing();
-#ifdef ANDROID_LAYOUT
- if (table()->isSingleColumn())
- w = table()->width()-(table()->borderLeft()+table()->borderRight()+
- (table()->collapseBorders()?0:(table()->paddingLeft()+table()->paddingRight()+
- 2*table()->hBorderSpacing())));
-#endif
+#ifdef ANDROID_LAYOUT
+ if (table()->isSingleColumn()) {
+ int b = table()->collapseBorders() ?
+ 0 : table()->paddingLeft() + table()->paddingRight() + 2 * table()->hBorderSpacing();
+ w = table()->width() - (table()->borderLeft() + table()->borderRight() + b);
+ }
+#endif
int oldWidth = cell->width();
#ifdef ANDROID_LAYOUT
if (w != oldWidth || (visibleWidth > 0 && visibleWidth != cell->getVisibleWidth())) {
@@ -328,9 +329,14 @@ int RenderTableSection::calcRowHeight()
ASSERT(!needsLayout());
#ifdef ANDROID_LAYOUT
- if (table()->isSingleColumn())
- return m_rowPos[m_gridRows];
-#endif
+ if (table()->isSingleColumn()) {
+ int height = 0;
+ int spacing = table()->vBorderSpacing();
+ for (int r = 0; r < m_gridRows; r++)
+ height += m_grid[r].height.calcMinValue(0) + (m_grid[r].rowRenderer ? spacing : 0);
+ return height;
+ }
+#endif
RenderTableCell* cell;
@@ -450,26 +456,26 @@ int RenderTableSection::layoutRows(int toAdd)
int hspacing = table()->hBorderSpacing();
int vspacing = table()->vBorderSpacing();
int rHeight = vspacing;
-
+
int leftOffset = hspacing;
-
+
int nEffCols = table()->numEffCols();
for (int r = 0; r < totalRows; r++) {
for (int c = 0; c < nEffCols; c++) {
CellStruct current = cellAt(r, c);
RenderTableCell* cell = current.cell;
-
+
if (!cell || current.inColSpan)
continue;
if (r > 0 && (cellAt(r-1, c).cell == cell))
continue;
-
+
// cell->setCellTopExtra(0);
// cell->setCellBottomExtra(0);
-
+
int oldCellX = cell->x();
int oldCellY = cell->y();
-
+
if (style()->direction() == RTL) {
cell->setX(table()->width());
cell->setY(rHeight);
@@ -489,7 +495,7 @@ int RenderTableSection::layoutRows(int toAdd)
rHeight += cell->height() + vspacing;
}
}
-
+
setHeight(rHeight);
return height();
}
@@ -501,10 +507,7 @@ int RenderTableSection::layoutRows(int toAdd)
// Set the width of our section now. The rows will also be this width.
setWidth(table()->contentWidth());
- m_overflowLeft = 0;
- m_overflowWidth = width();
- m_overflowTop = 0;
- m_overflowHeight = 0;
+ m_overflow.clear();
m_hasOverflowingCell = false;
if (toAdd && totalRows && (m_rowPos[totalRows] || !nextSibling())) {
@@ -705,12 +708,6 @@ int RenderTableSection::layoutRows(int toAdd)
} else
cell->setLocation(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]);
- m_overflowLeft = min(m_overflowLeft, cell->x() + cell->overflowLeft(false));
- m_overflowWidth = max(m_overflowWidth, cell->x() + cell->overflowWidth(false));
- m_overflowTop = min(m_overflowTop, cell->y() + cell->overflowTop(false));
- m_overflowHeight = max(m_overflowHeight, cell->y() + cell->overflowHeight(false));
- m_hasOverflowingCell |= cell->overflowLeft(false) || cell->overflowWidth(false) > cell->width() || cell->overflowTop(false) || cell->overflowHeight(false) > cell->height();
-
// If the cell moved, we have to repaint it as well as any floating/positioned
// descendants. An exception is if we need a layout. In this case, we know we're going to
// repaint ourselves (and the cell) anyway.
@@ -725,10 +722,22 @@ int RenderTableSection::layoutRows(int toAdd)
ASSERT(!needsLayout());
- statePusher.pop();
-
setHeight(m_rowPos[totalRows]);
- m_overflowHeight = max(m_overflowHeight, height());
+
+ // Now that our height has been determined, add in overflow from cells.
+ for (int r = 0; r < totalRows; r++) {
+ for (int c = 0; c < nEffCols; c++) {
+ RenderTableCell* cell = cellAt(r, c).cell;
+ if (!cell)
+ continue;
+ if (r < totalRows - 1 && cell == cellAt(r + 1, c).cell)
+ continue;
+ addOverflowFromChild(cell);
+ m_hasOverflowingCell |= cell->hasVisibleOverflow();
+ }
+ }
+
+ statePusher.pop();
return height();
}
@@ -1058,7 +1067,7 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty)
unsigned int startcol = 0;
unsigned int endcol = totalCols;
if (table()->isSingleColumn()) {
- // FIXME: should we be smarter too?
+ // FIXME: should we be smarter too?
} else {
// FIXME: possible to rollback to the common tree.
// rowPos size is set in calcRowHeight(), which is called from table layout().
@@ -1155,6 +1164,7 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty)
if (!row->hasSelfPaintingLayer())
cell->paintBackgroundsBehindCell(paintInfo, tx, ty, row);
}
+
if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer()) || paintInfo.phase == PaintPhaseCollapsedTableBorders)
cell->paint(paintInfo, tx, ty);
}
@@ -1184,6 +1194,7 @@ void RenderTableSection::recalcCells()
RenderTableRow* tableRow = toRenderTableRow(row);
m_grid[m_cRow].rowRenderer = tableRow;
+ setRowHeightToRowStyleHeightIfNotRelative(&m_grid[m_cRow]);
for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
if (cell->isTableCell())
diff --git a/WebCore/rendering/RenderTableSection.h b/WebCore/rendering/RenderTableSection.h
index c0098bc..9f6d5ea 100644
--- a/WebCore/rendering/RenderTableSection.h
+++ b/WebCore/rendering/RenderTableSection.h
@@ -73,11 +73,6 @@ public:
void appendColumn(int pos);
void splitColumn(int pos, int newSize);
- virtual int overflowWidth(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? width() : m_overflowWidth; }
- virtual int overflowLeft(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? 0 : m_overflowLeft; }
- virtual int overflowHeight(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? height() : m_overflowHeight; }
- virtual int overflowTop(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? 0 : m_overflowTop; }
-
int calcOuterBorderTop() const;
int calcOuterBorderBottom() const;
int calcOuterBorderLeft(bool rtl) const;
@@ -152,10 +147,6 @@ private:
int m_outerBorderRight;
int m_outerBorderTop;
int m_outerBorderBottom;
- int m_overflowLeft;
- int m_overflowWidth;
- int m_overflowTop;
- int m_overflowHeight;
bool m_needsCellRecalc;
bool m_hasOverflowingCell;
diff --git a/WebCore/rendering/RenderText.cpp b/WebCore/rendering/RenderText.cpp
index ada3961..2e696a9 100644
--- a/WebCore/rendering/RenderText.cpp
+++ b/WebCore/rendering/RenderText.cpp
@@ -25,7 +25,9 @@
#include "config.h"
#include "RenderText.h"
+#include "AXObjectCache.h"
#include "CharacterNames.h"
+#include "EllipsisBox.h"
#include "FloatQuad.h"
#include "FrameView.h"
#include "InlineTextBox.h"
@@ -207,7 +209,7 @@ void RenderText::deleteTextBoxes()
PassRefPtr<StringImpl> RenderText::originalText() const
{
Node* e = node();
- return e ? static_cast<Text*>(e)->string() : 0;
+ return e ? static_cast<Text*>(e)->dataImpl() : 0;
}
void RenderText::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
@@ -286,7 +288,7 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start,
} else {
unsigned realEnd = min(box->end() + 1, end);
IntRect r = box->selectionRect(0, 0, start, realEnd);
- if (!r.isEmpty()) {
+ if (r.height()) {
if (!useSelectionHeight) {
// change the height and y position because selectionRect uses selection-specific values
r.setHeight(box->height());
@@ -328,23 +330,23 @@ VisiblePosition RenderText::positionForPoint(const IntPoint& point)
int offset;
// FIXME: We should be able to roll these special cases into the general cases in the loop below.
- if (firstTextBox() && point.y() < firstTextBox()->root()->bottomOverflow() && point.x() < firstTextBox()->m_x) {
+ if (firstTextBox() && point.y() < firstTextBox()->root()->lineBottom() && point.x() < firstTextBox()->m_x) {
// at the y coordinate of the first line or above
// and the x coordinate is to the left of the first text box left edge
offset = firstTextBox()->offsetForPosition(point.x());
return createVisiblePosition(offset + firstTextBox()->start(), DOWNSTREAM);
}
- if (lastTextBox() && point.y() >= lastTextBox()->root()->topOverflow() && point.x() >= lastTextBox()->m_x + lastTextBox()->m_width) {
+ if (lastTextBox() && point.y() >= lastTextBox()->root()->lineTop() && point.x() >= lastTextBox()->m_x + lastTextBox()->m_width) {
// at the y coordinate of the last line or below
// and the x coordinate is to the right of the last text box right edge
offset = lastTextBox()->offsetForPosition(point.x());
- return createVisiblePosition(offset + lastTextBox()->start(), DOWNSTREAM);
+ return createVisiblePosition(offset + lastTextBox()->start(), VP_UPSTREAM_IF_POSSIBLE);
}
InlineTextBox* lastBoxAbove = 0;
for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- if (point.y() >= box->root()->topOverflow()) {
- int bottom = box->root()->nextRootBox() ? box->root()->nextRootBox()->topOverflow() : box->root()->bottomOverflow();
+ if (point.y() >= box->root()->lineTop()) {
+ int bottom = box->root()->nextRootBox() ? box->root()->nextRootBox()->lineTop() : box->root()->lineBottom();
if (point.y() < bottom) {
offset = box->offsetForPosition(point.x());
@@ -387,8 +389,8 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e
InlineTextBox* box = static_cast<InlineTextBox*>(inlineBox);
- int height = box->root()->bottomOverflow() - box->root()->topOverflow();
- int top = box->root()->topOverflow();
+ int height = box->root()->lineBottom() - box->root()->lineTop();
+ int top = box->root()->lineTop();
int left = box->positionForOffset(caretOffset);
@@ -757,6 +759,17 @@ void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& f
setPrefWidthsDirty(false);
}
+bool RenderText::isAllCollapsibleWhitespace()
+{
+ int length = textLength();
+ const UChar* text = characters();
+ for (int i = 0; i < length; i++) {
+ if (!style()->isCollapsibleWhiteSpace(text[i]))
+ return false;
+ }
+ return true;
+}
+
bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
{
unsigned currPos;
@@ -813,7 +826,9 @@ void RenderText::setSelectionState(SelectionState state)
}
}
- containingBlock()->setSelectionState(state);
+ // The returned value can be null in case of an orphaned tree.
+ if (RenderBlock* cb = containingBlock())
+ cb->setSelectionState(state);
}
void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
@@ -1001,6 +1016,10 @@ void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
setTextInternal(text);
setNeedsLayoutAndPrefWidthsRecalc();
m_knownNotToUseFallbackFonts = false;
+
+ AXObjectCache* axObjectCache = document()->axObjectCache();
+ if (axObjectCache->accessibilityEnabled())
+ axObjectCache->contentChanged(this);
}
int RenderText::lineHeight(bool firstLine, bool) const
@@ -1047,8 +1066,15 @@ void RenderText::positionLineBox(InlineBox* box)
if (!s->len()) {
// We want the box to be destroyed.
s->remove();
+ if (m_firstTextBox == s)
+ m_firstTextBox = s->nextTextBox();
+ else
+ s->prevTextBox()->setNextLineBox(s->nextTextBox());
+ if (m_lastTextBox == s)
+ m_lastTextBox = s->prevTextBox();
+ else
+ s->nextTextBox()->setPreviousLineBox(s->prevTextBox());
s->destroy(renderArena());
- m_firstTextBox = m_lastTextBox = 0;
return;
}
@@ -1151,9 +1177,25 @@ IntRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintContain
return IntRect();
IntRect rect;
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
rect.unite(box->selectionRect(0, 0, startPos, endPos));
+ // Check if there are ellipsis which fall within the selection.
+ unsigned short truncation = box->truncation();
+ if (truncation != cNoTruncation) {
+ if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) {
+ int ePos = min<int>(endPos - box->start(), box->len());
+ int sPos = max<int>(startPos - box->start(), 0);
+ // The ellipsis should be considered to be selected if the end of
+ // the selection is past the beginning of the truncation and the
+ // beginning of the selection is before or at the beginning of the
+ // truncation.
+ if (ePos >= truncation && sPos <= truncation)
+ rect.unite(ellipsis->selectionRect(0, 0));
+ }
+ }
+ }
+
if (clipToVisibleContent)
computeRectForRepaint(repaintContainer, rect);
else {
@@ -1349,7 +1391,7 @@ void RenderText::checkConsistency() const
#ifdef CHECK_CONSISTENCY
const InlineTextBox* prev = 0;
for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
- ASSERT(child->object() == this);
+ ASSERT(child->renderer() == this);
ASSERT(child->prevTextBox() == prev);
prev = child;
}
diff --git a/WebCore/rendering/RenderText.h b/WebCore/rendering/RenderText.h
index 915ff40..d46bce9 100644
--- a/WebCore/rendering/RenderText.h
+++ b/WebCore/rendering/RenderText.h
@@ -121,7 +121,8 @@ public:
void checkConsistency() const;
virtual void calcPrefWidths(int leadWidth);
-
+ bool isAllCollapsibleWhitespace();
+
protected:
virtual void styleWillChange(StyleDifference, const RenderStyle*) { }
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
diff --git a/WebCore/rendering/RenderTextControl.cpp b/WebCore/rendering/RenderTextControl.cpp
index 70b6518..c0ba070 100644
--- a/WebCore/rendering/RenderTextControl.cpp
+++ b/WebCore/rendering/RenderTextControl.cpp
@@ -67,10 +67,11 @@ static Color disabledTextColor(const Color& textColor, const Color& backgroundCo
return disabledColor;
}
-RenderTextControl::RenderTextControl(Node* node)
+RenderTextControl::RenderTextControl(Node* node, bool placeholderVisible)
: RenderBlock(node)
- , m_edited(false)
- , m_userEdited(false)
+ , m_placeholderVisible(placeholderVisible)
+ , m_wasChangedSinceLastChangeEvent(false)
+ , m_lastChangeWasUserEdit(false)
{
}
@@ -92,14 +93,22 @@ void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle*
// Reset them now to avoid getting a spurious layout hint.
textBlockRenderer->style()->setHeight(Length());
textBlockRenderer->style()->setWidth(Length());
- textBlockRenderer->setStyle(textBlockStyle);
+ setInnerTextStyle(textBlockStyle);
+ }
+
+ setReplaced(isInline());
+}
+
+void RenderTextControl::setInnerTextStyle(PassRefPtr<RenderStyle> style)
+{
+ if (m_innerText) {
+ RefPtr<RenderStyle> textStyle = style;
+ m_innerText->renderer()->setStyle(textStyle);
for (Node* n = m_innerText->firstChild(); n; n = n->traverseNextNode(m_innerText.get())) {
if (n->renderer())
- n->renderer()->setStyle(textBlockStyle);
+ n->renderer()->setStyle(textStyle);
}
}
-
- setReplaced(isInline());
}
static inline bool updateUserModifyProperty(Node* node, RenderStyle* style)
@@ -173,7 +182,7 @@ void RenderTextControl::setInnerTextValue(const String& innerTextValue)
frame->editor()->clearUndoRedoOperations();
if (AXObjectCache::accessibilityEnabled())
- document()->axObjectCache()->postNotification(this, "AXValueChanged", false);
+ document()->axObjectCache()->postNotification(this, AXObjectCache::AXValueChanged, false);
}
}
@@ -186,17 +195,17 @@ void RenderTextControl::setInnerTextValue(const String& innerTextValue)
ASSERT(!ec);
}
- m_edited = false;
- m_userEdited = false;
+ // We set m_lastChangeWasUserEdit to false since this change was not explicitly made by the user (say, via typing on the keyboard), see <rdar://problem/5359921>.
+ m_lastChangeWasUserEdit = false;
}
static_cast<Element*>(node())->setFormControlValueMatchesRenderer(true);
}
-void RenderTextControl::setUserEdited(bool isUserEdited)
+void RenderTextControl::setLastChangeWasUserEdit(bool lastChangeWasUserEdit)
{
- m_userEdited = isUserEdited;
- document()->setIgnoreAutofocus(isUserEdited);
+ m_lastChangeWasUserEdit = lastChangeWasUserEdit;
+ document()->setIgnoreAutofocus(lastChangeWasUserEdit);
}
int RenderTextControl::selectionStart()
@@ -303,15 +312,12 @@ int RenderTextControl::indexForVisiblePosition(const VisiblePosition& pos)
void RenderTextControl::subtreeHasChanged()
{
- m_edited = true;
- m_userEdited = true;
+ m_wasChangedSinceLastChangeEvent = true;
+ m_lastChangeWasUserEdit = true;
}
String RenderTextControl::finishText(Vector<UChar>& result) const
{
- // ANDROID: This method was modified with a fix from WebKit r31081. This
- // comment can be removed the next time we update.
-
// Remove one trailing newline; there's always one that's collapsed out by rendering.
size_t size = result.size();
if (size && result[size - 1] == '\n')
@@ -486,18 +492,6 @@ void RenderTextControl::calcPrefWidths()
m_minPrefWidth += toAdd;
m_maxPrefWidth += toAdd;
- // FIXME: This causes cnn.com loading way slow. Comment it out for now
-//#ifdef ANDROID_LAYOUT
-#if 0
- Frame* frame = document()->frame();
- if (frame && frame->settings()->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) {
- int maxWidth = frame->view()->visibleWidth() - 2 * ANDROID_FCTS_MARGIN_PADDING;
- if (maxWidth > 0 && maxWidth < m_minPrefWidth)
- m_minPrefWidth = maxWidth;
- if (maxWidth > 0 && maxWidth < m_maxPrefWidth)
- m_maxPrefWidth = maxWidth;
- }
-#endif
setPrefWidthsDirty(false);
}
@@ -507,13 +501,14 @@ void RenderTextControl::selectionChanged(bool userTriggered)
if (Frame* frame = document()->frame()) {
if (frame->selection()->isRange() && userTriggered)
- node()->dispatchEvent(eventNames().selectEvent, true, false);
+ node()->dispatchEvent(Event::create(eventNames().selectEvent, true, false));
}
}
-void RenderTextControl::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+void RenderTextControl::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
{
- graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
+ if (width() && height())
+ rects.append(IntRect(tx, ty, width(), height()));
}
HTMLElement* RenderTextControl::innerTextElement() const
@@ -521,4 +516,18 @@ HTMLElement* RenderTextControl::innerTextElement() const
return m_innerText.get();
}
+void RenderTextControl::updatePlaceholderVisibility(bool placeholderShouldBeVisible, bool placeholderValueChanged)
+{
+ bool oldPlaceholderVisible = m_placeholderVisible;
+ m_placeholderVisible = placeholderShouldBeVisible;
+ if (oldPlaceholderVisible != m_placeholderVisible || placeholderValueChanged) {
+ // Sets the inner text style to the normal style or :placeholder style.
+ setInnerTextStyle(createInnerTextStyle(textBaseStyle()));
+
+ // updateFromElement() of the subclasses updates the text content
+ // to the element's value(), placeholder(), or the empty string.
+ updateFromElement();
+ }
+}
+
} // namespace WebCore
diff --git a/WebCore/rendering/RenderTextControl.h b/WebCore/rendering/RenderTextControl.h
index c0fc343..d1f3749 100644
--- a/WebCore/rendering/RenderTextControl.h
+++ b/WebCore/rendering/RenderTextControl.h
@@ -34,11 +34,11 @@ class RenderTextControl : public RenderBlock {
public:
virtual ~RenderTextControl();
- bool isEdited() const { return m_edited; }
- void setEdited(bool isEdited) { m_edited = isEdited; }
+ bool wasChangedSinceLastChangeEvent() const { return m_wasChangedSinceLastChangeEvent; }
+ void setChangedSinceLastChangeEvent(bool wasChangedSinceLastChangeEvent) { m_wasChangedSinceLastChangeEvent = wasChangedSinceLastChangeEvent; }
- bool isUserEdited() const { return m_userEdited; }
- void setUserEdited(bool isUserEdited);
+ bool lastChangeWasUserEdit() const { return m_lastChangeWasUserEdit; }
+ void setLastChangeWasUserEdit(bool lastChangeWasUserEdit);
int selectionStart();
int selectionEnd();
@@ -56,8 +56,10 @@ public:
VisiblePosition visiblePositionForIndex(int index);
int indexForVisiblePosition(const VisiblePosition&);
+ void updatePlaceholderVisibility(bool, bool);
+
protected:
- RenderTextControl(Node*);
+ RenderTextControl(Node*, bool);
int scrollbarThickness() const;
void adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle* textBlockStyle) const;
@@ -76,6 +78,7 @@ protected:
virtual void adjustControlHeightBasedOnLineHeight(int lineHeight) = 0;
virtual void cacheSelection(int start, int end) = 0;
virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const = 0;
+ virtual RenderStyle* textBaseStyle() const = 0;
virtual void updateFromElement();
virtual void calcHeight();
@@ -83,6 +86,8 @@ protected:
friend class TextIterator;
HTMLElement* innerTextElement() const;
+ bool m_placeholderVisible;
+
private:
virtual const char* renderName() const { return "RenderTextControl"; }
virtual bool isTextControl() const { return true; }
@@ -92,15 +97,16 @@ private:
virtual void removeLeftoverAnonymousBlock(RenderBlock*) { }
virtual bool canHaveChildren() const { return false; }
virtual bool avoidsFloats() const { return true; }
+ void setInnerTextStyle(PassRefPtr<RenderStyle>);
- virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty);
virtual bool canBeProgramaticallyScrolled(bool) const { return true; }
String finishText(Vector<UChar>&) const;
- bool m_edited;
- bool m_userEdited;
+ bool m_wasChangedSinceLastChangeEvent;
+ bool m_lastChangeWasUserEdit;
RefPtr<TextControlInnerTextElement> m_innerText;
};
diff --git a/WebCore/rendering/RenderTextControlMultiLine.cpp b/WebCore/rendering/RenderTextControlMultiLine.cpp
index ac790e2..0b4c7a7 100644
--- a/WebCore/rendering/RenderTextControlMultiLine.cpp
+++ b/WebCore/rendering/RenderTextControlMultiLine.cpp
@@ -22,18 +22,20 @@
#include "config.h"
#include "RenderTextControlMultiLine.h"
+#include "Event.h"
#include "EventNames.h"
#include "Frame.h"
-#include "HitTestResult.h"
+#include "HTMLNames.h"
#include "HTMLTextAreaElement.h"
+#include "HitTestResult.h"
#ifdef ANDROID_LAYOUT
#include "Settings.h"
#endif
namespace WebCore {
-RenderTextControlMultiLine::RenderTextControlMultiLine(Node* node)
- : RenderTextControl(node)
+RenderTextControlMultiLine::RenderTextControlMultiLine(Node* node, bool placeholderVisible)
+ : RenderTextControl(node, placeholderVisible)
{
}
@@ -46,16 +48,17 @@ RenderTextControlMultiLine::~RenderTextControlMultiLine()
void RenderTextControlMultiLine::subtreeHasChanged()
{
RenderTextControl::subtreeHasChanged();
- static_cast<Element*>(node())->setFormControlValueMatchesRenderer(false);
+ HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(node());
+ textArea->setFormControlValueMatchesRenderer(false);
+ textArea->setNeedsValidityCheck();
if (!node()->focused())
return;
- // Fire the "input" DOM event
- node()->dispatchEvent(eventNames().inputEvent, true, false);
+ node()->dispatchEvent(Event::create(eventNames().inputEvent, true, false));
if (Frame* frame = document()->frame())
- frame->textDidChangeInTextArea(static_cast<Element*>(node()));
+ frame->textDidChangeInTextArea(textArea);
}
bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
@@ -63,7 +66,10 @@ bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitT
if (!RenderTextControl::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction))
return false;
- if (result.innerNode() == node() || result.innerNode() == innerTextElement())
+ bool resultIsTextValueOrPlaceholder
+ = (!m_placeholderVisible && result.innerNode() == innerTextElement())
+ || (m_placeholderVisible && result.innerNode()->isDescendantOf(innerTextElement()));
+ if (result.innerNode() == node() || resultIsTextValueOrPlaceholder)
hitInnerTextElement(result, x, y, tx, ty);
return true;
@@ -95,7 +101,11 @@ void RenderTextControlMultiLine::updateFromElement()
createSubtreeIfNeeded(0);
RenderTextControl::updateFromElement();
- setInnerTextValue(static_cast<HTMLTextAreaElement*>(node())->value());
+ HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(node());
+ if (m_placeholderVisible)
+ setInnerTextValue(textArea->getAttribute(HTMLNames::placeholderAttr));
+ else
+ setInnerTextValue(textArea->value());
}
void RenderTextControlMultiLine::cacheSelection(int start, int end)
@@ -105,8 +115,15 @@ void RenderTextControlMultiLine::cacheSelection(int start, int end)
PassRefPtr<RenderStyle> RenderTextControlMultiLine::createInnerTextStyle(const RenderStyle* startStyle) const
{
- RefPtr<RenderStyle> textBlockStyle = RenderStyle::create();
- textBlockStyle->inheritFrom(startStyle);
+ RefPtr<RenderStyle> textBlockStyle;
+ if (m_placeholderVisible) {
+ if (RenderStyle* pseudoStyle = getCachedPseudoStyle(INPUT_PLACEHOLDER))
+ textBlockStyle = RenderStyle::clone(pseudoStyle);
+ }
+ if (!textBlockStyle) {
+ textBlockStyle = RenderStyle::create();
+ textBlockStyle->inheritFrom(startStyle);
+ }
adjustInnerTextStyle(startStyle, textBlockStyle.get());
textBlockStyle->setDisplay(BLOCK);
@@ -114,4 +131,9 @@ PassRefPtr<RenderStyle> RenderTextControlMultiLine::createInnerTextStyle(const R
return textBlockStyle.release();
}
+RenderStyle* RenderTextControlMultiLine::textBaseStyle() const
+{
+ return style();
+}
+
}
diff --git a/WebCore/rendering/RenderTextControlMultiLine.h b/WebCore/rendering/RenderTextControlMultiLine.h
index 7296653..3371a8f 100644
--- a/WebCore/rendering/RenderTextControlMultiLine.h
+++ b/WebCore/rendering/RenderTextControlMultiLine.h
@@ -28,7 +28,7 @@ namespace WebCore {
class RenderTextControlMultiLine : public RenderTextControl {
public:
- RenderTextControlMultiLine(Node*);
+ RenderTextControlMultiLine(Node*, bool);
virtual ~RenderTextControlMultiLine();
void forwardEvent(Event*);
@@ -47,6 +47,7 @@ private:
virtual void updateFromElement();
virtual void cacheSelection(int start, int end);
+ virtual RenderStyle* textBaseStyle() const;
virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const;
};
diff --git a/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp
index b448eb7..b68f004 100644
--- a/WebCore/rendering/RenderTextControlSingleLine.cpp
+++ b/WebCore/rendering/RenderTextControlSingleLine.cpp
@@ -48,9 +48,8 @@ namespace WebCore {
using namespace HTMLNames;
-RenderTextControlSingleLine::RenderTextControlSingleLine(Node* node)
- : RenderTextControl(node)
- , m_placeholderVisible(false)
+RenderTextControlSingleLine::RenderTextControlSingleLine(Node* node, bool placeholderVisible)
+ : RenderTextControl(node, placeholderVisible)
, m_searchPopupIsVisible(false)
, m_shouldDrawCapsLockIndicator(false)
, m_searchEventTimer(this, &RenderTextControlSingleLine::searchEventTimerFired)
@@ -69,25 +68,9 @@ RenderTextControlSingleLine::~RenderTextControlSingleLine()
m_innerBlock->detach();
}
-bool RenderTextControlSingleLine::placeholderShouldBeVisible() const
+RenderStyle* RenderTextControlSingleLine::textBaseStyle() const
{
- return inputElement()->placeholderShouldBeVisible();
-}
-
-void RenderTextControlSingleLine::updatePlaceholderVisibility()
-{
- RenderStyle* parentStyle = m_innerBlock ? m_innerBlock->renderer()->style() : style();
-
- RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(parentStyle);
- HTMLElement* innerText = innerTextElement();
- innerText->renderer()->setStyle(textBlockStyle);
-
- for (Node* n = innerText->firstChild(); n; n = n->traverseNextNode(innerText)) {
- if (RenderObject* renderer = n->renderer())
- renderer->setStyle(textBlockStyle);
- }
-
- updateFromElement();
+ return m_innerBlock ? m_innerBlock->renderer()->style() : style();
}
void RenderTextControlSingleLine::addSearchResult()
@@ -163,17 +146,19 @@ void RenderTextControlSingleLine::hidePopup()
ASSERT(node()->isHTMLElement());
if (m_searchPopup)
m_searchPopup->hide();
-
- m_searchPopupIsVisible = false;
}
void RenderTextControlSingleLine::subtreeHasChanged()
{
- bool wasEdited = isEdited();
+ bool wasChanged = wasChangedSinceLastChangeEvent();
RenderTextControl::subtreeHasChanged();
InputElement* input = inputElement();
- input->setValueFromRenderer(input->constrainValue(text()));
+ // We don't need to call sanitizeUserInputValue() function here because
+ // InputElement::handleBeforeTextInsertedEvent() has already called
+ // sanitizeUserInputValue().
+ // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
+ input->setValueFromRenderer(input->sanitizeValue(text()));
if (m_cancelButton)
updateCancelButtonVisibility();
@@ -182,7 +167,7 @@ void RenderTextControlSingleLine::subtreeHasChanged()
if (input->searchEventsShouldBeDispatched())
startSearchEventTimer();
- if (!wasEdited && node()->focused()) {
+ if (!wasChanged && node()->focused()) {
if (Frame* frame = document()->frame())
frame->textFieldDidBeginEditing(static_cast<Element*>(node()));
}
@@ -480,18 +465,19 @@ void RenderTextControlSingleLine::updateFromElement()
createSubtreeIfNeeded();
RenderTextControl::updateFromElement();
- bool placeholderVisibilityShouldChange = m_placeholderVisible != placeholderShouldBeVisible();
- m_placeholderVisible = placeholderShouldBeVisible();
-
if (m_cancelButton)
updateCancelButtonVisibility();
if (m_placeholderVisible) {
ExceptionCode ec = 0;
- innerTextElement()->setInnerText(inputElement()->placeholder(), ec);
+ innerTextElement()->setInnerText(static_cast<Element*>(node())->getAttribute(placeholderAttr), ec);
ASSERT(!ec);
- } else if (!static_cast<Element*>(node())->formControlValueMatchesRenderer() || placeholderVisibilityShouldChange)
- setInnerTextValue(inputElement()->value());
+ } else {
+ if (!inputElement()->suggestedValue().isNull())
+ setInnerTextValue(inputElement()->suggestedValue());
+ else
+ setInnerTextValue(inputElement()->value());
+ }
if (m_searchPopupIsVisible)
m_searchPopup->updateFromElement();
@@ -505,7 +491,7 @@ void RenderTextControlSingleLine::cacheSelection(int start, int end)
PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const
{
RefPtr<RenderStyle> textBlockStyle;
- if (placeholderShouldBeVisible()) {
+ if (m_placeholderVisible) {
if (RenderStyle* pseudoStyle = getCachedPseudoStyle(INPUT_PLACEHOLDER))
textBlockStyle = RenderStyle::clone(pseudoStyle);
}
@@ -535,7 +521,7 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const
// After this, updateFromElement will immediately update the text displayed.
// When the placeholder is no longer visible, updatePlaceholderVisiblity will reset the style,
// and the text security mode will be set back to the computed value correctly.
- if (placeholderShouldBeVisible())
+ if (m_placeholderVisible)
textBlockStyle->setTextSecurity(TSNONE);
return textBlockStyle.release();
@@ -753,6 +739,11 @@ int RenderTextControlSingleLine::selectedIndex() const
return -1;
}
+void RenderTextControlSingleLine::popupDidHide()
+{
+ m_searchPopupIsVisible = false;
+}
+
bool RenderTextControlSingleLine::itemIsSeparator(unsigned listIndex) const
{
// The separator will be the second to last item in our list.
@@ -832,12 +823,12 @@ void RenderTextControlSingleLine::setScrollTop(int newTop)
innerTextElement()->setScrollTop(newTop);
}
-bool RenderTextControlSingleLine::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
+bool RenderTextControlSingleLine::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
{
RenderLayer* layer = innerTextElement()->renderBox()->layer();
if (layer && layer->scroll(direction, granularity, multiplier))
return true;
- return RenderBlock::scroll(direction, granularity, multiplier);
+ return RenderBlock::scroll(direction, granularity, multiplier, stopNode);
}
PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
diff --git a/WebCore/rendering/RenderTextControlSingleLine.h b/WebCore/rendering/RenderTextControlSingleLine.h
index da9838f..e30ff0d 100644
--- a/WebCore/rendering/RenderTextControlSingleLine.h
+++ b/WebCore/rendering/RenderTextControlSingleLine.h
@@ -36,19 +36,18 @@ class TextControlInnerElement;
class RenderTextControlSingleLine : public RenderTextControl, private PopupMenuClient {
public:
- RenderTextControlSingleLine(Node*);
+ RenderTextControlSingleLine(Node*, bool);
virtual ~RenderTextControlSingleLine();
bool placeholderIsVisible() const { return m_placeholderVisible; }
bool placeholderShouldBeVisible() const;
- void updatePlaceholderVisibility();
void addSearchResult();
void stopSearchEventTimer();
bool popupIsVisible() const { return m_searchPopupIsVisible; }
void showPopup();
- virtual void hidePopup(); // PopupMenuClient method
+ void hidePopup();
void forwardEvent(Event*);
@@ -73,7 +72,7 @@ private:
virtual int scrollHeight() const;
virtual void setScrollLeft(int);
virtual void setScrollTop(int);
- virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f);
+ virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f, Node** stopNode = 0);
int textBlockWidth() const;
virtual int preferredContentWidth(float charWidth) const;
@@ -84,6 +83,7 @@ private:
virtual void cacheSelection(int start, int end);
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+ virtual RenderStyle* textBaseStyle() const;
virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const;
PassRefPtr<RenderStyle> createInnerBlockStyle(const RenderStyle* startStyle) const;
PassRefPtr<RenderStyle> createResultsButtonStyle(const RenderStyle* startStyle) const;
@@ -109,6 +109,7 @@ private:
virtual int clientPaddingRight() const;
virtual int listSize() const;
virtual int selectedIndex() const;
+ virtual void popupDidHide();
virtual bool itemIsSeparator(unsigned listIndex) const;
virtual bool itemIsLabel(unsigned listIndex) const;
virtual bool itemIsSelected(unsigned listIndex) const;
@@ -121,7 +122,6 @@ private:
InputElement* inputElement() const;
- bool m_placeholderVisible;
bool m_searchPopupIsVisible;
bool m_shouldDrawCapsLockIndicator;
diff --git a/WebCore/rendering/RenderTextFragment.cpp b/WebCore/rendering/RenderTextFragment.cpp
index 7da9e5a..9ff1106 100644
--- a/WebCore/rendering/RenderTextFragment.cpp
+++ b/WebCore/rendering/RenderTextFragment.cpp
@@ -47,7 +47,7 @@ RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str)
PassRefPtr<StringImpl> RenderTextFragment::originalText() const
{
Node* e = node();
- RefPtr<StringImpl> result = (e ? static_cast<Text*>(e)->string() : contentString());
+ RefPtr<StringImpl> result = (e ? static_cast<Text*>(e)->dataImpl() : contentString());
if (result && (start() > 0 || start() < result->length()))
result = result->substring(start(), end());
return result.release();
@@ -76,7 +76,7 @@ UChar RenderTextFragment::previousCharacter()
{
if (start()) {
Node* e = node();
- StringImpl* original = (e ? static_cast<Text*>(e)->string() : contentString());
+ StringImpl* original = (e ? static_cast<Text*>(e)->dataImpl() : contentString());
if (original)
return (*original)[start() - 1];
}
diff --git a/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp
index 63e7d45..f1e564b 100644
--- a/WebCore/rendering/RenderTheme.cpp
+++ b/WebCore/rendering/RenderTheme.cpp
@@ -1,7 +1,7 @@
/**
* This file is part of the theme implementation for form controls in WebCore.
*
- * Copyright (C) 2005, 2006, 2007, 2008 Apple Computer, Inc.
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -30,6 +30,7 @@
#include "GraphicsContext.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
+#include "MediaControlElements.h"
#include "Page.h"
#include "RenderStyle.h"
#include "RenderView.h"
@@ -84,7 +85,10 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El
#if USE(NEW_THEME)
switch (part) {
+ case ListButtonPart:
case CheckboxPart:
+ case InnerSpinButtonPart:
+ case OuterSpinButtonPart:
case RadioPart:
case PushButtonPart:
case SquareButtonPart:
@@ -170,9 +174,14 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El
return adjustRadioStyle(selector, style, e);
case PushButtonPart:
case SquareButtonPart:
+ case ListButtonPart:
case DefaultButtonPart:
case ButtonPart:
return adjustButtonStyle(selector, style, e);
+ case InnerSpinButtonPart:
+ return adjustInnerSpinButtonStyle(selector, style, e);
+ case OuterSpinButtonPart:
+ return adjustOuterSpinButtonStyle(selector, style, e);
#endif
case TextFieldPart:
return adjustTextFieldStyle(selector, style, e);
@@ -187,6 +196,7 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El
case MenulistButtonPart:
return adjustMenuListButtonStyle(selector, style, e);
case MediaSliderPart:
+ case MediaVolumeSliderPart:
case SliderHorizontalPart:
case SliderVerticalPart:
return adjustSliderTrackStyle(selector, style, e);
@@ -229,8 +239,11 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf
case RadioPart:
case PushButtonPart:
case SquareButtonPart:
+ case ListButtonPart:
case DefaultButtonPart:
case ButtonPart:
+ case InnerSpinButtonPart:
+ case OuterSpinButtonPart:
m_theme->paint(part, controlStatesForRenderer(o), const_cast<GraphicsContext*>(paintInfo.context), r, o->style()->effectiveZoom(), o->view()->frameView());
return false;
default:
@@ -247,9 +260,14 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf
return paintRadio(o, paintInfo, r);
case PushButtonPart:
case SquareButtonPart:
+ case ListButtonPart:
case DefaultButtonPart:
case ButtonPart:
return paintButton(o, paintInfo, r);
+ case InnerSpinButtonPart:
+ return paintInnerSpinButton(o, paintInfo, r);
+ case OuterSpinButtonPart:
+ return paintOuterSpinButton(o, paintInfo, r);
#endif
case MenulistPart:
return paintMenuList(o, paintInfo, r);
@@ -276,12 +294,22 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf
return paintMediaRewindButton(o, paintInfo, r);
case MediaReturnToRealtimeButtonPart:
return paintMediaReturnToRealtimeButton(o, paintInfo, r);
+ case MediaToggleClosedCaptionsButtonPart:
+ return paintMediaToggleClosedCaptionsButton(o, paintInfo, r);
case MediaSliderPart:
return paintMediaSliderTrack(o, paintInfo, r);
case MediaSliderThumbPart:
if (o->parent()->isSlider())
return paintMediaSliderThumb(o, paintInfo, r);
break;
+ case MediaVolumeSliderContainerPart:
+ return paintMediaVolumeSliderContainer(o, paintInfo, r);
+ case MediaVolumeSliderPart:
+ return paintMediaVolumeSliderTrack(o, paintInfo, r);
+ case MediaVolumeSliderThumbPart:
+ if (o->parent()->isSlider())
+ return paintMediaVolumeSliderThumb(o, paintInfo, r);
+ break;
case MediaTimeRemainingPart:
return paintMediaTimeRemaining(o, paintInfo, r);
case MediaCurrentTimePart:
@@ -329,6 +357,7 @@ bool RenderTheme::paintBorderOnly(RenderObject* o, const RenderObject::PaintInfo
case RadioPart:
case PushButtonPart:
case SquareButtonPart:
+ case ListButtonPart:
case DefaultButtonPart:
case ButtonPart:
case MenulistPart:
@@ -363,6 +392,7 @@ bool RenderTheme::paintDecorations(RenderObject* o, const RenderObject::PaintInf
case RadioPart:
case PushButtonPart:
case SquareButtonPart:
+ case ListButtonPart:
case DefaultButtonPart:
case ButtonPart:
case MenulistPart:
@@ -391,6 +421,54 @@ bool RenderTheme::hitTestMediaControlPart(RenderObject* o, const IntPoint& absPo
FloatPoint localPoint = o->absoluteToLocal(absPoint, false, true); // respect transforms
return toRenderBox(o)->borderBoxRect().contains(roundedIntPoint(localPoint));
}
+
+bool RenderTheme::shouldRenderMediaControlPart(ControlPart part, Element* e)
+{
+ HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(e);
+ switch (part) {
+ case MediaMuteButtonPart:
+ return mediaElement->hasAudio();
+ case MediaRewindButtonPart:
+ return mediaElement->movieLoadType() != MediaPlayer::LiveStream;
+ case MediaReturnToRealtimeButtonPart:
+ return mediaElement->movieLoadType() == MediaPlayer::LiveStream;
+ case MediaFullscreenButtonPart:
+ return mediaElement->supportsFullscreen();
+ case MediaToggleClosedCaptionsButtonPart:
+ return mediaElement->hasClosedCaptions();
+ default:
+ return true;
+ }
+}
+
+String RenderTheme::formatMediaControlsTime(float time) const
+{
+ if (!isfinite(time))
+ time = 0;
+ int seconds = (int)fabsf(time);
+ int hours = seconds / (60 * 60);
+ int minutes = (seconds / 60) % 60;
+ seconds %= 60;
+ if (hours) {
+ if (hours > 9)
+ return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
+
+ return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds);
+ }
+
+ return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds);
+}
+
+String RenderTheme::formatMediaControlsCurrentTime(float currentTime, float /*duration*/) const
+{
+ return formatMediaControlsTime(currentTime);
+}
+
+String RenderTheme::formatMediaControlsRemainingTime(float currentTime, float duration) const
+{
+ return formatMediaControlsTime(currentTime - duration);
+}
+
#endif
Color RenderTheme::activeSelectionBackgroundColor() const
@@ -552,7 +630,7 @@ bool RenderTheme::supportsFocusRing(const RenderStyle* style) const
bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const
{
- // Default implementation assumes the controls dont respond to changes in :hover state
+ // Default implementation assumes the controls don't respond to changes in :hover state
if (state == HoverState && !supportsHover(o->style()))
return false;
@@ -672,6 +750,10 @@ bool RenderTheme::isHovered(const RenderObject* o) const
bool RenderTheme::isDefault(const RenderObject* o) const
{
+ // A button should only have the default appearance if the page is active
+ if (!isActive(o))
+ return false;
+
if (!o->document())
return false;
@@ -725,6 +807,14 @@ void RenderTheme::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Eleme
setButtonSize(style);
}
+void RenderTheme::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustOuterSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
#endif
void RenderTheme::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const
diff --git a/WebCore/rendering/RenderTheme.h b/WebCore/rendering/RenderTheme.h
index 4f37015..32ae5e5 100644
--- a/WebCore/rendering/RenderTheme.h
+++ b/WebCore/rendering/RenderTheme.h
@@ -172,6 +172,12 @@ public:
#if ENABLE(VIDEO)
// Media controls
virtual bool hitTestMediaControlPart(RenderObject*, const IntPoint& absPoint);
+ virtual bool shouldRenderMediaControlPart(ControlPart, Element*);
+ virtual double mediaControlsFadeInDuration() { return 0.1; }
+ virtual double mediaControlsFadeOutDuration() { return 0.3; }
+ virtual String formatMediaControlsTime(float time) const;
+ virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const;
+ virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const;
#endif
protected:
@@ -202,6 +208,11 @@ protected:
virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
virtual void setButtonSize(RenderStyle*) const { }
+
+ virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintInnerSpinButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual void adjustOuterSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintOuterSpinButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
#endif
virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
@@ -247,8 +258,12 @@ protected:
virtual bool paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual bool paintMediaVolumeSliderContainer(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual bool paintMediaVolumeSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual bool paintMediaVolumeSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
virtual bool paintMediaRewindButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
virtual bool paintMediaReturnToRealtimeButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
virtual bool paintMediaControlsBackground(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
virtual bool paintMediaCurrentTime(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
virtual bool paintMediaTimeRemaining(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
diff --git a/WebCore/rendering/RenderThemeChromiumLinux.cpp b/WebCore/rendering/RenderThemeChromiumLinux.cpp
index c4020d3..13c9cd6 100644
--- a/WebCore/rendering/RenderThemeChromiumLinux.cpp
+++ b/WebCore/rendering/RenderThemeChromiumLinux.cpp
@@ -25,13 +25,27 @@
#include "config.h"
#include "RenderThemeChromiumLinux.h"
-#include "Color.h"
#include "CSSValueKeywords.h"
+#include "Color.h"
#include "RenderObject.h"
#include "UserAgentStyleSheets.h"
namespace WebCore {
+unsigned RenderThemeChromiumLinux::m_thumbInactiveColor = 0xf0ebe5;
+unsigned RenderThemeChromiumLinux::m_thumbActiveColor = 0xfaf8f5;
+unsigned RenderThemeChromiumLinux::m_trackColor = 0xe3ddd8;
+unsigned RenderThemeChromiumLinux::m_activeSelectionBackgroundColor =
+ 0xff1e90ff;
+unsigned RenderThemeChromiumLinux::m_activeSelectionForegroundColor =
+ Color::black;
+unsigned RenderThemeChromiumLinux::m_inactiveSelectionBackgroundColor =
+ 0xffc8c8c8;
+unsigned RenderThemeChromiumLinux::m_inactiveSelectionForegroundColor =
+ 0xff323232;
+
+double RenderThemeChromiumLinux::m_caretBlinkInterval;
+
PassRefPtr<RenderTheme> RenderThemeChromiumLinux::create()
{
return adoptRef(new RenderThemeChromiumLinux());
@@ -45,6 +59,7 @@ PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
RenderThemeChromiumLinux::RenderThemeChromiumLinux()
{
+ m_caretBlinkInterval = RenderTheme::caretBlinkInterval();
}
RenderThemeChromiumLinux::~RenderThemeChromiumLinux()
@@ -91,9 +106,74 @@ Color RenderThemeChromiumLinux::inactiveListBoxSelectionForegroundColor() const
return Color(0x32, 0x32, 0x32);
}
+Color RenderThemeChromiumLinux::platformActiveSelectionBackgroundColor() const
+{
+ return m_activeSelectionBackgroundColor;
+}
+
+Color RenderThemeChromiumLinux::platformInactiveSelectionBackgroundColor() const
+{
+ return m_inactiveSelectionBackgroundColor;
+}
+
+Color RenderThemeChromiumLinux::platformActiveSelectionForegroundColor() const
+{
+ return m_activeSelectionForegroundColor;
+}
+
+Color RenderThemeChromiumLinux::platformInactiveSelectionForegroundColor() const
+{
+ return m_inactiveSelectionForegroundColor;
+}
+
+void RenderThemeChromiumLinux::adjustSliderThumbSize(RenderObject* o) const
+{
+ // These sizes match the sizes in Chromium Win.
+ const int sliderThumbAlongAxis = 11;
+ const int sliderThumbAcrossAxis = 21;
+ if (o->style()->appearance() == SliderThumbHorizontalPart) {
+ o->style()->setWidth(Length(sliderThumbAlongAxis, Fixed));
+ o->style()->setHeight(Length(sliderThumbAcrossAxis, Fixed));
+ } else if (o->style()->appearance() == SliderThumbVerticalPart) {
+ o->style()->setWidth(Length(sliderThumbAcrossAxis, Fixed));
+ o->style()->setHeight(Length(sliderThumbAlongAxis, Fixed));
+ } else
+ RenderThemeChromiumSkia::adjustSliderThumbSize(o);
+}
+
bool RenderThemeChromiumLinux::supportsControlTints() const
{
return true;
}
+void RenderThemeChromiumLinux::setCaretBlinkInterval(double interval)
+{
+ m_caretBlinkInterval = interval;
+}
+
+double RenderThemeChromiumLinux::caretBlinkIntervalInternal() const
+{
+ return m_caretBlinkInterval;
+}
+
+void RenderThemeChromiumLinux::setSelectionColors(
+ unsigned activeBackgroundColor,
+ unsigned activeForegroundColor,
+ unsigned inactiveBackgroundColor,
+ unsigned inactiveForegroundColor)
+{
+ m_activeSelectionBackgroundColor = activeBackgroundColor;
+ m_activeSelectionForegroundColor = activeForegroundColor;
+ m_inactiveSelectionBackgroundColor = inactiveBackgroundColor;
+ m_inactiveSelectionForegroundColor = inactiveForegroundColor;
+}
+
+void RenderThemeChromiumLinux::setScrollbarColors(
+ SkColor inactiveColor, SkColor activeColor, SkColor trackColor)
+{
+ m_thumbInactiveColor = inactiveColor;
+ m_thumbActiveColor = activeColor;
+ m_trackColor = trackColor;
+}
+
} // namespace WebCore
diff --git a/WebCore/rendering/RenderThemeChromiumLinux.h b/WebCore/rendering/RenderThemeChromiumLinux.h
index e75ddd5..c60dec3 100644
--- a/WebCore/rendering/RenderThemeChromiumLinux.h
+++ b/WebCore/rendering/RenderThemeChromiumLinux.h
@@ -49,12 +49,45 @@ namespace WebCore {
virtual Color inactiveListBoxSelectionBackgroundColor() const;
virtual Color inactiveListBoxSelectionForegroundColor() const;
+ virtual Color platformActiveSelectionBackgroundColor() const;
+ virtual Color platformInactiveSelectionBackgroundColor() const;
+ virtual Color platformActiveSelectionForegroundColor() const;
+ virtual Color platformInactiveSelectionForegroundColor() const;
+
+ virtual void adjustSliderThumbSize(RenderObject*) const;
+
+ static void setCaretBlinkInterval(double interval);
+ virtual double caretBlinkIntervalInternal() const;
+
+ static void setSelectionColors(unsigned activeBackgroundColor,
+ unsigned activeForegroundColor,
+ unsigned inactiveBackgroundColor,
+ unsigned inactiveForegroundColor);
+
+ static void setScrollbarColors(unsigned inactive_color,
+ unsigned active_color,
+ unsigned track_color);
+ static unsigned thumbInactiveColor() { return m_thumbInactiveColor; }
+ static unsigned thumbActiveColor() { return m_thumbActiveColor; }
+ static unsigned trackColor() { return m_trackColor; }
+
private:
RenderThemeChromiumLinux();
virtual ~RenderThemeChromiumLinux();
// A general method asking if any control tinting is supported at all.
virtual bool supportsControlTints() const;
+
+ static double m_caretBlinkInterval;
+
+ static unsigned m_activeSelectionBackgroundColor;
+ static unsigned m_activeSelectionForegroundColor;
+ static unsigned m_inactiveSelectionBackgroundColor;
+ static unsigned m_inactiveSelectionForegroundColor;
+
+ static unsigned m_thumbInactiveColor;
+ static unsigned m_thumbActiveColor;
+ static unsigned m_trackColor;
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderThemeChromiumMac.h b/WebCore/rendering/RenderThemeChromiumMac.h
index ffb2548..8101038 100644
--- a/WebCore/rendering/RenderThemeChromiumMac.h
+++ b/WebCore/rendering/RenderThemeChromiumMac.h
@@ -3,7 +3,6 @@
*
* Copyright (C) 2005 Apple Computer, Inc.
* Copyright (C) 2008, 2009 Google, Inc.
- * Copyright (C) 2009 Kenneth Rohde Christiansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -26,7 +25,6 @@
#define RenderThemeChromiumMac_h
#import "RenderTheme.h"
-#import <AppKit/AppKit.h>
#import <wtf/HashMap.h>
#import <wtf/RetainPtr.h>
@@ -36,185 +34,165 @@
class WebCoreRenderThemeNotificationObserver;
#endif
+// This file (and its associated .mm file) is a clone of RenderThemeMac.h. See
+// the .mm file for details.
+
namespace WebCore {
- class RenderStyle;
+class RenderStyle;
+
+class RenderThemeChromiumMac : public RenderTheme {
+public:
+ static PassRefPtr<RenderTheme> create();
+
+ // A method asking if the control changes its tint when the window has focus or not.
+ virtual bool controlSupportsTints(const RenderObject*) const;
+
+ // A general method asking if any control tinting is supported at all.
+ virtual bool supportsControlTints() const { return true; }
+
+ virtual void adjustRepaintRect(const RenderObject*, IntRect&);
+
+ virtual bool isControlStyled(const RenderStyle*, const BorderData&,
+ const FillLayer&, const Color& backgroundColor) const;
+
+ virtual Color platformActiveSelectionBackgroundColor() const;
+ virtual Color platformInactiveSelectionBackgroundColor() const;
+ virtual Color platformActiveListBoxSelectionBackgroundColor() const;
+ virtual Color platformActiveListBoxSelectionForegroundColor() const;
+ virtual Color platformInactiveListBoxSelectionBackgroundColor() const;
+ virtual Color platformInactiveListBoxSelectionForegroundColor() const;
+ virtual Color platformFocusRingColor() const;
- class RenderThemeChromiumMac : public RenderTheme {
- public:
- static PassRefPtr<RenderTheme> create();
+ virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; }
+
+ virtual void platformColorsDidChange();
+
+ // System fonts.
+ virtual void systemFont(int cssValueId, FontDescription&) const;
+
+ virtual int minimumMenuListSize(RenderStyle*) const;
+
+ virtual void adjustSliderThumbSize(RenderObject*) const;
+
+ virtual int popupInternalPaddingLeft(RenderStyle*) const;
+ virtual int popupInternalPaddingRight(RenderStyle*) const;
+ virtual int popupInternalPaddingTop(RenderStyle*) const;
+ virtual int popupInternalPaddingBottom(RenderStyle*) const;
+
+ virtual bool paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- // A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline
- // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of
- // controls that need to do this.
- virtual int baselinePosition(const RenderObject*) const;
+ virtual Color systemColor(int cssValueId) const;
- // A method asking if the control changes its tint when the window has focus or not.
- virtual bool controlSupportsTints(const RenderObject*) const;
+protected:
+ virtual bool supportsSelectionForegroundColors() const { return false; }
- // A general method asking if any control tinting is supported at all.
- virtual bool supportsControlTints() const { return true; }
+ virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- virtual void adjustRepaintRect(const RenderObject*, IntRect&);
+ virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- virtual bool isControlStyled(const RenderStyle*, const BorderData&,
- const FillLayer&, const Color& backgroundColor) const;
+ virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- virtual Color platformActiveSelectionBackgroundColor() const;
- virtual Color platformInactiveSelectionBackgroundColor() const;
- virtual Color platformActiveListBoxSelectionBackgroundColor() const;
+ virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- virtual Color platformFocusRingColor() const;
-
- virtual void platformColorsDidChange();
+ virtual bool paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- // System fonts.
- virtual void systemFont(int cssValueId, FontDescription&) const;
+ virtual bool paintSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- virtual int minimumMenuListSize(RenderStyle*) const;
+ virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- virtual void adjustSliderThumbSize(RenderObject*) const;
-
- virtual int popupInternalPaddingLeft(RenderStyle*) const;
- virtual int popupInternalPaddingRight(RenderStyle*) const;
- virtual int popupInternalPaddingTop(RenderStyle*) const;
- virtual int popupInternalPaddingBottom(RenderStyle*) const;
-
- virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; }
+ virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldResultsDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+#if ENABLE(VIDEO)
+ virtual bool shouldRenderMediaControlPart(ControlPart, Element*);
+ virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintMediaMuteButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintMediaVolumeSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintMediaVolumeSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintMediaControlsBackground(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ // Media controls
+ virtual String extraMediaControlsStyleSheet();
+#endif
+
+private:
+ RenderThemeChromiumMac();
+ virtual ~RenderThemeChromiumMac();
+
+ IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const;
+
+ FloatRect convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const;
- virtual bool paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ // Get the control size based off the font. Used by some of the controls (like buttons).
+ NSControlSize controlSizeForFont(RenderStyle*) const;
+ NSControlSize controlSizeForSystemFont(RenderStyle*) const;
+ void setControlSize(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel = 1.0f);
+ void setSizeFromFont(RenderStyle*, const IntSize* sizes) const;
+ IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const;
+ IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const;
+ void setFontFromControlSize(CSSStyleSelector*, RenderStyle*, NSControlSize) const;
+
+ void updateActiveState(NSCell*, const RenderObject*);
+ void updateCheckedState(NSCell*, const RenderObject*);
+ void updateEnabledState(NSCell*, const RenderObject*);
+ void updateFocusedState(NSCell*, const RenderObject*);
+ void updatePressedState(NSCell*, const RenderObject*);
+
+ // Helpers for adjusting appearance and for painting
+
+ void setPopupButtonCellState(const RenderObject*, const IntRect&);
+ const IntSize* popupButtonSizes() const;
+ const int* popupButtonMargins() const;
+ const int* popupButtonPadding(NSControlSize) const;
+ void paintMenuListButtonGradients(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ const IntSize* menuListSizes() const;
+
+ const IntSize* searchFieldSizes() const;
+ const IntSize* cancelButtonSizes() const;
+ const IntSize* resultsButtonSizes() const;
+ void setSearchCellState(RenderObject*, const IntRect&);
+ void setSearchFieldSize(RenderStyle*) const;
+
+ NSPopUpButtonCell* popupButton() const;
+ NSSearchFieldCell* search() const;
+ NSMenu* searchMenuTemplate() const;
+ NSSliderCell* sliderThumbHorizontal() const;
+ NSSliderCell* sliderThumbVertical() const;
+
+private:
+ mutable RetainPtr<NSPopUpButtonCell> m_popupButton;
+ mutable RetainPtr<NSSearchFieldCell> m_search;
+ mutable RetainPtr<NSMenu> m_searchMenuTemplate;
+ mutable RetainPtr<NSSliderCell> m_sliderThumbHorizontal;
+ mutable RetainPtr<NSSliderCell> m_sliderThumbVertical;
- virtual Color systemColor(int cssValueId) const;
+ bool m_isSliderThumbHorizontalPressed;
+ bool m_isSliderThumbVerticalPressed;
- protected:
- virtual bool supportsSelectionForegroundColors() const { return false; }
+ mutable HashMap<int, RGBA32> m_systemColorCache;
- // Methods for each appearance value.
- virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void setCheckboxSize(RenderStyle*) const;
-
- virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void setRadioSize(RenderStyle*) const;
-
- virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, WebCore::Element*) const;
- virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void setButtonSize(RenderStyle*) const;
-
- virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
-
- virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
-
- virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
-
- virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
-
- virtual bool paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
-
- virtual bool paintSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
-
- virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
-
- virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
-
- virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
-
- virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldResultsDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
-
- virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
- virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
-
- virtual bool paintMediaFullscreenButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual bool paintMediaMuteButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual bool paintMediaSeekBackButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual bool paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
-
- private:
- RenderThemeChromiumMac();
- virtual ~RenderThemeChromiumMac();
-
- IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const;
-
- // Get the control size based off the font. Used by some of the controls (like buttons).
- NSControlSize controlSizeForFont(RenderStyle*) const;
- NSControlSize controlSizeForSystemFont(RenderStyle*) const;
- void setControlSize(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel = 1.0f);
- void setSizeFromFont(RenderStyle*, const IntSize* sizes) const;
- IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const;
- IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const;
- void setFontFromControlSize(CSSStyleSelector*, RenderStyle*, NSControlSize) const;
-
- void updateCheckedState(NSCell*, const RenderObject*);
- void updateEnabledState(NSCell*, const RenderObject*);
- void updateFocusedState(NSCell*, const RenderObject*);
- void updatePressedState(NSCell*, const RenderObject*);
-
- // Helpers for adjusting appearance and for painting
- const IntSize* checkboxSizes() const;
- const int* checkboxMargins() const;
- void setCheckboxCellState(const RenderObject*, const IntRect&);
-
- const IntSize* radioSizes() const;
- const int* radioMargins() const;
- void setRadioCellState(const RenderObject*, const IntRect&);
-
- void setButtonPaddingFromControlSize(RenderStyle*, NSControlSize) const;
- const IntSize* buttonSizes() const;
- const int* buttonMargins() const;
- void setButtonCellState(const RenderObject*, const IntRect&);
-
- void setPopupButtonCellState(const RenderObject*, const IntRect&);
- const IntSize* popupButtonSizes() const;
- const int* popupButtonMargins() const;
- const int* popupButtonPadding(NSControlSize) const;
- void paintMenuListButtonGradients(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
- const IntSize* menuListSizes() const;
-
- const IntSize* searchFieldSizes() const;
- const IntSize* cancelButtonSizes() const;
- const IntSize* resultsButtonSizes() const;
- void setSearchCellState(RenderObject*, const IntRect&);
- void setSearchFieldSize(RenderStyle*) const;
-
- NSButtonCell* checkbox() const;
- NSButtonCell* radio() const;
- NSButtonCell* button() const;
- NSPopUpButtonCell* popupButton() const;
- NSSearchFieldCell* search() const;
- NSMenu* searchMenuTemplate() const;
- NSSliderCell* sliderThumbHorizontal() const;
- NSSliderCell* sliderThumbVertical() const;
-
- private:
- mutable RetainPtr<NSButtonCell> m_checkbox;
- mutable RetainPtr<NSButtonCell> m_radio;
- mutable RetainPtr<NSButtonCell> m_button;
- mutable RetainPtr<NSPopUpButtonCell> m_popupButton;
- mutable RetainPtr<NSSearchFieldCell> m_search;
- mutable RetainPtr<NSMenu> m_searchMenuTemplate;
- mutable RetainPtr<NSSliderCell> m_sliderThumbHorizontal;
- mutable RetainPtr<NSSliderCell> m_sliderThumbVertical;
-
- bool m_isSliderThumbHorizontalPressed;
- bool m_isSliderThumbVerticalPressed;
-
- mutable HashMap<int, RGBA32> m_systemColorCache;
-
- RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver;
- };
+ RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver;
+};
} // namespace WebCore
-#endif
+#endif // RenderThemeChromiumMac_h
diff --git a/WebCore/rendering/RenderThemeChromiumMac.mm b/WebCore/rendering/RenderThemeChromiumMac.mm
index 23201c9..e274b05 100644
--- a/WebCore/rendering/RenderThemeChromiumMac.mm
+++ b/WebCore/rendering/RenderThemeChromiumMac.mm
@@ -1,7 +1,6 @@
/*
- * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008, 2009 Google, Inc.
- * Copyright (C) 2009 Kenneth Rohde Christiansen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -19,25 +18,16 @@
* Boston, MA 02110-1301, USA.
*/
-// FIXME: we still need to figure out if passing a null view to the cell
-// drawing routines will work. I expect not, and if that's the case we'll have
-// to figure out something else. For now, at least leave the lines commented
-// in, but the procurement of the view if 0'd.
-
#import "config.h"
#import "RenderThemeChromiumMac.h"
-#import <Carbon/Carbon.h>
-#import <Cocoa/Cocoa.h>
-#import <math.h>
-
#import "BitmapImage.h"
#import "ChromiumBridge.h"
#import "ColorMac.h"
#import "CSSStyleSelector.h"
#import "CSSValueKeywords.h"
+#import "Document.h"
#import "Element.h"
-#import "FoundationExtras.h"
#import "FrameView.h"
#import "GraphicsContext.h"
#import "HTMLInputElement.h"
@@ -47,11 +37,18 @@
#import "LocalCurrentGraphicsContext.h"
#import "MediaControlElements.h"
#import "RenderMedia.h"
+#import "RenderMediaControlsChromium.h"
#import "RenderSlider.h"
#import "RenderView.h"
#import "SharedBuffer.h"
+#import "TimeRanges.h"
#import "WebCoreSystemInterface.h"
+#import "UserAgentStyleSheets.h"
+#import <Carbon/Carbon.h>
+#import <Cocoa/Cocoa.h>
#import <wtf/RetainPtr.h>
+#import <wtf/StdLibExtras.h>
+#import <math.h>
#ifdef BUILDING_ON_TIGER
typedef int NSInteger;
@@ -60,9 +57,28 @@ typedef unsigned NSUInteger;
using std::min;
+// This file (and its associated .h file) is a clone of RenderThemeMac.mm.
+// Because the original file is designed to run in-process inside a Cocoa view,
+// we must maintain a fork. Please maintain this file by performing parallel
+// changes to it.
+//
+// The only changes from RenderThemeMac should be:
+// - The classname change from RenderThemeMac to RenderThemeChromiumMac.
+// - The introduction of RTCMFlippedView and FlippedView() and its use as the
+// parent view for cell rendering.
+// - In platformFocusRingColor(), the use of ChromiumBridge to determine if
+// we're in layout test mode.
+// - updateActiveState() and its use to update the cells' visual appearance.
+// - All the paintMedia*() functions and extraMediaControlsStyleSheet()
+// are forked from RenderThemeChromiumSkia instead of RenderThemeMac.
+//
+// For all other differences, if it was introduced in this file, then the
+// maintainer forgot to include it in the list; otherwise it is an update that
+// should have been applied to this file but was not.
+
// The methods in this file are specific to the Mac OS X platform.
-// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari.
+// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari.
@interface WebCoreRenderThemeNotificationObserver : NSObject
{
@@ -80,52 +96,70 @@ using std::min;
{
[super init];
_theme = theme;
-
+
return self;
}
-- (void)systemColorsDidChange:(NSNotification *)notification
+- (void)systemColorsDidChange:(NSNotification *)unusedNotification
{
- ASSERT([[notification name] isEqualToString:NSSystemColorsDidChangeNotification]);
+ ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]);
_theme->platformColorsDidChange();
}
@end
+@interface RTCMFlippedView : NSView
+{}
+
+- (BOOL)isFlipped;
+- (NSText *)currentEditor;
+
+@end
+
+@implementation RTCMFlippedView
+
+- (BOOL)isFlipped {
+ return [[NSGraphicsContext currentContext] isFlipped];
+}
+
+- (NSText *)currentEditor {
+ return nil;
+}
+
+@end
+
namespace WebCore {
using namespace HTMLNames;
enum {
- TopMargin,
- RightMargin,
- BottomMargin,
- LeftMargin
+ topMargin,
+ rightMargin,
+ bottomMargin,
+ leftMargin
};
enum {
- TopPadding,
- RightPadding,
- BottomPadding,
- LeftPadding
+ topPadding,
+ rightPadding,
+ bottomPadding,
+ leftPadding
};
-// In our Mac port, we don't define PLATFORM(MAC) and thus don't pick up the
-// |operator NSRect()| on WebCore::IntRect and FloatRect. This substitues for
-// that missing conversion operator.
-NSRect IntRectToNSRect(const IntRect & rect)
-{
- return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
-}
-
-NSRect FloatRectToNSRect(const FloatRect & rect)
+// In Snow Leopard, many cells only check to see if the view they're passed is
+// flipped, and if a nil view is passed, neglect to check if the current
+// graphics context is flipped. Thus we pass a sham view to them, one whose
+// flipped state just reflects the state of the context.
+NSView* FlippedView()
{
- return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
+ static NSView* view = [[RTCMFlippedView alloc] init];
+ return view;
}
-IntRect NSRectToIntRect(const NSRect & rect)
+PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*)
{
- return IntRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+ static RenderTheme* rt = RenderThemeChromiumMac::create().releaseRef();
+ return rt;
}
PassRefPtr<RenderTheme> RenderThemeChromiumMac::create()
@@ -133,12 +167,6 @@ PassRefPtr<RenderTheme> RenderThemeChromiumMac::create()
return adoptRef(new RenderThemeChromiumMac);
}
-PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
-{
- static RenderTheme* rt = RenderThemeChromiumMac::create().releaseRef();
- return rt;
-}
-
RenderThemeChromiumMac::RenderThemeChromiumMac()
: m_isSliderThumbHorizontalPressed(false)
, m_isSliderThumbVerticalPressed(false)
@@ -173,6 +201,16 @@ Color RenderThemeChromiumMac::platformActiveListBoxSelectionBackgroundColor() co
return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent]));
}
+Color RenderThemeChromiumMac::platformActiveListBoxSelectionForegroundColor() const
+{
+ return Color::white;
+}
+
+Color RenderThemeChromiumMac::platformInactiveListBoxSelectionForegroundColor() const
+{
+ return Color::black;
+}
+
Color RenderThemeChromiumMac::platformFocusRingColor() const
{
if (ChromiumBridge::layoutTestMode())
@@ -181,6 +219,11 @@ Color RenderThemeChromiumMac::platformFocusRingColor() const
return systemColor(CSSValueWebkitFocusRingColor);
}
+Color RenderThemeChromiumMac::platformInactiveListBoxSelectionBackgroundColor() const
+{
+ return platformInactiveSelectionBackgroundColor();
+}
+
static FontWeight toFontWeight(NSInteger appKitFontWeight)
{
ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15);
@@ -210,51 +253,51 @@ static FontWeight toFontWeight(NSInteger appKitFontWeight)
void RenderThemeChromiumMac::systemFont(int cssValueId, FontDescription& fontDescription) const
{
- static FontDescription systemFont;
- static FontDescription smallSystemFont;
- static FontDescription menuFont;
- static FontDescription labelFont;
- static FontDescription miniControlFont;
- static FontDescription smallControlFont;
- static FontDescription controlFont;
+ DEFINE_STATIC_LOCAL(FontDescription, systemFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, menuFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, labelFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ());
+ DEFINE_STATIC_LOCAL(FontDescription, controlFont, ());
FontDescription* cachedDesc;
NSFont* font = nil;
switch (cssValueId) {
- case CSSValueSmallCaption:
- cachedDesc = &smallSystemFont;
- if (!smallSystemFont.isAbsoluteSize())
- font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
- break;
- case CSSValueMenu:
- cachedDesc = &menuFont;
- if (!menuFont.isAbsoluteSize())
- font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
- break;
- case CSSValueStatusBar:
- cachedDesc = &labelFont;
- if (!labelFont.isAbsoluteSize())
- font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
- break;
- case CSSValueWebkitMiniControl:
- cachedDesc = &miniControlFont;
- if (!miniControlFont.isAbsoluteSize())
- font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
- break;
- case CSSValueWebkitSmallControl:
- cachedDesc = &smallControlFont;
- if (!smallControlFont.isAbsoluteSize())
- font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
- break;
- case CSSValueWebkitControl:
- cachedDesc = &controlFont;
- if (!controlFont.isAbsoluteSize())
- font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
- break;
- default:
- cachedDesc = &systemFont;
- if (!systemFont.isAbsoluteSize())
- font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
+ case CSSValueSmallCaption:
+ cachedDesc = &smallSystemFont;
+ if (!smallSystemFont.isAbsoluteSize())
+ font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
+ break;
+ case CSSValueMenu:
+ cachedDesc = &menuFont;
+ if (!menuFont.isAbsoluteSize())
+ font = [NSFont menuFontOfSize:[NSFont systemFontSize]];
+ break;
+ case CSSValueStatusBar:
+ cachedDesc = &labelFont;
+ if (!labelFont.isAbsoluteSize())
+ font = [NSFont labelFontOfSize:[NSFont labelFontSize]];
+ break;
+ case CSSValueWebkitMiniControl:
+ cachedDesc = &miniControlFont;
+ if (!miniControlFont.isAbsoluteSize())
+ font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
+ break;
+ case CSSValueWebkitSmallControl:
+ cachedDesc = &smallControlFont;
+ if (!smallControlFont.isAbsoluteSize())
+ font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
+ break;
+ case CSSValueWebkitControl:
+ cachedDesc = &controlFont;
+ if (!controlFont.isAbsoluteSize())
+ font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ break;
+ default:
+ cachedDesc = &systemFont;
+ if (!systemFont.isAbsoluteSize())
+ font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
}
if (font) {
@@ -271,7 +314,7 @@ void RenderThemeChromiumMac::systemFont(int cssValueId, FontDescription& fontDes
static RGBA32 convertNSColorToColor(NSColor *color)
{
- NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+ NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
if (colorInColorSpace) {
static const double scaleFactor = nextafter(256.0, 0.0);
return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]),
@@ -279,7 +322,7 @@ static RGBA32 convertNSColorToColor(NSColor *color)
static_cast<int>(scaleFactor * [colorInColorSpace blueComponent]));
}
- // This conversion above can fail if the NSColor in question is an NSPatternColor
+ // This conversion above can fail if the NSColor in question is an NSPatternColor
// (as many system colors are). These colors are actually a repeating pattern
// not just a solid color. To work around this we simply draw a 1x1 image of
// the color and use that pixel's color. It might be better to use an average of
@@ -291,7 +334,7 @@ static RGBA32 convertNSColorToColor(NSColor *color)
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
- colorSpaceName:NSCalibratedRGBColorSpace
+ colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:4
bitsPerPixel:32];
@@ -318,7 +361,7 @@ static RGBA32 menuBackgroundColor()
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
- colorSpaceName:NSCalibratedRGBColorSpace
+ colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:4
bitsPerPixel:32];
@@ -347,104 +390,104 @@ Color RenderThemeChromiumMac::systemColor(int cssValueId) const
{
if (m_systemColorCache.contains(cssValueId))
return m_systemColorCache.get(cssValueId);
-
+
Color color;
switch (cssValueId) {
- case CSSValueActiveborder:
- color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
- break;
- case CSSValueActivecaption:
- color = convertNSColorToColor([NSColor windowFrameTextColor]);
- break;
- case CSSValueAppworkspace:
- color = convertNSColorToColor([NSColor headerColor]);
- break;
- case CSSValueBackground:
- // Use theme independent default
- break;
- case CSSValueButtonface:
- // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
- // We may want to change this to use the NSColor in future.
- color = 0xFFC0C0C0;
- break;
- case CSSValueButtonhighlight:
- color = convertNSColorToColor([NSColor controlHighlightColor]);
- break;
- case CSSValueButtonshadow:
- color = convertNSColorToColor([NSColor controlShadowColor]);
- break;
- case CSSValueButtontext:
- color = convertNSColorToColor([NSColor controlTextColor]);
- break;
- case CSSValueCaptiontext:
- color = convertNSColorToColor([NSColor textColor]);
- break;
- case CSSValueGraytext:
- color = convertNSColorToColor([NSColor disabledControlTextColor]);
- break;
- case CSSValueHighlight:
- color = convertNSColorToColor([NSColor selectedTextBackgroundColor]);
- break;
- case CSSValueHighlighttext:
- color = convertNSColorToColor([NSColor selectedTextColor]);
- break;
- case CSSValueInactiveborder:
- color = convertNSColorToColor([NSColor controlBackgroundColor]);
- break;
- case CSSValueInactivecaption:
- color = convertNSColorToColor([NSColor controlBackgroundColor]);
- break;
- case CSSValueInactivecaptiontext:
- color = convertNSColorToColor([NSColor textColor]);
- break;
- case CSSValueInfobackground:
- // There is no corresponding NSColor for this so we use a hard coded value.
- color = 0xFFFBFCC5;
- break;
- case CSSValueInfotext:
- color = convertNSColorToColor([NSColor textColor]);
- break;
- case CSSValueMenu:
- color = menuBackgroundColor();
- break;
- case CSSValueMenutext:
- color = convertNSColorToColor([NSColor selectedMenuItemTextColor]);
- break;
- case CSSValueScrollbar:
- color = convertNSColorToColor([NSColor scrollBarColor]);
- break;
- case CSSValueText:
- color = convertNSColorToColor([NSColor textColor]);
- break;
- case CSSValueThreeddarkshadow:
- color = convertNSColorToColor([NSColor controlDarkShadowColor]);
- break;
- case CSSValueThreedshadow:
- color = convertNSColorToColor([NSColor shadowColor]);
- break;
- case CSSValueThreedface:
- // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
- // We may want to change this to use the NSColor in future.
- color = 0xFFC0C0C0;
- break;
- case CSSValueThreedhighlight:
- color = convertNSColorToColor([NSColor highlightColor]);
- break;
- case CSSValueThreedlightshadow:
- color = convertNSColorToColor([NSColor controlLightHighlightColor]);
- break;
- case CSSValueWebkitFocusRingColor:
- color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
- break;
- case CSSValueWindow:
- color = convertNSColorToColor([NSColor windowBackgroundColor]);
- break;
- case CSSValueWindowframe:
- color = convertNSColorToColor([NSColor windowFrameColor]);
- break;
- case CSSValueWindowtext:
- color = convertNSColorToColor([NSColor windowFrameTextColor]);
- break;
+ case CSSValueActiveborder:
+ color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
+ break;
+ case CSSValueActivecaption:
+ color = convertNSColorToColor([NSColor windowFrameTextColor]);
+ break;
+ case CSSValueAppworkspace:
+ color = convertNSColorToColor([NSColor headerColor]);
+ break;
+ case CSSValueBackground:
+ // Use theme independent default
+ break;
+ case CSSValueButtonface:
+ // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
+ // We may want to change this to use the NSColor in future.
+ color = 0xFFC0C0C0;
+ break;
+ case CSSValueButtonhighlight:
+ color = convertNSColorToColor([NSColor controlHighlightColor]);
+ break;
+ case CSSValueButtonshadow:
+ color = convertNSColorToColor([NSColor controlShadowColor]);
+ break;
+ case CSSValueButtontext:
+ color = convertNSColorToColor([NSColor controlTextColor]);
+ break;
+ case CSSValueCaptiontext:
+ color = convertNSColorToColor([NSColor textColor]);
+ break;
+ case CSSValueGraytext:
+ color = convertNSColorToColor([NSColor disabledControlTextColor]);
+ break;
+ case CSSValueHighlight:
+ color = convertNSColorToColor([NSColor selectedTextBackgroundColor]);
+ break;
+ case CSSValueHighlighttext:
+ color = convertNSColorToColor([NSColor selectedTextColor]);
+ break;
+ case CSSValueInactiveborder:
+ color = convertNSColorToColor([NSColor controlBackgroundColor]);
+ break;
+ case CSSValueInactivecaption:
+ color = convertNSColorToColor([NSColor controlBackgroundColor]);
+ break;
+ case CSSValueInactivecaptiontext:
+ color = convertNSColorToColor([NSColor textColor]);
+ break;
+ case CSSValueInfobackground:
+ // There is no corresponding NSColor for this so we use a hard coded value.
+ color = 0xFFFBFCC5;
+ break;
+ case CSSValueInfotext:
+ color = convertNSColorToColor([NSColor textColor]);
+ break;
+ case CSSValueMenu:
+ color = menuBackgroundColor();
+ break;
+ case CSSValueMenutext:
+ color = convertNSColorToColor([NSColor selectedMenuItemTextColor]);
+ break;
+ case CSSValueScrollbar:
+ color = convertNSColorToColor([NSColor scrollBarColor]);
+ break;
+ case CSSValueText:
+ color = convertNSColorToColor([NSColor textColor]);
+ break;
+ case CSSValueThreeddarkshadow:
+ color = convertNSColorToColor([NSColor controlDarkShadowColor]);
+ break;
+ case CSSValueThreedshadow:
+ color = convertNSColorToColor([NSColor shadowColor]);
+ break;
+ case CSSValueThreedface:
+ // We use this value instead of NSColor's controlColor to avoid website incompatibilities.
+ // We may want to change this to use the NSColor in future.
+ color = 0xFFC0C0C0;
+ break;
+ case CSSValueThreedhighlight:
+ color = convertNSColorToColor([NSColor highlightColor]);
+ break;
+ case CSSValueThreedlightshadow:
+ color = convertNSColorToColor([NSColor controlLightHighlightColor]);
+ break;
+ case CSSValueWebkitFocusRingColor:
+ color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]);
+ break;
+ case CSSValueWindow:
+ color = convertNSColorToColor([NSColor windowBackgroundColor]);
+ break;
+ case CSSValueWindowframe:
+ color = convertNSColorToColor([NSColor windowFrameColor]);
+ break;
+ case CSSValueWindowtext:
+ color = convertNSColorToColor([NSColor windowFrameTextColor]);
+ break;
}
if (!color.isValid())
@@ -457,11 +500,11 @@ Color RenderThemeChromiumMac::systemColor(int cssValueId) const
}
bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const BorderData& border,
- const FillLayer& background, const Color& backgroundColor) const
+ const FillLayer& background, const Color& backgroundColor) const
{
if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart)
return style->border() != border;
-
+
// FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when
// scaled. They can't really draw properly when transformed either. We can't detect the transform case at style
// adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming
@@ -472,62 +515,33 @@ bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const Bor
return RenderTheme::isControlStyled(style, border, background, backgroundColor);
}
-// FIXME: Use the code from the old upstream version, before it was converted to the new theme API in r37731.
void RenderThemeChromiumMac::adjustRepaintRect(const RenderObject* o, IntRect& r)
{
- float zoomLevel = o->style()->effectiveZoom();
-
- switch (o->style()->appearance()) {
- case CheckboxPart: {
- // Since we query the prototype cell, we need to update its state to match.
- setCheckboxCellState(o, r);
-
- // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
- // shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
- IntSize size = checkboxSizes()[[checkbox() controlSize]];
- size.setHeight(size.height() * zoomLevel);
- size.setWidth(size.width() * zoomLevel);
- r = inflateRect(r, size, checkboxMargins(), zoomLevel);
- break;
+ ControlPart part = o->style()->appearance();
+
+#if USE(NEW_THEME)
+ switch (part) {
+ case CheckboxPart:
+ case RadioPart:
+ case PushButtonPart:
+ case SquareButtonPart:
+ case ListButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ return RenderTheme::adjustRepaintRect(o, r);
+ default:
+ break;
}
- case RadioPart: {
- // Since we query the prototype cell, we need to update its state to match.
- setRadioCellState(o, r);
+#endif
- // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
- // shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
- IntSize size = radioSizes()[[radio() controlSize]];
- size.setHeight(size.height() * zoomLevel);
- size.setWidth(size.width() * zoomLevel);
- r = inflateRect(r, size, radioMargins(), zoomLevel);
- break;
- }
- case PushButtonPart:
- case DefaultButtonPart:
- case ButtonPart: {
- // Since we query the prototype cell, we need to update its state to match.
- setButtonCellState(o, r);
-
- // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
- // shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
- if ([button() bezelStyle] == NSRoundedBezelStyle) {
- IntSize size = buttonSizes()[[button() controlSize]];
- size.setHeight(size.height() * zoomLevel);
- size.setWidth(r.width());
- r = inflateRect(r, size, buttonMargins(), zoomLevel);
- }
- break;
- }
- case MenulistPart: {
+ float zoomLevel = o->style()->effectiveZoom();
+
+ if (part == MenulistPart) {
setPopupButtonCellState(o, r);
IntSize size = popupButtonSizes()[[popupButton() controlSize]];
size.setHeight(size.height() * zoomLevel);
size.setWidth(r.width());
r = inflateRect(r, size, popupButtonMargins(), zoomLevel);
- break;
- }
- default:
- break;
}
}
@@ -535,20 +549,61 @@ IntRect RenderThemeChromiumMac::inflateRect(const IntRect& r, const IntSize& siz
{
// Only do the inflation if the available width/height are too small. Otherwise try to
// fit the glow/check space into the available box's width/height.
- int widthDelta = r.width() - (size.width() + margins[LeftMargin] * zoomLevel + margins[RightMargin] * zoomLevel);
- int heightDelta = r.height() - (size.height() + margins[TopMargin] * zoomLevel + margins[BottomMargin] * zoomLevel);
+ int widthDelta = r.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel);
+ int heightDelta = r.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel);
IntRect result(r);
if (widthDelta < 0) {
- result.setX(result.x() - margins[LeftMargin] * zoomLevel);
+ result.setX(result.x() - margins[leftMargin] * zoomLevel);
result.setWidth(result.width() - widthDelta);
}
if (heightDelta < 0) {
- result.setY(result.y() - margins[TopMargin] * zoomLevel);
+ result.setY(result.y() - margins[topMargin] * zoomLevel);
result.setHeight(result.height() - heightDelta);
}
return result;
}
+FloatRect RenderThemeChromiumMac::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const
+{
+ FloatRect partRect(inputRect);
+
+ // Compute an offset between the part renderer and the input renderer
+ FloatSize offsetFromInputRenderer;
+ const RenderObject* renderer = partRenderer;
+ while (renderer && renderer != inputRenderer) {
+ RenderObject* containingRenderer = renderer->container();
+ offsetFromInputRenderer -= renderer->offsetFromContainer(containingRenderer);
+ renderer = containingRenderer;
+ }
+ // If the input renderer was not a container, something went wrong
+ ASSERT(renderer == inputRenderer);
+ // Move the rect into partRenderer's coords
+ partRect.move(offsetFromInputRenderer);
+ // Account for the local drawing offset (tx, ty)
+ partRect.move(r.x(), r.y());
+
+ return partRect;
+}
+
+// Updates the control tint (a.k.a. active state) of |cell| (from |o|).
+// In the Chromium port, the renderer runs as a background process and controls'
+// NSCell(s) lack a parent NSView. Therefore controls don't have their tint
+// color updated correctly when the application is activated/deactivated.
+// FocusController's setActive() is called when the application is
+// activated/deactivated, which causes a repaint at which time this code is
+// called.
+// This function should be called before drawing any NSCell-derived controls,
+// unless you're sure it isn't needed.
+void RenderThemeChromiumMac::updateActiveState(NSCell* cell, const RenderObject* o)
+{
+ NSControlTint oldTint = [cell controlTint];
+ NSControlTint tint = isActive(o) ? [NSColor currentControlTint] :
+ NSClearControlTint;
+
+ if (tint != oldTint)
+ [cell setControlTint:tint];
+}
+
void RenderThemeChromiumMac::updateCheckedState(NSCell* cell, const RenderObject* o)
{
bool oldIndeterminate = [cell state] == NSMixedState;
@@ -589,19 +644,6 @@ void RenderThemeChromiumMac::updatePressedState(NSCell* cell, const RenderObject
[cell setHighlighted:pressed];
}
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-int RenderThemeChromiumMac::baselinePosition(const RenderObject* o) const
-{
- if (!o->isBox())
- return 0;
-
- if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) {
- const RenderBox* box = toRenderBox(o);
- return box->marginTop() + box->height() - 2 * o->style()->effectiveZoom(); // The baseline is 2px up from the bottom of the checkbox/radio in AppKit.
- }
- return RenderTheme::baselinePosition(o);
-}
-
bool RenderThemeChromiumMac::controlSupportsTints(const RenderObject* o) const
{
// An alternate way to implement this would be to get the appropriate cell object
@@ -673,7 +715,7 @@ void RenderThemeChromiumMac::setSizeFromFont(RenderStyle* style, const IntSize*
style->setHeight(Length(size.height(), Fixed));
}
-void RenderThemeChromiumMac::setFontFromControlSize(CSSStyleSelector* selector, RenderStyle* style, NSControlSize controlSize) const
+void RenderThemeChromiumMac::setFontFromControlSize(CSSStyleSelector*, RenderStyle* style, NSControlSize controlSize) const
{
FontDescription fontDescription;
fontDescription.setIsAbsoluteSize(true);
@@ -701,349 +743,10 @@ NSControlSize RenderThemeChromiumMac::controlSizeForSystemFont(RenderStyle* styl
return NSMiniControlSize;
}
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-bool RenderThemeChromiumMac::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
-{
- LocalCurrentGraphicsContext localContext(paintInfo.context);
-
- // Determine the width and height needed for the control and prepare the cell for painting.
- setCheckboxCellState(o, r);
-
- paintInfo.context->save();
-
- float zoomLevel = o->style()->effectiveZoom();
-
- // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
- // shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
- NSButtonCell* checkbox = this->checkbox();
- IntSize size = checkboxSizes()[[checkbox controlSize]];
- size.setWidth(size.width() * zoomLevel);
- size.setHeight(size.height() * zoomLevel);
- IntRect inflatedRect = inflateRect(r, size, checkboxMargins(), zoomLevel);
-
- if (zoomLevel != 1.0f) {
- inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
- inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
- paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
- paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
- paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
- }
-
- [checkbox drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:nil];
- [checkbox setControlView:nil];
-
- paintInfo.context->restore();
-
- return false;
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-const IntSize* RenderThemeChromiumMac::checkboxSizes() const
-{
- static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) };
- return sizes;
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-const int* RenderThemeChromiumMac::checkboxMargins() const
-{
- static const int margins[3][4] =
- {
- { 3, 4, 4, 2 },
- { 4, 3, 3, 3 },
- { 4, 3, 3, 3 },
- };
- return margins[[checkbox() controlSize]];
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-void RenderThemeChromiumMac::setCheckboxCellState(const RenderObject* o, const IntRect& r)
-{
- NSButtonCell* checkbox = this->checkbox();
-
- // Set the control size based off the rectangle we're painting into.
- setControlSize(checkbox, checkboxSizes(), r.size(), o->style()->effectiveZoom());
-
- // Update the various states we respond to.
- updateCheckedState(checkbox, o);
- updateEnabledState(checkbox, o);
- updatePressedState(checkbox, o);
- updateFocusedState(checkbox, o);
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-void RenderThemeChromiumMac::setCheckboxSize(RenderStyle* style) const
-{
- // If the width and height are both specified, then we have nothing to do.
- if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
- return;
-
- // Use the font size to determine the intrinsic width of the control.
- setSizeFromFont(style, checkboxSizes());
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-bool RenderThemeChromiumMac::paintRadio(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
-{
- LocalCurrentGraphicsContext localContext(paintInfo.context);
-
- // Determine the width and height needed for the control and prepare the cell for painting.
- setRadioCellState(o, r);
-
- paintInfo.context->save();
-
- float zoomLevel = o->style()->effectiveZoom();
-
- // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox
- // shadow" and the check. We don't consider this part of the bounds of the control in WebKit.
- NSButtonCell* radio = this->radio();
- IntSize size = radioSizes()[[radio controlSize]];
- size.setWidth(size.width() * zoomLevel);
- size.setHeight(size.height() * zoomLevel);
- IntRect inflatedRect = inflateRect(r, size, radioMargins(), zoomLevel);
-
- if (zoomLevel != 1.0f) {
- inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
- inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
- paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
- paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
- paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
- }
-
- [radio drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:nil];
- [radio setControlView:nil];
-
- paintInfo.context->restore();
-
- return false;
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-const IntSize* RenderThemeChromiumMac::radioSizes() const
-{
- static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) };
- return sizes;
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-const int* RenderThemeChromiumMac::radioMargins() const
-{
- static const int margins[3][4] =
- {
- { 2, 2, 4, 2 },
- { 3, 2, 3, 2 },
- { 1, 0, 2, 0 },
- };
- return margins[[radio() controlSize]];
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-void RenderThemeChromiumMac::setRadioCellState(const RenderObject* o, const IntRect& r)
-{
- NSButtonCell* radio = this->radio();
-
- // Set the control size based off the rectangle we're painting into.
- setControlSize(radio, radioSizes(), r.size(), o->style()->effectiveZoom());
-
- // Update the various states we respond to.
- updateCheckedState(radio, o);
- updateEnabledState(radio, o);
- updatePressedState(radio, o);
- updateFocusedState(radio, o);
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-void RenderThemeChromiumMac::setRadioSize(RenderStyle* style) const
-{
- // If the width and height are both specified, then we have nothing to do.
- if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
- return;
-
- // Use the font size to determine the intrinsic width of the control.
- setSizeFromFont(style, radioSizes());
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-void RenderThemeChromiumMac::setButtonPaddingFromControlSize(RenderStyle* style, NSControlSize size) const
-{
- // Just use 8px. AppKit wants to use 11px for mini buttons, but that padding is just too large
- // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is
- // by definition constrained, since we select mini only for small cramped environments.
- // This also guarantees the HTML4 <button> will match our rendering by default, since we're using a consistent
- // padding.
- const int padding = 8 * style->effectiveZoom();
- style->setPaddingLeft(Length(padding, Fixed));
- style->setPaddingRight(Length(padding, Fixed));
- style->setPaddingTop(Length(0, Fixed));
- style->setPaddingBottom(Length(0, Fixed));
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-void RenderThemeChromiumMac::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
-{
- // There are three appearance constants for buttons.
- // (1) Push-button is the constant for the default Aqua system button. Push buttons will not scale vertically and will not allow
- // custom fonts or colors. <input>s use this constant. This button will allow custom colors and font weights/variants but won't
- // scale vertically.
- // (2) square-button is the constant for the square button. This button will allow custom fonts and colors and will scale vertically.
- // (3) Button is the constant that means "pick the best button as appropriate." <button>s use this constant. This button will
- // also scale vertically and allow custom fonts and colors. It will attempt to use Aqua if possible and will make this determination
- // solely on the rectangle of the control.
-
- // Determine our control size based off our font.
- NSControlSize controlSize = controlSizeForFont(style);
-
- if (style->appearance() == PushButtonPart) {
- // Ditch the border.
- style->resetBorder();
-
- // Height is locked to auto.
- style->setHeight(Length(Auto));
-
- // White-space is locked to pre
- style->setWhiteSpace(PRE);
-
- // Set the button's vertical size.
- setButtonSize(style);
-
- // Add in the padding that we'd like to use.
- setButtonPaddingFromControlSize(style, controlSize);
-
- // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out
- // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate
- // system font for the control size instead.
- setFontFromControlSize(selector, style, controlSize);
- } else {
- // Set a min-height so that we can't get smaller than the mini button.
- style->setMinHeight(Length(static_cast<int>(15 * style->effectiveZoom()), Fixed));
-
- // Reset the top and bottom borders.
- style->resetBorderTop();
- style->resetBorderBottom();
- }
-
- style->setBoxShadow(0);
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-const IntSize* RenderThemeChromiumMac::buttonSizes() const
-{
- static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
- return sizes;
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-const int* RenderThemeChromiumMac::buttonMargins() const
-{
- static const int margins[3][4] =
- {
- { 4, 6, 7, 6 },
- { 4, 5, 6, 5 },
- { 0, 1, 1, 1 },
- };
- return margins[[button() controlSize]];
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-void RenderThemeChromiumMac::setButtonSize(RenderStyle* style) const
-{
- // If the width and height are both specified, then we have nothing to do.
- if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
- return;
-
- // Use the font size to determine the intrinsic width of the control.
- setSizeFromFont(style, buttonSizes());
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-void RenderThemeChromiumMac::setButtonCellState(const RenderObject* o, const IntRect& r)
-{
- NSButtonCell* button = this->button();
-
- // Set the control size based off the rectangle we're painting into.
- if (o->style()->appearance() == SquareButtonPart ||
- r.height() > buttonSizes()[NSRegularControlSize].height() * o->style()->effectiveZoom()) {
- // Use the square button
- if ([button bezelStyle] != NSShadowlessSquareBezelStyle)
- [button setBezelStyle:NSShadowlessSquareBezelStyle];
- } else if ([button bezelStyle] != NSRoundedBezelStyle)
- [button setBezelStyle:NSRoundedBezelStyle];
-
- setControlSize(button, buttonSizes(), r.size(), o->style()->effectiveZoom());
-
- NSWindow *window = [nil window];
- BOOL isDefaultButton = (isDefault(o) && [window isKeyWindow]);
- [button setKeyEquivalent:(isDefaultButton ? @"\r" : @"")];
-
- // Update the various states we respond to.
- updateCheckedState(button, o);
- updateEnabledState(button, o);
- updatePressedState(button, o);
- updateFocusedState(button, o);
-}
-
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-bool RenderThemeChromiumMac::paintButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
-{
- NSButtonCell* button = this->button();
- LocalCurrentGraphicsContext localContext(paintInfo.context);
-
- // Determine the width and height needed for the control and prepare the cell for painting.
- setButtonCellState(o, r);
-
- paintInfo.context->save();
-
- // We inflate the rect as needed to account for padding included in the cell to accommodate the button
- // shadow. We don't consider this part of the bounds of the control in WebKit.
- float zoomLevel = o->style()->effectiveZoom();
- IntSize size = buttonSizes()[[button controlSize]];
- size.setWidth(r.width());
- size.setHeight(size.height() * zoomLevel);
- IntRect inflatedRect = r;
- if ([button bezelStyle] == NSRoundedBezelStyle) {
- // Center the button within the available space.
- if (inflatedRect.height() > size.height()) {
- inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - size.height()) / 2);
- inflatedRect.setHeight(size.height());
- }
-
- // Now inflate it to account for the shadow.
- inflatedRect = inflateRect(inflatedRect, size, buttonMargins(), zoomLevel);
-
- if (zoomLevel != 1.0f) {
- inflatedRect.setWidth(inflatedRect.width() / zoomLevel);
- inflatedRect.setHeight(inflatedRect.height() / zoomLevel);
- paintInfo.context->translate(inflatedRect.x(), inflatedRect.y());
- paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
- paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
- }
- }
-
- NSView *view = nil;
- NSWindow *window = [view window];
- NSButtonCell *previousDefaultButtonCell = [window defaultButtonCell];
-
- if (isDefault(o) && [window isKeyWindow]) {
- [window setDefaultButtonCell:button];
- wkAdvanceDefaultButtonPulseAnimation(button);
- } else if ([previousDefaultButtonCell isEqual:button])
- [window setDefaultButtonCell:nil];
-
- [button drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:view];
- [button setControlView:nil];
-
- if (![previousDefaultButtonCell isEqual:button])
- [window setDefaultButtonCell:previousDefaultButtonCell];
-
- paintInfo.context->restore();
-
- return false;
-}
-
bool RenderThemeChromiumMac::paintTextField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawBezeledTextFieldCell(IntRectToNSRect(r), isEnabled(o) && !isReadOnlyControl(o));
+ wkDrawBezeledTextFieldCell(r, isEnabled(o) && !isReadOnlyControl(o));
return false;
}
@@ -1051,21 +754,21 @@ void RenderThemeChromiumMac::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle
{
}
-bool RenderThemeChromiumMac::paintCapsLockIndicator(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeChromiumMac::paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
if (paintInfo.context->paintingDisabled())
return true;
LocalCurrentGraphicsContext localContext(paintInfo.context);
wkDrawCapsLockIndicator(paintInfo.context->platformContext(), r);
-
+
return false;
}
bool RenderThemeChromiumMac::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawBezeledTextArea(IntRectToNSRect(r), isEnabled(o) && !isReadOnlyControl(o));
+ wkDrawBezeledTextArea(r, isEnabled(o) && !isReadOnlyControl(o));
return false;
}
@@ -1103,8 +806,6 @@ const int* RenderThemeChromiumMac::popupButtonPadding(NSControlSize size) const
bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- LocalCurrentGraphicsContext localContext(paintInfo.context);
-
setPopupButtonCellState(o, r);
NSPopUpButtonCell* popupButton = this->popupButton();
@@ -1120,7 +821,7 @@ bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const RenderObject::
inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel);
paintInfo.context->save();
-
+
#ifndef BUILDING_ON_TIGER
// On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect
paintInfo.context->clip(inflatedRect);
@@ -1134,7 +835,7 @@ bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const RenderObject::
paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y());
}
- [popupButton drawWithFrame:IntRectToNSRect(inflatedRect) inView:nil];
+ [popupButton drawWithFrame:inflatedRect inView:FlippedView()];
[popupButton setControlView:nil];
paintInfo.context->restore();
@@ -1142,19 +843,19 @@ bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const RenderObject::
return false;
}
-static const float baseFontSize = 11.0f;
-static const float baseArrowHeight = 4.0f;
-static const float baseArrowWidth = 5.0f;
-static const float baseSpaceBetweenArrows = 2.0f;
-static const int arrowPaddingLeft = 6;
-static const int arrowPaddingRight = 6;
-static const int paddingBeforeSeparator = 4;
-static const int baseBorderRadius = 5;
-static const int styledPopupPaddingLeft = 8;
-static const int styledPopupPaddingTop = 1;
-static const int styledPopupPaddingBottom = 2;
+const float baseFontSize = 11.0f;
+const float baseArrowHeight = 4.0f;
+const float baseArrowWidth = 5.0f;
+const float baseSpaceBetweenArrows = 2.0f;
+const int arrowPaddingLeft = 6;
+const int arrowPaddingRight = 6;
+const int paddingBeforeSeparator = 4;
+const int baseBorderRadius = 5;
+const int styledPopupPaddingLeft = 8;
+const int styledPopupPaddingTop = 1;
+const int styledPopupPaddingBottom = 2;
-static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
+static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
{
static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
@@ -1164,7 +865,7 @@ static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* o
outData[i] = (1.0f - a) * dark[i] + a * light[i];
}
-static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
+static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
{
static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f };
@@ -1174,7 +875,7 @@ static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat
outData[i] = (1.0f - a) * dark[i] + a * light[i];
}
-static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
+static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
{
static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f };
static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
@@ -1184,7 +885,7 @@ static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat*
outData[i] = (1.0f - a) * dark[i] + a * light[i];
}
-static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData)
+static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData)
{
static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f };
static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f };
@@ -1196,11 +897,21 @@ static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat*
void RenderThemeChromiumMac::paintMenuListButtonGradients(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
+ if (r.isEmpty())
+ return;
+
CGContextRef context = paintInfo.context->platformContext();
paintInfo.context->save();
- int radius = o->style()->borderTopLeftRadius().width();
+ IntSize topLeftRadius;
+ IntSize topRightRadius;
+ IntSize bottomLeftRadius;
+ IntSize bottomRightRadius;
+
+ o->style()->getBorderRadiiForRect(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+
+ int radius = topLeftRadius.width();
RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
@@ -1223,33 +934,27 @@ void RenderThemeChromiumMac::paintMenuListButtonGradients(RenderObject* o, const
RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.right(), r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false));
paintInfo.context->save();
CGContextClipToRect(context, r);
- paintInfo.context->addRoundedRectClip(r,
- o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
- o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
+ paintInfo.context->addRoundedRectClip(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
CGContextDrawShading(context, mainShading.get());
paintInfo.context->restore();
paintInfo.context->save();
CGContextClipToRect(context, topGradient);
- paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient),
- o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
- IntSize(), IntSize());
+ paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient), topLeftRadius, topRightRadius, IntSize(), IntSize());
CGContextDrawShading(context, topShading.get());
paintInfo.context->restore();
- paintInfo.context->save();
- CGContextClipToRect(context, bottomGradient);
- paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient),
- IntSize(), IntSize(),
- o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
- CGContextDrawShading(context, bottomShading.get());
- paintInfo.context->restore();
+ if (!bottomGradient.isEmpty()) {
+ paintInfo.context->save();
+ CGContextClipToRect(context, bottomGradient);
+ paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient), IntSize(), IntSize(), bottomLeftRadius, bottomRightRadius);
+ CGContextDrawShading(context, bottomShading.get());
+ paintInfo.context->restore();
+ }
paintInfo.context->save();
CGContextClipToRect(context, r);
- paintInfo.context->addRoundedRectClip(r,
- o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
- o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
+ paintInfo.context->addRoundedRectClip(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
CGContextDrawShading(context, leftShading.get());
CGContextDrawShading(context, rightShading.get());
paintInfo.context->restore();
@@ -1259,8 +964,6 @@ void RenderThemeChromiumMac::paintMenuListButtonGradients(RenderObject* o, const
bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- paintInfo.context->save();
-
IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
r.y() + o->style()->borderTopWidth(),
r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
@@ -1278,8 +981,10 @@ bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const RenderOb
if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom())
return false;
-
- paintInfo.context->setFillColor(o->style()->color());
+
+ paintInfo.context->save();
+
+ paintInfo.context->setFillColor(o->style()->color(), o->style()->colorSpace());
paintInfo.context->setStrokeStyle(NoStroke);
FloatPoint arrow1[3];
@@ -1308,11 +1013,11 @@ bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const RenderOb
// Draw the separator to the left of the arrows
paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin.
paintInfo.context->setStrokeStyle(SolidStroke);
- paintInfo.context->setStrokeColor(leftSeparatorColor);
+ paintInfo.context->setStrokeColor(leftSeparatorColor, DeviceColorSpace);
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
IntPoint(leftEdgeOfSeparator, bounds.bottom()));
- paintInfo.context->setStrokeColor(rightSeparatorColor);
+ paintInfo.context->setStrokeColor(rightSeparatorColor, DeviceColorSpace);
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom()));
@@ -1332,7 +1037,7 @@ void RenderThemeChromiumMac::adjustMenuListStyle(CSSStyleSelector* selector, Ren
style->resetBorder();
style->resetPadding();
-
+
// Height is locked to auto.
style->setHeight(Length(Auto));
@@ -1357,7 +1062,7 @@ void RenderThemeChromiumMac::adjustMenuListStyle(CSSStyleSelector* selector, Ren
int RenderThemeChromiumMac::popupInternalPaddingLeft(RenderStyle* style) const
{
if (style->appearance() == MenulistPart)
- return popupButtonPadding(controlSizeForFont(style))[LeftPadding] * style->effectiveZoom();
+ return popupButtonPadding(controlSizeForFont(style))[leftPadding] * style->effectiveZoom();
if (style->appearance() == MenulistButtonPart)
return styledPopupPaddingLeft * style->effectiveZoom();
return 0;
@@ -1366,7 +1071,7 @@ int RenderThemeChromiumMac::popupInternalPaddingLeft(RenderStyle* style) const
int RenderThemeChromiumMac::popupInternalPaddingRight(RenderStyle* style) const
{
if (style->appearance() == MenulistPart)
- return popupButtonPadding(controlSizeForFont(style))[RightPadding] * style->effectiveZoom();
+ return popupButtonPadding(controlSizeForFont(style))[rightPadding] * style->effectiveZoom();
if (style->appearance() == MenulistButtonPart) {
float fontScale = style->fontSize() / baseFontSize;
float arrowWidth = baseArrowWidth * fontScale;
@@ -1378,7 +1083,7 @@ int RenderThemeChromiumMac::popupInternalPaddingRight(RenderStyle* style) const
int RenderThemeChromiumMac::popupInternalPaddingTop(RenderStyle* style) const
{
if (style->appearance() == MenulistPart)
- return popupButtonPadding(controlSizeForFont(style))[TopPadding] * style->effectiveZoom();
+ return popupButtonPadding(controlSizeForFont(style))[topPadding] * style->effectiveZoom();
if (style->appearance() == MenulistButtonPart)
return styledPopupPaddingTop * style->effectiveZoom();
return 0;
@@ -1387,13 +1092,13 @@ int RenderThemeChromiumMac::popupInternalPaddingTop(RenderStyle* style) const
int RenderThemeChromiumMac::popupInternalPaddingBottom(RenderStyle* style) const
{
if (style->appearance() == MenulistPart)
- return popupButtonPadding(controlSizeForFont(style))[BottomPadding] * style->effectiveZoom();
+ return popupButtonPadding(controlSizeForFont(style))[bottomPadding] * style->effectiveZoom();
if (style->appearance() == MenulistButtonPart)
return styledPopupPaddingBottom * style->effectiveZoom();
return 0;
}
-void RenderThemeChromiumMac::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeChromiumMac::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
{
float fontScale = style->fontSize() / baseFontSize;
@@ -1402,7 +1107,7 @@ void RenderThemeChromiumMac::adjustMenuListButtonStyle(CSSStyleSelector* selecto
const int minHeight = 15;
style->setMinHeight(Length(minHeight, Fixed));
-
+
style->setLineHeight(RenderStyle::initialLineHeight());
}
@@ -1414,6 +1119,7 @@ void RenderThemeChromiumMac::setPopupButtonCellState(const RenderObject* o, cons
setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom());
// Update the various states we respond to.
+ updateActiveState(popupButton, o);
updateCheckedState(popupButton, o);
updateEnabledState(popupButton, o);
updatePressedState(popupButton, o);
@@ -1431,10 +1137,10 @@ int RenderThemeChromiumMac::minimumMenuListSize(RenderStyle* style) const
return sizeForSystemFont(style, menuListSizes()).width();
}
-static const int trackWidth = 5;
-static const int trackRadius = 2;
+const int trackWidth = 5;
+const int trackRadius = 2;
-void RenderThemeChromiumMac::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeChromiumMac::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
{
style->setBoxShadow(0);
}
@@ -1474,16 +1180,16 @@ bool RenderThemeChromiumMac::paintSliderTrack(RenderObject* o, const RenderObjec
radius, radius);
CGContextDrawShading(context, mainShading.get());
paintInfo.context->restore();
-
+
return false;
}
-void RenderThemeChromiumMac::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeChromiumMac::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
{
style->setBoxShadow(0);
}
-static const float verticalSliderHeightPadding = 0.1f;
+const float verticalSliderHeightPadding = 0.1f;
bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
@@ -1496,6 +1202,7 @@ bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObjec
LocalCurrentGraphicsContext localContext(paintInfo.context);
// Update the various states we respond to.
+ updateActiveState(sliderThumbCell, o->parent());
updateEnabledState(sliderThumbCell, o->parent());
updateFocusedState(sliderThumbCell, o->parent());
@@ -1527,7 +1234,7 @@ bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObjec
paintInfo.context->save();
float zoomLevel = o->style()->effectiveZoom();
-
+
FloatRect unzoomedRect = bounds;
if (zoomLevel != 1.0f) {
unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
@@ -1537,7 +1244,7 @@ bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObjec
paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
}
- [sliderThumbCell drawWithFrame:FloatRectToNSRect(unzoomedRect) inView:nil];
+ [sliderThumbCell drawWithFrame:unzoomedRect inView:FlippedView()];
[sliderThumbCell setControlView:nil];
paintInfo.context->restore();
@@ -1545,23 +1252,6 @@ bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObjec
return false;
}
-const int sliderThumbWidth = 15;
-const int sliderThumbHeight = 15;
-const int mediaSliderThumbWidth = 13;
-const int mediaSliderThumbHeight = 14;
-
-void RenderThemeChromiumMac::adjustSliderThumbSize(RenderObject* o) const
-{
- float zoomLevel = o->style()->effectiveZoom();
- if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) {
- o->style()->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
- o->style()->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
- } else if (o->style()->appearance() == MediaSliderThumbPart) {
- o->style()->setWidth(Length(mediaSliderThumbWidth, Fixed));
- o->style()->setHeight(Length(mediaSliderThumbHeight, Fixed));
- }
-}
-
bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
NSSearchFieldCell* search = this->search();
@@ -1574,7 +1264,7 @@ bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const RenderObjec
float zoomLevel = o->style()->effectiveZoom();
IntRect unzoomedRect = r;
-
+
if (zoomLevel != 1.0f) {
unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
@@ -1586,7 +1276,7 @@ bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const RenderObjec
// Set the search button to nil before drawing. Then reset it so we can draw it later.
[search setSearchButtonCell:nil];
- [search drawWithFrame:NSRect(IntRectToNSRect(unzoomedRect)) inView:nil];
+ [search drawWithFrame:NSRect(unzoomedRect) inView:FlippedView()];
#ifdef BUILDING_ON_TIGER
if ([search showsFirstResponder])
wkDrawTextFieldCellFocusRing(search, NSRect(unzoomedRect));
@@ -1600,13 +1290,14 @@ bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const RenderObjec
return false;
}
-void RenderThemeChromiumMac::setSearchCellState(RenderObject* o, const IntRect& r)
+void RenderThemeChromiumMac::setSearchCellState(RenderObject* o, const IntRect&)
{
NSSearchFieldCell* search = this->search();
[search setControlSize:controlSizeForFont(o->style())];
// Update the various states we respond to.
+ updateActiveState(search, o);
updateEnabledState(search, o);
updateFocusedState(search, o);
}
@@ -1622,12 +1313,12 @@ void RenderThemeChromiumMac::setSearchFieldSize(RenderStyle* style) const
// If the width and height are both specified, then we have nothing to do.
if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
return;
-
+
// Use the font size to determine the intrinsic width of the control.
setSizeFromFont(style, searchFieldSizes());
}
-void RenderThemeChromiumMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeChromiumMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const
{
// Override border.
style->resetBorder();
@@ -1639,19 +1330,19 @@ void RenderThemeChromiumMac::adjustSearchFieldStyle(CSSStyleSelector* selector,
style->setBorderBottomWidth(borderWidth);
style->setBorderBottomStyle(INSET);
style->setBorderTopWidth(borderWidth);
- style->setBorderTopStyle(INSET);
-
+ style->setBorderTopStyle(INSET);
+
// Override height.
style->setHeight(Length(Auto));
setSearchFieldSize(style);
-
+
// Override padding size to match AppKit text positioning.
const int padding = 1 * style->effectiveZoom();
style->setPaddingLeft(Length(padding, Fixed));
style->setPaddingRight(Length(padding, Fixed));
style->setPaddingTop(Length(padding, Fixed));
style->setPaddingBottom(Length(padding, Fixed));
-
+
NSControlSize controlSize = controlSizeForFont(style);
setFontFromControlSize(selector, style, controlSize);
@@ -1660,22 +1351,25 @@ void RenderThemeChromiumMac::adjustSearchFieldStyle(CSSStyleSelector* selector,
bool RenderThemeChromiumMac::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- LocalCurrentGraphicsContext localContext(paintInfo.context);
-
Node* input = o->node()->shadowAncestorNode();
+ if (!input->renderer()->isBox())
+ return false;
+
setSearchCellState(input->renderer(), r);
NSSearchFieldCell* search = this->search();
+ updateActiveState([search cancelButtonCell], o);
updatePressedState([search cancelButtonCell], o);
paintInfo.context->save();
float zoomLevel = o->style()->effectiveZoom();
- NSRect bounds = [search cancelButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))];
-
- IntRect unzoomedRect(NSRectToIntRect(bounds));
+ FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())];
+ localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
+
+ FloatRect unzoomedRect(localBounds);
if (zoomLevel != 1.0f) {
unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
@@ -1684,7 +1378,7 @@ bool RenderThemeChromiumMac::paintSearchFieldCancelButton(RenderObject* o, const
paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
}
- [[search cancelButtonCell] drawWithFrame:IntRectToNSRect(unzoomedRect) inView:nil];
+ [[search cancelButtonCell] drawWithFrame:unzoomedRect inView:FlippedView()];
[[search cancelButtonCell] setControlView:nil];
paintInfo.context->restore();
@@ -1697,7 +1391,7 @@ const IntSize* RenderThemeChromiumMac::cancelButtonSizes() const
return sizes;
}
-void RenderThemeChromiumMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeChromiumMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
{
IntSize size = sizeForSystemFont(style, cancelButtonSizes());
style->setWidth(Length(size.width(), Fixed));
@@ -1711,8 +1405,8 @@ const IntSize* RenderThemeChromiumMac::resultsButtonSizes() const
return sizes;
}
-static const int emptyResultsOffset = 9;
-void RenderThemeChromiumMac::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+const int emptyResultsOffset = 9;
+void RenderThemeChromiumMac::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
{
IntSize size = sizeForSystemFont(style, resultsButtonSizes());
style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
@@ -1720,12 +1414,12 @@ void RenderThemeChromiumMac::adjustSearchFieldDecorationStyle(CSSStyleSelector*
style->setBoxShadow(0);
}
-bool RenderThemeChromiumMac::paintSearchFieldDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeChromiumMac::paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&)
{
return false;
}
-void RenderThemeChromiumMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeChromiumMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
{
IntSize size = sizeForSystemFont(style, resultsButtonSizes());
style->setWidth(Length(size.width(), Fixed));
@@ -1735,24 +1429,29 @@ void RenderThemeChromiumMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSel
bool RenderThemeChromiumMac::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- LocalCurrentGraphicsContext localContext(paintInfo.context);
-
Node* input = o->node()->shadowAncestorNode();
+ if (!input->renderer()->isBox())
+ return false;
+
setSearchCellState(input->renderer(), r);
NSSearchFieldCell* search = this->search();
+ updateActiveState([search searchButtonCell], o);
+
if ([search searchMenuTemplate] != nil)
[search setSearchMenuTemplate:nil];
- NSRect bounds = [search searchButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))];
- [[search searchButtonCell] drawWithFrame:bounds inView:nil];
+ FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())];
+ localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
+
+ [[search searchButtonCell] drawWithFrame:localBounds inView:FlippedView()];
[[search searchButtonCell] setControlView:nil];
return false;
}
-static const int resultsArrowWidth = 5;
-void RenderThemeChromiumMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+const int resultsArrowWidth = 5;
+void RenderThemeChromiumMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
{
IntSize size = sizeForSystemFont(style, resultsButtonSizes());
style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
@@ -1762,13 +1461,16 @@ void RenderThemeChromiumMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelecto
bool RenderThemeChromiumMac::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- LocalCurrentGraphicsContext localContext(paintInfo.context);
-
Node* input = o->node()->shadowAncestorNode();
+ if (!input->renderer()->isBox())
+ return false;
+
setSearchCellState(input->renderer(), r);
NSSearchFieldCell* search = this->search();
+ updateActiveState([search searchButtonCell], o);
+
if (![search searchMenuTemplate])
[search setSearchMenuTemplate:searchMenuTemplate()];
@@ -1776,9 +1478,10 @@ bool RenderThemeChromiumMac::paintSearchFieldResultsButton(RenderObject* o, cons
float zoomLevel = o->style()->effectiveZoom();
- NSRect bounds = [search searchButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))];
-
- IntRect unzoomedRect(NSRectToIntRect(bounds));
+ FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())];
+ localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r);
+
+ IntRect unzoomedRect(localBounds);
if (zoomLevel != 1.0f) {
unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
@@ -1787,188 +1490,78 @@ bool RenderThemeChromiumMac::paintSearchFieldResultsButton(RenderObject* o, cons
paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
}
- [[search searchButtonCell] drawWithFrame:IntRectToNSRect(unzoomedRect) inView:nil];
+ [[search searchButtonCell] drawWithFrame:unzoomedRect inView:FlippedView()];
[[search searchButtonCell] setControlView:nil];
-
+
paintInfo.context->restore();
return false;
}
-#if ENABLE(VIDEO)
-// FIXME: This enum is lifted from RenderThemeMac.mm We need to decide which theme to use for the default controls, or decide to avoid wkDrawMediaUIPart and render our own.
-typedef enum {
- MediaControllerThemeClassic = 1,
- MediaControllerThemeQT = 2
-} MediaControllerThemeStyle;
-
-enum WKMediaControllerThemeState {
- MediaUIPartDisabledFlag = 1 << 0,
- MediaUIPartPressedFlag = 1 << 1,
- MediaUIPartDrawEndCapsFlag = 1 << 3,
-};
-#endif
+const int sliderThumbWidth = 15;
+const int sliderThumbHeight = 15;
-bool RenderThemeChromiumMac::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+void RenderThemeChromiumMac::adjustSliderThumbSize(RenderObject* o) const
{
-#if ENABLE(VIDEO)
- Node* node = o->node();
- if (!node)
- return false;
+ float zoomLevel = o->style()->effectiveZoom();
+ if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) {
+ o->style()->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed));
+ o->style()->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed));
+ }
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawMediaUIPart(MediaFullscreenButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r,
- node->active() ? MediaUIPartPressedFlag : 0);
+#if ENABLE(VIDEO)
+ RenderMediaControlsChromium::adjustMediaSliderThumbSize(o);
#endif
- return false;
}
-bool RenderThemeChromiumMac::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
-{
#if ENABLE(VIDEO)
- Node* node = o->node();
- Node* mediaNode = node ? node->shadowAncestorNode() : 0;
- if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
- return false;
-
- HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
- if (!mediaElement)
- return false;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawMediaUIPart(mediaElement->muted() ? MediaUnMuteButton : MediaMuteButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r,
- node->active() ? MediaUIPartPressedFlag : 0);
-#endif
- return false;
+bool RenderThemeChromiumMac::shouldRenderMediaControlPart(ControlPart part, Element* e)
+{
+ return RenderMediaControlsChromium::shouldRenderMediaControlPart(part, e);
}
-bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
-#if ENABLE(VIDEO)
- Node* node = o->node();
- Node* mediaNode = node ? node->shadowAncestorNode() : 0;
- if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
- return false;
-
- HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
- if (!mediaElement)
- return false;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawMediaUIPart(mediaElement->canPlay() ? MediaPlayButton : MediaPauseButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r,
- node->active() ? MediaUIPartPressedFlag : 0);
-#endif
- return false;
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect);
}
-bool RenderThemeChromiumMac::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeChromiumMac::paintMediaMuteButton(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
-#if ENABLE(VIDEO)
- Node* node = o->node();
- if (!node)
- return false;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawMediaUIPart(MediaSeekBackButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r,
- node->active() ? MediaUIPartPressedFlag : 0);
-#endif
- return false;
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect);
}
-bool RenderThemeChromiumMac::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeChromiumMac::paintMediaSliderTrack(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
-#if ENABLE(VIDEO)
- Node* node = o->node();
- if (!node)
- return false;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawMediaUIPart(MediaSeekForwardButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r,
- node->active() ? MediaUIPartPressedFlag : 0);
-#endif
- return false;
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaSlider, object, paintInfo, rect);
}
-bool RenderThemeChromiumMac::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeChromiumMac::paintMediaVolumeSliderTrack(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
-#if ENABLE(VIDEO)
- Node* node = o->node();
- Node* mediaNode = node ? node->shadowAncestorNode() : 0;
- if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
- return false;
-
- HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
- if (!mediaElement)
- return false;
-
- float timeLoaded = 0;
- float currentTime = 0;
- float duration = 0;
- if (MediaPlayer* player = mediaElement->player()) {
- duration = player->duration();
- timeLoaded = player->maxTimeBuffered();
- currentTime = player->currentTime();
- }
-
- bool shouldDrawEndCaps = !toRenderMedia(mediaElement->renderer())->shouldShowTimeDisplayControls();
- wkDrawMediaSliderTrack(MediaControllerThemeClassic, paintInfo.context->platformContext(), r, timeLoaded, currentTime, duration, shouldDrawEndCaps ? MediaUIPartDrawEndCapsFlag : 0);
-#endif
- return false;
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect);
}
-bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
-#if ENABLE(VIDEO)
- Node* node = o->node();
- if (!node)
- return false;
-
- LocalCurrentGraphicsContext localContext(paintInfo.context);
- wkDrawMediaUIPart(MediaSliderThumb, MediaControllerThemeClassic, paintInfo.context->platformContext(), r,
- node->active() ? MediaUIPartPressedFlag : 0);
-#endif
- return false;
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect);
}
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-NSButtonCell* RenderThemeChromiumMac::checkbox() const
+bool RenderThemeChromiumMac::paintMediaVolumeSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
- if (!m_checkbox) {
- m_checkbox.adoptNS([[NSButtonCell alloc] init]);
- [m_checkbox.get() setButtonType:NSSwitchButton];
- [m_checkbox.get() setTitle:nil];
- [m_checkbox.get() setAllowsMixedState:YES];
- [m_checkbox.get() setFocusRingType:NSFocusRingTypeExterior];
- }
-
- return m_checkbox.get();
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect);
}
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-NSButtonCell* RenderThemeChromiumMac::radio() const
+bool RenderThemeChromiumMac::paintMediaControlsBackground(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
- if (!m_radio) {
- m_radio.adoptNS([[NSButtonCell alloc] init]);
- [m_radio.get() setButtonType:NSRadioButton];
- [m_radio.get() setTitle:nil];
- [m_radio.get() setFocusRingType:NSFocusRingTypeExterior];
- }
-
- return m_radio.get();
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaTimelineContainer, object, paintInfo, rect);
}
-// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731.
-NSButtonCell* RenderThemeChromiumMac::button() const
+String RenderThemeChromiumMac::extraMediaControlsStyleSheet()
{
- if (!m_button) {
- m_button.adoptNS([[NSButtonCell alloc] init]);
- [m_button.get() setTitle:nil];
- [m_button.get() setButtonType:NSMomentaryPushInButton];
- }
-
- return m_button.get();
+ return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet));
}
+#endif
+
NSPopUpButtonCell* RenderThemeChromiumMac::popupButton() const
{
if (!m_popupButton) {
@@ -1976,7 +1569,7 @@ NSPopUpButtonCell* RenderThemeChromiumMac::popupButton() const
[m_popupButton.get() setUsesItemFromMenu:NO];
[m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior];
}
-
+
return m_popupButton.get();
}
@@ -2010,7 +1603,7 @@ NSSliderCell* RenderThemeChromiumMac::sliderThumbHorizontal() const
[m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize];
[m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior];
}
-
+
return m_sliderThumbHorizontal.get();
}
@@ -2023,7 +1616,7 @@ NSSliderCell* RenderThemeChromiumMac::sliderThumbVertical() const
[m_sliderThumbVertical.get() setControlSize:NSSmallControlSize];
[m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior];
}
-
+
return m_sliderThumbVertical.get();
}
diff --git a/WebCore/rendering/RenderThemeChromiumSkia.cpp b/WebCore/rendering/RenderThemeChromiumSkia.cpp
index 79804ac..7d3bcec 100644
--- a/WebCore/rendering/RenderThemeChromiumSkia.cpp
+++ b/WebCore/rendering/RenderThemeChromiumSkia.cpp
@@ -33,8 +33,11 @@
#include "MediaControlElements.h"
#include "PlatformContextSkia.h"
#include "RenderBox.h"
+#include "RenderMediaControlsChromium.h"
#include "RenderObject.h"
+#include "RenderSlider.h"
#include "ScrollbarTheme.h"
+#include "TimeRanges.h"
#include "TransformationMatrix.h"
#include "UserAgentStyleSheets.h"
@@ -70,19 +73,29 @@ static void setSizeIfAuto(RenderStyle* style, const IntSize& size)
style->setHeight(Length(size.height(), Fixed));
}
-#if ENABLE(VIDEO)
-// Attempt to retrieve a HTMLMediaElement from a Node. Returns NULL if one cannot be found.
-static HTMLMediaElement* mediaElementParent(Node* node)
+static void drawVertLine(SkCanvas* canvas, int x, int y1, int y2, const SkPaint& paint)
{
- if (!node)
- return 0;
- Node* mediaNode = node->shadowAncestorNode();
- if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag)))
- return 0;
+ SkIRect skrect;
+ skrect.set(x, y1, x + 1, y2 + 1);
+ canvas->drawIRect(skrect, paint);
+}
- return static_cast<HTMLMediaElement*>(mediaNode);
+static void drawHorizLine(SkCanvas* canvas, int x1, int x2, int y, const SkPaint& paint)
+{
+ SkIRect skrect;
+ skrect.set(x1, y, x2 + 1, y + 1);
+ canvas->drawIRect(skrect, paint);
+}
+
+static void drawBox(SkCanvas* canvas, const IntRect& rect, const SkPaint& paint)
+{
+ const int right = rect.x() + rect.width() - 1;
+ const int bottom = rect.y() + rect.height() - 1;
+ drawHorizLine(canvas, rect.x(), right, rect.y(), paint);
+ drawVertLine(canvas, right, rect.y(), bottom, paint);
+ drawHorizLine(canvas, rect.x(), right, bottom, paint);
+ drawVertLine(canvas, rect.x(), rect.y(), bottom, paint);
}
-#endif
// We aim to match IE here.
// -IE uses a font based on the encoding as the default font for form controls.
@@ -204,6 +217,22 @@ int RenderThemeChromiumSkia::minimumMenuListSize(RenderStyle* style) const
return 0;
}
+// These are the default dimensions of radio buttons and checkboxes.
+static const int widgetStandardWidth = 13;
+static const int widgetStandardHeight = 13;
+
+// Return a rectangle that has the same center point as |original|, but with a
+// size capped at |width| by |height|.
+IntRect center(const IntRect& original, int width, int height)
+{
+ width = std::min(original.width(), width);
+ height = std::min(original.height(), height);
+ int x = original.x() + (original.width() - width) / 2;
+ int y = original.y() + (original.height() - height) / 2;
+
+ return IntRect(x, y, width, height);
+}
+
bool RenderThemeChromiumSkia::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
static Image* const checkedImage = Image::loadPlatformResource("linuxCheckboxOn").releaseRef();
@@ -218,7 +247,7 @@ bool RenderThemeChromiumSkia::paintCheckbox(RenderObject* o, const RenderObject:
else
image = this->isChecked(o) ? disabledCheckedImage : disabledUncheckedImage;
- i.context->drawImage(image, rect);
+ i.context->drawImage(image, o->style()->colorSpace(), center(rect, widgetStandardHeight, widgetStandardWidth));
return false;
}
@@ -233,7 +262,7 @@ void RenderThemeChromiumSkia::setCheckboxSize(RenderStyle* style) const
// querying the theme gives you a larger size that accounts for the higher
// DPI. Until our entire engine honors a DPI setting other than 96, we
// can't rely on the theme's metrics.
- const IntSize size(13, 13);
+ const IntSize size(widgetStandardHeight, widgetStandardWidth);
setSizeIfAuto(style, size);
}
@@ -250,7 +279,7 @@ bool RenderThemeChromiumSkia::paintRadio(RenderObject* o, const RenderObject::Pa
else
image = this->isChecked(o) ? disabledCheckedImage : disabledUncheckedImage;
- i.context->drawImage(image, rect);
+ i.context->drawImage(image, o->style()->colorSpace(), center(rect, widgetStandardHeight, widgetStandardWidth));
return false;
}
@@ -302,7 +331,7 @@ static void paintButtonLike(RenderTheme* theme, RenderObject* o, const RenderObj
canvas->drawLine(rect.x() + 1, bottom - 1, right - 1, bottom - 1, paint);
canvas->drawLine(rect.x(), rect.y() + 1, rect.x(), bottom - 1, paint);
- paint.setARGB(0xff, 0, 0, 0);
+ paint.setColor(SK_ColorBLACK);
SkPoint p[2];
const int lightEnd = theme->isPressed(o) ? 1 : 0;
const int darkEnd = !lightEnd;
@@ -335,6 +364,15 @@ bool RenderThemeChromiumSkia::paintButton(RenderObject* o, const RenderObject::P
return false;
}
+void RenderThemeChromiumSkia::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
+{
+ if (style->appearance() == PushButtonPart) {
+ // Ignore line-height.
+ style->setLineHeight(RenderStyle::initialLineHeight());
+ }
+}
+
+
bool RenderThemeChromiumSkia::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
return true;
@@ -345,6 +383,12 @@ bool RenderThemeChromiumSkia::paintTextArea(RenderObject* o, const RenderObject:
return paintTextField(o, i, r);
}
+void RenderThemeChromiumSkia::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
+{
+ // Ignore line-height.
+ style->setLineHeight(RenderStyle::initialLineHeight());
+}
+
bool RenderThemeChromiumSkia::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
{
return paintTextField(o, i, r);
@@ -380,7 +424,7 @@ bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* o, cons
static Image* cancelImage = Image::loadPlatformResource("searchCancel").releaseRef();
static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").releaseRef();
- i.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds);
+ i.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, o->style()->colorSpace(), bounds);
return false;
}
@@ -420,7 +464,7 @@ bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* o,
bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef();
- i.context->drawImage(magnifierImage, bounds);
+ i.context->drawImage(magnifierImage, o->style()->colorSpace(), bounds);
return false;
}
@@ -456,46 +500,14 @@ bool RenderThemeChromiumSkia::paintSearchFieldResultsButton(RenderObject* o, con
bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").releaseRef();
- i.context->drawImage(magnifierImage, bounds);
+ i.context->drawImage(magnifierImage, o->style()->colorSpace(), bounds);
return false;
}
-bool RenderThemeChromiumSkia::paintMediaButtonInternal(GraphicsContext* context, const IntRect& rect, Image* image)
-{
- // Create a destination rectangle for the image that is centered in the drawing rectangle, rounded left, and down.
- IntRect imageRect = image->rect();
- imageRect.setY(rect.y() + (rect.height() - image->height() + 1) / 2);
- imageRect.setX(rect.x() + (rect.width() - image->width() + 1) / 2);
-
- context->drawImage(image, imageRect);
- return true;
-}
-
bool RenderThemeChromiumSkia::paintMediaControlsBackground(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
#if ENABLE(VIDEO)
- HTMLMediaElement* mediaElement = mediaElementParent(object->node());
- if (!mediaElement)
- return false;
-
- if (!rect.isEmpty())
- {
- SkCanvas* canvas = paintInfo.context->platformContext()->canvas();
- SkPaint paint;
-
- // Draws the left border, it is always 1px wide.
- paint.setColor(object->style()->borderLeftColor().rgb());
- canvas->drawLine(rect.x() + 1, rect.y(),
- rect.x() + 1, rect.y() + rect.height(),
- paint);
-
- // Draws the right border, it is always 1px wide.
- paint.setColor(object->style()->borderRightColor().rgb());
- canvas->drawLine(rect.x() + rect.width() - 1, rect.y(),
- rect.x() + rect.width() - 1, rect.y() + rect.height(),
- paint);
- }
- return true;
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaTimelineContainer, object, paintInfo, rect);
#else
UNUSED_PARAM(object);
UNUSED_PARAM(paintInfo);
@@ -507,62 +519,7 @@ bool RenderThemeChromiumSkia::paintMediaControlsBackground(RenderObject* object,
bool RenderThemeChromiumSkia::paintMediaSliderTrack(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
#if ENABLE(VIDEO)
- HTMLMediaElement* mediaElement = mediaElementParent(object->node());
- if (!mediaElement)
- return false;
-
- SkCanvas* canvas = paintInfo.context->platformContext()->canvas();
- SkRect backgroundRect;
- backgroundRect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
-
- SkPaint paint;
- paint.setAntiAlias(true);
-
- // Draw the border of the time bar. The border only has one single color,
- // width and radius. So use the property of the left border.
- SkColor borderColor = object->style()->borderLeftColor().rgb();
- int borderWidth = object->style()->borderLeftWidth();
- IntSize borderRadius = object->style()->borderTopLeftRadius();
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(borderWidth);
- paint.setColor(borderColor);
- canvas->drawRoundRect(backgroundRect, borderRadius.width(), borderRadius.height(), paint);
-
- // Draw the background of the time bar.
- SkColor backgroundColor = object->style()->backgroundColor().rgb();
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(backgroundColor);
- canvas->drawRoundRect(backgroundRect, borderRadius.width(), borderRadius.height(), paint);
-
- if (backgroundRect.width() >= 3 && backgroundRect.height() >= 3)
- {
- // Draw the buffered ranges.
- // FIXME: Draw multiple ranges if there are multiple buffered ranges.
- SkRect bufferedRect;
- bufferedRect.set(backgroundRect.fLeft + 2, backgroundRect.fTop + 2,
- backgroundRect.fRight - 1, backgroundRect.fBottom - 1);
- int width = static_cast<int>(bufferedRect.width() * mediaElement->percentLoaded());
- bufferedRect.fRight = bufferedRect.fLeft + width;
-
- SkPoint points[2] = { { 0, bufferedRect.fTop }, { 0, bufferedRect.fBottom } };
- SkColor startColor = object->style()->color().rgb();
- SkColor endColor = SkColorSetRGB(SkColorGetR(startColor) / 2,
- SkColorGetG(startColor) / 2,
- SkColorGetB(startColor) / 2);
- SkColor colors[2] = { startColor, endColor };
- SkShader* gradient = SkGradientShader::CreateLinear(points, colors, 0,
- sizeof(points) / sizeof(points[0]),
- SkShader::kMirror_TileMode, 0);
-
- paint.reset();
- paint.setShader(gradient);
- paint.setAntiAlias(true);
- // Check for round rect with zero width or height, otherwise Skia will assert
- if (bufferedRect.width() > 0 && bufferedRect.height() > 0)
- canvas->drawRoundRect(bufferedRect, borderRadius.width(), borderRadius.height(), paint);
- gradient->unref();
- }
- return true;
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaSlider, object, paintInfo, rect);
#else
UNUSED_PARAM(object);
UNUSED_PARAM(paintInfo);
@@ -571,14 +528,22 @@ bool RenderThemeChromiumSkia::paintMediaSliderTrack(RenderObject* object, const
#endif
}
-void RenderThemeChromiumSkia::adjustSliderThumbSize(RenderObject* object) const {
+bool RenderThemeChromiumSkia::paintMediaVolumeSliderTrack(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
+{
#if ENABLE(VIDEO)
- if (object->style()->appearance() == MediaSliderThumbPart) {
- static Image* mediaSliderThumb = Image::loadPlatformResource("mediaSliderThumb").releaseRef();
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect);
+#else
+ UNUSED_PARAM(object);
+ UNUSED_PARAM(paintInfo);
+ UNUSED_PARAM(rect);
+ return false;
+#endif
+}
- object->style()->setWidth(Length(mediaSliderThumb->width(), Fixed));
- object->style()->setHeight(Length(mediaSliderThumb->height(), Fixed));
- }
+void RenderThemeChromiumSkia::adjustSliderThumbSize(RenderObject* object) const
+{
+#if ENABLE(VIDEO)
+ RenderMediaControlsChromium::adjustMediaSliderThumbSize(object);
#else
UNUSED_PARAM(object);
#endif
@@ -587,12 +552,19 @@ void RenderThemeChromiumSkia::adjustSliderThumbSize(RenderObject* object) const
bool RenderThemeChromiumSkia::paintMediaSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
#if ENABLE(VIDEO)
- if (!object->parent()->isSlider())
- return false;
-
- static Image* mediaSliderThumb = Image::loadPlatformResource("mediaSliderThumb").releaseRef();
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect);
+#else
+ UNUSED_PARAM(object);
+ UNUSED_PARAM(paintInfo);
+ UNUSED_PARAM(rect);
+ return false;
+#endif
+}
- return paintMediaButtonInternal(paintInfo.context, rect, mediaSliderThumb);
+bool RenderThemeChromiumSkia::paintMediaVolumeSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
+{
+#if ENABLE(VIDEO)
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect);
#else
UNUSED_PARAM(object);
UNUSED_PARAM(paintInfo);
@@ -604,14 +576,7 @@ bool RenderThemeChromiumSkia::paintMediaSliderThumb(RenderObject* object, const
bool RenderThemeChromiumSkia::paintMediaPlayButton(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
#if ENABLE(VIDEO)
- HTMLMediaElement* mediaElement = mediaElementParent(object->node());
- if (!mediaElement)
- return false;
-
- static Image* mediaPlay = Image::loadPlatformResource("mediaPlay").releaseRef();
- static Image* mediaPause = Image::loadPlatformResource("mediaPause").releaseRef();
-
- return paintMediaButtonInternal(paintInfo.context, rect, mediaElement->paused() ? mediaPlay : mediaPause);
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect);
#else
UNUSED_PARAM(object);
UNUSED_PARAM(paintInfo);
@@ -623,14 +588,7 @@ bool RenderThemeChromiumSkia::paintMediaPlayButton(RenderObject* object, const R
bool RenderThemeChromiumSkia::paintMediaMuteButton(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
{
#if ENABLE(VIDEO)
- HTMLMediaElement* mediaElement = mediaElementParent(object->node());
- if (!mediaElement)
- return false;
-
- static Image* soundFull = Image::loadPlatformResource("mediaSoundFull").releaseRef();
- static Image* soundNone = Image::loadPlatformResource("mediaSoundNone").releaseRef();
-
- return paintMediaButtonInternal(paintInfo.context, rect, mediaElement->muted() ? soundNone: soundFull);
+ return RenderMediaControlsChromium::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect);
#else
UNUSED_PARAM(object);
UNUSED_PARAM(paintInfo);
@@ -654,12 +612,13 @@ bool RenderThemeChromiumSkia::paintMenuList(RenderObject* o, const RenderObject:
paintButtonLike(this, o, i, rect);
SkPaint paint;
- paint.setARGB(0xff, 0, 0, 0);
+ paint.setColor(SK_ColorBLACK);
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kFill_Style);
+ int arrowXPosition = (o->style()->direction() == RTL) ? rect.x() + 7 : right - 13;
SkPath path;
- path.moveTo(right - 13, middle - 3);
+ path.moveTo(arrowXPosition, middle - 3);
path.rLineTo(6, 0);
path.rLineTo(-3, 6);
path.close();
@@ -679,6 +638,69 @@ bool RenderThemeChromiumSkia::paintMenuListButton(RenderObject* o, const RenderO
return paintMenuList(o, i, rect);
}
+bool RenderThemeChromiumSkia::paintSliderTrack(RenderObject*, const RenderObject::PaintInfo& i, const IntRect& rect)
+{
+ // Just paint a grey box for now (matches the color of a scrollbar background.
+ SkCanvas* const canvas = i.context->platformContext()->canvas();
+ int verticalCenter = rect.y() + rect.height() / 2;
+ int top = std::max(rect.y(), verticalCenter - 2);
+ int bottom = std::min(rect.y() + rect.height(), verticalCenter + 2);
+
+ SkPaint paint;
+ const SkColor grey = SkColorSetARGB(0xff, 0xe3, 0xdd, 0xd8);
+ paint.setColor(grey);
+
+ SkRect skrect;
+ skrect.set(rect.x(), top, rect.x() + rect.width(), bottom);
+ canvas->drawRect(skrect, paint);
+
+ return false;
+}
+
+bool RenderThemeChromiumSkia::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
+{
+ // Make a thumb similar to the scrollbar thumb.
+ const bool hovered = isHovered(o) || toRenderSlider(o->parent())->inDragMode();
+ const int midx = rect.x() + rect.width() / 2;
+ const int midy = rect.y() + rect.height() / 2;
+ const bool vertical = (o->style()->appearance() == SliderThumbVerticalPart);
+ SkCanvas* const canvas = i.context->platformContext()->canvas();
+
+ const SkColor thumbLightGrey = SkColorSetARGB(0xff, 0xf4, 0xf2, 0xef);
+ const SkColor thumbDarkGrey = SkColorSetARGB(0xff, 0xea, 0xe5, 0xe0);
+ SkPaint paint;
+ paint.setColor(hovered ? SK_ColorWHITE : thumbLightGrey);
+
+ SkIRect skrect;
+ if (vertical)
+ skrect.set(rect.x(), rect.y(), midx + 1, rect.bottom());
+ else
+ skrect.set(rect.x(), rect.y(), rect.right(), midy + 1);
+
+ canvas->drawIRect(skrect, paint);
+
+ paint.setColor(hovered ? thumbLightGrey : thumbDarkGrey);
+
+ if (vertical)
+ skrect.set(midx + 1, rect.y(), rect.right(), rect.bottom());
+ else
+ skrect.set(rect.x(), midy + 1, rect.right(), rect.bottom());
+
+ canvas->drawIRect(skrect, paint);
+
+ const SkColor borderDarkGrey = SkColorSetARGB(0xff, 0x9d, 0x96, 0x8e);
+ paint.setColor(borderDarkGrey);
+ drawBox(canvas, rect, paint);
+
+ if (rect.height() > 10 && rect.width() > 10) {
+ drawHorizLine(canvas, midx - 2, midx + 2, midy, paint);
+ drawHorizLine(canvas, midx - 2, midx + 2, midy - 3, paint);
+ drawHorizLine(canvas, midx - 2, midx + 2, midy + 3, paint);
+ }
+
+ return false;
+}
+
int RenderThemeChromiumSkia::popupInternalPaddingLeft(RenderStyle* style) const
{
return menuListInternalPadding(style, LeftPadding);
@@ -719,6 +741,13 @@ int RenderThemeChromiumSkia::buttonInternalPaddingBottom() const
return 1;
}
+#if ENABLE(VIDEO)
+bool RenderThemeChromiumSkia::shouldRenderMediaControlPart(ControlPart part, Element* e)
+{
+ return RenderMediaControlsChromium::shouldRenderMediaControlPart(part, e);
+}
+#endif
+
// static
void RenderThemeChromiumSkia::setDefaultFontSize(int fontSize)
{
diff --git a/WebCore/rendering/RenderThemeChromiumSkia.h b/WebCore/rendering/RenderThemeChromiumSkia.h
index 7544c22..18fa859 100644
--- a/WebCore/rendering/RenderThemeChromiumSkia.h
+++ b/WebCore/rendering/RenderThemeChromiumSkia.h
@@ -71,11 +71,13 @@ namespace WebCore {
virtual void setRadioSize(RenderStyle*) const;
virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
@@ -91,8 +93,10 @@ namespace WebCore {
virtual bool paintMediaControlsBackground(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintMediaVolumeSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual void adjustSliderThumbSize(RenderObject*) const;
virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintMediaVolumeSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaMuteButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
@@ -110,6 +114,9 @@ namespace WebCore {
virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
// These methods define the padding for the MenuList's inner block.
virtual int popupInternalPaddingLeft(RenderStyle*) const;
virtual int popupInternalPaddingRight(RenderStyle*) const;
@@ -121,6 +128,11 @@ namespace WebCore {
virtual int buttonInternalPaddingTop() const;
virtual int buttonInternalPaddingBottom() const;
+#if ENABLE(VIDEO)
+ // Media controls
+ virtual bool shouldRenderMediaControlPart(ControlPart, Element*);
+#endif
+
// Provide a way to pass the default font size from the Settings object
// to the render theme. FIXME: http://b/1129186 A cleaner way would be
// to remove the default font size from this object and have callers
diff --git a/WebCore/rendering/RenderThemeChromiumWin.cpp b/WebCore/rendering/RenderThemeChromiumWin.cpp
index 35d1580..db31825 100644
--- a/WebCore/rendering/RenderThemeChromiumWin.cpp
+++ b/WebCore/rendering/RenderThemeChromiumWin.cpp
@@ -86,7 +86,7 @@ private:
return transformMode == KeepTransform ? NoLayer : OpaqueCompositeLayer;
}
- static TransformMode getTransformMode(const TransformationMatrix& matrix)
+ static TransformMode getTransformMode(const AffineTransform& matrix)
{
if (matrix.b() != 0 || matrix.c() != 0) // Skew.
return Untransform;
@@ -311,6 +311,52 @@ void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescrip
fontDescription = *cachedDesc;
}
+// Map a CSSValue* system color to an index understood by GetSysColor().
+static int cssValueIdToSysColorIndex(int cssValueId)
+{
+ switch (cssValueId) {
+ case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
+ case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
+ case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
+ case CSSValueBackground: return COLOR_BACKGROUND;
+ case CSSValueButtonface: return COLOR_BTNFACE;
+ case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
+ case CSSValueButtonshadow: return COLOR_BTNSHADOW;
+ case CSSValueButtontext: return COLOR_BTNTEXT;
+ case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
+ case CSSValueGraytext: return COLOR_GRAYTEXT;
+ case CSSValueHighlight: return COLOR_HIGHLIGHT;
+ case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
+ case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
+ case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
+ case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
+ case CSSValueInfobackground: return COLOR_INFOBK;
+ case CSSValueInfotext: return COLOR_INFOTEXT;
+ case CSSValueMenu: return COLOR_MENU;
+ case CSSValueMenutext: return COLOR_MENUTEXT;
+ case CSSValueScrollbar: return COLOR_SCROLLBAR;
+ case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
+ case CSSValueThreedface: return COLOR_3DFACE;
+ case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
+ case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
+ case CSSValueThreedshadow: return COLOR_3DSHADOW;
+ case CSSValueWindow: return COLOR_WINDOW;
+ case CSSValueWindowframe: return COLOR_WINDOWFRAME;
+ case CSSValueWindowtext: return COLOR_WINDOWTEXT;
+ default: return -1; // Unsupported CSSValue
+ }
+}
+
+Color RenderThemeChromiumWin::systemColor(int cssValueId) const
+{
+ int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
+ if (ChromiumBridge::layoutTestMode() || (sysColorIndex == -1))
+ return RenderTheme::systemColor(cssValueId);
+
+ COLORREF color = GetSysColor(sysColorIndex);
+ return Color(GetRValue(color), GetGValue(color), GetBValue(color));
+}
+
void RenderThemeChromiumWin::adjustSliderThumbSize(RenderObject* o) const
{
// These sizes match what WinXP draws for various menus.
@@ -475,14 +521,36 @@ unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o)
unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o)
{
unsigned result = 0;
- if (!isEnabled(o))
- result = DFCS_INACTIVE;
- else if (isPressed(o)) // Active supersedes hover
- result = DFCS_PUSHED;
- else if (isHovered(o))
- result = DFCS_HOT;
- if (isChecked(o))
- result |= DFCS_CHECKED;
+
+ ControlPart part = o->style()->appearance();
+
+ // Sliders are always in the normal state.
+ if (part == SliderHorizontalPart || part == SliderVerticalPart)
+ return result;
+
+ // So are readonly text fields.
+ if (isReadOnlyControl(o) && (part == TextFieldPart || part == TextAreaPart || part == SearchFieldPart))
+ return result;
+
+ if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) {
+ if (!isEnabled(o->parent()))
+ result = DFCS_INACTIVE;
+ else if (toRenderSlider(o->parent())->inDragMode()) // Active supersedes hover
+ result = DFCS_PUSHED;
+ else if (isHovered(o))
+ result = DFCS_HOT;
+ } else {
+ if (!isEnabled(o))
+ result = DFCS_INACTIVE;
+ else if (isPressed(o)) // Active supersedes hover
+ result = DFCS_PUSHED;
+ else if (supportsFocus(part) && isFocused(o)) // So does focused
+ result = 0;
+ else if (isHovered(o))
+ result = DFCS_HOT;
+ if (isChecked(o))
+ result |= DFCS_CHECKED;
+ }
return result;
}
@@ -524,6 +592,7 @@ ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o)
break;
case ListboxPart:
case MenulistPart:
+ case MenulistButtonPart:
case SearchFieldPart:
case TextFieldPart:
case TextAreaPart:
@@ -542,21 +611,11 @@ bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o,
const IntRect& r,
bool drawEdges)
{
- // Nasty hack to make us not paint the border on text fields with a
- // border-radius. Webkit paints elements with border-radius for us.
- // FIXME: Get rid of this if-check once we can properly clip rounded
- // borders: http://b/1112604 and http://b/1108635
- // FIXME: make sure we do the right thing if css background-clip is set.
- if (o->style()->hasBorderRadius())
- return false;
-
- const ThemeData& themeData = getThemeData(o);
-
// Fallback to white if the specified color object is invalid.
+ // (Note ChromiumBridge::paintTextField duplicates this check).
Color backgroundColor(Color::white);
- if (o->style()->backgroundColor().isValid()) {
+ if (o->style()->backgroundColor().isValid())
backgroundColor = o->style()->backgroundColor();
- }
// If we have background-image, don't fill the content area to expose the
// parent's background. Also, we shouldn't fill the content area if the
@@ -565,17 +624,32 @@ bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o,
// Note that we should paint the content area white if we have neither the
// background color nor background image explicitly specified to keep the
// appearance of select element consistent with other browsers.
- bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha() != 0;
-
- WebCore::ThemePainter painter(i.context, r);
- ChromiumBridge::paintTextField(painter.context(),
- themeData.m_part,
- themeData.m_state,
- themeData.m_classicState,
- painter.drawRect(),
- backgroundColor,
- fillContentArea,
- drawEdges);
+ bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha();
+
+ if (o->style()->hasBorderRadius()) {
+ // If the style has rounded borders, setup the context to clip the
+ // background (themed or filled) appropriately.
+ // FIXME: make sure we do the right thing if css background-clip is set.
+ i.context->save();
+ IntSize topLeft, topRight, bottomLeft, bottomRight;
+ o->style()->getBorderRadiiForRect(r, topLeft, topRight, bottomLeft, bottomRight);
+ i.context->addRoundedRectClip(r, topLeft, topRight, bottomLeft, bottomRight);
+ }
+ {
+ const ThemeData& themeData = getThemeData(o);
+ WebCore::ThemePainter painter(i.context, r);
+ ChromiumBridge::paintTextField(painter.context(),
+ themeData.m_part,
+ themeData.m_state,
+ themeData.m_classicState,
+ painter.drawRect(),
+ backgroundColor,
+ fillContentArea,
+ drawEdges);
+ // End of block commits the painter before restoring context.
+ }
+ if (o->style()->hasBorderRadius())
+ i.context->restore();
return false;
}
diff --git a/WebCore/rendering/RenderThemeChromiumWin.h b/WebCore/rendering/RenderThemeChromiumWin.h
index 5e98c9b..3b86980 100644
--- a/WebCore/rendering/RenderThemeChromiumWin.h
+++ b/WebCore/rendering/RenderThemeChromiumWin.h
@@ -59,6 +59,7 @@ namespace WebCore {
// System fonts.
virtual void systemFont(int propId, FontDescription&) const;
+ virtual Color systemColor(int cssValueId) const;
virtual void adjustSliderThumbSize(RenderObject*) const;
diff --git a/WebCore/rendering/RenderThemeMac.h b/WebCore/rendering/RenderThemeMac.h
index 85f141f..48c6c42 100644
--- a/WebCore/rendering/RenderThemeMac.h
+++ b/WebCore/rendering/RenderThemeMac.h
@@ -126,12 +126,15 @@ protected:
virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaRewindButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaReturnToRealtimeButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaControlsBackground(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaCurrentTime(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaTimeRemaining(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
// Media controls
virtual String extraMediaControlsStyleSheet();
+
+ virtual bool shouldRenderMediaControlPart(ControlPart, Element*);
#endif
private:
diff --git a/WebCore/rendering/RenderThemeMac.mm b/WebCore/rendering/RenderThemeMac.mm
index 6315f9f..ddb538b 100644
--- a/WebCore/rendering/RenderThemeMac.mm
+++ b/WebCore/rendering/RenderThemeMac.mm
@@ -38,6 +38,7 @@
#import "RenderSlider.h"
#import "RenderView.h"
#import "SharedBuffer.h"
+#import "TimeRanges.h"
#import "WebCoreSystemInterface.h"
#import "UserAgentStyleSheets.h"
#import <Carbon/Carbon.h>
@@ -472,6 +473,7 @@ void RenderThemeMac::adjustRepaintRect(const RenderObject* o, IntRect& r)
case RadioPart:
case PushButtonPart:
case SquareButtonPart:
+ case ListButtonPart:
case DefaultButtonPart:
case ButtonPart:
return RenderTheme::adjustRepaintRect(o, r);
@@ -824,11 +826,21 @@ static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outD
void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
+ if (r.isEmpty())
+ return;
+
CGContextRef context = paintInfo.context->platformContext();
paintInfo.context->save();
- int radius = o->style()->borderTopLeftRadius().width();
+ IntSize topLeftRadius;
+ IntSize topRightRadius;
+ IntSize bottomLeftRadius;
+ IntSize bottomRightRadius;
+
+ o->style()->getBorderRadiiForRect(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+
+ int radius = topLeftRadius.width();
RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
@@ -851,33 +863,27 @@ void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const RenderO
RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.right(), r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false));
paintInfo.context->save();
CGContextClipToRect(context, r);
- paintInfo.context->addRoundedRectClip(r,
- o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
- o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
+ paintInfo.context->addRoundedRectClip(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
CGContextDrawShading(context, mainShading.get());
paintInfo.context->restore();
paintInfo.context->save();
CGContextClipToRect(context, topGradient);
- paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient),
- o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
- IntSize(), IntSize());
+ paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient), topLeftRadius, topRightRadius, IntSize(), IntSize());
CGContextDrawShading(context, topShading.get());
paintInfo.context->restore();
- paintInfo.context->save();
- CGContextClipToRect(context, bottomGradient);
- paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient),
- IntSize(), IntSize(),
- o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
- CGContextDrawShading(context, bottomShading.get());
- paintInfo.context->restore();
+ if (!bottomGradient.isEmpty()) {
+ paintInfo.context->save();
+ CGContextClipToRect(context, bottomGradient);
+ paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient), IntSize(), IntSize(), bottomLeftRadius, bottomRightRadius);
+ CGContextDrawShading(context, bottomShading.get());
+ paintInfo.context->restore();
+ }
paintInfo.context->save();
CGContextClipToRect(context, r);
- paintInfo.context->addRoundedRectClip(r,
- o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
- o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
+ paintInfo.context->addRoundedRectClip(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
CGContextDrawShading(context, leftShading.get());
CGContextDrawShading(context, rightShading.get());
paintInfo.context->restore();
@@ -887,8 +893,6 @@ void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const RenderO
bool RenderThemeMac::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- paintInfo.context->save();
-
IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
r.y() + o->style()->borderTopWidth(),
r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
@@ -907,7 +911,9 @@ bool RenderThemeMac::paintMenuListButton(RenderObject* o, const RenderObject::Pa
if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom())
return false;
- paintInfo.context->setFillColor(o->style()->color());
+ paintInfo.context->save();
+
+ paintInfo.context->setFillColor(o->style()->color(), o->style()->colorSpace());
paintInfo.context->setStrokeStyle(NoStroke);
FloatPoint arrow1[3];
@@ -936,11 +942,11 @@ bool RenderThemeMac::paintMenuListButton(RenderObject* o, const RenderObject::Pa
// Draw the separator to the left of the arrows
paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin.
paintInfo.context->setStrokeStyle(SolidStroke);
- paintInfo.context->setStrokeColor(leftSeparatorColor);
+ paintInfo.context->setStrokeColor(leftSeparatorColor, DeviceColorSpace);
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
IntPoint(leftEdgeOfSeparator, bounds.bottom()));
- paintInfo.context->setStrokeColor(rightSeparatorColor);
+ paintInfo.context->setStrokeColor(rightSeparatorColor, DeviceColorSpace);
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom()));
@@ -1416,13 +1422,11 @@ bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const Render
#if ENABLE(VIDEO)
typedef enum {
MediaControllerThemeClassic = 1,
- MediaControllerThemeQT = 2
+ MediaControllerThemeQuickTime = 2
} MediaControllerThemeStyle;
static int mediaControllerTheme()
{
- static const long minimumQuickTimeVersion = 0x07630000; // 7.6.3
- static SInt32 quickTimeVersion = 0;
static int controllerTheme = -1;
if (controllerTheme != -1)
@@ -1430,27 +1434,18 @@ static int mediaControllerTheme()
controllerTheme = MediaControllerThemeClassic;
- if (!quickTimeVersion) {
- OSErr err;
- err = Gestalt(gestaltQuickTime, &quickTimeVersion);
- if (err != noErr)
- return controllerTheme;
- }
- if (quickTimeVersion < minimumQuickTimeVersion)
- return controllerTheme;
-
Boolean validKey;
- Boolean useQTMediaUI = CFPreferencesGetAppBooleanValue(CFSTR("UseQuickTimeMediaUI"), CFSTR("com.apple.WebCore"), &validKey);
+ Boolean useQTMediaUIPref = CFPreferencesGetAppBooleanValue(CFSTR("UseQuickTimeMediaUI"), CFSTR("com.apple.WebCore"), &validKey);
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
- if (validKey && !useQTMediaUI)
+#if !defined(BUILDING_ON_TIGER)
+ if (validKey && !useQTMediaUIPref)
return controllerTheme;
#else
- if (!validKey || !useQTMediaUI)
+ if (!validKey || !useQTMediaUIPref)
return controllerTheme;
#endif
- controllerTheme = MediaControllerThemeQT;
+ controllerTheme = MediaControllerThemeQuickTime;
return controllerTheme;
}
#endif
@@ -1473,10 +1468,10 @@ void RenderThemeMac::adjustSliderThumbSize(RenderObject* o) const
int width = mediaSliderThumbWidth;
int height = mediaSliderThumbHeight;
- if (mediaControllerTheme() == MediaControllerThemeQT) {
+ if (mediaControllerTheme() == MediaControllerThemeQuickTime) {
CGSize size;
- wkMeasureMediaUIPart(MediaSliderThumb, MediaControllerThemeQT, NULL, &size);
+ wkMeasureMediaUIPart(MediaSliderThumb, MediaControllerThemeQuickTime, NULL, &size);
width = size.width;
height = size.height;
}
@@ -1500,7 +1495,9 @@ static unsigned getMediaUIPartStateFlags(Node* node)
{
unsigned flags = 0;
- if (node->active())
+ if (node->disabled())
+ flags |= MediaUIPartDisabledFlag;
+ else if (node->active())
flags |= MediaUIPartPressedFlag;
return flags;
}
@@ -1510,7 +1507,7 @@ static FloatRect getUnzoomedRectAndAdjustCurrentContext(RenderObject* o, const R
{
float zoomLevel = o->style()->effectiveZoom();
FloatRect unzoomedRect(originalRect);
- if (zoomLevel != 1.0f && mediaControllerTheme() == MediaControllerThemeQT) {
+ if (zoomLevel != 1.0f && mediaControllerTheme() == MediaControllerThemeQuickTime) {
unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
@@ -1539,7 +1536,7 @@ bool RenderThemeMac::paintMediaMuteButton(RenderObject* o, const RenderObject::P
if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
return false;
- if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(node)) {
+ if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(node)) {
LocalCurrentGraphicsContext localContext(paintInfo.context);
wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
@@ -1594,14 +1591,13 @@ bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const RenderObject::
if (!mediaElement)
return false;
- float timeLoaded = 0;
- float currentTime = 0;
- float duration = 0;
- if (MediaPlayer* player = mediaElement->player()) {
- duration = player->duration();
- timeLoaded = player->maxTimeBuffered();
- currentTime = player->currentTime();
- }
+ RefPtr<TimeRanges> timeRanges = mediaElement->buffered();
+ ExceptionCode ignoredException;
+ float timeLoaded = timeRanges->length() ? timeRanges->end(0, ignoredException) : 0;
+ float currentTime = mediaElement->currentTime();
+ float duration = mediaElement->duration();
+ if (isnan(duration))
+ duration = 0;
paintInfo.context->save();
FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
@@ -1645,7 +1641,22 @@ bool RenderThemeMac::paintMediaReturnToRealtimeButton(RenderObject* o, const Ren
return false;
}
+bool RenderThemeMac::paintMediaToggleClosedCaptionsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ HTMLInputElement* node = static_cast<HTMLInputElement*>(o->node());
+ if (!node)
+ return false;
+
+ MediaControlToggleClosedCaptionsButtonElement* btn = static_cast<MediaControlToggleClosedCaptionsButtonElement*>(node);
+ if (!btn)
+ return false;
+
+ LocalCurrentGraphicsContext localContext(paintInfo.context);
+ wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node));
+ return false;
+}
+
bool RenderThemeMac::paintMediaControlsBackground(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
Node* node = o->node();
@@ -1685,12 +1696,25 @@ bool RenderThemeMac::paintMediaTimeRemaining(RenderObject* o, const RenderObject
String RenderThemeMac::extraMediaControlsStyleSheet()
{
- if (mediaControllerTheme() == MediaControllerThemeQT)
- return String(mediaControlsQTUserAgentStyleSheet, sizeof(mediaControlsQTUserAgentStyleSheet));
+ if (mediaControllerTheme() == MediaControllerThemeQuickTime)
+ return String(mediaControlsQuickTimeUserAgentStyleSheet, sizeof(mediaControlsQuickTimeUserAgentStyleSheet));
else
return String();
}
-#endif
+
+bool RenderThemeMac::shouldRenderMediaControlPart(ControlPart part, Element* element)
+{
+ if (part == MediaToggleClosedCaptionsButtonPart) {
+
+ // We rely on QTKit to render captions so don't enable the button unless it will be able to do so.
+ if (!element->hasTagName(videoTag))
+ return false;
+ }
+
+ return RenderTheme::shouldRenderMediaControlPart(part, element);
+}
+
+#endif // ENABLE(VIDEO)
NSPopUpButtonCell* RenderThemeMac::popupButton() const
{
diff --git a/WebCore/rendering/RenderThemeSafari.cpp b/WebCore/rendering/RenderThemeSafari.cpp
index 23998d4..9e97079 100644
--- a/WebCore/rendering/RenderThemeSafari.cpp
+++ b/WebCore/rendering/RenderThemeSafari.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc.
* Copyright (C) 2009 Kenneth Rohde Christiansen
*
* This library is free software; you can redistribute it and/or
@@ -86,7 +86,7 @@ PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
return safariTheme; // keep the reference of one.
}
-#if !defined(NDEBUG) && defined(USE_DEBUG_SAFARI_THEME)
+#ifdef DEBUG_ALL
SOFT_LINK_DEBUG_LIBRARY(SafariTheme)
#else
SOFT_LINK_LIBRARY(SafariTheme)
@@ -744,11 +744,21 @@ static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat*
void RenderThemeSafari::paintMenuListButtonGradients(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
+ if (r.isEmpty())
+ return;
+
CGContextRef context = paintInfo.context->platformContext();
paintInfo.context->save();
- int radius = o->style()->borderTopLeftRadius().width();
+ IntSize topLeftRadius;
+ IntSize topRightRadius;
+ IntSize bottomLeftRadius;
+ IntSize bottomRightRadius;
+
+ o->style()->getBorderRadiiForRect(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+
+ int radius = topLeftRadius.width();
RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
@@ -771,33 +781,27 @@ void RenderThemeSafari::paintMenuListButtonGradients(RenderObject* o, const Rend
RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.right(), r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false));
paintInfo.context->save();
CGContextClipToRect(context, r);
- paintInfo.context->addRoundedRectClip(r,
- o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
- o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
+ paintInfo.context->addRoundedRectClip(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
CGContextDrawShading(context, mainShading.get());
paintInfo.context->restore();
paintInfo.context->save();
CGContextClipToRect(context, topGradient);
- paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient),
- o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
- IntSize(), IntSize());
+ paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient), topLeftRadius, topRightRadius, IntSize(), IntSize());
CGContextDrawShading(context, topShading.get());
paintInfo.context->restore();
- paintInfo.context->save();
- CGContextClipToRect(context, bottomGradient);
- paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient),
- IntSize(), IntSize(),
- o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
- CGContextDrawShading(context, bottomShading.get());
- paintInfo.context->restore();
+ if (!bottomGradient.isEmpty()) {
+ paintInfo.context->save();
+ CGContextClipToRect(context, bottomGradient);
+ paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient), IntSize(), IntSize(), bottomLeftRadius, bottomRightRadius);
+ CGContextDrawShading(context, bottomShading.get());
+ paintInfo.context->restore();
+ }
paintInfo.context->save();
CGContextClipToRect(context, r);
- paintInfo.context->addRoundedRectClip(r,
- o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
- o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
+ paintInfo.context->addRoundedRectClip(r, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
CGContextDrawShading(context, leftShading.get());
CGContextDrawShading(context, rightShading.get());
paintInfo.context->restore();
@@ -807,8 +811,6 @@ void RenderThemeSafari::paintMenuListButtonGradients(RenderObject* o, const Rend
bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
- paintInfo.context->save();
-
IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(),
r.y() + o->style()->borderTopWidth(),
r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(),
@@ -826,8 +828,10 @@ bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const RenderObject:
if (bounds.width() < arrowWidth + arrowPaddingLeft)
return false;
- paintInfo.context->setFillColor(o->style()->color());
- paintInfo.context->setStrokeColor(NoStroke);
+ paintInfo.context->save();
+
+ paintInfo.context->setFillColor(o->style()->color(), DeviceColorSpace);
+ paintInfo.context->setStrokeColor(NoStroke, DeviceColorSpace);
FloatPoint arrow[3];
arrow[0] = FloatPoint(leftEdge, centerY - arrowHeight / 2.0f);
@@ -847,11 +851,11 @@ bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const RenderObject:
// Draw the separator to the left of the arrows
paintInfo.context->setStrokeThickness(1.0f);
paintInfo.context->setStrokeStyle(SolidStroke);
- paintInfo.context->setStrokeColor(leftSeparatorColor);
+ paintInfo.context->setStrokeColor(leftSeparatorColor, DeviceColorSpace);
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
IntPoint(leftEdgeOfSeparator, bounds.bottom()));
- paintInfo.context->setStrokeColor(rightSeparatorColor);
+ paintInfo.context->setStrokeColor(rightSeparatorColor, DeviceColorSpace);
paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom()));
diff --git a/WebCore/rendering/RenderThemeWin.cpp b/WebCore/rendering/RenderThemeWin.cpp
index 92bfd03..52afbd6 100644
--- a/WebCore/rendering/RenderThemeWin.cpp
+++ b/WebCore/rendering/RenderThemeWin.cpp
@@ -819,7 +819,7 @@ bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const RenderO
static Image* cancelImage = Image::loadPlatformResource("searchCancel").releaseRef();
static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").releaseRef();
- paintInfo.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds);
+ paintInfo.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, o->style()->colorSpace(), bounds);
return false;
}
@@ -868,7 +868,7 @@ bool RenderThemeWin::paintSearchFieldResultsDecoration(RenderObject* o, const Re
bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef();
- paintInfo.context->drawImage(magnifierImage, bounds);
+ paintInfo.context->drawImage(magnifierImage, o->style()->colorSpace(), bounds);
return false;
}
@@ -904,7 +904,7 @@ bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const Render
bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2);
static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").releaseRef();
- paintInfo.context->drawImage(magnifierImage, bounds);
+ paintInfo.context->drawImage(magnifierImage, o->style()->colorSpace(), bounds);
return false;
}
@@ -955,6 +955,23 @@ Color RenderThemeWin::systemColor(int cssValueId) const
}
#if ENABLE(VIDEO)
+
+bool RenderThemeWin::shouldRenderMediaControlPart(ControlPart part, Element* element)
+{
+ if (part == MediaToggleClosedCaptionsButtonPart) {
+ // We rely on QuickTime to render captions so only enable the button for a video element.
+#if SAFARI_THEME_VERSION >= 4
+ if (!element->hasTagName(videoTag))
+ return false;
+#else
+ return false;
+#endif
+ }
+
+ return RenderTheme::shouldRenderMediaControlPart(part, element);
+}
+
+
bool RenderThemeWin::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
return RenderMediaControls::paintMediaControlsPart(MediaFullscreenButton, o, paintInfo, r);
@@ -989,6 +1006,12 @@ bool RenderThemeWin::paintMediaSliderThumb(RenderObject* o, const RenderObject::
{
return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, o, paintInfo, r);
}
+
+bool RenderThemeWin::paintMediaToggleClosedCaptionsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ return RenderMediaControls::paintMediaControlsPart(MediaShowClosedCaptionsButton, o, paintInfo, r);
+}
+
#endif
}
diff --git a/WebCore/rendering/RenderThemeWin.h b/WebCore/rendering/RenderThemeWin.h
index 99c2004..a9fa5e6 100644
--- a/WebCore/rendering/RenderThemeWin.h
+++ b/WebCore/rendering/RenderThemeWin.h
@@ -125,6 +125,7 @@ public:
virtual bool supportsFocusRing(const RenderStyle*) const;
#if ENABLE(VIDEO)
+ virtual bool shouldRenderMediaControlPart(ControlPart, Element*);
virtual bool paintMediaFullscreenButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaMuteButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
@@ -132,6 +133,7 @@ public:
virtual bool paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
#endif
private:
diff --git a/WebCore/rendering/RenderThemeWince.cpp b/WebCore/rendering/RenderThemeWince.cpp
index fb89678..c4aaaad 100644
--- a/WebCore/rendering/RenderThemeWince.cpp
+++ b/WebCore/rendering/RenderThemeWince.cpp
@@ -28,6 +28,7 @@
#include "CSSValueKeywords.h"
#include "Document.h"
#include "GraphicsContext.h"
+#include "NotImplemented.h"
#if ENABLE(VIDEO)
#include "HTMLMediaElement.h"
#endif
@@ -377,12 +378,12 @@ bool RenderThemeWince::paintSearchFieldCancelButton(RenderObject* o, const Rende
IntRect cancelBounds(IntPoint(x, y), cancelSize);
paintInfo.context->save();
paintInfo.context->addRoundedRectClip(cancelBounds, cancelRadius, cancelRadius, cancelRadius, cancelRadius);
- paintInfo.context->fillRect(cancelBounds, buttonColor);
+ paintInfo.context->fillRect(cancelBounds, buttonColor, DeviceColorSpace);
// Draw the 'x'
IntSize xSize(3, 3);
IntRect xBounds(cancelBounds.location() + IntSize(3, 3), xSize);
- paintInfo.context->setStrokeColor(Color::white);
+ paintInfo.context->setStrokeColor(Color::white, DeviceColorSpace);
paintInfo.context->drawLine(xBounds.location(), xBounds.location() + xBounds.size());
paintInfo.context->drawLine(IntPoint(xBounds.right(), xBounds.y()), IntPoint(xBounds.x(), xBounds.bottom()));
@@ -489,11 +490,11 @@ bool RenderThemeWince::paintSliderTrack(RenderObject* o, const RenderObject::Pai
bool rc = RenderTheme::paintSliderTrack(o, i, r);
IntPoint left = IntPoint(r.x() + 2, (r.y() + r.bottom()) / 2);
i.context->save();
- i.context->setStrokeColor(Color::gray);
- i.context->setFillColor(Color::gray);
+ i.context->setStrokeColor(Color::gray, DeviceColorSpace);
+ i.context->setFillColor(Color::gray, DeviceColorSpace);
i.context->fillRect(r);
#if ENABLE(VIDEO)
- HTMLMediaElement *mediaElement = mediaElementParent(o->node());
+ HTMLMediaElement* mediaElement = mediaElementParent(o->node());
if (mediaElement) {
i.context->setStrokeColor(Color(0, 0xff, 0));
IntPoint right = IntPoint(left.x() + mediaElement->percentLoaded() * (r.right() - r.x() - 4), (r.y() + r.bottom()) / 2);
@@ -501,7 +502,7 @@ bool RenderThemeWince::paintSliderTrack(RenderObject* o, const RenderObject::Pai
left = right;
}
#endif
- i.context->setStrokeColor(Color::black);
+ i.context->setStrokeColor(Color::black, DeviceColorSpace);
i.context->drawLine(left, IntPoint(r.right() - 2, left.y()));
i.context->restore();
return rc;
@@ -511,10 +512,10 @@ bool RenderThemeWince::paintSliderThumb(RenderObject* o, const RenderObject::Pai
{
bool rc = RenderTheme::paintSliderThumb(o, i, r);
i.context->save();
- i.context->setStrokeColor(Color::black);
- i.context->setFillColor(Color::black);
+ i.context->setStrokeColor(Color::black, DeviceColorSpace);
+ i.context->setFillColor(Color::black, DeviceColorSpace);
#if ENABLE(VIDEO)
- HTMLMediaElement *mediaElement = mediaElementParent(o->node());
+ HTMLMediaElement* mediaElement = mediaElementParent(o->node());
if (mediaElement) {
float pt = (mediaElement->currentTime() - mediaElement->startTime()) / mediaElement->duration();
FloatRect intRect = r;
@@ -574,7 +575,7 @@ bool RenderThemeWince::paintMediaFullscreenButton(RenderObject* o, const RenderO
bool RenderThemeWince::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
{
bool rc = paintButton(o, paintInfo, r);
- HTMLMediaElement *mediaElement = mediaElementParent(o->node());
+ HTMLMediaElement* mediaElement = mediaElementParent(o->node());
bool muted = !mediaElement || mediaElement->muted();
FloatRect imRect = r;
imRect.inflate(-2);
@@ -604,7 +605,7 @@ bool RenderThemeWince::paintMediaPlayButton(RenderObject* o, const RenderObject:
paintInfo.context->save();
paintInfo.context->setStrokeColor(Color::black);
paintInfo.context->setFillColor(Color::black);
- HTMLMediaElement *mediaElement = mediaElementParent(o->node());
+ HTMLMediaElement* mediaElement = mediaElementParent(o->node());
bool paused = !mediaElement || mediaElement->paused();
if (paused) {
float width = imRect.width();
diff --git a/WebCore/rendering/RenderTreeAsText.cpp b/WebCore/rendering/RenderTreeAsText.cpp
index 5c6e738..ca4d9d1 100644
--- a/WebCore/rendering/RenderTreeAsText.cpp
+++ b/WebCore/rendering/RenderTreeAsText.cpp
@@ -28,6 +28,7 @@
#include "CSSMutableStyleDeclaration.h"
#include "CharacterNames.h"
+#include "CString.h"
#include "Document.h"
#include "Frame.h"
#include "FrameView.h"
@@ -35,13 +36,16 @@
#include "HTMLNames.h"
#include "InlineTextBox.h"
#include "RenderBR.h"
+#include "RenderFileUploadControl.h"
#include "RenderInline.h"
#include "RenderListMarker.h"
+#include "RenderPart.h"
#include "RenderTableCell.h"
#include "RenderView.h"
#include "RenderWidget.h"
#include "SelectionController.h"
#include "TextStream.h"
+#include <wtf/UnusedParam.h>
#include <wtf/Vector.h>
#if ENABLE(SVG)
@@ -54,11 +58,19 @@
#include "SVGRenderTreeAsText.h"
#endif
+#if USE(ACCELERATED_COMPOSITING)
+#include "RenderLayerBacking.h"
+#endif
+
+#if PLATFORM(QT)
+#include <QWidget>
+#endif
+
namespace WebCore {
using namespace HTMLNames;
-static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const IntRect& paintDirtyRect, int indent = 0);
+static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const IntRect& paintDirtyRect, int indent = 0, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal);
#if !ENABLE(SVG)
static TextStream &operator<<(TextStream& ts, const IntRect& r)
@@ -216,6 +228,9 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o)
ts << " " << r;
if (!(o.isText() && !o.isBR())) {
+ if (o.isFileUploadControl()) {
+ ts << " " << quoteAndEscapeNonPrintables(toRenderFileUploadControl(&o)->fileTextValue());
+ }
if (o.parent() && (o.parent()->style()->color() != o.style()->color()))
ts << " [color=" << o.style()->color().name() << "]";
@@ -335,6 +350,24 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o)
}
}
+#if PLATFORM(QT)
+ // Print attributes of embedded QWidgets. E.g. when the WebCore::Widget
+ // is invisible the QWidget should be invisible too.
+ if (o.isRenderPart()) {
+ const RenderPart* part = toRenderPart(const_cast<RenderObject*>(&o));
+ if (part->widget() && part->widget()->platformWidget()) {
+ QWidget* wid = part->widget()->platformWidget();
+
+ ts << " [QT: ";
+ ts << "geometry: {" << wid->geometry() << "} ";
+ ts << "isHidden: " << wid->isHidden() << " ";
+ ts << "isSelfVisible: " << part->widget()->isSelfVisible() << " ";
+ ts << "isParentVisible: " << part->widget()->isParentVisible() << " ";
+ ts << "mask: {" << wid->mask().boundingRect() << "} ] ";
+ }
+ }
+#endif
+
return ts;
}
@@ -416,9 +449,15 @@ void write(TextStream& ts, const RenderObject& o, int indent)
}
}
+enum LayerPaintPhase {
+ LayerPaintPhaseAll = 0,
+ LayerPaintPhaseBackground = -1,
+ LayerPaintPhaseForeground = 1
+};
+
static void write(TextStream& ts, RenderLayer& l,
const IntRect& layerBounds, const IntRect& backgroundClipRect, const IntRect& clipRect, const IntRect& outlineClipRect,
- int layerType = 0, int indent = 0)
+ LayerPaintPhase paintPhase = LayerPaintPhaseAll, int indent = 0, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal)
{
writeIndent(ts, indent);
@@ -444,19 +483,28 @@ static void write(TextStream& ts, RenderLayer& l,
ts << " scrollHeight " << l.scrollHeight();
}
- if (layerType == -1)
+ if (paintPhase == LayerPaintPhaseBackground)
ts << " layerType: background only";
- else if (layerType == 1)
+ else if (paintPhase == LayerPaintPhaseForeground)
ts << " layerType: foreground only";
-
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (behavior & RenderAsTextShowCompositedLayers) {
+ if (l.isComposited())
+ ts << " (composited, bounds " << l.backing()->compositedBounds() << ")";
+ }
+#else
+ UNUSED_PARAM(behavior);
+#endif
+
ts << "\n";
- if (layerType != -1)
+ if (paintPhase != LayerPaintPhaseBackground)
write(ts, *l.renderer(), indent + 1);
}
static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLayer* l,
- const IntRect& paintDirtyRect, int indent)
+ const IntRect& paintDirtyRect, int indent, RenderAsTextBehavior behavior)
{
// Calculate the clip rects we should use.
IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
@@ -466,29 +514,46 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye
l->updateZOrderLists();
l->updateNormalFlowList();
- bool shouldPaint = l->intersectsDamageRect(layerBounds, damageRect, rootLayer);
+ bool shouldPaint = (behavior & RenderAsTextShowAllLayers) ? true : l->intersectsDamageRect(layerBounds, damageRect, rootLayer);
Vector<RenderLayer*>* negList = l->negZOrderList();
- if (shouldPaint && negList && negList->size() > 0)
- write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, -1, indent);
+ bool paintsBackgroundSeparately = negList && negList->size() > 0;
+ if (shouldPaint && paintsBackgroundSeparately)
+ write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, LayerPaintPhaseBackground, indent, behavior);
if (negList) {
+ int currIndent = indent;
+ if (behavior & RenderAsTextShowLayerNesting) {
+ writeIndent(ts, indent);
+ ts << " negative z-order list(" << negList->size() << ")\n";
+ ++currIndent;
+ }
for (unsigned i = 0; i != negList->size(); ++i)
- writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, indent);
+ writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, currIndent, behavior);
}
if (shouldPaint)
- write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, negList && negList->size() > 0, indent);
-
- Vector<RenderLayer*>* normalFlowList = l->normalFlowList();
- if (normalFlowList) {
+ write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, paintsBackgroundSeparately ? LayerPaintPhaseForeground : LayerPaintPhaseAll, indent, behavior);
+
+ if (Vector<RenderLayer*>* normalFlowList = l->normalFlowList()) {
+ int currIndent = indent;
+ if (behavior & RenderAsTextShowLayerNesting) {
+ writeIndent(ts, indent);
+ ts << " normal flow list(" << normalFlowList->size() << ")\n";
+ ++currIndent;
+ }
for (unsigned i = 0; i != normalFlowList->size(); ++i)
- writeLayers(ts, rootLayer, normalFlowList->at(i), paintDirtyRect, indent);
+ writeLayers(ts, rootLayer, normalFlowList->at(i), paintDirtyRect, currIndent, behavior);
}
- Vector<RenderLayer*>* posList = l->posZOrderList();
- if (posList) {
+ if (Vector<RenderLayer*>* posList = l->posZOrderList()) {
+ int currIndent = indent;
+ if (behavior & RenderAsTextShowLayerNesting) {
+ writeIndent(ts, indent);
+ ts << " positive z-order list(" << posList->size() << ")\n";
+ ++currIndent;
+ }
for (unsigned i = 0; i != posList->size(); ++i)
- writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, indent);
+ writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, currIndent, behavior);
}
}
@@ -534,8 +599,11 @@ static void writeSelection(TextStream& ts, const RenderObject* o)
<< "selection end: position " << selection.end().deprecatedEditingOffset() << " of " << nodePosition(selection.end().node()) << "\n";
}
-String externalRepresentation(RenderObject* o)
+String externalRepresentation(Frame* frame, RenderAsTextBehavior behavior)
{
+ frame->document()->updateLayout();
+
+ RenderObject* o = frame->contentRenderer();
if (!o)
return String();
@@ -543,14 +611,43 @@ String externalRepresentation(RenderObject* o)
#if ENABLE(SVG)
writeRenderResources(ts, o->document());
#endif
- if (o->view()->frameView())
- o->view()->frameView()->layout();
if (o->hasLayer()) {
RenderLayer* l = toRenderBox(o)->layer();
- writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()));
+ writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()), 0, behavior);
writeSelection(ts, o);
}
return ts.release();
}
+static void writeCounterValuesFromChildren(TextStream& stream, RenderObject* parent, bool& isFirstCounter)
+{
+ for (RenderObject* child = parent->firstChild(); child; child = child->nextSibling()) {
+ if (child->isCounter()) {
+ if (!isFirstCounter)
+ stream << " ";
+ isFirstCounter = false;
+ String str(toRenderText(child)->text());
+ stream << str;
+ }
+ }
+}
+
+String counterValueForElement(Element* element)
+{
+ // Make sure the element is not freed during the layout.
+ RefPtr<Element> elementRef(element);
+ element->document()->updateLayout();
+ TextStream stream;
+ bool isFirstCounter = true;
+ // The counter renderers should be children of anonymous children
+ // (i.e., :before or :after pseudo-elements).
+ if (RenderObject* renderer = element->renderer()) {
+ for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) {
+ if (child->isAnonymous())
+ writeCounterValuesFromChildren(stream, child, isFirstCounter);
+ }
+ }
+ return stream.release();
+}
+
} // namespace WebCore
diff --git a/WebCore/rendering/RenderTreeAsText.h b/WebCore/rendering/RenderTreeAsText.h
index daca253..13525e7 100644
--- a/WebCore/rendering/RenderTreeAsText.h
+++ b/WebCore/rendering/RenderTreeAsText.h
@@ -28,15 +28,27 @@
namespace WebCore {
- class RenderObject;
- class String;
- class TextStream;
+class Element;
+class Frame;
+class RenderObject;
+class String;
+class TextStream;
- String externalRepresentation(RenderObject*);
- void write(TextStream&, const RenderObject&, int indent = 0);
+enum RenderAsTextBehaviorFlags {
+ RenderAsTextBehaviorNormal = 0,
+ RenderAsTextShowAllLayers = 1 << 0, // Dump all layers, not just those that would paint.
+ RenderAsTextShowLayerNesting = 1 << 1, // Annotate the layer lists.
+ RenderAsTextShowCompositedLayers = 1 << 2 // Show which layers are composited.
+};
+typedef unsigned RenderAsTextBehavior;
- // Helper function shared with SVGRenderTreeAsText
- String quoteAndEscapeNonPrintables(const String&);
+String externalRepresentation(Frame*, RenderAsTextBehavior = RenderAsTextBehaviorNormal);
+void write(TextStream&, const RenderObject&, int indent = 0);
+
+// Helper function shared with SVGRenderTreeAsText
+String quoteAndEscapeNonPrintables(const String&);
+
+String counterValueForElement(Element*);
} // namespace WebCore
diff --git a/WebCore/rendering/RenderVideo.cpp b/WebCore/rendering/RenderVideo.cpp
index 246d0c0..813f2ef 100644
--- a/WebCore/rendering/RenderVideo.cpp
+++ b/WebCore/rendering/RenderVideo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -34,6 +34,7 @@
#include "HTMLNames.h"
#include "HTMLVideoElement.h"
#include "MediaPlayer.h"
+#include "RenderView.h"
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayer.h"
@@ -49,18 +50,25 @@ using namespace HTMLNames;
static const int cDefaultWidth = 300;
static const int cDefaultHeight = 150;
-RenderVideo::RenderVideo(HTMLMediaElement* video)
+RenderVideo::RenderVideo(HTMLVideoElement* video)
: RenderMedia(video)
{
if (video->player())
setIntrinsicSize(video->player()->naturalSize());
else {
- // Video in standalone media documents should not use the default 300x150
- // size since they also have audio thrown at them. By setting the intrinsic
- // size to 300x1 the video will resize itself in these cases, and audio will
- // have the correct height (it needs to be > 0 for controls to render properly).
- if (video->ownerDocument() && video->ownerDocument()->isMediaDocument())
+ // When the natural size of the video is unavailable, we use the provided
+ // width and height attributes of the video element as the intrinsic size until
+ // better values become available. If these attributes are not set, we fall back
+ // to a default video size (300x150).
+ if (video->hasAttribute(widthAttr) && video->hasAttribute(heightAttr))
+ setIntrinsicSize(IntSize(video->width(), video->height()));
+ else if (video->ownerDocument() && video->ownerDocument()->isMediaDocument()) {
+ // Video in standalone media documents should not use the default 300x150
+ // size since they also have audio thrown at them. By setting the intrinsic
+ // size to 300x1 the video will resize itself in these cases, and audio will
+ // have the correct height (it needs to be > 0 for controls to render properly).
setIntrinsicSize(IntSize(cDefaultWidth, 1));
+ }
else
setIntrinsicSize(IntSize(cDefaultWidth, cDefaultHeight));
}
@@ -73,7 +81,15 @@ RenderVideo::~RenderVideo()
p->setFrameView(0);
}
}
-
+
+void RenderVideo::intrinsicSizeChanged()
+{
+ if (videoElement()->shouldDisplayPosterImage())
+ RenderMedia::intrinsicSizeChanged();
+ videoSizeChanged();
+}
+
+
void RenderVideo::videoSizeChanged()
{
if (!player())
@@ -86,41 +102,72 @@ void RenderVideo::videoSizeChanged()
}
}
-IntRect RenderVideo::videoBox() const
+void RenderVideo::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
{
+ RenderMedia::imageChanged(newImage, rect);
+
+ // Cache the image intrinsic size so we can continue to use it to draw the image correctly
+ // even after we know the video intrisic size but aren't able to draw video frames yet
+ // (we don't want to scale the poster to the video size).
+ if (videoElement()->shouldDisplayPosterImage())
+ m_cachedImageSize = intrinsicSize();
+}
+
+IntRect RenderVideo::videoBox() const
+{
+ if (m_cachedImageSize.isEmpty() && videoElement()->shouldDisplayPosterImage())
+ return IntRect();
+
+ IntSize elementSize;
+ if (videoElement()->shouldDisplayPosterImage())
+ elementSize = m_cachedImageSize;
+ else
+ elementSize = intrinsicSize();
+
IntRect contentRect = contentBoxRect();
-
- if (intrinsicSize().isEmpty() || contentRect.isEmpty())
+ if (elementSize.isEmpty() || contentRect.isEmpty())
return IntRect();
- IntRect resultRect = contentRect;
- int ratio = contentRect.width() * intrinsicSize().height() - contentRect.height() * intrinsicSize().width();
+ IntRect renderBox = contentRect;
+ int ratio = renderBox.width() * elementSize.height() - renderBox.height() * elementSize.width();
if (ratio > 0) {
- int newWidth = contentRect.height() * intrinsicSize().width() / intrinsicSize().height();
+ int newWidth = renderBox.height() * elementSize.width() / elementSize.height();
// Just fill the whole area if the difference is one pixel or less (in both sides)
- if (resultRect.width() - newWidth > 2)
- resultRect.setWidth(newWidth);
- resultRect.move((contentRect.width() - resultRect.width()) / 2, 0);
+ if (renderBox.width() - newWidth > 2)
+ renderBox.setWidth(newWidth);
+ renderBox.move((contentRect.width() - renderBox.width()) / 2, 0);
} else if (ratio < 0) {
- int newHeight = contentRect.width() * intrinsicSize().height() / intrinsicSize().width();
- if (resultRect.height() - newHeight > 2)
- resultRect.setHeight(newHeight);
- resultRect.move(0, (contentRect.height() - resultRect.height()) / 2);
+ int newHeight = renderBox.width() * elementSize.height() / elementSize.width();
+ if (renderBox.height() - newHeight > 2)
+ renderBox.setHeight(newHeight);
+ renderBox.move(0, (contentRect.height() - renderBox.height()) / 2);
}
- return resultRect;
+
+ return renderBox;
}
void RenderVideo::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
{
MediaPlayer* mediaPlayer = player();
- if (!mediaPlayer)
+ bool displayingPoster = videoElement()->shouldDisplayPosterImage();
+
+ if (displayingPoster && document()->printing() && !view()->printImages())
return;
- updatePlayer();
+
+ if (!displayingPoster) {
+ if (!mediaPlayer)
+ return;
+ updatePlayer();
+ }
+
IntRect rect = videoBox();
if (rect.isEmpty())
return;
rect.move(tx, ty);
- mediaPlayer->paint(paintInfo.context, rect);
+ if (displayingPoster)
+ paintIntoRect(paintInfo.context, rect);
+ else
+ mediaPlayer->paint(paintInfo.context, rect);
}
void RenderVideo::layout()
@@ -129,6 +176,12 @@ void RenderVideo::layout()
updatePlayer();
}
+HTMLVideoElement* RenderVideo::videoElement() const
+{
+ ASSERT(node()->hasTagName(videoTag));
+ return static_cast<HTMLVideoElement*>(node());
+}
+
void RenderVideo::updateFromElement()
{
RenderMedia::updateFromElement();
@@ -140,7 +193,7 @@ void RenderVideo::updatePlayer()
MediaPlayer* mediaPlayer = player();
if (!mediaPlayer)
return;
- if (!mediaElement()->inActiveDocument()) {
+ if (!videoElement()->inActiveDocument()) {
mediaPlayer->setVisible(false);
return;
}
@@ -155,40 +208,6 @@ void RenderVideo::updatePlayer()
mediaPlayer->setVisible(true);
}
-bool RenderVideo::isWidthSpecified() const
-{
- switch (style()->width().type()) {
- case Fixed:
- case Percent:
- return true;
- case Auto:
- case Relative: // FIXME: Shouldn't this case return true? It doesn't for images.
- case Static:
- case Intrinsic:
- case MinIntrinsic:
- return false;
- }
- ASSERT(false);
- return false;
-}
-
-bool RenderVideo::isHeightSpecified() const
-{
- switch (style()->height().type()) {
- case Fixed:
- case Percent:
- return true;
- case Auto:
- case Relative: // FIXME: Shouldn't this case return true? It doesn't for images.
- case Static:
- case Intrinsic:
- case MinIntrinsic:
- return false;
- }
- ASSERT(false);
- return false;
-}
-
int RenderVideo::calcReplacedWidth(bool includeMaxWidth) const
{
int width;
@@ -235,24 +254,9 @@ int RenderVideo::calcAspectRatioHeight() const
return RenderBox::calcReplacedWidth() * intrinsicHeight / intrinsicWidth;
}
-void RenderVideo::calcPrefWidths()
+int RenderVideo::minimumReplacedHeight() const
{
- ASSERT(prefWidthsDirty());
-
- int paddingAndBorders = paddingLeft() + paddingRight() + borderLeft() + borderRight();
- m_maxPrefWidth = calcReplacedWidth(false) + paddingAndBorders;
-
- if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
- m_maxPrefWidth = min(m_maxPrefWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? paddingAndBorders : 0));
-
- if (style()->width().isPercent() || style()->height().isPercent() ||
- style()->maxWidth().isPercent() || style()->maxHeight().isPercent() ||
- style()->minWidth().isPercent() || style()->minHeight().isPercent())
- m_minPrefWidth = 0;
- else
- m_minPrefWidth = m_maxPrefWidth;
-
- setPrefWidthsDirty(false);
+ return 0;
}
#if USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/rendering/RenderVideo.h b/WebCore/rendering/RenderVideo.h
index 79e5b4e..3ca5328 100644
--- a/WebCore/rendering/RenderVideo.h
+++ b/WebCore/rendering/RenderVideo.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,13 +33,14 @@
namespace WebCore {
class HTMLMediaElement;
+class HTMLVideoElement;
#if USE(ACCELERATED_COMPOSITING)
class GraphicsLayer;
#endif
class RenderVideo : public RenderMedia {
public:
- RenderVideo(HTMLMediaElement*);
+ RenderVideo(HTMLVideoElement*);
virtual ~RenderVideo();
void videoSizeChanged();
@@ -53,8 +54,10 @@ public:
private:
virtual void updateFromElement();
+ inline HTMLVideoElement* videoElement() const;
- virtual void intrinsicSizeChanged() { videoSizeChanged(); }
+ virtual void intrinsicSizeChanged();
+ virtual void imageChanged(WrappedImagePtr, const IntRect*);
virtual const char* renderName() const { return "RenderVideo"; }
@@ -67,16 +70,14 @@ private:
virtual int calcReplacedWidth(bool includeMaxWidth = true) const;
virtual int calcReplacedHeight() const;
-
- virtual void calcPrefWidths();
+ virtual int minimumReplacedHeight() const;
int calcAspectRatioWidth() const;
int calcAspectRatioHeight() const;
- bool isWidthSpecified() const;
- bool isHeightSpecified() const;
-
void updatePlayer();
+
+ IntSize m_cachedImageSize;
};
inline RenderVideo* toRenderVideo(RenderObject* object)
diff --git a/WebCore/rendering/RenderView.cpp b/WebCore/rendering/RenderView.cpp
index 584e38a..094abfd 100644
--- a/WebCore/rendering/RenderView.cpp
+++ b/WebCore/rendering/RenderView.cpp
@@ -133,12 +133,10 @@ void RenderView::layout()
if (needsLayout())
RenderBlock::layout();
- // Reset overflowWidth and overflowHeight, since they act as a lower bound for docWidth() and docHeight().
- setOverflowWidth(width());
- setOverflowHeight(height());
-
- setOverflowWidth(docWidth());
- setOverflowHeight(docHeight());
+ // Reset overflow and then replace it with docWidth and docHeight.
+ m_overflow.clear();
+ addLayoutOverflow(IntRect(0, 0, docWidth(), docHeight()));
+
ASSERT(layoutDelta() == IntSize());
ASSERT(m_layoutStateDisableCount == 0);
@@ -153,12 +151,30 @@ void RenderView::mapLocalToContainer(RenderBoxModelObject* repaintContainer, boo
// then we should have found it by now.
ASSERT_UNUSED(repaintContainer, !repaintContainer || repaintContainer == this);
+#ifdef ANDROID_FIXED_ELEMENTS
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ const Settings * settings = document()->settings();
+ if (settings && (settings->viewportWidth() == -1 || settings->viewportWidth() == 0) &&
+ !settings->viewportUserScalable())
+#else
+ if (false)
+#endif
+#endif
if (fixed && m_frameView)
transformState.move(m_frameView->scrollOffset());
}
void RenderView::mapAbsoluteToLocalPoint(bool fixed, bool /*useTransforms*/, TransformState& transformState) const
{
+#ifdef ANDROID_FIXED_ELEMENTS
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ const Settings * settings = document()->settings();
+ if (settings && (settings->viewportWidth() == -1 || settings->viewportWidth() == 0) &&
+ !settings->viewportUserScalable())
+#else
+ if (false)
+#endif
+#endif
if (fixed && m_frameView)
transformState.move(-m_frameView->scrollOffset());
}
@@ -212,7 +228,7 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, int, int)
if (baseColor.alpha() > 0) {
paintInfo.context->save();
paintInfo.context->setCompositeOperation(CompositeCopy);
- paintInfo.context->fillRect(paintInfo.rect, baseColor);
+ paintInfo.context->fillRect(paintInfo.rect, baseColor, style()->colorSpace());
paintInfo.context->restore();
} else
paintInfo.context->clearRect(paintInfo.rect);
@@ -282,6 +298,15 @@ void RenderView::computeRectForRepaint(RenderBoxModelObject* repaintContainer, I
if (printing())
return;
+#ifdef ANDROID_FIXED_ELEMENTS
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ const Settings * settings = document()->settings();
+ if (settings && (settings->viewportWidth() == -1 || settings->viewportWidth() == 0) &&
+ !settings->viewportUserScalable())
+#else
+ if (false)
+#endif
+#endif
if (fixed && m_frameView)
rect.move(m_frameView->scrollX(), m_frameView->scrollY());
@@ -340,7 +365,13 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const
SelectionMap::iterator end = selectedObjects.end();
for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) {
RenderSelectionInfo* info = i->second;
- selRect.unite(info->rect());
+ // RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates.
+ IntRect currRect = info->rect();
+ if (RenderBoxModelObject* repaintContainer = info->repaintContainer()) {
+ FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect));
+ currRect = absQuad.enclosingBoundingBox();
+ }
+ selRect.unite(currRect);
delete info;
}
return selRect;
@@ -439,7 +470,7 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e
o = o->nextInPreOrder();
}
- m_cachedSelectionBounds = IntRect();
+ m_layer->clearBlockSelectionGapsBounds();
// Now that the selection state has been updated for the new objects, walk them again and
// put them in the new objects list.
@@ -452,9 +483,7 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e
RenderBlockSelectionInfo* blockInfo = newSelectedBlocks.get(cb);
if (blockInfo)
break;
- blockInfo = new RenderBlockSelectionInfo(cb);
- newSelectedBlocks.set(cb, blockInfo);
- m_cachedSelectionBounds.unite(blockInfo->rects());
+ newSelectedBlocks.set(cb, new RenderBlockSelectionInfo(cb));
cb = cb->containingBlock();
}
}
@@ -472,6 +501,8 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e
return;
}
+ m_frameView->beginDeferredRepaints();
+
// Have any of the old selected objects changed compared to the new selection?
for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) {
RenderObject* obj = i->first;
@@ -523,11 +554,13 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e
newInfo->repaint();
delete newInfo;
}
+
+ m_frameView->endDeferredRepaints();
}
void RenderView::clearSelection()
{
- repaintViewRectangle(m_cachedSelectionBounds);
+ m_layer->repaintBlockSelectionGaps();
setSelection(0, -1, 0, -1, RepaintNewMinusOld);
}
@@ -658,6 +691,17 @@ void RenderView::pushLayoutState(RenderObject* root)
m_layoutState = new (renderArena()) LayoutState(root);
}
+bool RenderView::shouldDisableLayoutStateForSubtree(RenderObject* renderer) const
+{
+ RenderObject* o = renderer;
+ while (o) {
+ if (o->hasColumns() || o->hasTransform() || o->hasReflection())
+ return true;
+ o = o->container();
+ }
+ return false;
+}
+
void RenderView::updateHitTestResult(HitTestResult& result, const IntPoint& point)
{
if (result.innerNode())
diff --git a/WebCore/rendering/RenderView.h b/WebCore/rendering/RenderView.h
index 089fe85..faa2465 100644
--- a/WebCore/rendering/RenderView.h
+++ b/WebCore/rendering/RenderView.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the HTML widget for KDE.
- *
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* Copyright (C) 2006 Apple Computer, Inc.
*
@@ -77,9 +75,11 @@ public:
bool printing() const;
void setPrintImages(bool enable) { m_printImages = enable; }
bool printImages() const { return m_printImages; }
- void setTruncatedAt(int y) { m_truncatedAt = y; m_bestTruncatedAt = m_truncatorWidth = 0; m_forcedPageBreak = false; }
+ void setTruncatedAt(int y) { m_truncatedAt = y; m_bestTruncatedAt = m_truncatorWidth = 0; m_minimumColumnHeight = 0; m_forcedPageBreak = false; }
void setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak = false);
+ void setMinimumColumnHeight(int height) { m_minimumColumnHeight = height; }
int bestTruncatedAt() const { return m_bestTruncatedAt; }
+ int minimumColumnHeight() const { return m_minimumColumnHeight; }
int truncatedAt() const { return m_truncatedAt; }
@@ -105,6 +105,9 @@ public:
void updateWidgetPositions();
void addWidget(RenderWidget*);
void removeWidget(RenderWidget*);
+#ifdef ANDROID_PLUGINS
+ const HashSet<RenderWidget*>& widgets() const { return m_widgets; }
+#endif
// layoutDelta is used transiently during layout to store how far an object has moved from its
// last layout location, in order to repaint correctly.
@@ -140,6 +143,8 @@ public:
state->destroy(renderArena());
}
+ bool shouldDisableLayoutStateForSubtree(RenderObject*) const;
+
// Returns true if layoutState should be used for its cached offset and clip.
bool layoutStateEnabled() const { return m_layoutStateDisableCount == 0 && m_layoutState; }
LayoutState* layoutState() const { return m_layoutState; }
@@ -169,7 +174,7 @@ protected:
private:
bool shouldRepaint(const IntRect& r) const;
-
+
#ifdef FLATTEN_FRAMESET
public: // used by layout function
#endif
@@ -196,10 +201,9 @@ protected:
RenderWidgetSet m_widgets;
private:
- IntRect m_cachedSelectionBounds;
-
int m_bestTruncatedAt;
int m_truncatorWidth;
+ int m_minimumColumnHeight;
bool m_forcedPageBreak;
LayoutState* m_layoutState;
unsigned m_layoutStateDisableCount;
diff --git a/WebCore/rendering/RenderWidget.cpp b/WebCore/rendering/RenderWidget.cpp
index 36f4fed..f6f6da8 100644
--- a/WebCore/rendering/RenderWidget.cpp
+++ b/WebCore/rendering/RenderWidget.cpp
@@ -23,11 +23,12 @@
#include "config.h"
#include "RenderWidget.h"
-#include "AnimationController.h"
#include "AXObjectCache.h"
+#include "AnimationController.h"
#include "GraphicsContext.h"
#include "HitTestResult.h"
#include "RenderView.h"
+#include "RenderWidgetProtector.h"
using namespace std;
@@ -39,18 +40,65 @@ static HashMap<const Widget*, RenderWidget*>& widgetRendererMap()
return *staticWidgetRendererMap;
}
+static size_t widgetHierarchyUpdateSuspendCount;
+
+typedef HashMap<RefPtr<Widget>, FrameView*> WidgetToParentMap;
+
+static WidgetToParentMap& widgetNewParentMap()
+{
+ DEFINE_STATIC_LOCAL(WidgetToParentMap, map, ());
+ return map;
+}
+
+void RenderWidget::suspendWidgetHierarchyUpdates()
+{
+ widgetHierarchyUpdateSuspendCount++;
+}
+
+void RenderWidget::resumeWidgetHierarchyUpdates()
+{
+ ASSERT(widgetHierarchyUpdateSuspendCount);
+ if (widgetHierarchyUpdateSuspendCount == 1) {
+ WidgetToParentMap map = widgetNewParentMap();
+ widgetNewParentMap().clear();
+ WidgetToParentMap::iterator end = map.end();
+ for (WidgetToParentMap::iterator it = map.begin(); it != end; ++it) {
+ Widget* child = it->first.get();
+ ScrollView* currentParent = child->parent();
+ FrameView* newParent = it->second;
+ if (newParent != currentParent) {
+ if (currentParent)
+ currentParent->removeChild(child);
+ if (newParent)
+ newParent->addChild(child);
+ }
+ }
+ }
+ widgetHierarchyUpdateSuspendCount--;
+}
+
+static void moveWidgetToParentSoon(Widget* child, FrameView* parent)
+{
+ if (!widgetHierarchyUpdateSuspendCount) {
+ if (parent)
+ parent->addChild(child);
+ else
+ child->removeFromParent();
+ return;
+ }
+ widgetNewParentMap().set(child, parent);
+}
+
RenderWidget::RenderWidget(Node* node)
: RenderReplaced(node)
, m_widget(0)
, m_frameView(node->document()->view())
- , m_refCount(0)
-{
- view()->addWidget(this);
-
// Reference counting is used to prevent the widget from being
// destroyed while inside the Widget code, which might not be
// able to handle that.
- ref();
+ , m_refCount(1)
+{
+ view()->addWidget(this);
}
void RenderWidget::destroy()
@@ -60,6 +108,7 @@ void RenderWidget::destroy()
// So the code below includes copied and pasted contents of
// both RenderBox::destroy() and RenderObject::destroy().
// Fix originally made for <rdar://problem/4228818>.
+
animation()->cancelAnimations(this);
if (RenderView* v = view())
@@ -71,12 +120,8 @@ void RenderWidget::destroy()
}
remove();
- if (m_widget) {
- if (m_frameView)
- m_frameView->removeChild(m_widget.get());
- widgetRendererMap().remove(m_widget.get());
- }
-
+ setWidget(0);
+
// removes from override size map
if (hasOverrideSize())
setOverrideSize(-1);
@@ -103,40 +148,43 @@ RenderWidget::~RenderWidget()
clearWidget();
}
-void RenderWidget::setWidgetGeometry(const IntRect& frame)
+bool RenderWidget::setWidgetGeometry(const IntRect& frame)
{
- if (node() && m_widget->frameRect() != frame) {
- RenderArena* arena = ref();
- RefPtr<Node> protectedElement(node());
- m_widget->setFrameRect(frame);
- deref(arena);
- }
+ ASSERT(!widgetHierarchyUpdateSuspendCount);
+ if (!node() || m_widget->frameRect() == frame)
+ return false;
+
+ RenderWidgetProtector protector(this);
+ RefPtr<Node> protectedNode(node());
+ m_widget->setFrameRect(frame);
+ return true;
}
void RenderWidget::setWidget(PassRefPtr<Widget> widget)
{
- if (widget != m_widget) {
- if (m_widget) {
- m_widget->removeFromParent();
- widgetRendererMap().remove(m_widget.get());
- clearWidget();
- }
- m_widget = widget;
- if (m_widget) {
- widgetRendererMap().add(m_widget.get(), this);
- // if we've already received a layout, apply the calculated space to the
- // widget immediately, but we have to have really been full constructed (with a non-null
- // style pointer).
- if (style()) {
- if (!needsLayout())
- setWidgetGeometry(absoluteContentBox());
- if (style()->visibility() != VISIBLE)
- m_widget->hide();
- else
- m_widget->show();
- }
- m_frameView->addChild(m_widget.get());
+ if (widget == m_widget)
+ return;
+
+ if (m_widget) {
+ moveWidgetToParentSoon(m_widget.get(), 0);
+ widgetRendererMap().remove(m_widget.get());
+ clearWidget();
+ }
+ m_widget = widget;
+ if (m_widget) {
+ widgetRendererMap().add(m_widget.get(), this);
+ // If we've already received a layout, apply the calculated space to the
+ // widget immediately, but we have to have really been fully constructed (with a non-null
+ // style pointer).
+ if (style()) {
+ if (!needsLayout())
+ setWidgetGeometry(absoluteContentBox());
+ if (style()->visibility() != VISIBLE)
+ m_widget->hide();
+ else
+ m_widget->show();
}
+ moveWidgetToParentSoon(m_widget.get(), m_frameView);
}
}
@@ -158,6 +206,12 @@ void RenderWidget::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
}
}
+void RenderWidget::showSubstituteImage(PassRefPtr<Image> prpImage)
+{
+ m_substituteImage = prpImage;
+ repaint();
+}
+
void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty)
{
if (!shouldPaint(paintInfo, tx, ty))
@@ -183,27 +237,43 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty)
#endif
if (style()->hasBorderRadius()) {
+ IntRect borderRect = IntRect(tx, ty, width(), height());
+
+ if (borderRect.isEmpty())
+ return;
+
// Push a clip if we have a border radius, since we want to round the foreground content that gets painted.
paintInfo.context->save();
IntSize topLeft, topRight, bottomLeft, bottomRight;
- IntRect borderRect = IntRect(tx, ty, width(), height());
style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight);
paintInfo.context->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight);
}
if (m_widget) {
- // Move the widget if necessary. We normally move and resize widgets during layout, but sometimes
- // widgets can move without layout occurring (most notably when you scroll a document that
- // contains fixed positioned elements).
- m_widget->move(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop());
-
// Tell the widget to paint now. This is the only time the widget is allowed
// to paint itself. That way it will composite properly with z-indexed layers.
- m_widget->paint(paintInfo.context, paintInfo.rect);
+ if (m_substituteImage)
+ paintInfo.context->drawImage(m_substituteImage.get(), style()->colorSpace(), m_widget->frameRect());
+ else {
+ IntPoint widgetLocation = m_widget->frameRect().location();
+ IntPoint paintLocation(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop());
+ IntRect paintRect = paintInfo.rect;
+
+ IntSize paintOffset = paintLocation - widgetLocation;
+ // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer,
+ // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing.
+ if (!paintOffset.isZero()) {
+ paintInfo.context->translate(paintOffset);
+ paintRect.move(-paintOffset);
+ }
+ m_widget->paint(paintInfo.context, paintRect);
- if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget.get())->useSlowRepaints()) {
+ if (!paintOffset.isZero())
+ paintInfo.context->translate(-paintOffset);
+ }
+ if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget.get())->useSlowRepaintsIfNotOverlapped()) {
ASSERT(!paintInfo.overlapTestRequests->contains(this));
paintInfo.overlapTestRequests->set(this, m_widget->frameRect());
}
@@ -215,7 +285,7 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty)
// Paint a partially transparent wash over selected widgets.
if (isSelected() && !document()->printing()) {
// FIXME: selectionRect() is in absolute, not painting coordinates.
- paintInfo.context->fillRect(selectionRect(), selectionBackgroundColor());
+ paintInfo.context->fillRect(selectionRect(), selectionBackgroundColor(), style()->colorSpace());
}
}
@@ -244,17 +314,8 @@ void RenderWidget::updateWidgetPosition()
int w = width() - borderLeft() - borderRight() - paddingLeft() - paddingRight();
int h = height() - borderTop() - borderBottom() - paddingTop() - paddingBottom();
- IntRect newBounds(absPos.x(), absPos.y(), w, h);
- IntRect oldBounds(m_widget->frameRect());
- bool boundsChanged = newBounds != oldBounds;
- if (boundsChanged) {
- RenderArena* arena = ref();
- node()->ref();
- m_widget->setFrameRect(newBounds);
- node()->deref();
- deref(arena);
- }
-
+ bool boundsChanged = setWidgetGeometry(IntRect(absPos.x(), absPos.y(), w, h));
+
#ifndef FLATTEN_IFRAME
// if the frame bounds got changed, or if view needs layout (possibly indicating
// content size is wrong) we have to do a layout to set the right widget size
diff --git a/WebCore/rendering/RenderWidget.h b/WebCore/rendering/RenderWidget.h
index bb68143..6cad04a 100644
--- a/WebCore/rendering/RenderWidget.h
+++ b/WebCore/rendering/RenderWidget.h
@@ -40,6 +40,11 @@ public:
void updateWidgetPosition();
+ void showSubstituteImage(PassRefPtr<Image>);
+
+ static void suspendWidgetHierarchyUpdates();
+ static void resumeWidgetHierarchyUpdates();
+
protected:
RenderWidget(Node*);
@@ -59,12 +64,14 @@ private:
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
virtual void setOverlapTestResult(bool);
- void setWidgetGeometry(const IntRect&);
+ bool setWidgetGeometry(const IntRect&);
+ friend class RenderWidgetProtector;
RenderArena* ref() { ++m_refCount; return renderArena(); }
void deref(RenderArena*);
RefPtr<Widget> m_widget;
+ RefPtr<Image> m_substituteImage;
FrameView* m_frameView;
int m_refCount;
};
diff --git a/WebCore/rendering/RenderWidgetProtector.h b/WebCore/rendering/RenderWidgetProtector.h
new file mode 100644
index 0000000..788304c
--- /dev/null
+++ b/WebCore/rendering/RenderWidgetProtector.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2009 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 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 RenderWidgetProtector_h
+#define RenderWidgetProtector_h
+
+#include "RenderWidget.h"
+
+namespace WebCore {
+
+class RenderWidgetProtector : private Noncopyable {
+public:
+ RenderWidgetProtector(RenderWidget* object)
+ : m_object(object)
+ , m_arena(object->ref())
+ {
+ }
+
+ ~RenderWidgetProtector()
+ {
+ m_object->deref(m_arena);
+ }
+
+private:
+ RenderWidget* m_object;
+ RenderArena* m_arena;
+};
+
+}
+
+#endif // RenderWidgetProtector_h
diff --git a/WebCore/rendering/RootInlineBox.cpp b/WebCore/rendering/RootInlineBox.cpp
index e8f04da..23316f7 100644
--- a/WebCore/rendering/RootInlineBox.cpp
+++ b/WebCore/rendering/RootInlineBox.cpp
@@ -21,6 +21,7 @@
#include "RootInlineBox.h"
#include "BidiResolver.h"
+#include "Chrome.h"
#include "ChromeClient.h"
#include "Document.h"
#include "EllipsisBox.h"
@@ -38,28 +39,8 @@ namespace WebCore {
typedef WTF::HashMap<const RootInlineBox*, EllipsisBox*> EllipsisBoxMap;
static EllipsisBoxMap* gEllipsisBoxMap = 0;
-void* RootInlineBox::Overflow::operator new(size_t sz, RenderArena* renderArena) throw()
-{
- return renderArena->allocate(sz);
-}
-
-void RootInlineBox::Overflow::operator delete(void* ptr, size_t sz)
-{
- // Stash size where destroy can find it.
- *(size_t *)ptr = sz;
-}
-
-void RootInlineBox::Overflow::destroy(RenderArena* renderArena)
-{
- delete this;
- // Recover the size left there for us by operator delete and free the memory.
- renderArena->free(*(size_t *)this, this);
-}
-
void RootInlineBox::destroy(RenderArena* arena)
{
- if (m_overflow)
- m_overflow->destroy(arena);
detachEllipsisBox(arena);
InlineFlowBox::destroy(arena);
}
@@ -155,8 +136,8 @@ void RootInlineBox::addHighlightOverflow()
// Highlight acts as a selection inflation.
FloatRect rootRect(0, selectionTop(), width(), selectionHeight());
IntRect inflatedRect = enclosingIntRect(page->chrome()->client()->customHighlightRect(renderer()->node(), renderer()->style()->highlight(), rootRect));
- setHorizontalOverflowPositions(min(leftOverflow(), inflatedRect.x()), max(rightOverflow(), inflatedRect.right()));
- setVerticalOverflowPositions(min(topOverflow(), inflatedRect.y()), max(bottomOverflow(), inflatedRect.bottom()));
+ setHorizontalOverflowPositions(leftLayoutOverflow(), rightLayoutOverflow(), min(leftVisualOverflow(), inflatedRect.x()), max(rightVisualOverflow(), inflatedRect.right()));
+ setVerticalOverflowPositions(topLayoutOverflow(), bottomLayoutOverflow(), min(topVisualOverflow(), inflatedRect.y()), max(bottomVisualOverflow(), inflatedRect.bottom()), height());
}
void RootInlineBox::paintCustomHighlight(RenderObject::PaintInfo& paintInfo, int tx, int ty, const AtomicString& highlightType)
@@ -205,12 +186,8 @@ bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
void RootInlineBox::adjustPosition(int dx, int dy)
{
InlineFlowBox::adjustPosition(dx, dy);
- if (m_overflow) {
- m_overflow->m_topOverflow += dy;
- m_overflow->m_bottomOverflow += dy;
- m_overflow->m_selectionTop += dy;
- m_overflow->m_selectionBottom += dy;
- }
+ m_lineTop += dy;
+ m_lineBottom += dy;
m_blockHeight += dy;
}
@@ -225,6 +202,37 @@ void RootInlineBox::childRemoved(InlineBox* box)
}
}
+int RootInlineBox::verticallyAlignBoxes(int heightOfBlock)
+{
+ int maxPositionTop = 0;
+ int maxPositionBottom = 0;
+ int maxAscent = 0;
+ int maxDescent = 0;
+
+ // Figure out if we're in strict mode. Note that we can't simply use !style()->htmlHacks(),
+ // because that would match almost strict mode as well.
+ RenderObject* curr = renderer();
+ while (curr && !curr->node())
+ curr = curr->container();
+ bool strictMode = (curr && curr->document()->inStrictMode());
+
+ computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode);
+
+ if (maxAscent + maxDescent < max(maxPositionTop, maxPositionBottom))
+ adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
+
+ int maxHeight = maxAscent + maxDescent;
+ int lineTop = heightOfBlock;
+ int lineBottom = heightOfBlock;
+ placeBoxesVertically(heightOfBlock, maxHeight, maxAscent, strictMode, lineTop, lineBottom);
+ computeVerticalOverflow(lineTop, lineBottom, strictMode);
+ setLineTopBottomPositions(lineTop, lineBottom);
+
+ heightOfBlock += maxHeight;
+
+ return heightOfBlock;
+}
+
GapRects RootInlineBox::fillLineSelectionGap(int selTop, int selHeight, RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
const RenderObject::PaintInfo* paintInfo)
{
@@ -321,9 +329,9 @@ InlineBox* RootInlineBox::lastSelectedBox()
return 0;
}
-int RootInlineBox::selectionTop()
+int RootInlineBox::selectionTop() const
{
- int selectionTop = m_overflow ? m_overflow->m_selectionTop : m_y;
+ int selectionTop = m_lineTop;
if (!prevRootBox())
return selectionTop;
@@ -407,18 +415,6 @@ EllipsisBox* RootInlineBox::ellipsisBox() const
return gEllipsisBoxMap->get(this);
}
-void RootInlineBox::setVerticalOverflowPositions(int top, int bottom)
-{
- if (!m_overflow) {
- const Font& font = renderer()->style(m_firstLine)->font();
- if (top == m_y && bottom == m_y + font.height())
- return;
- m_overflow = new (renderer()->renderArena()) Overflow(this);
- }
- m_overflow->m_topOverflow = top;
- m_overflow->m_bottomOverflow = bottom;
-}
-
void RootInlineBox::removeLineBoxFromRenderObject()
{
block()->lineBoxes()->removeLineBox(this);
diff --git a/WebCore/rendering/RootInlineBox.h b/WebCore/rendering/RootInlineBox.h
index 171be9d..7fce1d3 100644
--- a/WebCore/rendering/RootInlineBox.h
+++ b/WebCore/rendering/RootInlineBox.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the line box implementation for KDE.
- *
* Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -38,31 +36,33 @@ class RootInlineBox : public InlineFlowBox {
public:
RootInlineBox(RenderObject* obj)
: InlineFlowBox(obj)
- , m_overflow(0)
, m_lineBreakObj(0)
, m_lineBreakPos(0)
+ , m_lineTop(0)
+ , m_lineBottom(0)
{
}
+ virtual void destroy(RenderArena*);
+
virtual bool isRootInlineBox() const { return true; }
- virtual void destroy(RenderArena*);
void detachEllipsisBox(RenderArena*);
- RootInlineBox* nextRootBox() { return static_cast<RootInlineBox*>(m_nextLine); }
- RootInlineBox* prevRootBox() { return static_cast<RootInlineBox*>(m_prevLine); }
+ RootInlineBox* nextRootBox() const { return static_cast<RootInlineBox*>(m_nextLine); }
+ RootInlineBox* prevRootBox() const { return static_cast<RootInlineBox*>(m_prevLine); }
virtual void adjustPosition(int dx, int dy);
- virtual int topOverflow() const { return m_overflow ? m_overflow->m_topOverflow : m_y; }
- virtual int bottomOverflow() const { return m_overflow ? m_overflow->m_bottomOverflow : m_y + m_renderer->style(m_firstLine)->font().height(); }
- virtual int leftOverflow() const { return m_overflow ? m_overflow->m_leftOverflow : m_x; }
- virtual int rightOverflow() const { return m_overflow ? m_overflow->m_rightOverflow : m_x + m_width; }
+ int lineTop() const { return m_lineTop; }
+ int lineBottom() const { return m_lineBottom; }
- virtual void setVerticalOverflowPositions(int top, int bottom);
- void setHorizontalOverflowPositions(int left, int right);
+ int selectionTop() const;
+ int selectionBottom() const { return lineBottom(); }
+ int selectionHeight() const { return max(0, selectionBottom() - selectionTop()); }
- virtual void setVerticalSelectionPositions(int top, int bottom);
+ virtual int verticallyAlignBoxes(int heightOfBlock);
+ void setLineTopBottomPositions(int top, int bottom);
virtual RenderLineBoxList* rendererLineBoxes() const;
@@ -116,68 +116,36 @@ public:
RenderBlock* block() const;
- int selectionTop();
- int selectionBottom() { return m_overflow ? m_overflow->m_selectionBottom : m_y + height(); }
- int selectionHeight() { return max(0, selectionBottom() - selectionTop()); }
-
InlineBox* closestLeafChildForXPos(int x, bool onlyEditableLeaves = false);
Vector<RenderBox*>& floats()
{
ASSERT(!isDirty());
- if (!m_overflow)
- m_overflow = new (m_renderer->renderArena()) Overflow(this);
- return m_overflow->floats;
+ if (!m_floats)
+ m_floats.set(new Vector<RenderBox*>());
+ return *m_floats;
}
- Vector<RenderBox*>* floatsPtr() { ASSERT(!isDirty()); return m_overflow ? &m_overflow->floats : 0; }
+ Vector<RenderBox*>* floatsPtr() { ASSERT(!isDirty()); return m_floats.get(); }
virtual void extractLineBoxFromRenderObject();
virtual void attachLineBoxToRenderObject();
virtual void removeLineBoxFromRenderObject();
protected:
- // Normally we are only as tall as the style on our block dictates, but we might have content
- // that spills out above the height of our font (e.g, a tall image), or something that extends further
- // below our line (e.g., a child whose font has a huge descent).
-
- // Allocated only when some of these fields have non-default values
- struct Overflow {
- Overflow(RootInlineBox* box)
- : m_topOverflow(box->m_y)
- , m_bottomOverflow(box->m_y + box->height())
- , m_leftOverflow(box->m_x)
- , m_rightOverflow(box->m_x + box->m_width)
- , m_selectionTop(box->m_y)
- , m_selectionBottom(box->m_y + box->height())
- {
- }
-
- void destroy(RenderArena*);
- void* operator new(size_t, RenderArena*) throw();
- void operator delete(void*, size_t);
-
- int m_topOverflow;
- int m_bottomOverflow;
- int m_leftOverflow;
- int m_rightOverflow;
- int m_selectionTop;
- int m_selectionBottom;
- // Floats hanging off the line are pushed into this vector during layout. It is only
- // good for as long as the line has not been marked dirty.
- Vector<RenderBox*> floats;
- private:
- void* operator new(size_t) throw();
- };
-
- Overflow* m_overflow;
-
// Where this line ended. The exact object and the position within that object are stored so that
// we can create an InlineIterator beginning just after the end of this line.
RenderObject* m_lineBreakObj;
unsigned m_lineBreakPos;
RefPtr<BidiContext> m_lineBreakContext;
+ int m_lineTop;
+ int m_lineBottom;
+
+ // Floats hanging off the line are pushed into this vector during layout. It is only
+ // good for as long as the line has not been marked dirty.
+ OwnPtr<Vector<RenderBox*> > m_floats;
+
// The height of the block at the end of this line. This is where the next line starts.
int m_blockHeight;
@@ -186,27 +154,10 @@ protected:
WTF::Unicode::Direction m_lineBreakBidiStatusLast : 5;
};
-inline void RootInlineBox::setHorizontalOverflowPositions(int left, int right)
-{
- if (!m_overflow) {
- if (left == m_x && right == m_x + m_width)
- return;
- m_overflow = new (m_renderer->renderArena()) Overflow(this);
- }
- m_overflow->m_leftOverflow = left;
- m_overflow->m_rightOverflow = right;
-}
-
-inline void RootInlineBox::setVerticalSelectionPositions(int top, int bottom)
+inline void RootInlineBox::setLineTopBottomPositions(int top, int bottom)
{
- if (!m_overflow) {
- const Font& font = m_renderer->style(m_firstLine)->font();
- if (top == m_y && bottom == m_y + font.height())
- return;
- m_overflow = new (m_renderer->renderArena()) Overflow(this);
- }
- m_overflow->m_selectionTop = top;
- m_overflow->m_selectionBottom = bottom;
+ m_lineTop = top;
+ m_lineBottom = bottom;
}
} // namespace WebCore
diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.cpp b/WebCore/rendering/SVGCharacterLayoutInfo.cpp
index 900e0ba..7e85672 100644
--- a/WebCore/rendering/SVGCharacterLayoutInfo.cpp
+++ b/WebCore/rendering/SVGCharacterLayoutInfo.cpp
@@ -512,9 +512,9 @@ bool SVGChar::isHidden() const
return pathData && pathData->hidden;
}
-TransformationMatrix SVGChar::characterTransform() const
+AffineTransform SVGChar::characterTransform() const
{
- TransformationMatrix ctm;
+ AffineTransform ctm;
// Rotate character around angle, and possibly scale.
ctm.translate(x, y);
diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.h b/WebCore/rendering/SVGCharacterLayoutInfo.h
index b5b4f3e..f80c79c 100644
--- a/WebCore/rendering/SVGCharacterLayoutInfo.h
+++ b/WebCore/rendering/SVGCharacterLayoutInfo.h
@@ -24,15 +24,15 @@
#define SVGCharacterLayoutInfo_h
#if ENABLE(SVG)
+#include "AffineTransform.h"
+#include "SVGRenderStyle.h"
+#include "SVGTextContentElement.h"
+
#include <wtf/Assertions.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
-#include <wtf/Vector.h>
-
-#include "TransformationMatrix.h"
#include <wtf/RefCounted.h>
-#include "SVGRenderStyle.h"
-#include "SVGTextContentElement.h"
+#include <wtf/Vector.h>
namespace WebCore {
@@ -234,7 +234,7 @@ struct SVGChar {
// Helper methods
bool isHidden() const;
- TransformationMatrix characterTransform() const;
+ AffineTransform characterTransform() const;
};
struct SVGInlineBoxCharacterRange {
@@ -275,7 +275,7 @@ struct SVGTextChunk {
// textLength & lengthAdjust support
float textLength;
ELengthAdjust lengthAdjust;
- TransformationMatrix ctm;
+ AffineTransform ctm;
// status flags
bool isVerticalText : 1;
@@ -291,15 +291,19 @@ struct SVGTextChunk {
struct SVGTextChunkWalkerBase {
virtual ~SVGTextChunkWalkerBase() { }
- virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
+ virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) = 0;
// Followings methods are only used for painting text chunks
virtual void start(InlineBox*) = 0;
virtual void end(InlineBox*) = 0;
+ virtual bool setupBackground(InlineBox*) = 0;
virtual bool setupFill(InlineBox*) = 0;
+ virtual bool setupFillSelection(InlineBox*) = 0;
virtual bool setupStroke(InlineBox*) = 0;
+ virtual bool setupStrokeSelection(InlineBox*) = 0;
+ virtual bool setupForeground(InlineBox*) = 0;
};
template<typename CallbackClass>
@@ -307,7 +311,7 @@ struct SVGTextChunkWalker : public SVGTextChunkWalkerBase {
public:
typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox,
int startOffset,
- const TransformationMatrix& chunkCtm,
+ const AffineTransform& chunkCtm,
const Vector<SVGChar>::iterator& start,
const Vector<SVGChar>::iterator& end);
@@ -315,27 +319,37 @@ public:
typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox* box);
typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox* box);
+ typedef bool (CallbackClass::*SVGTextChunkSetupBackgroundCallback)(InlineBox* box);
typedef bool (CallbackClass::*SVGTextChunkSetupFillCallback)(InlineBox* box);
typedef bool (CallbackClass::*SVGTextChunkSetupStrokeCallback)(InlineBox* box);
+ typedef bool (CallbackClass::*SVGTextChunkSetupForegroundCallback)(InlineBox* box);
SVGTextChunkWalker(CallbackClass* object,
SVGTextChunkWalkerCallback walker,
SVGTextChunkStartCallback start = 0,
SVGTextChunkEndCallback end = 0,
+ SVGTextChunkSetupBackgroundCallback background = 0,
SVGTextChunkSetupFillCallback fill = 0,
- SVGTextChunkSetupStrokeCallback stroke = 0)
+ SVGTextChunkSetupFillCallback fillSelection = 0,
+ SVGTextChunkSetupStrokeCallback stroke = 0,
+ SVGTextChunkSetupStrokeCallback strokeSelection = 0,
+ SVGTextChunkSetupForegroundCallback foreground = 0)
: m_object(object)
, m_walkerCallback(walker)
, m_startCallback(start)
, m_endCallback(end)
+ , m_setupBackgroundCallback(background)
, m_setupFillCallback(fill)
+ , m_setupFillSelectionCallback(fillSelection)
, m_setupStrokeCallback(stroke)
+ , m_setupStrokeSelectionCallback(strokeSelection)
+ , m_setupForegroundCallback(foreground)
{
ASSERT(object);
ASSERT(walker);
}
- virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
+ virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
{
(*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end);
@@ -358,6 +372,15 @@ public:
ASSERT_NOT_REACHED();
}
+ virtual bool setupBackground(InlineBox* box)
+ {
+ if (m_setupBackgroundCallback)
+ return (*m_object.*m_setupBackgroundCallback)(box);
+
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
virtual bool setupFill(InlineBox* box)
{
if (m_setupFillCallback)
@@ -367,6 +390,15 @@ public:
return false;
}
+ virtual bool setupFillSelection(InlineBox* box)
+ {
+ if (m_setupFillSelectionCallback)
+ return (*m_object.*m_setupFillSelectionCallback)(box);
+
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
virtual bool setupStroke(InlineBox* box)
{
if (m_setupStrokeCallback)
@@ -376,13 +408,35 @@ public:
return false;
}
+ virtual bool setupStrokeSelection(InlineBox* box)
+ {
+ if (m_setupStrokeSelectionCallback)
+ return (*m_object.*m_setupStrokeSelectionCallback)(box);
+
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ virtual bool setupForeground(InlineBox* box)
+ {
+ if (m_setupForegroundCallback)
+ return (*m_object.*m_setupForegroundCallback)(box);
+
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
private:
CallbackClass* m_object;
SVGTextChunkWalkerCallback m_walkerCallback;
SVGTextChunkStartCallback m_startCallback;
SVGTextChunkEndCallback m_endCallback;
+ SVGTextChunkSetupBackgroundCallback m_setupBackgroundCallback;
SVGTextChunkSetupFillCallback m_setupFillCallback;
+ SVGTextChunkSetupFillCallback m_setupFillSelectionCallback;
SVGTextChunkSetupStrokeCallback m_setupStrokeCallback;
+ SVGTextChunkSetupStrokeCallback m_setupStrokeSelectionCallback;
+ SVGTextChunkSetupForegroundCallback m_setupForegroundCallback;
};
struct SVGTextChunkLayoutInfo {
diff --git a/WebCore/rendering/SVGInlineTextBox.cpp b/WebCore/rendering/SVGInlineTextBox.cpp
index d0fa9ae..65aa5a1 100644
--- a/WebCore/rendering/SVGInlineTextBox.cpp
+++ b/WebCore/rendering/SVGInlineTextBox.cpp
@@ -1,6 +1,4 @@
/**
- * This file is part of the DOM implementation for KDE.
- *
* Copyright (C) 2007 Rob Buis <buis@kde.org>
* (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
*
@@ -110,9 +108,7 @@ FloatRect SVGInlineTextBox::calculateGlyphBoundaries(RenderStyle* style, int off
FloatRect glyphRect(x1, y1, x2 - x1, y2 - y1);
// Take per-character transformations into account
- TransformationMatrix ctm = svgChar.characterTransform();
- if (!ctm.isIdentity())
- glyphRect = ctm.mapRect(glyphRect);
+ glyphRect = svgChar.characterTransform().mapRect(glyphRect);
return glyphRect;
}
@@ -128,7 +124,7 @@ struct SVGInlineTextBoxClosestCharacterToPositionWalker {
{
}
- void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
+ void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
{
RenderStyle* style = textBox->textRenderer()->style();
@@ -195,7 +191,7 @@ struct SVGInlineTextBoxSelectionRectWalker {
{
}
- void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
+ void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
{
RenderStyle* style = textBox->textRenderer()->style();
@@ -326,7 +322,33 @@ IntRect SVGInlineTextBox::selectionRect(int, int, int startPos, int endPos)
return enclosingIntRect(walkerCallback.selectionRect());
}
-void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int tx, int ty, const SVGChar& svgChar, const UChar* chars, int length, SVGPaintServer* activePaintServer)
+bool SVGInlineTextBox::chunkSelectionStartEnd(const UChar* chunk, int chunkLength, int& selectionStart, int& selectionEnd)
+{
+ // NOTE: We ignore SVGInlineTextBox::m_start here because it is always 0.
+ // Curently SVG doesn't use HTML block-level layout, in which m_start would be set.
+
+ int chunkStart = chunk - textRenderer()->characters();
+ ASSERT(0 <= chunkStart);
+
+ selectionStartEnd(selectionStart, selectionEnd);
+ if (selectionEnd <= chunkStart)
+ return false;
+ if (chunkStart + chunkLength <= selectionStart)
+ return false;
+
+ // Map indices from view-global to chunk-local.
+ selectionStart -= chunkStart;
+ selectionEnd -= chunkStart;
+ // Then clamp with chunk range
+ if (selectionStart < 0)
+ selectionStart = 0;
+ if (chunkLength < selectionEnd)
+ selectionEnd = chunkLength;
+
+ return selectionStart < selectionEnd;
+}
+
+void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int tx, int ty, const SVGChar& svgChar, const UChar* chars, int length, SVGTextPaintInfo& textPaintInfo)
{
if (renderer()->style()->visibility() != VISIBLE || paintInfo.phase == PaintPhaseOutline)
return;
@@ -352,13 +374,13 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t
RenderStyle* styleToUse = text->style(isFirstLineStyle());
const Font& font = styleToUse->font();
- TransformationMatrix ctm = svgChar.characterTransform();
+ AffineTransform ctm = svgChar.characterTransform();
if (!ctm.isIdentity())
paintInfo.context->concatCTM(ctm);
// 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection
// and marked text.
- if (paintInfo.phase != PaintPhaseSelection && !isPrinting) {
+ if (paintInfo.phase != PaintPhaseSelection && !isPrinting && textPaintInfo.subphase == SVGTextPaintSubphaseBackground) {
#if PLATFORM(MAC)
// Custom highlighters go behind everything else.
if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
@@ -378,28 +400,52 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t
}
}
- // Set a text shadow if we have one.
- // FIXME: Support multiple shadow effects. Need more from the CG API before
- // we can do this.
- bool setShadow = false;
- if (styleToUse->textShadow()) {
- paintInfo.context->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y),
- styleToUse->textShadow()->blur, styleToUse->textShadow()->color);
- setShadow = true;
- }
+ bool isGlyphPhase = textPaintInfo.subphase == SVGTextPaintSubphaseGlyphFill || textPaintInfo.subphase == SVGTextPaintSubphaseGlyphStroke;
+ bool isSelectionGlyphPhase = textPaintInfo.subphase == SVGTextPaintSubphaseGlyphFillSelection || textPaintInfo.subphase == SVGTextPaintSubphaseGlyphStrokeSelection;
+
+ if (isGlyphPhase || isSelectionGlyphPhase) {
+ // Set a text shadow if we have one.
+ // FIXME: Support multiple shadow effects. Need more from the CG API before
+ // we can do this.
+ bool setShadow = false;
+ if (styleToUse->textShadow()) {
+ paintInfo.context->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y),
+ styleToUse->textShadow()->blur, styleToUse->textShadow()->color,
+ styleToUse->colorSpace());
+ setShadow = true;
+ }
- IntPoint origin((int) svgChar.x, (int) svgChar.y);
- TextRun run = svgTextRunForInlineTextBox(chars, length, styleToUse, this, svgChar.x);
+ IntPoint origin((int) svgChar.x, (int) svgChar.y);
+ TextRun run = svgTextRunForInlineTextBox(chars, length, styleToUse, this, svgChar.x);
#if ENABLE(SVG_FONTS)
- // SVG Fonts need access to the paint server used to draw the current text chunk.
- // They need to be able to call renderPath() on a SVGPaintServer object.
- run.setActivePaintServer(activePaintServer);
+ // SVG Fonts need access to the paint server used to draw the current text chunk.
+ // They need to be able to call renderPath() on a SVGPaintServer object.
+ ASSERT(textPaintInfo.activePaintServer);
+ run.setActivePaintServer(textPaintInfo.activePaintServer);
#endif
- paintInfo.context->drawText(font, run, origin);
+ int selectionStart = 0;
+ int selectionEnd = 0;
+ bool haveSelectedRange = haveSelection && chunkSelectionStartEnd(chars, length, selectionStart, selectionEnd);
+
+ if (isGlyphPhase) {
+ if (haveSelectedRange) {
+ paintInfo.context->drawText(font, run, origin, 0, selectionStart);
+ paintInfo.context->drawText(font, run, origin, selectionEnd, run.length());
+ } else
+ paintInfo.context->drawText(font, run, origin);
+ } else {
+ ASSERT(isSelectionGlyphPhase);
+ if (haveSelectedRange)
+ paintInfo.context->drawText(font, run, origin, selectionStart, selectionEnd);
+ }
+
+ if (setShadow)
+ paintInfo.context->clearShadow();
+ }
- if (paintInfo.phase != PaintPhaseSelection) {
+ if (paintInfo.phase != PaintPhaseSelection && textPaintInfo.subphase == SVGTextPaintSubphaseForeground) {
paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, false);
if (useCustomUnderlines) {
@@ -429,9 +475,6 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t
}
- if (setShadow)
- paintInfo.context->clearShadow();
-
if (!ctm.isIdentity())
paintInfo.context->concatCTM(ctm.inverse());
}
@@ -477,7 +520,7 @@ void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar
int adjust = startPos >= boxStartOffset ? boxStartOffset : 0;
p->drawHighlightForText(font, svgTextRunForInlineTextBox(textRenderer()->text()->characters() + start() + boxStartOffset, length, style, this, svgChar.x),
IntPoint((int) svgChar.x, (int) svgChar.y - font.ascent()),
- font.ascent() + font.descent(), color, startPos - adjust, endPos - adjust);
+ font.ascent() + font.descent(), color, style->colorSpace(), startPos - adjust, endPos - adjust);
p->restore();
}
@@ -521,7 +564,7 @@ void SVGInlineTextBox::paintDecoration(ETextDecoration decoration, GraphicsConte
context->save();
context->beginPath();
- TransformationMatrix ctm = svgChar.characterTransform();
+ AffineTransform ctm = svgChar.characterTransform();
if (!ctm.isIdentity())
context->concatCTM(ctm);
diff --git a/WebCore/rendering/SVGInlineTextBox.h b/WebCore/rendering/SVGInlineTextBox.h
index 76837cc..596fdf3 100644
--- a/WebCore/rendering/SVGInlineTextBox.h
+++ b/WebCore/rendering/SVGInlineTextBox.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the DOM implementation for KDE.
- *
* Copyright (C) 2007 Rob Buis <buis@kde.org>
* (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
*
@@ -34,6 +32,22 @@ namespace WebCore {
struct SVGChar;
struct SVGTextDecorationInfo;
+ enum SVGTextPaintSubphase {
+ SVGTextPaintSubphaseBackground,
+ SVGTextPaintSubphaseGlyphFill,
+ SVGTextPaintSubphaseGlyphFillSelection,
+ SVGTextPaintSubphaseGlyphStroke,
+ SVGTextPaintSubphaseGlyphStrokeSelection,
+ SVGTextPaintSubphaseForeground
+ };
+
+ struct SVGTextPaintInfo {
+ SVGTextPaintInfo() : activePaintServer(0), subphase(SVGTextPaintSubphaseBackground) {}
+
+ SVGPaintServer* activePaintServer;
+ SVGTextPaintSubphase subphase;
+ };
+
class SVGInlineTextBox : public InlineTextBox {
public:
SVGInlineTextBox(RenderObject* obj);
@@ -51,7 +65,7 @@ namespace WebCore {
virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos);
// SVGs custom paint text method
- void paintCharacters(RenderObject::PaintInfo&, int tx, int ty, const SVGChar&, const UChar* chars, int length, SVGPaintServer*);
+ void paintCharacters(RenderObject::PaintInfo&, int tx, int ty, const SVGChar&, const UChar* chars, int length, SVGTextPaintInfo&);
// SVGs custom paint selection method
void paintSelection(int boxStartOffset, const SVGChar&, const UChar*, int length, GraphicsContext*, RenderStyle*, const Font&);
@@ -71,6 +85,7 @@ namespace WebCore {
private:
friend class RenderSVGInlineText;
bool svgCharacterHitsPosition(int x, int y, int& offset) const;
+ bool chunkSelectionStartEnd(const UChar* chunk, int chunkLength, int& selectionStart, int& selectionEnd);
int m_height;
};
diff --git a/WebCore/rendering/SVGMarkerData.h b/WebCore/rendering/SVGMarkerData.h
new file mode 100644
index 0000000..5ff2993
--- /dev/null
+++ b/WebCore/rendering/SVGMarkerData.h
@@ -0,0 +1,134 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. 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
+ aint 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 SVGMarkerData_h
+#define SVGMarkerData_h
+
+#if ENABLE(SVG)
+#include "FloatConversion.h"
+#include "Path.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+class SVGResourceMarker;
+
+class SVGMarkerData {
+public:
+ enum Type {
+ Unknown = 0,
+ Start,
+ Mid,
+ End
+ };
+
+ SVGMarkerData(const Type& type = Unknown, SVGResourceMarker* marker = 0)
+ : m_type(type)
+ , m_marker(marker)
+ {
+ }
+
+ FloatPoint origin() const { return m_origin; }
+ SVGResourceMarker* marker() const { return m_marker; }
+
+ float currentAngle() const
+ {
+ FloatSize inslopeChange = m_inslopePoints[1] - m_inslopePoints[0];
+ FloatSize outslopeChange = m_outslopePoints[1] - m_outslopePoints[0];
+
+ double inslope = rad2deg(atan2(inslopeChange.height(), inslopeChange.width()));
+ double outslope = rad2deg(atan2(outslopeChange.height(), outslopeChange.width()));
+
+ double angle = 0;
+ switch (m_type) {
+ case Start:
+ angle = outslope;
+ break;
+ case Mid:
+ angle = (inslope + outslope) / 2;
+ break;
+ case End:
+ angle = inslope;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ return narrowPrecisionToFloat(angle);
+ }
+
+ void updateTypeAndMarker(const Type& type, SVGResourceMarker* marker)
+ {
+ m_type = type;
+ m_marker = marker;
+ }
+
+ void updateOutslope(const FloatPoint& point)
+ {
+ m_outslopePoints[0] = m_origin;
+ m_outslopePoints[1] = point;
+ }
+
+ void updateMarkerDataForPathElement(const PathElement* element)
+ {
+ FloatPoint* points = element->points;
+
+ switch (element->type) {
+ case PathElementAddQuadCurveToPoint:
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>)
+ m_origin = points[1];
+ break;
+ case PathElementAddCurveToPoint:
+ m_inslopePoints[0] = points[1];
+ m_inslopePoints[1] = points[2];
+ m_origin = points[2];
+ break;
+ case PathElementMoveToPoint:
+ m_subpathStart = points[0];
+ case PathElementAddLineToPoint:
+ updateInslope(points[0]);
+ m_origin = points[0];
+ break;
+ case PathElementCloseSubpath:
+ updateInslope(points[0]);
+ m_origin = m_subpathStart;
+ m_subpathStart = FloatPoint();
+ }
+ }
+
+private:
+ void updateInslope(const FloatPoint& point)
+ {
+ m_inslopePoints[0] = m_origin;
+ m_inslopePoints[1] = point;
+ }
+
+ Type m_type;
+ SVGResourceMarker* m_marker;
+ FloatPoint m_origin;
+ FloatPoint m_subpathStart;
+ FloatPoint m_inslopePoints[2];
+ FloatPoint m_outslopePoints[2];
+};
+
+}
+
+#endif // ENABLE(SVG)
+#endif // SVGMarkerData_h
diff --git a/WebCore/rendering/SVGMarkerLayoutInfo.cpp b/WebCore/rendering/SVGMarkerLayoutInfo.cpp
new file mode 100644
index 0000000..3fe513f
--- /dev/null
+++ b/WebCore/rendering/SVGMarkerLayoutInfo.cpp
@@ -0,0 +1,124 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 2008 Rob Buis <buis@kde.org>
+ 2005, 2007 Eric Seidel <eric@webkit.org>
+ 2009 Google, Inc.
+
+ 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
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGMarkerLayoutInfo.h"
+
+#include "RenderSVGViewportContainer.h"
+#include "SVGResourceMarker.h"
+
+namespace WebCore {
+
+SVGMarkerLayoutInfo::SVGMarkerLayoutInfo()
+ : m_midMarker(0)
+ , m_elementIndex(0)
+ , m_strokeWidth(0)
+{
+}
+
+SVGMarkerLayoutInfo::~SVGMarkerLayoutInfo()
+{
+}
+
+static inline void processStartAndMidMarkers(void* infoPtr, const PathElement* element)
+{
+ SVGMarkerLayoutInfo& info = *reinterpret_cast<SVGMarkerLayoutInfo*>(infoPtr);
+ SVGMarkerData& markerData = info.markerData();
+ int& elementIndex = info.elementIndex();
+
+ // First update the outslope for the previous element
+ markerData.updateOutslope(element->points[0]);
+
+ // Draw the marker for the previous element
+ SVGResourceMarker* marker = markerData.marker();
+ if (elementIndex > 0 && marker)
+ info.addLayoutedMarker(marker, markerData.origin(), markerData.currentAngle());
+
+ // Update our marker data for this element
+ markerData.updateMarkerDataForPathElement(element);
+
+ // After drawing the start marker, switch to drawing mid markers
+ if (elementIndex == 1)
+ markerData.updateTypeAndMarker(SVGMarkerData::Mid, info.midMarker());
+
+ ++elementIndex;
+}
+
+FloatRect SVGMarkerLayoutInfo::calculateBoundaries(SVGResourceMarker* startMarker, SVGResourceMarker* midMarker, SVGResourceMarker* endMarker, float strokeWidth, const Path& path)
+{
+ m_layout.clear();
+ m_midMarker = midMarker;
+ m_strokeWidth = strokeWidth;
+ m_elementIndex = 0;
+ m_markerData = SVGMarkerData(SVGMarkerData::Start, startMarker);
+ path.apply(this, processStartAndMidMarkers);
+
+ if (endMarker) {
+ m_markerData.updateTypeAndMarker(SVGMarkerData::End, endMarker);
+ addLayoutedMarker(endMarker, m_markerData.origin(), m_markerData.currentAngle());
+ }
+
+ if (m_layout.isEmpty())
+ return FloatRect();
+
+ Vector<MarkerLayout>::iterator it = m_layout.begin();
+ Vector<MarkerLayout>::iterator end = m_layout.end();
+
+ FloatRect bounds;
+ for (; it != end; ++it) {
+ MarkerLayout& layout = *it;
+
+ RenderSVGViewportContainer* markerContent = layout.marker->renderer();
+ ASSERT(markerContent);
+
+ bounds.unite(markerContent->markerBoundaries(layout.matrix));
+ }
+
+ return bounds;
+}
+
+void SVGMarkerLayoutInfo::drawMarkers(RenderObject::PaintInfo& paintInfo)
+{
+ if (m_layout.isEmpty())
+ return;
+
+ Vector<MarkerLayout>::iterator it = m_layout.begin();
+ Vector<MarkerLayout>::iterator end = m_layout.end();
+
+ for (; it != end; ++it) {
+ MarkerLayout& layout = *it;
+ layout.marker->draw(paintInfo, layout.matrix);
+ }
+}
+
+void SVGMarkerLayoutInfo::addLayoutedMarker(SVGResourceMarker* marker, const FloatPoint& origin, float angle)
+{
+ ASSERT(marker);
+ m_layout.append(MarkerLayout(marker, marker->markerTransformation(origin, angle, m_strokeWidth)));
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/SVGMarkerLayoutInfo.h b/WebCore/rendering/SVGMarkerLayoutInfo.h
new file mode 100644
index 0000000..517c993
--- /dev/null
+++ b/WebCore/rendering/SVGMarkerLayoutInfo.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. 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
+ aint 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 SVGMarkerLayoutInfo_h
+#define SVGMarkerLayoutInfo_h
+
+#if ENABLE(SVG)
+#include "RenderObject.h"
+#include "SVGMarkerData.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class Path;
+class SVGResourceMarker;
+
+struct MarkerLayout {
+ MarkerLayout(SVGResourceMarker* markerObj = 0, AffineTransform matrixObj = AffineTransform())
+ : marker(markerObj)
+ , matrix(matrixObj)
+ {
+ ASSERT(marker);
+ }
+
+ SVGResourceMarker* marker;
+ AffineTransform matrix;
+};
+
+class SVGMarkerLayoutInfo : public Noncopyable {
+public:
+ SVGMarkerLayoutInfo();
+ ~SVGMarkerLayoutInfo();
+
+ FloatRect calculateBoundaries(SVGResourceMarker* startMarker, SVGResourceMarker* midMarker, SVGResourceMarker* endMarker, float strokeWidth, const Path&);
+ void drawMarkers(RenderObject::PaintInfo&);
+
+ // Used by static inline helper functions in SVGMarkerLayoutInfo.cpp
+ SVGMarkerData& markerData() { return m_markerData; }
+ SVGResourceMarker* midMarker() const { return m_midMarker; }
+ int& elementIndex() { return m_elementIndex; }
+ void addLayoutedMarker(SVGResourceMarker*, const FloatPoint& origin, float angle);
+
+private:
+ SVGResourceMarker* m_midMarker;
+
+ // Used while layouting markers
+ int m_elementIndex;
+ SVGMarkerData m_markerData;
+ float m_strokeWidth;
+
+ // Holds the final computed result
+ Vector<MarkerLayout> m_layout;
+};
+
+}
+
+#endif // ENABLE(SVG)
+#endif // SVGMarkerLayoutInfo_h
diff --git a/WebCore/rendering/SVGRenderSupport.cpp b/WebCore/rendering/SVGRenderSupport.cpp
index fb6866f..079a36e 100644
--- a/WebCore/rendering/SVGRenderSupport.cpp
+++ b/WebCore/rendering/SVGRenderSupport.cpp
@@ -2,7 +2,8 @@
* Copyright (C) 2007, 2008 Rob Buis <buis@kde.org>
* (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
* (C) 2007 Eric Seidel <eric@webkit.org>
- * Copyright (C) 2009 Google, Inc. All rights reserved.
+ * (C) 2009 Google, Inc. All rights reserved.
+ * (C) 2009 Dirk Schulze <krit@webkit.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -26,6 +27,7 @@
#if ENABLE(SVG)
#include "SVGRenderSupport.h"
+#include "AffineTransform.h"
#include "ImageBuffer.h"
#include "RenderObject.h"
#include "RenderSVGContainer.h"
@@ -36,11 +38,14 @@
#include "SVGStyledElement.h"
#include "SVGURIReference.h"
#include "TransformState.h"
-#include "TransformationMatrix.h"
#include <wtf/UnusedParam.h>
namespace WebCore {
+SVGRenderBase::~SVGRenderBase()
+{
+}
+
IntRect SVGRenderBase::clippedOverflowRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer)
{
// Return early for any cases where we don't actually paint
@@ -56,6 +61,8 @@ IntRect SVGRenderBase::clippedOverflowRectForRepaint(RenderObject* object, Rende
void SVGRenderBase::computeRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
{
+ object->style()->svgStyle()->inflateForShadow(repaintRect);
+
// Translate to coords in our parent renderer, and then call computeRectForRepaint on our parent
repaintRect = object->localToParentTransform().mapRect(repaintRect);
object->parent()->computeRectForRepaint(repaintContainer, repaintRect, fixed);
@@ -64,12 +71,12 @@ void SVGRenderBase::computeRectForRepaint(RenderObject* object, RenderBoxModelOb
void SVGRenderBase::mapLocalToContainer(const RenderObject* object, RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState)
{
ASSERT(!fixed); // We should have no fixed content in the SVG rendering tree.
- ASSERT(useTransforms); // mapping a point through SVG w/o respecting trasnforms is useless.
+ ASSERT(useTransforms); // Mapping a point through SVG w/o respecting transforms is useless.
transformState.applyTransform(object->localToParentTransform());
object->parent()->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
}
-void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter)
+bool SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& repaintRect, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter)
{
#if !ENABLE(FILTERS)
UNUSED_PARAM(filter);
@@ -90,10 +97,16 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject
// Setup transparency layers before setting up filters!
float opacity = style->opacity();
if (opacity < 1.0f) {
- paintInfo.context->clip(enclosingIntRect(boundingBox));
+ paintInfo.context->clip(repaintRect);
paintInfo.context->beginTransparencyLayer(opacity);
}
+ if (ShadowData* shadow = svgStyle->shadow()) {
+ paintInfo.context->clip(repaintRect);
+ paintInfo.context->setShadow(IntSize(shadow->x, shadow->y), shadow->blur, shadow->color, style->colorSpace());
+ paintInfo.context->beginTransparencyLayer(1.0f);
+ }
+
#if ENABLE(FILTERS)
AtomicString filterId(svgStyle->filter());
#endif
@@ -104,7 +117,7 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject
Document* document = object->document();
#if ENABLE(FILTERS)
- SVGResourceFilter* newFilter = getFilterById(document, filterId);
+ SVGResourceFilter* newFilter = getFilterById(document, filterId, object);
if (newFilter == rootFilter) {
// Catch <text filter="url(#foo)">Test<tspan filter="url(#foo)">123</tspan></text>.
// The filter is NOT meant to be applied twice in that case!
@@ -114,28 +127,32 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject
filter = newFilter;
#endif
- SVGResourceClipper* clipper = getClipperById(document, clipperId);
- SVGResourceMasker* masker = getMaskerById(document, maskerId);
+ SVGResourceClipper* clipper = getClipperById(document, clipperId, object);
+ SVGResourceMasker* masker = getMaskerById(document, maskerId, object);
+
+ if (masker) {
+ masker->addClient(styledElement);
+ if (!masker->applyMask(paintInfo.context, object))
+ return false;
+ } else if (!maskerId.isEmpty())
+ svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);
+
+ if (clipper) {
+ clipper->addClient(styledElement);
+ clipper->applyClip(paintInfo.context, object->objectBoundingBox());
+ } else if (!clipperId.isEmpty())
+ svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);
#if ENABLE(FILTERS)
if (filter) {
filter->addClient(styledElement);
- filter->prepareFilter(paintInfo.context, object);
+ if (!filter->prepareFilter(paintInfo.context, object))
+ return false;
} else if (!filterId.isEmpty())
svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement);
#endif
- if (clipper) {
- clipper->addClient(styledElement);
- clipper->applyClip(paintInfo.context, boundingBox);
- } else if (!clipperId.isEmpty())
- svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);
-
- if (masker) {
- masker->addClient(styledElement);
- masker->applyMask(paintInfo.context, boundingBox);
- } else if (!maskerId.isEmpty())
- svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);
+ return true;
}
void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, SVGResourceFilter*& filter, GraphicsContext* savedContext)
@@ -160,6 +177,11 @@ void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::P
float opacity = style->opacity();
if (opacity < 1.0f)
paintInfo.context->endTransparencyLayer();
+
+ // This needs to be done separately from opacity, because if both properties are set,
+ // then the transparency layers are nested.
+ if (style->svgStyle()->shadow())
+ paintInfo.context->endTransparencyLayer();
}
void renderSubtreeToImage(ImageBuffer* image, RenderObject* item)
@@ -215,19 +237,74 @@ FloatRect SVGRenderBase::computeContainerBoundingBox(const RenderObject* contain
return boundingBox;
}
-FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object)
+void SVGRenderBase::layoutChildren(RenderObject* start, bool selfNeedsLayout)
+{
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
+ // Only force our kids to layout if we're being asked to relayout as a result of a parent changing
+ // FIXME: We should be able to skip relayout of non-relative kids when only bounds size has changed
+ // that's a possible future optimization using LayoutState
+ // http://bugs.webkit.org/show_bug.cgi?id=15391
+ bool needsLayout = selfNeedsLayout;
+ if (!needsLayout) {
+ if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) {
+ if (element->isStyled())
+ needsLayout = static_cast<SVGStyledElement*>(element)->hasRelativeValues();
+ }
+ }
+
+ if (needsLayout)
+ child->setNeedsLayout(true, false);
+
+ child->layoutIfNeeded();
+ ASSERT(!child->needsLayout());
+ }
+}
+
+bool SVGRenderBase::isOverflowHidden(const RenderObject* object)
+{
+ // SVG doesn't support independent x/y overflow
+ ASSERT(object->style()->overflowX() == object->style()->overflowY());
+
+ // OSCROLL is never set for SVG - see CSSStyleSelector::adjustRenderStyle
+ ASSERT(object->style()->overflowX() != OSCROLL);
+
+ // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size.
+ ASSERT(!object->isRoot());
+
+ return object->style()->overflowX() == OHIDDEN;
+}
+
+FloatRect SVGRenderBase::filterBoundingBoxForRenderer(const RenderObject* object) const
{
#if ENABLE(FILTERS)
- SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter());
+ SVGResourceFilter* filter = getFilterById(object->document(), object->style()->svgStyle()->filter(), object);
if (filter)
- return filter->filterBBoxForItemBBox(object->objectBoundingBox());
+ return filter->filterBoundingBox(object->objectBoundingBox());
#else
UNUSED_PARAM(object);
#endif
return FloatRect();
}
-void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const TransformationMatrix& localToAncestorTransform)
+FloatRect SVGRenderBase::clipperBoundingBoxForRenderer(const RenderObject* object) const
+{
+ SVGResourceClipper* clipper = getClipperById(object->document(), object->style()->svgStyle()->clipPath(), object);
+ if (clipper)
+ return clipper->clipperBoundingBox(object->objectBoundingBox());
+
+ return FloatRect();
+}
+
+FloatRect SVGRenderBase::maskerBoundingBoxForRenderer(const RenderObject* object) const
+{
+ SVGResourceMasker* masker = getMaskerById(object->document(), object->style()->svgStyle()->maskElement(), object);
+ if (masker)
+ return masker->maskerBoundingBox(object->objectBoundingBox());
+
+ return FloatRect();
+}
+
+void applyTransformToPaintInfo(RenderObject::PaintInfo& paintInfo, const AffineTransform& localToAncestorTransform)
{
if (localToAncestorTransform.isIdentity())
return;
diff --git a/WebCore/rendering/SVGRenderSupport.h b/WebCore/rendering/SVGRenderSupport.h
index da2bf59..cf75365 100644
--- a/WebCore/rendering/SVGRenderSupport.h
+++ b/WebCore/rendering/SVGRenderSupport.h
@@ -38,12 +38,30 @@ namespace WebCore {
// all SVG renderers inherit from RenderSVGModelObject.
class SVGRenderBase {
public:
+ virtual ~SVGRenderBase();
+
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
+
// FIXME: These are only public for SVGRootInlineBox.
// It's unclear if these should be exposed or not. SVGRootInlineBox may
// pass the wrong RenderObject* and boundingBox to these functions.
- static void prepareToRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, const FloatRect& boundingBox, SVGResourceFilter*&, SVGResourceFilter* rootFilter = 0);
+ static bool prepareToRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, const FloatRect& boundingBox, SVGResourceFilter*&, SVGResourceFilter* rootFilter = 0);
static void finishRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, SVGResourceFilter*&, GraphicsContext* savedContext);
+ // Layout all children of the passed render object
+ static void layoutChildren(RenderObject*, bool selfNeedsLayout);
+
+ // Helper function determining wheter overflow is hidden
+ static bool isOverflowHidden(const RenderObject*);
+
+ virtual FloatRect strokeBoundingBox() const { return FloatRect(); }
+ virtual FloatRect markerBoundingBox() const { return FloatRect(); }
+
+ // returns the bounding box of filter, clipper, marker and masker (or the empty rect if no filter) in local coordinates
+ FloatRect filterBoundingBoxForRenderer(const RenderObject*) const;
+ FloatRect clipperBoundingBoxForRenderer(const RenderObject*) const;
+ FloatRect maskerBoundingBoxForRenderer(const RenderObject*) const;
+
protected:
static IntRect clippedOverflowRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer);
static void computeRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer, IntRect&, bool fixed);
@@ -53,14 +71,11 @@ namespace WebCore {
// Used to share the "walk all the children" logic between objectBoundingBox
// and repaintRectInLocalCoordinates in RenderSVGRoot and RenderSVGContainer
static FloatRect computeContainerBoundingBox(const RenderObject* container, bool includeAllPaintedContent);
-
- // returns the filter bounding box (or the empty rect if no filter) in local coordinates
- static FloatRect filterBoundingBoxForRenderer(const RenderObject*);
};
// FIXME: This should move to RenderObject or PaintInfo
// Used for transforming the GraphicsContext and damage rect before passing PaintInfo to child renderers.
- void applyTransformToPaintInfo(RenderObject::PaintInfo&, const TransformationMatrix& localToChildTransform);
+ void applyTransformToPaintInfo(RenderObject::PaintInfo&, const AffineTransform& localToChildTransform);
// This offers a way to render parts of a WebKit rendering tree into a ImageBuffer.
void renderSubtreeToImage(ImageBuffer*, RenderObject*);
diff --git a/WebCore/rendering/SVGRenderTreeAsText.cpp b/WebCore/rendering/SVGRenderTreeAsText.cpp
index 28e506a..aff718f 100644
--- a/WebCore/rendering/SVGRenderTreeAsText.cpp
+++ b/WebCore/rendering/SVGRenderTreeAsText.cpp
@@ -179,7 +179,7 @@ TextStream& operator<<(TextStream& ts, const FloatSize& s)
return ts;
}
-TextStream& operator<<(TextStream& ts, const TransformationMatrix& transform)
+TextStream& operator<<(TextStream& ts, const AffineTransform& transform)
{
if (transform.isIdentity())
ts << "identity";
@@ -310,7 +310,7 @@ static void writeStyle(TextStream& ts, const RenderObject& object)
static TextStream& writePositionAndStyle(TextStream& ts, const RenderObject& object)
{
- ts << " " << object.absoluteTransform().mapRect(object.repaintRectInLocalCoordinates());
+ ts << " " << const_cast<RenderObject&>(object).absoluteClippedOverflowRect();
writeStyle(ts, object);
return ts;
}
@@ -521,11 +521,11 @@ void writeRenderResources(TextStream& ts, Node* parent)
continue;
SVGStyledElement* styled = static_cast<SVGStyledElement*>(svgElement);
- RefPtr<SVGResource> resource(styled->canvasResource());
+ RefPtr<SVGResource> resource(styled->canvasResource(node->renderer()));
if (!resource)
continue;
- String elementId = svgElement->getAttribute(HTMLNames::idAttr);
+ String elementId = svgElement->getAttribute(svgElement->idAttributeName());
// FIXME: These names are lies!
if (resource->isPaintServer()) {
RefPtr<SVGPaintServer> paintServer = WTF::static_pointer_cast<SVGPaintServer>(resource);
diff --git a/WebCore/rendering/SVGRenderTreeAsText.h b/WebCore/rendering/SVGRenderTreeAsText.h
index bee4f36..13fc475 100644
--- a/WebCore/rendering/SVGRenderTreeAsText.h
+++ b/WebCore/rendering/SVGRenderTreeAsText.h
@@ -45,7 +45,7 @@ namespace WebCore {
class RenderPath;
class RenderSVGRoot;
class RenderText;
- class TransformationMatrix;
+ class AffineTransform;
// functions used by the main RenderTreeAsText code
void write(TextStream&, const RenderPath&, int indent);
@@ -58,7 +58,7 @@ void writeSVGText(TextStream&, const RenderBlock&, int indent);
void writeRenderResources(TextStream&, Node* parent);
// helper operators defined used in various classes to dump the render tree.
-TextStream& operator<<(TextStream&, const TransformationMatrix&);
+TextStream& operator<<(TextStream&, const AffineTransform&);
TextStream& operator<<(TextStream&, const IntRect&);
TextStream& operator<<(TextStream&, const Color&);
TextStream& operator<<(TextStream&, const IntPoint&);
diff --git a/WebCore/rendering/SVGRootInlineBox.cpp b/WebCore/rendering/SVGRootInlineBox.cpp
index 8319e7c..d0dd4a8 100644
--- a/WebCore/rendering/SVGRootInlineBox.cpp
+++ b/WebCore/rendering/SVGRootInlineBox.cpp
@@ -363,6 +363,13 @@ struct SVGRootInlineBoxPaintWalker {
ASSERT(!m_chunkStarted);
}
+ bool mayHaveSelection(InlineBox* box) const
+ {
+ int selectionStart = 0, selectionEnd = 0;
+ box->renderer()->selectionStartEnd(selectionStart, selectionEnd);
+ return selectionStart < selectionEnd;
+ }
+
void teardownFillPaintServer()
{
if (!m_fillPaintServer)
@@ -429,6 +436,12 @@ struct SVGRootInlineBoxPaintWalker {
m_paintInfo.rect = m_savedInfo.rect;
}
+ bool chunkSetupBackgroundCallback(InlineBox* /*box*/)
+ {
+ m_textPaintInfo.subphase = SVGTextPaintSubphaseBackground;
+ return true;
+ }
+
bool chunkSetupFillCallback(InlineBox* box)
{
InlineFlowBox* flowBox = box->parent();
@@ -440,6 +453,7 @@ struct SVGRootInlineBoxPaintWalker {
ASSERT(!m_strokePaintServer);
teardownFillPaintServer();
+ m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphFill;
m_fillPaintServer = SVGPaintServer::fillPaintServer(object->style(), object);
if (m_fillPaintServer) {
m_fillPaintServer->setup(m_paintInfo.context, object, ApplyToFillTargetType, true);
@@ -450,6 +464,34 @@ struct SVGRootInlineBoxPaintWalker {
return false;
}
+ bool chunkSetupFillSelectionCallback(InlineBox* box)
+ {
+ InlineFlowBox* flowBox = box->parent();
+
+ // Setup fill paint server
+ RenderObject* object = flowBox->renderer();
+ ASSERT(object);
+ RenderStyle* style = object->getCachedPseudoStyle(SELECTION);
+ if (!style)
+ style = object->style();
+
+ ASSERT(!m_strokePaintServer);
+ teardownFillPaintServer();
+
+ if (!mayHaveSelection(box))
+ return false;
+
+ m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphFillSelection;
+ m_fillPaintServer = SVGPaintServer::fillPaintServer(style, object);
+ if (m_fillPaintServer) {
+ m_fillPaintServer->setup(m_paintInfo.context, object, style, ApplyToFillTargetType, true);
+ m_fillPaintServerObject = object;
+ return true;
+ }
+
+ return false;
+ }
+
bool chunkSetupStrokeCallback(InlineBox* box)
{
InlineFlowBox* flowBox = box->parent();
@@ -462,6 +504,7 @@ struct SVGRootInlineBoxPaintWalker {
teardownFillPaintServer();
teardownStrokePaintServer();
+ m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphStroke;
m_strokePaintServer = SVGPaintServer::strokePaintServer(object->style(), object);
if (m_strokePaintServer) {
@@ -473,7 +516,64 @@ struct SVGRootInlineBoxPaintWalker {
return false;
}
- void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
+ bool chunkSetupStrokeSelectionCallback(InlineBox* box)
+ {
+ InlineFlowBox* flowBox = box->parent();
+
+ // Setup stroke paint server
+ RenderObject* object = flowBox->renderer();
+ ASSERT(object);
+ RenderStyle* style = object->getCachedPseudoStyle(SELECTION);
+ if (!style)
+ style = object->style();
+
+ // If we're both stroked & filled, teardown fill paint server before stroking.
+ teardownFillPaintServer();
+ teardownStrokePaintServer();
+
+ if (!mayHaveSelection(box))
+ return false;
+
+ m_textPaintInfo.subphase = SVGTextPaintSubphaseGlyphStrokeSelection;
+ m_strokePaintServer = SVGPaintServer::strokePaintServer(style, object);
+ if (m_strokePaintServer) {
+ m_strokePaintServer->setup(m_paintInfo.context, object, style, ApplyToStrokeTargetType, true);
+ m_strokePaintServerObject = object;
+ return true;
+ }
+
+ return false;
+ }
+
+ bool chunkSetupForegroundCallback(InlineBox* /*box*/)
+ {
+ teardownFillPaintServer();
+ teardownStrokePaintServer();
+
+ m_textPaintInfo.subphase = SVGTextPaintSubphaseForeground;
+
+ return true;
+ }
+
+ SVGPaintServer* activePaintServer() const
+ {
+ switch (m_textPaintInfo.subphase) {
+ case SVGTextPaintSubphaseGlyphFill:
+ case SVGTextPaintSubphaseGlyphFillSelection:
+ ASSERT(m_fillPaintServer);
+ return m_fillPaintServer;
+ case SVGTextPaintSubphaseGlyphStroke:
+ case SVGTextPaintSubphaseGlyphStrokeSelection:
+ ASSERT(m_strokePaintServer);
+ return m_strokePaintServer;
+ case SVGTextPaintSubphaseBackground:
+ case SVGTextPaintSubphaseForeground:
+ default:
+ return 0;
+ }
+ }
+
+ void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
{
RenderText* text = textBox->textRenderer();
@@ -523,12 +623,8 @@ struct SVGRootInlineBoxPaintWalker {
textBox->paintDecoration(OVERLINE, m_paintInfo.context, decorationOrigin.x(), decorationOrigin.y(), textWidth, *it, info);
// Paint text
- SVGPaintServer* activePaintServer = m_fillPaintServer;
- if (!activePaintServer)
- activePaintServer = m_strokePaintServer;
-
- ASSERT(activePaintServer);
- textBox->paintCharacters(m_paintInfo, m_tx, m_ty, *it, stringStart, stringLength, activePaintServer);
+ m_textPaintInfo.activePaintServer = activePaintServer();
+ textBox->paintCharacters(m_paintInfo, m_tx, m_ty, *it, stringStart, stringLength, m_textPaintInfo);
// Paint decorations, that have to be drawn afterwards
if (textDecorations & LINE_THROUGH && textWidth != 0.0f)
@@ -561,6 +657,8 @@ private:
int m_tx;
int m_ty;
+
+ SVGTextPaintInfo m_textPaintInfo;
};
void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
@@ -575,18 +673,22 @@ void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
FloatRect boundingBox(tx + x(), ty + y(), width(), height());
// Initialize text rendering
- SVGRenderBase::prepareToRenderSVGContent(renderer(), paintInfo, boundingBox, filter);
-
- // Render text, chunk-by-chunk
- SVGRootInlineBoxPaintWalker walkerCallback(this, filter, paintInfo, tx, ty);
- SVGTextChunkWalker<SVGRootInlineBoxPaintWalker> walker(&walkerCallback,
- &SVGRootInlineBoxPaintWalker::chunkPortionCallback,
- &SVGRootInlineBoxPaintWalker::chunkStartCallback,
- &SVGRootInlineBoxPaintWalker::chunkEndCallback,
- &SVGRootInlineBoxPaintWalker::chunkSetupFillCallback,
- &SVGRootInlineBoxPaintWalker::chunkSetupStrokeCallback);
-
- walkTextChunks(&walker);
+ if (SVGRenderBase::prepareToRenderSVGContent(renderer(), paintInfo, boundingBox, filter)) {
+ // Render text, chunk-by-chunk
+ SVGRootInlineBoxPaintWalker walkerCallback(this, filter, paintInfo, tx, ty);
+ SVGTextChunkWalker<SVGRootInlineBoxPaintWalker> walker(&walkerCallback,
+ &SVGRootInlineBoxPaintWalker::chunkPortionCallback,
+ &SVGRootInlineBoxPaintWalker::chunkStartCallback,
+ &SVGRootInlineBoxPaintWalker::chunkEndCallback,
+ &SVGRootInlineBoxPaintWalker::chunkSetupBackgroundCallback,
+ &SVGRootInlineBoxPaintWalker::chunkSetupFillCallback,
+ &SVGRootInlineBoxPaintWalker::chunkSetupFillSelectionCallback,
+ &SVGRootInlineBoxPaintWalker::chunkSetupStrokeCallback,
+ &SVGRootInlineBoxPaintWalker::chunkSetupStrokeSelectionCallback,
+ &SVGRootInlineBoxPaintWalker::chunkSetupForegroundCallback);
+
+ walkTextChunks(&walker);
+ }
// Finalize text rendering
SVGRenderBase::finishRenderSVGContent(renderer(), paintInfo, filter, savedInfo.context);
@@ -831,9 +933,8 @@ static void applyTextLengthCorrectionToTextChunk(SVGTextChunk& chunk)
SVGChar& firstChar = *(chunk.start);
// Assure we apply the chunk scaling in the right origin
- TransformationMatrix newChunkCtm;
- newChunkCtm.translate(firstChar.x, firstChar.y);
- newChunkCtm = chunk.ctm * newChunkCtm;
+ AffineTransform newChunkCtm(chunk.ctm);
+ newChunkCtm.translateRight(firstChar.x, firstChar.y);
newChunkCtm.translate(-firstChar.x, -firstChar.y);
chunk.ctm = newChunkCtm;
@@ -944,7 +1045,6 @@ void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacter
Vector<SVGTextChunk>::iterator it = tempChunks.begin();
Vector<SVGTextChunk>::iterator end = tempChunks.end();
- TransformationMatrix ctm;
float computedLength = 0.0f;
for (; it != end; ++it) {
@@ -1087,8 +1187,8 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>::
start->setWidth(highX - lowX);
static_cast<SVGRootInlineBox*>(start)->setHeight(highY - lowY);
- start->setVerticalOverflowPositions(top, bottom);
- start->setVerticalSelectionPositions(top, bottom);
+ start->computeVerticalOverflow(top, bottom, true);
+ static_cast<SVGRootInlineBox*>(start)->setLineTopBottomPositions(top, bottom);
}
}
@@ -1388,7 +1488,7 @@ void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox*
} else
ASSERT(!info.chunk.boxes.isEmpty());
- // Walk string to find out new chunk positions, if existant
+ // Walk string to find out new chunk positions, if existent
for (unsigned i = 0; i < length; ++i) {
ASSERT(info.it != svgChars.end());
@@ -1680,11 +1780,24 @@ void SVGRootInlineBox::walkTextChunks(SVGTextChunkWalkerBase* walker, const SVGI
if (textBox)
(*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
else {
+ if (walker->setupBackground(range.box))
+ (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+
if (walker->setupFill(range.box))
(*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+ if (walker->setupFillSelection(range.box))
+ (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+
if (walker->setupStroke(range.box))
(*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+
+ if (walker->setupStrokeSelection(range.box))
+ (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+
+ if (walker->setupForeground(range.box))
+ (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+
}
chunkOffset += length;
diff --git a/WebCore/rendering/SVGRootInlineBox.h b/WebCore/rendering/SVGRootInlineBox.h
index 65bade0..7b1dcc4 100644
--- a/WebCore/rendering/SVGRootInlineBox.h
+++ b/WebCore/rendering/SVGRootInlineBox.h
@@ -28,6 +28,7 @@
#if ENABLE(SVG)
#include "RootInlineBox.h"
#include "SVGCharacterLayoutInfo.h"
+#include "SVGRenderSupport.h"
namespace WebCore {
@@ -43,13 +44,14 @@ struct LastGlyphInfo {
bool isValid;
};
-class SVGRootInlineBox : public RootInlineBox {
+class SVGRootInlineBox : public RootInlineBox, protected SVGRenderBase {
public:
SVGRootInlineBox(RenderObject* obj)
: RootInlineBox(obj)
, m_height(0)
{
}
+ virtual const SVGRenderBase* toSVGRenderBase() const { return this; }
virtual bool isSVGRootInlineBox() { return true; }
@@ -63,6 +65,9 @@ public:
virtual void computePerCharacterLayoutInformation();
+ virtual FloatRect objectBoundingBox() const { return FloatRect(); }
+ virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); }
+
// Used by SVGInlineTextBox
const Vector<SVGTextChunk>& svgTextChunks() const;
diff --git a/WebCore/rendering/SVGShadowTreeElements.cpp b/WebCore/rendering/SVGShadowTreeElements.cpp
new file mode 100644
index 0000000..d9ce640
--- /dev/null
+++ b/WebCore/rendering/SVGShadowTreeElements.cpp
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. 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
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGShadowTreeElements.h"
+
+#include "Document.h"
+#include "FloatSize.h"
+#include "RenderObject.h"
+#include "SVGNames.h"
+
+namespace WebCore {
+
+// SVGShadowTreeContainerElement
+SVGShadowTreeContainerElement::SVGShadowTreeContainerElement(Document* document)
+ : SVGGElement(SVGNames::gTag, document)
+{
+}
+
+SVGShadowTreeContainerElement::~SVGShadowTreeContainerElement()
+{
+}
+
+FloatSize SVGShadowTreeContainerElement::containerTranslation() const
+{
+ return FloatSize(m_xOffset.value(this), m_yOffset.value(this));
+}
+
+// SVGShadowTreeRootElement
+SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, Node* shadowParent)
+ : SVGShadowTreeContainerElement(document)
+ , m_shadowParent(shadowParent)
+{
+ setInDocument(true);
+}
+
+SVGShadowTreeRootElement::~SVGShadowTreeRootElement()
+{
+}
+
+void SVGShadowTreeRootElement::attachElement(PassRefPtr<RenderStyle> style, RenderArena* arena)
+{
+ ASSERT(m_shadowParent);
+
+ // Create the renderer with the specified style
+ RenderObject* renderer = createRenderer(arena, style.get());
+ if (renderer) {
+ setRenderer(renderer);
+ renderer->setStyle(style);
+ }
+
+ // Set these explicitly since this normally happens during an attach()
+ setAttached();
+
+ // Add the renderer to the render tree
+ if (renderer)
+ m_shadowParent->renderer()->addChild(renderer);
+}
+
+}
+
+#endif
diff --git a/WebCore/rendering/SVGShadowTreeElements.h b/WebCore/rendering/SVGShadowTreeElements.h
new file mode 100644
index 0000000..ed42e89
--- /dev/null
+++ b/WebCore/rendering/SVGShadowTreeElements.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) Research In Motion Limited 2010. 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
+ aint 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 SVGShadowTreeElements_h
+#define SVGShadowTreeElements_h
+
+#if ENABLE(SVG)
+#include "SVGGElement.h"
+#include "SVGLength.h"
+
+namespace WebCore {
+
+class FloatSize;
+
+class SVGShadowTreeContainerElement : public SVGGElement {
+public:
+ SVGShadowTreeContainerElement(Document*);
+ virtual ~SVGShadowTreeContainerElement();
+
+ virtual bool isShadowTreeContainerElement() const { return true; }
+
+ FloatSize containerTranslation() const;
+ void setContainerOffset(const SVGLength& x, const SVGLength& y)
+ {
+ m_xOffset = x;
+ m_yOffset = y;
+ }
+
+private:
+ SVGLength m_xOffset;
+ SVGLength m_yOffset;
+};
+
+class SVGShadowTreeRootElement : public SVGShadowTreeContainerElement {
+public:
+ SVGShadowTreeRootElement(Document*, Node* shadowParent);
+ virtual ~SVGShadowTreeRootElement();
+
+ virtual bool isShadowNode() const { return m_shadowParent; }
+ virtual Node* shadowParentNode() { return m_shadowParent; }
+
+ void attachElement(PassRefPtr<RenderStyle>, RenderArena*);
+
+private:
+ Node* m_shadowParent;
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/rendering/TableLayout.h b/WebCore/rendering/TableLayout.h
index 8ae0ce7..10d6e26 100644
--- a/WebCore/rendering/TableLayout.h
+++ b/WebCore/rendering/TableLayout.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the HTML rendering engine for KDE.
- *
* Copyright (C) 2002 Lars Knoll (knoll@kde.org)
* (C) 2002 Dirk Mueller (mueller@kde.org)
*
@@ -23,11 +21,13 @@
#ifndef TableLayout_h
#define TableLayout_h
+#include <wtf/Noncopyable.h>
+
namespace WebCore {
class RenderTable;
-class TableLayout {
+class TableLayout : public Noncopyable {
public:
TableLayout(RenderTable* table)
: m_table(table)
diff --git a/WebCore/rendering/TrailingFloatsRootInlineBox.h b/WebCore/rendering/TrailingFloatsRootInlineBox.h
new file mode 100644
index 0000000..68bf637
--- /dev/null
+++ b/WebCore/rendering/TrailingFloatsRootInlineBox.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 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 TrailingFloatsRootInlineBox_h
+#define TrailingFloatsRootInlineBox_h
+
+#include "RootInlineBox.h"
+
+namespace WebCore {
+
+class TrailingFloatsRootInlineBox : public RootInlineBox {
+public:
+ TrailingFloatsRootInlineBox(RenderObject* object) : RootInlineBox(object)
+ {
+#if ENABLE(SVG)
+ setHasVirtualHeight();
+#endif
+ }
+
+private:
+ virtual int virtualHeight() const { return 0; }
+};
+
+} // namespace WebCore
+
+#endif // TrailingFloatsRootInlineBox_h
diff --git a/WebCore/rendering/TransformState.cpp b/WebCore/rendering/TransformState.cpp
index a9e68f4..ecc614e 100644
--- a/WebCore/rendering/TransformState.cpp
+++ b/WebCore/rendering/TransformState.cpp
@@ -49,6 +49,12 @@ void TransformState::move(int x, int y, TransformAccumulation accumulate)
m_accumulatingTransform = accumulate == AccumulateTransform;
}
+// FIXME: We transform AffineTransform to TransformationMatrix. This is rather inefficient.
+void TransformState::applyTransform(const AffineTransform& transformFromContainer, TransformAccumulation accumulate)
+{
+ applyTransform(transformFromContainer.toTransformationMatrix(), accumulate);
+}
+
void TransformState::applyTransform(const TransformationMatrix& transformFromContainer, TransformAccumulation accumulate)
{
// If we have an accumulated transform from last time, multiply in this transform
@@ -115,7 +121,7 @@ void TransformState::flattenWithTransform(const TransformationMatrix& t)
}
// We could throw away m_accumulatedTransform if we wanted to here, but that
- // would cause thrash when traversing hierarachies with alternating
+ // would cause thrash when traversing hierarchies with alternating
// preserve-3d and flat elements.
if (m_accumulatedTransform)
m_accumulatedTransform->makeIdentity();
diff --git a/WebCore/rendering/TransformState.h b/WebCore/rendering/TransformState.h
index d2c962a..0b4ca46 100644
--- a/WebCore/rendering/TransformState.h
+++ b/WebCore/rendering/TransformState.h
@@ -26,6 +26,7 @@
#ifndef TransformState_h
#define TransformState_h
+#include "AffineTransform.h"
#include "FloatPoint.h"
#include "FloatQuad.h"
#include "IntSize.h"
@@ -59,6 +60,7 @@ public:
}
void move(int x, int y, TransformAccumulation = FlattenTransform);
+ void applyTransform(const AffineTransform& transformFromContainer, TransformAccumulation = FlattenTransform);
void applyTransform(const TransformationMatrix& transformFromContainer, TransformAccumulation = FlattenTransform);
void flatten();
diff --git a/WebCore/rendering/break_lines.cpp b/WebCore/rendering/break_lines.cpp
index 0e81caa..4b6c0aa 100644
--- a/WebCore/rendering/break_lines.cpp
+++ b/WebCore/rendering/break_lines.cpp
@@ -1,21 +1,26 @@
/*
- * Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2007, 2010 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
- * 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.
+ * 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.
*/
#include "config.h"
@@ -44,23 +49,40 @@ static inline bool isBreakableSpace(UChar ch, bool treatNoBreakSpaceAsBreak)
}
}
-static inline bool shouldBreakAfter(UChar ch)
+// This differs from the Unicode algorithm only in that Unicode does not break
+// between a question mark and a vertical line (U+007C).
+static const unsigned char internetExplorerLineBreaksAfterQuestionMarkTable[0x80] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, // \t
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, // ! " ' ) , . /
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, // : ; ?
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, // ]
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 // }
+};
+
+static const size_t internetExplorerLineBreaksAfterQuestionMarkTableSize = sizeof(internetExplorerLineBreaksAfterQuestionMarkTable) / sizeof(*internetExplorerLineBreaksAfterQuestionMarkTable);
+
+static inline bool shouldBreakAfter(UChar ch, UChar nextCh)
{
- // Match WinIE's breaking strategy, which is to always allow breaks after hyphens and question marks.
- // FIXME: it appears that IE behavior is more complex, see <http://bugs.webkit.org/show_bug.cgi?id=17475>.
switch (ch) {
- case '-':
+ // For a question mark preceding a non-ASCII characters, defer to the Unicode algorithm by returning false.
+ // For ASCII characters, use a lookup table for enhanced speed and for compatibility with Internet Explorer.
case '?':
-#ifdef ANDROID_LAYOUT
- // as '/' is used in uri which is always long, we would like to break it
- case '/':
-#endif
+ return nextCh < internetExplorerLineBreaksAfterQuestionMarkTableSize && internetExplorerLineBreaksAfterQuestionMarkTable[nextCh];
+ // Internet Explorer always allows breaking after a hyphen.
+ case '-':
case softHyphen:
// FIXME: cases for ideographicComma and ideographicFullStop are a workaround for an issue in Unicode 5.0
// which is likely to be resolved in Unicode 5.1 <http://bugs.webkit.org/show_bug.cgi?id=17411>.
// We may want to remove or conditionalize this workaround at some point.
case ideographicComma:
case ideographicFullStop:
+#ifdef ANDROID_LAYOUT
+ // as '/' is used in uri which is always long, we would like to break it
+ case '/':
+#endif
return true;
default:
return false;
@@ -92,7 +114,7 @@ int nextBreakablePosition(const UChar* str, int pos, int len, bool treatNoBreakS
for (int i = pos; i < len; i++) {
UChar ch = str[i];
- if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastCh))
+ if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastCh, ch))
return i;
if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) {
diff --git a/WebCore/rendering/break_lines.h b/WebCore/rendering/break_lines.h
index 14f740f..4d6b8dc 100644
--- a/WebCore/rendering/break_lines.h
+++ b/WebCore/rendering/break_lines.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the DOM implementation for KDE.
- *
* Copyright (C) 2005 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
diff --git a/WebCore/rendering/style/ContentData.h b/WebCore/rendering/style/ContentData.h
index 24d5f86..2c261f8 100644
--- a/WebCore/rendering/style/ContentData.h
+++ b/WebCore/rendering/style/ContentData.h
@@ -25,15 +25,15 @@
#ifndef ContentData_h
#define ContentData_h
-#include "PlatformString.h"
#include "RenderStyleConstants.h"
-#include "StringImpl.h"
-#include "StyleImage.h"
#include <wtf/Noncopyable.h>
+#include <wtf/PassRefPtr.h>
namespace WebCore {
class CounterContent;
+class StringImpl;
+class StyleImage;
struct ContentData : Noncopyable {
public:
diff --git a/WebCore/rendering/style/CounterContent.h b/WebCore/rendering/style/CounterContent.h
index cf11813..702d9c2 100644
--- a/WebCore/rendering/style/CounterContent.h
+++ b/WebCore/rendering/style/CounterContent.h
@@ -30,7 +30,7 @@
namespace WebCore {
-class CounterContent {
+class CounterContent : public FastAllocBase {
public:
CounterContent(const AtomicString& identifier, EListStyleType style, const AtomicString& separator)
: m_identifier(identifier)
diff --git a/WebCore/rendering/style/FillLayer.cpp b/WebCore/rendering/style/FillLayer.cpp
index 9c491aa..597e919 100644
--- a/WebCore/rendering/style/FillLayer.cpp
+++ b/WebCore/rendering/style/FillLayer.cpp
@@ -31,18 +31,20 @@ FillLayer::FillLayer(EFillLayerType type)
, m_attachment(FillLayer::initialFillAttachment(type))
, m_clip(FillLayer::initialFillClip(type))
, m_origin(FillLayer::initialFillOrigin(type))
- , m_repeat(FillLayer::initialFillRepeat(type))
+ , m_repeatX(FillLayer::initialFillRepeatX(type))
+ , m_repeatY(FillLayer::initialFillRepeatY(type))
, m_composite(FillLayer::initialFillComposite(type))
- , m_size(FillLayer::initialFillSize(type))
+ , m_sizeType(SizeNone)
+ , m_sizeLength(FillLayer::initialFillSizeLength(type))
, m_imageSet(false)
, m_attachmentSet(false)
, m_clipSet(false)
, m_originSet(false)
- , m_repeatSet(false)
+ , m_repeatXSet(false)
+ , m_repeatYSet(false)
, m_xPosSet(false)
, m_yPosSet(false)
, m_compositeSet(type == MaskFillLayer)
- , m_sizeSet(false)
, m_type(type)
, m_next(0)
{
@@ -55,18 +57,20 @@ FillLayer::FillLayer(const FillLayer& o)
, m_attachment(o.m_attachment)
, m_clip(o.m_clip)
, m_origin(o.m_origin)
- , m_repeat(o.m_repeat)
+ , m_repeatX(o.m_repeatX)
+ , m_repeatY(o.m_repeatY)
, m_composite(o.m_composite)
- , m_size(o.m_size)
+ , m_sizeType(o.m_sizeType)
+ , m_sizeLength(o.m_sizeLength)
, m_imageSet(o.m_imageSet)
, m_attachmentSet(o.m_attachmentSet)
, m_clipSet(o.m_clipSet)
, m_originSet(o.m_originSet)
- , m_repeatSet(o.m_repeatSet)
+ , m_repeatXSet(o.m_repeatXSet)
+ , m_repeatYSet(o.m_repeatYSet)
, m_xPosSet(o.m_xPosSet)
, m_yPosSet(o.m_yPosSet)
, m_compositeSet(o.m_compositeSet)
- , m_sizeSet(o.m_sizeSet)
, m_type(o.m_type)
, m_next(o.m_next ? new FillLayer(*o.m_next) : 0)
{
@@ -91,18 +95,20 @@ FillLayer& FillLayer::operator=(const FillLayer& o)
m_clip = o.m_clip;
m_composite = o.m_composite;
m_origin = o.m_origin;
- m_repeat = o.m_repeat;
- m_size = o.m_size;
+ m_repeatX = o.m_repeatX;
+ m_repeatY = o.m_repeatY;
+ m_sizeType = o.m_sizeType;
+ m_sizeLength = o.m_sizeLength;
m_imageSet = o.m_imageSet;
m_attachmentSet = o.m_attachmentSet;
m_clipSet = o.m_clipSet;
m_compositeSet = o.m_compositeSet;
m_originSet = o.m_originSet;
- m_repeatSet = o.m_repeatSet;
+ m_repeatXSet = o.m_repeatXSet;
+ m_repeatYSet = o.m_repeatYSet;
m_xPosSet = o.m_xPosSet;
m_yPosSet = o.m_yPosSet;
- m_sizeSet = o.m_sizeSet;
m_type = o.m_type;
@@ -115,9 +121,9 @@ bool FillLayer::operator==(const FillLayer& o) const
// to propagate patterns into layers. All layer comparisons happen after values have all been filled in anyway.
return StyleImage::imagesEquivalent(m_image.get(), o.m_image.get()) && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition &&
m_attachment == o.m_attachment && m_clip == o.m_clip &&
- m_composite == o.m_composite && m_origin == o.m_origin && m_repeat == o.m_repeat &&
- m_size == o.m_size && m_type == o.m_type &&
- ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
+ m_composite == o.m_composite && m_origin == o.m_origin && m_repeatX == o.m_repeatX &&
+ m_repeatY == o.m_repeatY && m_sizeType == o.m_sizeType && m_sizeLength == o.m_sizeLength &&
+ m_type == o.m_type && ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
}
void FillLayer::fillUnsetProperties()
@@ -200,11 +206,22 @@ void FillLayer::fillUnsetProperties()
}
}
- for (curr = this; curr && curr->isRepeatSet(); curr = curr->next()) { }
+ for (curr = this; curr && curr->isRepeatXSet(); curr = curr->next()) { }
if (curr && curr != this) {
// We need to fill in the remaining values with the pattern specified.
for (FillLayer* pattern = this; curr; curr = curr->next()) {
- curr->m_repeat = pattern->m_repeat;
+ curr->m_repeatX = pattern->m_repeatX;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isRepeatYSet(); curr = curr->next()) { }
+ if (curr && curr != this) {
+ // We need to fill in the remaining values with the pattern specified.
+ for (FillLayer* pattern = this; curr; curr = curr->next()) {
+ curr->m_repeatY = pattern->m_repeatY;
pattern = pattern->next();
if (pattern == curr || !pattern)
pattern = this;
@@ -215,7 +232,8 @@ void FillLayer::fillUnsetProperties()
if (curr && curr != this) {
// We need to fill in the remaining values with the pattern specified.
for (FillLayer* pattern = this; curr; curr = curr->next()) {
- curr->m_size = pattern->m_size;
+ curr->m_sizeType = pattern->m_sizeType;
+ curr->m_sizeLength = pattern->m_sizeLength;
pattern = pattern->next();
if (pattern == curr || !pattern)
pattern = this;
@@ -232,7 +250,8 @@ void FillLayer::cullEmptyLayers()
!next->isXPositionSet() && !next->isYPositionSet() &&
!next->isAttachmentSet() && !next->isClipSet() &&
!next->isCompositeSet() && !next->isOriginSet() &&
- !next->isRepeatSet() && !next->isSizeSet()) {
+ !next->isRepeatXSet() && !next->isRepeatYSet()
+ && !next->isSizeSet()) {
delete next;
p->m_next = 0;
break;
@@ -251,4 +270,15 @@ bool FillLayer::containsImage(StyleImage* s) const
return false;
}
+bool FillLayer::imagesAreLoaded() const
+{
+ const FillLayer* curr;
+ for (curr = this; curr; curr = curr->next()) {
+ if (curr->m_image && !curr->m_image->isLoaded())
+ return false;
+ }
+
+ return true;
+}
+
} // namespace WebCore
diff --git a/WebCore/rendering/style/FillLayer.h b/WebCore/rendering/style/FillLayer.h
index c3944ad..cef6b19 100644
--- a/WebCore/rendering/style/FillLayer.h
+++ b/WebCore/rendering/style/FillLayer.h
@@ -34,7 +34,32 @@
namespace WebCore {
-struct FillLayer {
+struct FillSize {
+ FillSize()
+ : type(SizeLength)
+ {
+ }
+
+ FillSize(EFillSizeType t, LengthSize l)
+ : type(t)
+ , size(l)
+ {
+ }
+
+ bool operator==(const FillSize& o) const
+ {
+ return type == o.type && size == o.size;
+ }
+ bool operator!=(const FillSize& o) const
+ {
+ return !(*this == o);
+ }
+
+ EFillSizeType type;
+ LengthSize size;
+};
+
+struct FillLayer : FastAllocBase {
public:
FillLayer(EFillLayerType);
~FillLayer();
@@ -45,9 +70,11 @@ public:
EFillAttachment attachment() const { return static_cast<EFillAttachment>(m_attachment); }
EFillBox clip() const { return static_cast<EFillBox>(m_clip); }
EFillBox origin() const { return static_cast<EFillBox>(m_origin); }
- EFillRepeat repeat() const { return static_cast<EFillRepeat>(m_repeat); }
+ EFillRepeat repeatX() const { return static_cast<EFillRepeat>(m_repeatX); }
+ EFillRepeat repeatY() const { return static_cast<EFillRepeat>(m_repeatY); }
CompositeOperator composite() const { return static_cast<CompositeOperator>(m_composite); }
- LengthSize size() const { return m_size; }
+ LengthSize sizeLength() const { return m_sizeLength; }
+ FillSize size() const { return FillSize(static_cast<EFillSizeType>(m_sizeType), m_sizeLength); }
const FillLayer* next() const { return m_next; }
FillLayer* next() { return m_next; }
@@ -58,19 +85,23 @@ public:
bool isAttachmentSet() const { return m_attachmentSet; }
bool isClipSet() const { return m_clipSet; }
bool isOriginSet() const { return m_originSet; }
- bool isRepeatSet() const { return m_repeatSet; }
+ bool isRepeatXSet() const { return m_repeatXSet; }
+ bool isRepeatYSet() const { return m_repeatYSet; }
bool isCompositeSet() const { return m_compositeSet; }
- bool isSizeSet() const { return m_sizeSet; }
+ bool isSizeSet() const { return m_sizeType != SizeNone; }
void setImage(StyleImage* i) { m_image = i; m_imageSet = true; }
- void setXPosition(const Length& l) { m_xPosition = l; m_xPosSet = true; }
- void setYPosition(const Length& l) { m_yPosition = l; m_yPosSet = true; }
+ void setXPosition(Length l) { m_xPosition = l; m_xPosSet = true; }
+ void setYPosition(Length l) { m_yPosition = l; m_yPosSet = true; }
void setAttachment(EFillAttachment attachment) { m_attachment = attachment; m_attachmentSet = true; }
void setClip(EFillBox b) { m_clip = b; m_clipSet = true; }
void setOrigin(EFillBox b) { m_origin = b; m_originSet = true; }
- void setRepeat(EFillRepeat r) { m_repeat = r; m_repeatSet = true; }
+ void setRepeatX(EFillRepeat r) { m_repeatX = r; m_repeatXSet = true; }
+ void setRepeatY(EFillRepeat r) { m_repeatY = r; m_repeatYSet = true; }
void setComposite(CompositeOperator c) { m_composite = c; m_compositeSet = true; }
- void setSize(const LengthSize& b) { m_size = b; m_sizeSet = true; }
+ void setSizeType(EFillSizeType b) { m_sizeType = b; }
+ void setSizeLength(LengthSize l) { m_sizeLength = l; }
+ void setSize(FillSize f) { m_sizeType = f.type; m_sizeLength = f.size; }
void clearImage() { m_imageSet = false; }
void clearXPosition() { m_xPosSet = false; }
@@ -78,9 +109,10 @@ public:
void clearAttachment() { m_attachmentSet = false; }
void clearClip() { m_clipSet = false; }
void clearOrigin() { m_originSet = false; }
- void clearRepeat() { m_repeatSet = false; }
+ void clearRepeatX() { m_repeatXSet = false; }
+ void clearRepeatY() { m_repeatYSet = false; }
void clearComposite() { m_compositeSet = false; }
- void clearSize() { m_sizeSet = false; }
+ void clearSize() { m_sizeType = SizeNone; }
void setNext(FillLayer* n) { if (m_next != n) { delete m_next; m_next = n; } }
@@ -94,6 +126,7 @@ public:
}
bool containsImage(StyleImage*) const;
+ bool imagesAreLoaded() const;
bool hasImage() const
{
@@ -117,9 +150,12 @@ public:
static EFillAttachment initialFillAttachment(EFillLayerType) { return ScrollBackgroundAttachment; }
static EFillBox initialFillClip(EFillLayerType) { return BorderFillBox; }
static EFillBox initialFillOrigin(EFillLayerType type) { return type == BackgroundFillLayer ? PaddingFillBox : BorderFillBox; }
- static EFillRepeat initialFillRepeat(EFillLayerType) { return RepeatFill; }
+ static EFillRepeat initialFillRepeatX(EFillLayerType) { return RepeatFill; }
+ static EFillRepeat initialFillRepeatY(EFillLayerType) { return RepeatFill; }
static CompositeOperator initialFillComposite(EFillLayerType) { return CompositeSourceOver; }
- static LengthSize initialFillSize(EFillLayerType) { return LengthSize(); }
+ static EFillSizeType initialFillSizeType(EFillLayerType) { return SizeLength; }
+ static LengthSize initialFillSizeLength(EFillLayerType) { return LengthSize(); }
+ static FillSize initialFillSize(EFillLayerType) { return FillSize(); }
static Length initialFillXPosition(EFillLayerType) { return Length(0.0, Percent); }
static Length initialFillYPosition(EFillLayerType) { return Length(0.0, Percent); }
static StyleImage* initialFillImage(EFillLayerType) { return 0; }
@@ -136,20 +172,22 @@ public:
unsigned m_attachment : 2; // EFillAttachment
unsigned m_clip : 2; // EFillBox
unsigned m_origin : 2; // EFillBox
- unsigned m_repeat : 2; // EFillRepeat
+ unsigned m_repeatX : 3; // EFillRepeat
+ unsigned m_repeatY : 3; // EFillRepeat
unsigned m_composite : 4; // CompositeOperator
-
- LengthSize m_size;
+ unsigned m_sizeType : 2; // EFillSizeType
+
+ LengthSize m_sizeLength;
bool m_imageSet : 1;
bool m_attachmentSet : 1;
bool m_clipSet : 1;
bool m_originSet : 1;
- bool m_repeatSet : 1;
+ bool m_repeatXSet : 1;
+ bool m_repeatYSet : 1;
bool m_xPosSet : 1;
bool m_yPosSet : 1;
bool m_compositeSet : 1;
- bool m_sizeSet : 1;
unsigned m_type : 1; // EFillLayerType
diff --git a/WebCore/rendering/style/LineClampValue.h b/WebCore/rendering/style/LineClampValue.h
new file mode 100644
index 0000000..2119ca2
--- /dev/null
+++ b/WebCore/rendering/style/LineClampValue.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 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 LineClampValue_h
+#define LineClampValue_h
+
+#include "RenderStyleConstants.h"
+
+namespace WebCore {
+
+class LineClampValue {
+public:
+ LineClampValue()
+ : m_type(LineClampLineCount)
+ , m_value(-1)
+ {
+ }
+
+ LineClampValue(int value, ELineClampType type)
+ : m_type(type)
+ , m_value(value)
+ {
+ }
+
+ int value() const { return m_value; }
+
+ bool isPercentage() const { return m_type == LineClampPercentage; }
+
+ bool isNone() const { return m_value == -1; }
+
+ bool operator==(const LineClampValue& o) const
+ {
+ return value() == o.value() && isPercentage() == o.isPercentage();
+ }
+
+ bool operator!=(const LineClampValue& o) const
+ {
+ return !(*this == o);
+ }
+
+private:
+ ELineClampType m_type;
+ int m_value;
+};
+
+} // namespace WebCore
+
+#endif // LineClampValue_h
diff --git a/WebCore/rendering/style/RenderStyle.cpp b/WebCore/rendering/style/RenderStyle.cpp
index 0e258c8..0952557 100644
--- a/WebCore/rendering/style/RenderStyle.cpp
+++ b/WebCore/rendering/style/RenderStyle.cpp
@@ -324,6 +324,7 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
*rareNonInheritedData->flexibleBox.get() != *other->rareNonInheritedData->flexibleBox.get())
return StyleDifferenceLayout;
+ // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get()))
return StyleDifferenceLayout;
@@ -453,6 +454,12 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
if (inherited->m_effectiveZoom != other->inherited->m_effectiveZoom)
return StyleDifferenceLayout;
+ if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) ||
+ (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) {
+ // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
+ return StyleDifferenceLayout;
+ }
+
// Make sure these left/top/right/bottom checks stay below all layout checks and above
// all visible checks.
if (position() != StaticPosition) {
@@ -695,7 +702,7 @@ void RenderStyle::addBindingURI(StringImpl* uri)
void RenderStyle::setTextShadow(ShadowData* val, bool add)
{
- ASSERT(!val || !val->spread && val->style == Normal);
+ ASSERT(!val || (!val->spread && val->style == Normal));
StyleRareInheritedData* rareData = rareInheritedData.access();
if (!add) {
diff --git a/WebCore/rendering/style/RenderStyle.h b/WebCore/rendering/style/RenderStyle.h
index 720bc8d..696a2b7 100644
--- a/WebCore/rendering/style/RenderStyle.h
+++ b/WebCore/rendering/style/RenderStyle.h
@@ -37,6 +37,7 @@
#include "CachedImage.h"
#include "CollapsedBorderValue.h"
#include "Color.h"
+#include "ColorSpace.h"
#include "ContentData.h"
#include "CounterDirectives.h"
#include "CursorList.h"
@@ -49,6 +50,7 @@
#include "Length.h"
#include "LengthBox.h"
#include "LengthSize.h"
+#include "LineClampValue.h"
#include "NinePieceImage.h"
#include "OutlineValue.h"
#include "Pair.h"
@@ -87,7 +89,11 @@
#include "BindingURI.h"
#endif
+#if COMPILER(WINSCW)
+#define compareEqual(t, u) ((t) == (u))
+#else
template<typename T, typename U> inline bool compareEqual(const T& t, const U& u) { return t == static_cast<T>(u); }
+#endif
#define SET_VAR(group, variable, value) \
if (!compareEqual(group->variable, value)) \
@@ -177,7 +183,7 @@ protected:
unsigned _empty_cells : 1; // EEmptyCell
unsigned _caption_side : 2; // ECaptionSide
- unsigned _list_style_type : 5 ; // EListStyleType
+ unsigned _list_style_type : 7; // EListStyleType
unsigned _list_style_position : 1; // EListStylePosition
unsigned _visibility : 2; // EVisibility
unsigned _text_align : 3; // ETextAlign
@@ -188,37 +194,38 @@ protected:
bool _border_collapse : 1 ;
unsigned _white_space : 3; // EWhiteSpace
unsigned _box_direction : 1; // EBoxDirection (CSS3 box_direction property, flexible box layout module)
- // 32 bits
+ // 34 bits
// non CSS2 inherited
bool _visuallyOrdered : 1;
bool _htmlHacks : 1;
bool _force_backgrounds_to_white : 1;
unsigned _pointerEvents : 4; // EPointerEvents
- // 39 bits
+ // 41 bits
} inherited_flags;
// don't inherit
struct NonInheritedFlags {
bool operator==(const NonInheritedFlags& other) const
{
- return (_effectiveDisplay == other._effectiveDisplay) &&
- (_originalDisplay == other._originalDisplay) &&
- (_overflowX == other._overflowX) &&
- (_overflowY == other._overflowY) &&
- (_vertical_align == other._vertical_align) &&
- (_clear == other._clear) &&
- (_position == other._position) &&
- (_floating == other._floating) &&
- (_table_layout == other._table_layout) &&
- (_page_break_before == other._page_break_before) &&
- (_page_break_after == other._page_break_after) &&
- (_styleType == other._styleType) &&
- (_affectedByHover == other._affectedByHover) &&
- (_affectedByActive == other._affectedByActive) &&
- (_affectedByDrag == other._affectedByDrag) &&
- (_pseudoBits == other._pseudoBits) &&
- (_unicodeBidi == other._unicodeBidi);
+ return _effectiveDisplay == other._effectiveDisplay
+ && _originalDisplay == other._originalDisplay
+ && _overflowX == other._overflowX
+ && _overflowY == other._overflowY
+ && _vertical_align == other._vertical_align
+ && _clear == other._clear
+ && _position == other._position
+ && _floating == other._floating
+ && _table_layout == other._table_layout
+ && _page_break_before == other._page_break_before
+ && _page_break_after == other._page_break_after
+ && _page_break_inside == other._page_break_inside
+ && _styleType == other._styleType
+ && _affectedByHover == other._affectedByHover
+ && _affectedByActive == other._affectedByActive
+ && _affectedByDrag == other._affectedByDrag
+ && _pseudoBits == other._pseudoBits
+ && _unicodeBidi == other._unicodeBidi;
}
bool operator!=(const NonInheritedFlags& other) const { return !(*this == other); }
@@ -235,6 +242,7 @@ protected:
unsigned _page_break_before : 2; // EPageBreak
unsigned _page_break_after : 2; // EPageBreak
+ unsigned _page_break_inside : 2; // EPageBreak
unsigned _styleType : 5; // PseudoId
bool _affectedByHover : 1;
@@ -242,7 +250,7 @@ protected:
bool _affectedByDrag : 1;
unsigned _pseudoBits : 7;
unsigned _unicodeBidi : 2; // EUnicodeBidi
- // 48 bits
+ // 50 bits
} noninherited_flags;
// !END SYNC!
@@ -278,6 +286,7 @@ protected:
noninherited_flags._table_layout = initialTableLayout();
noninherited_flags._page_break_before = initialPageBreak();
noninherited_flags._page_break_after = initialPageBreak();
+ noninherited_flags._page_break_inside = initialPageBreak();
noninherited_flags._styleType = NOPSEUDO;
noninherited_flags._affectedByHover = false;
noninherited_flags._affectedByActive = false;
@@ -521,26 +530,29 @@ public:
const Color& backgroundColor() const { return background->m_color; }
StyleImage* backgroundImage() const { return background->m_background.m_image.get(); }
- EFillRepeat backgroundRepeat() const { return static_cast<EFillRepeat>(background->m_background.m_repeat); }
+ EFillRepeat backgroundRepeatX() const { return static_cast<EFillRepeat>(background->m_background.m_repeatX); }
+ EFillRepeat backgroundRepeatY() const { return static_cast<EFillRepeat>(background->m_background.m_repeatY); }
CompositeOperator backgroundComposite() const { return static_cast<CompositeOperator>(background->m_background.m_composite); }
EFillAttachment backgroundAttachment() const { return static_cast<EFillAttachment>(background->m_background.m_attachment); }
EFillBox backgroundClip() const { return static_cast<EFillBox>(background->m_background.m_clip); }
EFillBox backgroundOrigin() const { return static_cast<EFillBox>(background->m_background.m_origin); }
Length backgroundXPosition() const { return background->m_background.m_xPosition; }
Length backgroundYPosition() const { return background->m_background.m_yPosition; }
- LengthSize backgroundSize() const { return background->m_background.m_size; }
+ EFillSizeType backgroundSizeType() const { return static_cast<EFillSizeType>(background->m_background.m_sizeType); }
+ LengthSize backgroundSizeLength() const { return background->m_background.m_sizeLength; }
FillLayer* accessBackgroundLayers() { return &(background.access()->m_background); }
const FillLayer* backgroundLayers() const { return &(background->m_background); }
StyleImage* maskImage() const { return rareNonInheritedData->m_mask.m_image.get(); }
- EFillRepeat maskRepeat() const { return static_cast<EFillRepeat>(rareNonInheritedData->m_mask.m_repeat); }
+ EFillRepeat maskRepeatX() const { return static_cast<EFillRepeat>(rareNonInheritedData->m_mask.m_repeatX); }
+ EFillRepeat maskRepeatY() const { return static_cast<EFillRepeat>(rareNonInheritedData->m_mask.m_repeatY); }
CompositeOperator maskComposite() const { return static_cast<CompositeOperator>(rareNonInheritedData->m_mask.m_composite); }
EFillAttachment maskAttachment() const { return static_cast<EFillAttachment>(rareNonInheritedData->m_mask.m_attachment); }
EFillBox maskClip() const { return static_cast<EFillBox>(rareNonInheritedData->m_mask.m_clip); }
EFillBox maskOrigin() const { return static_cast<EFillBox>(rareNonInheritedData->m_mask.m_origin); }
Length maskXPosition() const { return rareNonInheritedData->m_mask.m_xPosition; }
Length maskYPosition() const { return rareNonInheritedData->m_mask.m_yPosition; }
- LengthSize maskSize() const { return rareNonInheritedData->m_mask.m_size; }
+ LengthSize maskSize() const { return rareNonInheritedData->m_mask.m_sizeLength; }
FillLayer* accessMaskLayers() { return &(rareNonInheritedData.access()->m_mask); }
const FillLayer* maskLayers() const { return &(rareNonInheritedData->m_mask); }
const NinePieceImage& maskBoxImage() const { return rareNonInheritedData->m_maskBoxImage; }
@@ -576,7 +588,7 @@ public:
short widows() const { return inherited->widows; }
short orphans() const { return inherited->orphans; }
- EPageBreak pageBreakInside() const { return static_cast<EPageBreak>(inherited->page_break_inside); }
+ EPageBreak pageBreakInside() const { return static_cast<EPageBreak>(noninherited_flags._page_break_inside); }
EPageBreak pageBreakBefore() const { return static_cast<EPageBreak>(noninherited_flags._page_break_before); }
EPageBreak pageBreakAfter() const { return static_cast<EPageBreak>(noninherited_flags._page_break_after); }
@@ -596,6 +608,7 @@ public:
const Color& textStrokeColor() const { return rareInheritedData->textStrokeColor; }
float textStrokeWidth() const { return rareInheritedData->textStrokeWidth; }
const Color& textFillColor() const { return rareInheritedData->textFillColor; }
+ ColorSpace colorSpace() const { return static_cast<ColorSpace>(rareInheritedData->colorSpace); }
float opacity() const { return rareNonInheritedData->opacity; }
ControlPart appearance() const { return static_cast<ControlPart>(rareNonInheritedData->m_appearance); }
EBoxAlignment boxAlign() const { return static_cast<EBoxAlignment>(rareNonInheritedData->flexibleBox->align); }
@@ -690,7 +703,7 @@ public:
bool isRunningAcceleratedAnimation() const { return rareNonInheritedData->m_runningAcceleratedAnimation; }
#endif
- int lineClamp() const { return rareNonInheritedData->lineClamp; }
+ const LineClampValue& lineClamp() const { return rareNonInheritedData->lineClamp; }
bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; }
ETextSecurity textSecurity() const { return static_cast<ETextSecurity>(rareInheritedData->textSecurity); }
@@ -755,7 +768,8 @@ public:
void setBackgroundXPosition(Length l) { SET_VAR(background, m_background.m_xPosition, l) }
void setBackgroundYPosition(Length l) { SET_VAR(background, m_background.m_yPosition, l) }
- void setBackgroundSize(LengthSize l) { SET_VAR(background, m_background.m_size, l) }
+ void setBackgroundSize(EFillSizeType b) { SET_VAR(background, m_background.m_sizeType, b) }
+ void setBackgroundSizeLength(LengthSize l) { SET_VAR(background, m_background.m_sizeLength, l) }
void setBorderImage(const NinePieceImage& b) { SET_VAR(surround, border.image, b) }
@@ -868,7 +882,7 @@ public:
void setMaskBoxImage(const NinePieceImage& b) { SET_VAR(rareNonInheritedData, m_maskBoxImage, b) }
void setMaskXPosition(Length l) { SET_VAR(rareNonInheritedData, m_mask.m_xPosition, l) }
void setMaskYPosition(Length l) { SET_VAR(rareNonInheritedData, m_mask.m_yPosition, l) }
- void setMaskSize(LengthSize l) { SET_VAR(rareNonInheritedData, m_mask.m_size, l) }
+ void setMaskSize(LengthSize l) { SET_VAR(rareNonInheritedData, m_mask.m_sizeLength, l) }
void setBorderCollapse(bool collapse) { inherited_flags._border_collapse = collapse; }
void setHorizontalBorderSpacing(short v) { SET_VAR(inherited, horizontal_border_spacing, v) }
@@ -914,7 +928,7 @@ public:
void setWidows(short w) { SET_VAR(inherited, widows, w); }
void setOrphans(short o) { SET_VAR(inherited, orphans, o); }
- void setPageBreakInside(EPageBreak b) { SET_VAR(inherited, page_break_inside, b); }
+ void setPageBreakInside(EPageBreak b) { noninherited_flags._page_break_inside = b; }
void setPageBreakBefore(EPageBreak b) { noninherited_flags._page_break_before = b; }
void setPageBreakAfter(EPageBreak b) { noninherited_flags._page_break_after = b; }
@@ -930,6 +944,7 @@ public:
void setTextStrokeColor(const Color& c) { SET_VAR(rareInheritedData, textStrokeColor, c) }
void setTextStrokeWidth(float w) { SET_VAR(rareInheritedData, textStrokeWidth, w) }
void setTextFillColor(const Color& c) { SET_VAR(rareInheritedData, textFillColor, c) }
+ void setColorSpace(ColorSpace space) { SET_VAR(rareInheritedData, colorSpace, space) }
void setOpacity(float f) { SET_VAR(rareNonInheritedData, opacity, f); }
void setAppearance(ControlPart a) { SET_VAR(rareNonInheritedData, m_appearance, a); }
void setBoxAlign(EBoxAlignment a) { SET_VAR(rareNonInheritedData.access()->flexibleBox, align, a); }
@@ -1009,7 +1024,7 @@ public:
void setIsRunningAcceleratedAnimation(bool b = true) { SET_VAR(rareNonInheritedData, m_runningAcceleratedAnimation, b); }
#endif
- void setLineClamp(int c) { SET_VAR(rareNonInheritedData, lineClamp, c); }
+ void setLineClamp(LineClampValue c) { SET_VAR(rareNonInheritedData, lineClamp, c); }
void setTextSizeAdjust(bool b) { SET_VAR(rareInheritedData, textSizeAdjust, b); }
void setTextSecurity(ETextSecurity aTextSecurity) { SET_VAR(rareInheritedData, textSecurity, aTextSecurity); }
@@ -1106,7 +1121,7 @@ public:
static EEmptyCell initialEmptyCells() { return SHOW; }
static EFloat initialFloating() { return FNONE; }
static EListStylePosition initialListStylePosition() { return OUTSIDE; }
- static EListStyleType initialListStyleType() { return DISC; }
+ static EListStyleType initialListStyleType() { return Disc; }
static EOverflow initialOverflowX() { return OVISIBLE; }
static EOverflow initialOverflowY() { return OVISIBLE; }
static EPageBreak initialPageBreak() { return PBAUTO; }
@@ -1182,9 +1197,10 @@ public:
static float initialPerspective() { return 0; }
static Length initialPerspectiveOriginX() { return Length(50.0, Percent); }
static Length initialPerspectiveOriginY() { return Length(50.0, Percent); }
+ static Color initialBackgroundColor() { return Color::transparent; }
// Keep these at the end.
- static int initialLineClamp() { return -1; }
+ static LineClampValue initialLineClamp() { return LineClampValue(); }
static bool initialTextSizeAdjust() { return true; }
static ETextSecurity initialTextSecurity() { return TSNONE; }
#if ENABLE(DASHBOARD_SUPPORT)
diff --git a/WebCore/rendering/style/RenderStyleConstants.h b/WebCore/rendering/style/RenderStyleConstants.h
index c491816..01862f6 100644
--- a/WebCore/rendering/style/RenderStyleConstants.h
+++ b/WebCore/rendering/style/RenderStyleConstants.h
@@ -2,8 +2,9 @@
* 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, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -68,10 +69,11 @@ enum PseudoId {
NOPSEUDO, FIRST_LINE, FIRST_LETTER, BEFORE, AFTER, SELECTION, FIRST_LINE_INHERITED, SCROLLBAR, FILE_UPLOAD_BUTTON, INPUT_PLACEHOLDER,
SLIDER_THUMB, SEARCH_CANCEL_BUTTON, SEARCH_DECORATION, SEARCH_RESULTS_DECORATION, SEARCH_RESULTS_BUTTON, MEDIA_CONTROLS_PANEL,
MEDIA_CONTROLS_PLAY_BUTTON, MEDIA_CONTROLS_MUTE_BUTTON, MEDIA_CONTROLS_TIMELINE, MEDIA_CONTROLS_TIMELINE_CONTAINER,
- MEDIA_CONTROLS_CURRENT_TIME_DISPLAY, MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, MEDIA_CONTROLS_SEEK_BACK_BUTTON,
- MEDIA_CONTROLS_SEEK_FORWARD_BUTTON, MEDIA_CONTROLS_FULLSCREEN_BUTTON, MEDIA_CONTROLS_REWIND_BUTTON,
- MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, MEDIA_CONTROLS_STATUS_DISPLAY,
- SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER,
+ MEDIA_CONTROLS_VOLUME_SLIDER, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER, MEDIA_CONTROLS_CURRENT_TIME_DISPLAY, MEDIA_CONTROLS_TIME_REMAINING_DISPLAY,
+ MEDIA_CONTROLS_SEEK_BACK_BUTTON, MEDIA_CONTROLS_SEEK_FORWARD_BUTTON, MEDIA_CONTROLS_FULLSCREEN_BUTTON, MEDIA_CONTROLS_REWIND_BUTTON,
+ MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON,
+ MEDIA_CONTROLS_STATUS_DISPLAY, SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER,
+ INPUT_LIST_BUTTON, INNER_SPIN_BUTTON, OUTER_SPIN_BUTTON,
FIRST_INTERNAL_PSEUDOID = FILE_UPLOAD_BUTTON
};
@@ -131,13 +133,16 @@ enum EFillBox {
};
enum EFillRepeat {
- RepeatFill, RepeatXFill, RepeatYFill, NoRepeatFill
+ RepeatFill, NoRepeatFill, RoundFill, SpaceFill
};
enum EFillLayerType {
BackgroundFillLayer, MaskFillLayer
};
+// CSS3 Background Values
+enum EFillSizeType { Contain, Cover, SizeLength, SizeNone };
+
// CSS3 Marquee Properties
enum EMarqueeBehavior { MNONE, MSCROLL, MSLIDE, MALTERNATE };
@@ -198,12 +203,85 @@ enum EResize {
RESIZE_NONE, RESIZE_BOTH, RESIZE_HORIZONTAL, RESIZE_VERTICAL
};
+// The order of this enum must match the order of the list style types in CSSValueKeywords.in.
enum EListStyleType {
- DISC, CIRCLE, SQUARE, LDECIMAL, DECIMAL_LEADING_ZERO,
- LOWER_ROMAN, UPPER_ROMAN, LOWER_GREEK,
- LOWER_ALPHA, LOWER_LATIN, UPPER_ALPHA, UPPER_LATIN,
- HEBREW, ARMENIAN, GEORGIAN, CJK_IDEOGRAPHIC,
- HIRAGANA, KATAKANA, HIRAGANA_IROHA, KATAKANA_IROHA, LNONE
+ Disc,
+ Circle,
+ Square,
+ DecimalListStyle,
+ DecimalLeadingZero,
+ ArabicIndic,
+ BinaryListStyle,
+ Bengali,
+ Cambodian,
+ Khmer,
+ Devanagari,
+ Gujarati,
+ Gurmukhi,
+ Kannada,
+ LowerHexadecimal,
+ Lao,
+ Malayalam,
+ Mongolian,
+ Myanmar,
+ Octal,
+ Oriya,
+ Persian,
+ Urdu,
+ Telugu,
+ Tibetan,
+ Thai,
+ UpperHexadecimal,
+ LowerRoman,
+ UpperRoman,
+ LowerGreek,
+ LowerAlpha,
+ LowerLatin,
+ UpperAlpha,
+ UpperLatin,
+ Afar,
+ EthiopicHalehameAaEt,
+ EthiopicHalehameAaEr,
+ Amharic,
+ EthiopicHalehameAmEt,
+ AmharicAbegede,
+ EthiopicAbegedeAmEt,
+ CjkEarthlyBranch,
+ CjkHeavenlyStem,
+ Ethiopic,
+ EthiopicHalehameGez,
+ EthiopicAbegede,
+ EthiopicAbegedeGez,
+ HangulConsonant,
+ Hangul,
+ LowerNorwegian,
+ Oromo,
+ EthiopicHalehameOmEt,
+ Sidama,
+ EthiopicHalehameSidEt,
+ Somali,
+ EthiopicHalehameSoEt,
+ Tigre,
+ EthiopicHalehameTig,
+ TigrinyaEr,
+ EthiopicHalehameTiEr,
+ TigrinyaErAbegede,
+ EthiopicAbegedeTiEr,
+ TigrinyaEt,
+ EthiopicHalehameTiEt,
+ TigrinyaEtAbegede,
+ EthiopicAbegedeTiEt,
+ UpperGreek,
+ UpperNorwegian,
+ Hebrew,
+ Armenian,
+ Georgian,
+ CJKIdeographic,
+ Hiragana,
+ Katakana,
+ HiraganaIroha,
+ KatakanaIroha,
+ NoneListStyle
};
enum StyleContentType {
@@ -298,7 +376,11 @@ enum EDisplay {
TABLE, INLINE_TABLE, TABLE_ROW_GROUP,
TABLE_HEADER_GROUP, TABLE_FOOTER_GROUP, TABLE_ROW,
TABLE_COLUMN_GROUP, TABLE_COLUMN, TABLE_CELL,
- TABLE_CAPTION, BOX, INLINE_BOX, NONE
+ TABLE_CAPTION, BOX, INLINE_BOX,
+#if ENABLE(WCSS)
+ WAP_MARQUEE,
+#endif
+ NONE
};
enum EPointerEvents {
@@ -313,6 +395,8 @@ enum ETransformStyle3D {
enum EBackfaceVisibility {
BackfaceVisibilityVisible, BackfaceVisibilityHidden
};
+
+enum ELineClampType { LineClampLineCount, LineClampPercentage };
} // namespace WebCore
diff --git a/WebCore/rendering/style/SVGRenderStyle.cpp b/WebCore/rendering/style/SVGRenderStyle.cpp
index 1289b06..7958088 100644
--- a/WebCore/rendering/style/SVGRenderStyle.cpp
+++ b/WebCore/rendering/style/SVGRenderStyle.cpp
@@ -8,8 +8,6 @@
Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Apple Computer, Inc.
- This file is part of the KDE project
-
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
@@ -32,11 +30,14 @@
#include "CSSPrimitiveValue.h"
#include "CSSValueList.h"
+#include "IntRect.h"
#include "NodeRenderStyle.h"
#include "RenderObject.h"
#include "RenderStyle.h"
#include "SVGStyledElement.h"
+using namespace std;
+
namespace WebCore {
SVGRenderStyle::SVGRenderStyle()
@@ -51,6 +52,7 @@ SVGRenderStyle::SVGRenderStyle()
mask = defaultStyle->mask;
misc = defaultStyle->misc;
markers = defaultStyle->markers;
+ shadowSVG = defaultStyle->shadowSVG;
setBitDefaults();
}
@@ -67,6 +69,7 @@ SVGRenderStyle::SVGRenderStyle(CreateDefaultType)
mask.init();
misc.init();
markers.init();
+ shadowSVG.init();
}
SVGRenderStyle::SVGRenderStyle(const SVGRenderStyle& other)
@@ -80,6 +83,7 @@ SVGRenderStyle::SVGRenderStyle(const SVGRenderStyle& other)
mask = other.mask;
misc = other.misc;
markers = other.markers;
+ shadowSVG = other.shadowSVG;
svg_inherited_flags = other.svg_inherited_flags;
svg_noninherited_flags = other.svg_noninherited_flags;
@@ -93,7 +97,7 @@ bool SVGRenderStyle::operator==(const SVGRenderStyle& o) const
{
return (fill == o.fill && stroke == o.stroke && text == o.text &&
stops == o.stops && clip == o.clip && mask == o.mask &&
- misc == o.misc && markers == o.markers &&
+ misc == o.misc && markers == o.markers && shadowSVG == o.shadowSVG &&
svg_inherited_flags == o.svg_inherited_flags &&
svg_noninherited_flags == o.svg_noninherited_flags);
}
@@ -140,6 +144,56 @@ float SVGRenderStyle::cssPrimitiveToLength(const RenderObject* item, CSSValue* v
return primitive->computeLengthFloat(const_cast<RenderStyle*>(item->style()), item->document()->documentElement()->renderStyle());
}
+
+static void getSVGShadowExtent(ShadowData* shadow, int& top, int& right, int& bottom, int& left)
+{
+ top = 0;
+ right = 0;
+ bottom = 0;
+ left = 0;
+
+ int blurAndSpread = shadow->blur + shadow->spread;
+
+ top = min(top, shadow->y - blurAndSpread);
+ right = max(right, shadow->x + blurAndSpread);
+ bottom = max(bottom, shadow->y + blurAndSpread);
+ left = min(left, shadow->x - blurAndSpread);
+}
+
+void SVGRenderStyle::inflateForShadow(IntRect& repaintRect) const
+{
+ ShadowData* svgShadow = shadow();
+ if (!svgShadow)
+ return;
+
+ FloatRect repaintFloatRect = FloatRect(repaintRect);
+ inflateForShadow(repaintFloatRect);
+ repaintRect = enclosingIntRect(repaintFloatRect);
+}
+
+void SVGRenderStyle::inflateForShadow(FloatRect& repaintRect) const
+{
+ ShadowData* svgShadow = shadow();
+ if (!svgShadow)
+ return;
+
+ int shadowTop;
+ int shadowRight;
+ int shadowBottom;
+ int shadowLeft;
+ getSVGShadowExtent(svgShadow, shadowTop, shadowRight, shadowBottom, shadowLeft);
+
+ int overflowLeft = repaintRect.x() + shadowLeft;
+ int overflowRight = repaintRect.right() + shadowRight;
+ int overflowTop = repaintRect.y() + shadowTop;
+ int overflowBottom = repaintRect.bottom() + shadowBottom;
+
+ repaintRect.setX(overflowLeft);
+ repaintRect.setY(overflowTop);
+ repaintRect.setWidth(overflowRight - overflowLeft);
+ repaintRect.setHeight(overflowBottom - overflowTop);
+}
+
}
#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/style/SVGRenderStyle.h b/WebCore/rendering/style/SVGRenderStyle.h
index 0e9dae4..c7f85db 100644
--- a/WebCore/rendering/style/SVGRenderStyle.h
+++ b/WebCore/rendering/style/SVGRenderStyle.h
@@ -3,8 +3,6 @@
2004, 2005 Rob Buis <buis@kde.org>
Copyright (C) 2005, 2006 Apple Computer, Inc.
- This file is part of the KDE project
-
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
@@ -30,182 +28,188 @@
#include "GraphicsTypes.h"
#include "SVGPaint.h"
#include "SVGRenderStyleDefs.h"
+#include "ShadowData.h"
#include <wtf/Platform.h>
namespace WebCore {
- class RenderObject;
- class RenderStyle;
-
- class SVGRenderStyle : public RefCounted<SVGRenderStyle> {
- public:
- static PassRefPtr<SVGRenderStyle> create() { return adoptRef(new SVGRenderStyle); }
- PassRefPtr<SVGRenderStyle> copy() const { return adoptRef(new SVGRenderStyle(*this));}
- ~SVGRenderStyle();
+class FloatRect;
+class IntRect;
+class RenderObject;
+class RenderStyle;
+
+class SVGRenderStyle : public RefCounted<SVGRenderStyle> {
+public:
+ static PassRefPtr<SVGRenderStyle> create() { return adoptRef(new SVGRenderStyle); }
+ PassRefPtr<SVGRenderStyle> copy() const { return adoptRef(new SVGRenderStyle(*this));}
+ ~SVGRenderStyle();
+
+ bool inheritedNotEqual(const SVGRenderStyle*) const;
+ void inheritFrom(const SVGRenderStyle*);
+
+ // FIXME: These functions should move to ShadowData.
+ void inflateForShadow(IntRect&) const;
+ void inflateForShadow(FloatRect&) const;
+
+ bool operator==(const SVGRenderStyle&) const;
+ bool operator!=(const SVGRenderStyle& o) const { return !(*this == o); }
+
+ // SVG CSS Properties
+ SVG_RS_DEFINE_ATTRIBUTE(EAlignmentBaseline, AlignmentBaseline, alignmentBaseline, AB_AUTO)
+ SVG_RS_DEFINE_ATTRIBUTE(EDominantBaseline, DominantBaseline, dominantBaseline, DB_AUTO)
+ SVG_RS_DEFINE_ATTRIBUTE(EBaselineShift, BaselineShift, baselineShift, BS_BASELINE)
+
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineCap, CapStyle, capStyle, ButtCap)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, ClipRule, clipRule, RULE_NONZERO)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolation, colorInterpolation, CI_SRGB)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolationFilters, colorInterpolationFilters, CI_LINEARRGB)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorRendering, ColorRendering, colorRendering, CR_AUTO)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, FillRule, fillRule, RULE_NONZERO)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EImageRendering, ImageRendering, imageRendering, IR_AUTO)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineJoin, JoinStyle, joinStyle, MiterJoin)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EShapeRendering, ShapeRendering, shapeRendering, SR_AUTO)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(ETextAnchor, TextAnchor, textAnchor, TA_START)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EWritingMode, WritingMode, writingMode, WM_LRTB)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationHorizontal, glyphOrientationHorizontal, GO_0DEG)
+ SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationVertical, glyphOrientationVertical, GO_AUTO)
+
+ // SVG CSS Properties (using DataRef's)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, fill, opacity, FillOpacity, fillOpacity, 1.0f)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, fill, paint, FillPaint, fillPaint, SVGPaint::defaultFill())
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, opacity, StrokeOpacity, strokeOpacity, 1.0f)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, stroke, paint, StrokePaint, strokePaint, SVGPaint::defaultStroke())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValueList, stroke, dashArray, StrokeDashArray, strokeDashArray, 0)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, miterLimit, StrokeMiterLimit, strokeMiterLimit, 4.0f)
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, width, StrokeWidth, strokeWidth, 0)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, dashOffset, StrokeDashOffset, strokeDashOffset, 0);
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, text, kerning, Kerning, kerning, 0)
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stops, opacity, StopOpacity, stopOpacity, 1.0f)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, stops, color, StopColor, stopColor, Color(0, 0, 0))
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, clip, clipPath, ClipPath, clipPath, String())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, mask, maskElement, MaskElement, maskElement, String())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, startMarker, StartMarker, startMarker, String())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, midMarker, MidMarker, midMarker, String())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, endMarker, EndMarker, endMarker, String())
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, misc, filter, Filter, filter, String())
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, misc, floodOpacity, FloodOpacity, floodOpacity, 1.0f)
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, floodColor, FloodColor, floodColor, Color(0, 0, 0))
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, lightingColor, LightingColor, lightingColor, Color(255, 255, 255))
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, misc, baselineShiftValue, BaselineShiftValue, baselineShiftValue, 0)
+
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_OWNPTR(ShadowData, shadowSVG, shadow, Shadow, shadow, 0)
+
+ // convenience
+ bool hasStroke() const { return (strokePaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); }
+ bool hasFill() const { return (fillPaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); }
+
+ static float cssPrimitiveToLength(const RenderObject*, CSSValue*, float defaultValue = 0.0f);
+
+protected:
+ // inherit
+ struct InheritedFlags {
+ bool operator==(const InheritedFlags& other) const
+ {
+ return (_colorRendering == other._colorRendering)
+ && (_imageRendering == other._imageRendering)
+ && (_shapeRendering == other._shapeRendering)
+ && (_clipRule == other._clipRule)
+ && (_fillRule == other._fillRule)
+ && (_capStyle == other._capStyle)
+ && (_joinStyle == other._joinStyle)
+ && (_textAnchor == other._textAnchor)
+ && (_colorInterpolation == other._colorInterpolation)
+ && (_colorInterpolationFilters == other._colorInterpolationFilters)
+ && (_writingMode == other._writingMode)
+ && (_glyphOrientationHorizontal == other._glyphOrientationHorizontal)
+ && (_glyphOrientationVertical == other._glyphOrientationVertical);
+ }
- bool inheritedNotEqual(const SVGRenderStyle*) const;
- void inheritFrom(const SVGRenderStyle*);
-
- bool operator==(const SVGRenderStyle&) const;
- bool operator!=(const SVGRenderStyle& o) const { return !(*this == o); }
-
- // SVG CSS Properties
- SVG_RS_DEFINE_ATTRIBUTE(EAlignmentBaseline, AlignmentBaseline, alignmentBaseline, AB_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE(EDominantBaseline, DominantBaseline, dominantBaseline, DB_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE(EBaselineShift, BaselineShift, baselineShift, BS_BASELINE)
-
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineCap, CapStyle, capStyle, ButtCap)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, ClipRule, clipRule, RULE_NONZERO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolation, colorInterpolation, CI_SRGB)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorInterpolation, ColorInterpolationFilters, colorInterpolationFilters, CI_LINEARRGB)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EColorRendering, ColorRendering, colorRendering, CR_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, FillRule, fillRule, RULE_NONZERO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EImageRendering, ImageRendering, imageRendering, IR_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineJoin, JoinStyle, joinStyle, MiterJoin)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EShapeRendering, ShapeRendering, shapeRendering, SR_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(ETextAnchor, TextAnchor, textAnchor, TA_START)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(ETextRendering, TextRendering, textRendering, TR_AUTO)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EWritingMode, WritingMode, writingMode, WM_LRTB)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationHorizontal, glyphOrientationHorizontal, GO_0DEG)
- SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EGlyphOrientation, GlyphOrientationVertical, glyphOrientationVertical, GO_AUTO)
-
- // SVG CSS Properties (using DataRef's)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, fill, opacity, FillOpacity, fillOpacity, 1.0f)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, fill, paint, FillPaint, fillPaint, SVGPaint::defaultFill())
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, opacity, StrokeOpacity, strokeOpacity, 1.0f)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(SVGPaint, stroke, paint, StrokePaint, strokePaint, SVGPaint::defaultStroke())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValueList, stroke, dashArray, StrokeDashArray, strokeDashArray, 0)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stroke, miterLimit, StrokeMiterLimit, strokeMiterLimit, 4.0f)
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, width, StrokeWidth, strokeWidth, 0)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, stroke, dashOffset, StrokeDashOffset, strokeDashOffset, 0);
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, text, kerning, Kerning, kerning, 0)
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, stops, opacity, StopOpacity, stopOpacity, 1.0f)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, stops, color, StopColor, stopColor, Color(0, 0, 0))
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, clip, clipPath, ClipPath, clipPath, String())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, mask, maskElement, MaskElement, maskElement, String())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, startMarker, StartMarker, startMarker, String())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, midMarker, MidMarker, midMarker, String())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, markers, endMarker, EndMarker, endMarker, String())
-
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(String, misc, filter, Filter, filter, String())
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(float, misc, floodOpacity, FloodOpacity, floodOpacity, 1.0f)
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, floodColor, FloodColor, floodColor, Color(0, 0, 0))
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Color, misc, lightingColor, LightingColor, lightingColor, Color(255, 255, 255))
- SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(CSSValue, misc, baselineShiftValue, BaselineShiftValue, baselineShiftValue, 0)
-
- // convenience
- bool hasStroke() const { return (strokePaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); }
- bool hasFill() const { return (fillPaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE); }
-
- static float cssPrimitiveToLength(const RenderObject*, CSSValue*, float defaultValue = 0.0f);
-
- protected:
- // inherit
- struct InheritedFlags {
- bool operator==(const InheritedFlags& other) const
- {
- return (_colorRendering == other._colorRendering) &&
- (_imageRendering == other._imageRendering) &&
- (_shapeRendering == other._shapeRendering) &&
- (_textRendering == other._textRendering) &&
- (_clipRule == other._clipRule) &&
- (_fillRule == other._fillRule) &&
- (_capStyle == other._capStyle) &&
- (_joinStyle == other._joinStyle) &&
- (_textAnchor == other._textAnchor) &&
- (_colorInterpolation == other._colorInterpolation) &&
- (_colorInterpolationFilters == other._colorInterpolationFilters) &&
- (_writingMode == other._writingMode) &&
- (_glyphOrientationHorizontal == other._glyphOrientationHorizontal) &&
- (_glyphOrientationVertical == other._glyphOrientationVertical);
- }
-
- bool operator!=(const InheritedFlags& other) const
- {
- return !(*this == other);
- }
-
- unsigned _colorRendering : 2; // EColorRendering
- unsigned _imageRendering : 2; // EImageRendering
- unsigned _shapeRendering : 2; // EShapeRendering
- unsigned _textRendering : 2; // ETextRendering
- unsigned _clipRule : 1; // WindRule
- unsigned _fillRule : 1; // WindRule
- unsigned _capStyle : 2; // LineCap
- unsigned _joinStyle : 2; // LineJoin
- unsigned _textAnchor : 2; // ETextAnchor
- unsigned _colorInterpolation : 2; // EColorInterpolation
- unsigned _colorInterpolationFilters : 2; // EColorInterpolation
- unsigned _writingMode : 3; // EWritingMode
- unsigned _glyphOrientationHorizontal : 3; // EGlyphOrientation
- unsigned _glyphOrientationVertical : 3; // EGlyphOrientation
- } svg_inherited_flags;
-
- // don't inherit
- struct NonInheritedFlags {
- // 32 bit non-inherited, don't add to the struct, or the operator will break.
- bool operator==(const NonInheritedFlags &other) const { return _niflags == other._niflags; }
- bool operator!=(const NonInheritedFlags &other) const { return _niflags != other._niflags; }
-
- union {
- struct {
- unsigned _alignmentBaseline : 4; // EAlignmentBaseline
- unsigned _dominantBaseline : 4; // EDominantBaseline
- unsigned _baselineShift : 2; // EBaselineShift
- // 22 bits unused
- } f;
- uint32_t _niflags;
- };
- } svg_noninherited_flags;
-
- // inherited attributes
- DataRef<StyleFillData> fill;
- DataRef<StyleStrokeData> stroke;
- DataRef<StyleMarkerData> markers;
- DataRef<StyleTextData> text;
-
- // non-inherited attributes
- DataRef<StyleStopData> stops;
- DataRef<StyleClipData> clip;
- DataRef<StyleMaskData> mask;
- DataRef<StyleMiscData> misc;
-
- private:
- enum CreateDefaultType { CreateDefault };
-
- SVGRenderStyle();
- SVGRenderStyle(const SVGRenderStyle&);
- SVGRenderStyle(CreateDefaultType); // Used to create the default style.
-
- void setBitDefaults()
+ bool operator!=(const InheritedFlags& other) const
{
- svg_inherited_flags._clipRule = initialClipRule();
- svg_inherited_flags._colorRendering = initialColorRendering();
- svg_inherited_flags._fillRule = initialFillRule();
- svg_inherited_flags._imageRendering = initialImageRendering();
- svg_inherited_flags._shapeRendering = initialShapeRendering();
- svg_inherited_flags._textRendering = initialTextRendering();
- svg_inherited_flags._textAnchor = initialTextAnchor();
- svg_inherited_flags._capStyle = initialCapStyle();
- svg_inherited_flags._joinStyle = initialJoinStyle();
- svg_inherited_flags._colorInterpolation = initialColorInterpolation();
- svg_inherited_flags._colorInterpolationFilters = initialColorInterpolationFilters();
- svg_inherited_flags._writingMode = initialWritingMode();
- svg_inherited_flags._glyphOrientationHorizontal = initialGlyphOrientationHorizontal();
- svg_inherited_flags._glyphOrientationVertical = initialGlyphOrientationVertical();
-
- svg_noninherited_flags._niflags = 0;
- svg_noninherited_flags.f._alignmentBaseline = initialAlignmentBaseline();
- svg_noninherited_flags.f._dominantBaseline = initialDominantBaseline();
- svg_noninherited_flags.f._baselineShift = initialBaselineShift();
+ return !(*this == other);
}
- };
+
+ unsigned _colorRendering : 2; // EColorRendering
+ unsigned _imageRendering : 2; // EImageRendering
+ unsigned _shapeRendering : 2; // EShapeRendering
+ unsigned _clipRule : 1; // WindRule
+ unsigned _fillRule : 1; // WindRule
+ unsigned _capStyle : 2; // LineCap
+ unsigned _joinStyle : 2; // LineJoin
+ unsigned _textAnchor : 2; // ETextAnchor
+ unsigned _colorInterpolation : 2; // EColorInterpolation
+ unsigned _colorInterpolationFilters : 2; // EColorInterpolation
+ unsigned _writingMode : 3; // EWritingMode
+ unsigned _glyphOrientationHorizontal : 3; // EGlyphOrientation
+ unsigned _glyphOrientationVertical : 3; // EGlyphOrientation
+ } svg_inherited_flags;
+
+ // don't inherit
+ struct NonInheritedFlags {
+ // 32 bit non-inherited, don't add to the struct, or the operator will break.
+ bool operator==(const NonInheritedFlags &other) const { return _niflags == other._niflags; }
+ bool operator!=(const NonInheritedFlags &other) const { return _niflags != other._niflags; }
+
+ union {
+ struct {
+ unsigned _alignmentBaseline : 4; // EAlignmentBaseline
+ unsigned _dominantBaseline : 4; // EDominantBaseline
+ unsigned _baselineShift : 2; // EBaselineShift
+ // 22 bits unused
+ } f;
+ uint32_t _niflags;
+ };
+ } svg_noninherited_flags;
+
+ // inherited attributes
+ DataRef<StyleFillData> fill;
+ DataRef<StyleStrokeData> stroke;
+ DataRef<StyleMarkerData> markers;
+ DataRef<StyleTextData> text;
+
+ // non-inherited attributes
+ DataRef<StyleStopData> stops;
+ DataRef<StyleClipData> clip;
+ DataRef<StyleMaskData> mask;
+ DataRef<StyleMiscData> misc;
+ DataRef<StyleShadowSVGData> shadowSVG;
+
+private:
+ enum CreateDefaultType { CreateDefault };
+
+ SVGRenderStyle();
+ SVGRenderStyle(const SVGRenderStyle&);
+ SVGRenderStyle(CreateDefaultType); // Used to create the default style.
+
+ void setBitDefaults()
+ {
+ svg_inherited_flags._clipRule = initialClipRule();
+ svg_inherited_flags._colorRendering = initialColorRendering();
+ svg_inherited_flags._fillRule = initialFillRule();
+ svg_inherited_flags._imageRendering = initialImageRendering();
+ svg_inherited_flags._shapeRendering = initialShapeRendering();
+ svg_inherited_flags._textAnchor = initialTextAnchor();
+ svg_inherited_flags._capStyle = initialCapStyle();
+ svg_inherited_flags._joinStyle = initialJoinStyle();
+ svg_inherited_flags._colorInterpolation = initialColorInterpolation();
+ svg_inherited_flags._colorInterpolationFilters = initialColorInterpolationFilters();
+ svg_inherited_flags._writingMode = initialWritingMode();
+ svg_inherited_flags._glyphOrientationHorizontal = initialGlyphOrientationHorizontal();
+ svg_inherited_flags._glyphOrientationVertical = initialGlyphOrientationVertical();
+
+ svg_noninherited_flags._niflags = 0;
+ svg_noninherited_flags.f._alignmentBaseline = initialAlignmentBaseline();
+ svg_noninherited_flags.f._dominantBaseline = initialDominantBaseline();
+ svg_noninherited_flags.f._baselineShift = initialBaselineShift();
+ }
+};
} // namespace WebCore
diff --git a/WebCore/rendering/style/SVGRenderStyleDefs.cpp b/WebCore/rendering/style/SVGRenderStyleDefs.cpp
index f5faad3..093f1f1 100644
--- a/WebCore/rendering/style/SVGRenderStyleDefs.cpp
+++ b/WebCore/rendering/style/SVGRenderStyleDefs.cpp
@@ -8,8 +8,6 @@
Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Apple Computer, Inc.
- This file is part of the KDE project
-
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
@@ -213,6 +211,25 @@ bool StyleMiscData::operator==(const StyleMiscData &other) const
&& baselineShiftValue == other.baselineShiftValue;
}
+StyleShadowSVGData::StyleShadowSVGData()
+{
+}
+
+StyleShadowSVGData::StyleShadowSVGData(const StyleShadowSVGData& other)
+ : RefCounted<StyleShadowSVGData>()
+ , shadow(other.shadow ? new ShadowData(*other.shadow) : 0)
+{
+}
+
+bool StyleShadowSVGData::operator==(const StyleShadowSVGData& other) const
+{
+ if ((!shadow && other.shadow) || (shadow && !other.shadow))
+ return false;
+ if (shadow && other.shadow && (*shadow != *other.shadow))
+ return false;
+ return true;
+}
+
#endif // ENABLE(SVG)
// vim:ts=4:noet
diff --git a/WebCore/rendering/style/SVGRenderStyleDefs.h b/WebCore/rendering/style/SVGRenderStyleDefs.h
index b7bf026..8f01d9f 100644
--- a/WebCore/rendering/style/SVGRenderStyleDefs.h
+++ b/WebCore/rendering/style/SVGRenderStyleDefs.h
@@ -8,8 +8,6 @@
(C) 2000-2003 Dirk Mueller (mueller@kde.org)
(C) 2002-2003 Apple Computer, Inc.
- This file is part of the KDE project
-
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
@@ -33,6 +31,9 @@
#include "Color.h"
#include "Path.h"
#include "PlatformString.h"
+#include "ShadowData.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
@@ -65,6 +66,13 @@
} \
static Data* initial##Type() { return Initial; }
+#define SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_OWNPTR(Data, Group, Variable, Type, Name, Initial) \
+ Data* Name() const { return Group->Variable.get(); } \
+ void set##Type(Data* obj) { \
+ Group.access()->Variable.set(obj); \
+ } \
+ static Data* initial##Type() { return Initial; }
+
#define SVG_RS_SET_VARIABLE(Group, Variable, Value) \
if (!(Group->Variable == Value)) \
Group.access()->Variable = Value;
@@ -95,10 +103,6 @@ namespace WebCore {
SR_AUTO, SR_OPTIMIZESPEED, SR_CRISPEDGES, SR_GEOMETRICPRECISION
};
- enum ETextRendering {
- TR_AUTO, TR_OPTIMIZESPEED, TR_OPTIMIZELEGIBILITY, TR_GEOMETRICPRECISION
- };
-
enum EWritingMode {
WM_LRTB, WM_LR, WM_RLTB, WM_RL, WM_TBRL, WM_TB
};
@@ -283,6 +287,24 @@ namespace WebCore {
StyleMiscData();
StyleMiscData(const StyleMiscData&);
};
+
+ class StyleShadowSVGData : public RefCounted<StyleShadowSVGData> {
+ public:
+ static PassRefPtr<StyleShadowSVGData> create() { return adoptRef(new StyleShadowSVGData); }
+ PassRefPtr<StyleShadowSVGData> copy() const { return adoptRef(new StyleShadowSVGData(*this)); }
+
+ bool operator==(const StyleShadowSVGData& other) const;
+ bool operator!=(const StyleShadowSVGData& other) const
+ {
+ return !(*this == other);
+ }
+
+ OwnPtr<ShadowData> shadow;
+
+ private:
+ StyleShadowSVGData();
+ StyleShadowSVGData(const StyleShadowSVGData& other);
+ };
} // namespace WebCore
diff --git a/WebCore/rendering/style/ShadowData.h b/WebCore/rendering/style/ShadowData.h
index f4061f2..089cf77 100644
--- a/WebCore/rendering/style/ShadowData.h
+++ b/WebCore/rendering/style/ShadowData.h
@@ -26,6 +26,7 @@
#define ShadowData_h
#include "Color.h"
+#include <wtf/FastAllocBase.h>
namespace WebCore {
@@ -33,7 +34,7 @@ enum ShadowStyle { Normal, Inset };
// This struct holds information about shadows for the text-shadow and box-shadow properties.
-struct ShadowData {
+struct ShadowData : FastAllocBase {
ShadowData()
: x(0)
, y(0)
diff --git a/WebCore/rendering/style/StyleBackgroundData.cpp b/WebCore/rendering/style/StyleBackgroundData.cpp
index 68a9ddd..08f5527 100644
--- a/WebCore/rendering/style/StyleBackgroundData.cpp
+++ b/WebCore/rendering/style/StyleBackgroundData.cpp
@@ -22,12 +22,14 @@
#include "config.h"
#include "StyleBackgroundData.h"
+#include "RenderStyle.h"
#include "RenderStyleConstants.h"
namespace WebCore {
StyleBackgroundData::StyleBackgroundData()
: m_background(BackgroundFillLayer)
+ , m_color(RenderStyle::initialBackgroundColor())
{
}
diff --git a/WebCore/rendering/style/StyleInheritedData.cpp b/WebCore/rendering/style/StyleInheritedData.cpp
index f59c0c2..c73497f 100644
--- a/WebCore/rendering/style/StyleInheritedData.cpp
+++ b/WebCore/rendering/style/StyleInheritedData.cpp
@@ -37,7 +37,6 @@ StyleInheritedData::StyleInheritedData()
, vertical_border_spacing(RenderStyle::initialVerticalBorderSpacing())
, widows(RenderStyle::initialWidows())
, orphans(RenderStyle::initialOrphans())
- , page_break_inside(RenderStyle::initialPageBreak())
{
}
@@ -58,7 +57,6 @@ StyleInheritedData::StyleInheritedData(const StyleInheritedData& o)
, vertical_border_spacing(o.vertical_border_spacing)
, widows(o.widows)
, orphans(o.orphans)
- , page_break_inside(o.page_break_inside)
{
}
@@ -84,8 +82,7 @@ bool StyleInheritedData::operator==(const StyleInheritedData& o) const
horizontal_border_spacing == o.horizontal_border_spacing &&
vertical_border_spacing == o.vertical_border_spacing &&
widows == o.widows &&
- orphans == o.orphans &&
- page_break_inside == o.page_break_inside;
+ orphans == o.orphans;
}
} // namespace WebCore
diff --git a/WebCore/rendering/style/StyleInheritedData.h b/WebCore/rendering/style/StyleInheritedData.h
index 548ca72..3b30b8f 100644
--- a/WebCore/rendering/style/StyleInheritedData.h
+++ b/WebCore/rendering/style/StyleInheritedData.h
@@ -68,7 +68,6 @@ public:
// Paged media properties.
short widows;
short orphans;
- unsigned page_break_inside : 2; // EPageBreak
private:
StyleInheritedData();
diff --git a/WebCore/rendering/style/StyleRareInheritedData.cpp b/WebCore/rendering/style/StyleRareInheritedData.cpp
index 0f3b7e7..ff626b7 100644
--- a/WebCore/rendering/style/StyleRareInheritedData.cpp
+++ b/WebCore/rendering/style/StyleRareInheritedData.cpp
@@ -42,6 +42,7 @@ StyleRareInheritedData::StyleRareInheritedData()
, textSizeAdjust(RenderStyle::initialTextSizeAdjust())
, resize(RenderStyle::initialResize())
, userSelect(RenderStyle::initialUserSelect())
+ , colorSpace(DeviceColorSpace)
{
}
@@ -64,6 +65,7 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o)
, textSizeAdjust(o.textSizeAdjust)
, resize(o.resize)
, userSelect(o.userSelect)
+ , colorSpace(o.colorSpace)
{
}
@@ -90,7 +92,8 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
&& tapHighlightColor == o.tapHighlightColor
#endif
&& resize == o.resize
- && userSelect == o.userSelect;
+ && userSelect == o.userSelect
+ && colorSpace == o.colorSpace;
}
bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& o) const
diff --git a/WebCore/rendering/style/StyleRareInheritedData.h b/WebCore/rendering/style/StyleRareInheritedData.h
index 4abd3cf..1aa7b05 100644
--- a/WebCore/rendering/style/StyleRareInheritedData.h
+++ b/WebCore/rendering/style/StyleRareInheritedData.h
@@ -68,6 +68,7 @@ public:
bool textSizeAdjust : 1; // An Apple extension.
unsigned resize : 2; // EResize
unsigned userSelect : 1; // EUserSelect
+ unsigned colorSpace : 1; // ColorSpace
private:
StyleRareInheritedData();
diff --git a/WebCore/rendering/style/StyleRareNonInheritedData.h b/WebCore/rendering/style/StyleRareNonInheritedData.h
index 8dd22b3..452b273 100644
--- a/WebCore/rendering/style/StyleRareNonInheritedData.h
+++ b/WebCore/rendering/style/StyleRareNonInheritedData.h
@@ -29,6 +29,7 @@
#include "CursorData.h"
#include "DataRef.h"
#include "FillLayer.h"
+#include "LineClampValue.h"
#include "NinePieceImage.h"
#include "StyleTransformData.h"
#include <wtf/OwnPtr.h>
@@ -77,7 +78,7 @@ public:
bool animationDataEquivalent(const StyleRareNonInheritedData&) const;
bool transitionDataEquivalent(const StyleRareNonInheritedData&) const;
- int lineClamp; // An Apple extension.
+ LineClampValue lineClamp; // An Apple extension.
#if ENABLE(DASHBOARD_SUPPORT)
Vector<StyleDashboardRegion> m_dashboardRegions;
#endif