summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/webkit/WebCore/rendering
diff options
context:
space:
mode:
authorAlexis Menard <alexis.menard@nokia.com>2009-04-17 14:06:06 (GMT)
committerAlexis Menard <alexis.menard@nokia.com>2009-04-17 14:06:06 (GMT)
commitf15b8a83e2e51955776a3f07cb85ebfc342dd8ef (patch)
treec5dc684986051654898db11ce73e03b9fec8db99 /src/3rdparty/webkit/WebCore/rendering
downloadQt-f15b8a83e2e51955776a3f07cb85ebfc342dd8ef.zip
Qt-f15b8a83e2e51955776a3f07cb85ebfc342dd8ef.tar.gz
Qt-f15b8a83e2e51955776a3f07cb85ebfc342dd8ef.tar.bz2
Initial import of statemachine branch from the old kinetic repository
Diffstat (limited to 'src/3rdparty/webkit/WebCore/rendering')
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp785
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.h87
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/CounterNode.cpp192
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/CounterNode.h81
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp85
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h53
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp309
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.h49
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/GapRects.h62
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h44
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/HitTestResult.cpp334
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/HitTestResult.h94
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/InlineBox.cpp258
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/InlineBox.h316
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp1064
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h171
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/InlineRunBox.h54
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp909
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h139
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp114
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/LayoutState.h71
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.cpp45
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.h41
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp254
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h136
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.cpp110
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h50
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderApplet.cpp98
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderApplet.h52
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp135
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderArena.h64
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp111
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderBR.h71
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp4671
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderBlock.h504
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp2768
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderBox.h257
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp183
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderButton.h77
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderContainer.cpp701
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderContainer.h75
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp306
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderCounter.h54
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp282
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFieldset.h60
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp298
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h70
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp1157
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.h66
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp883
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFlow.h146
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp132
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h61
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp62
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFrame.h50
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp669
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h122
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.cpp74
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.h52
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp577
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderImage.h107
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.cpp53
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.h64
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp399
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderInline.h84
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp2609
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderLayer.h523
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderLegend.cpp36
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderLegend.h42
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp649
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderListBox.h132
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp335
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderListItem.h83
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp905
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h85
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderMarquee.cpp311
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h97
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderMedia.cpp424
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderMedia.h118
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderMenuList.cpp441
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h119
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp3303
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderObject.h991
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp116
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderPart.h62
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp317
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h47
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp484
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderPath.h95
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp416
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h87
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp80
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderReplica.h53
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.cpp63
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h41
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp438
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h122
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp72
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.h59
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp116
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h67
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp280
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h75
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp58
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h41
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.cpp180
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h59
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp347
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h82
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.cpp82
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h41
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGText.cpp242
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h71
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.cpp122
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.h55
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp47
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h39
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp198
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h64
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.cpp320
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.h83
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.cpp169
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.h67
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.cpp140
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.h82
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp402
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderSlider.h73
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp1152
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTable.h226
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp882
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h133
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTableCol.cpp92
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTableCol.h61
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp219
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTableRow.h67
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp1080
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTableSection.h154
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderText.cpp1216
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderText.h183
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp591
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h121
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp157
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h54
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp759
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h123
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp87
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.h64
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp776
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTheme.h234
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h177
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp1235
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.h181
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp852
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h147
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp512
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.h43
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp239
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderVideo.h75
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderView.cpp611
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderView.h226
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp278
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderWidget.h77
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderWordBreak.cpp49
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RenderWordBreak.h46
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp405
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h206
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp535
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.h416
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.cpp53
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.h48
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp548
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h75
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp167
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h42
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp562
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h111
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp1718
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h99
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/TableLayout.h48
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp178
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.h73
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/bidi.cpp2222
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/bidi.h67
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/break_lines.cpp120
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/break_lines.h41
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/BindingURI.cpp71
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/BindingURI.h59
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/BorderData.h109
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/BorderValue.h75
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/CollapsedBorderValue.h66
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/ContentData.cpp66
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/ContentData.h62
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h62
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/CounterDirectives.cpp38
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/CounterDirectives.h54
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/CursorData.h56
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/CursorList.h59
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/DataRef.h71
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/FillLayer.cpp254
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/FillLayer.h161
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/KeyframeList.cpp88
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/KeyframeList.h90
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/NinePieceImage.cpp35
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/NinePieceImage.h70
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/OutlineValue.h56
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp844
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h1129
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h268
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp146
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.h215
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.cpp218
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.h292
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/ShadowData.cpp45
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/ShadowData.h71
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleBackgroundData.cpp47
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleBackgroundData.h59
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleBoxData.cpp67
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleBoxData.h67
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleCachedImage.cpp92
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleCachedImage.h67
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleDashboardRegion.h61
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleFlexibleBoxData.cpp59
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleFlexibleBoxData.h60
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.cpp65
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.h69
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleImage.h81
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp91
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.h80
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleMarqueeData.cpp54
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleMarqueeData.h61
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleMultiColData.cpp65
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleMultiColData.h75
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp95
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.h76
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.cpp167
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h120
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleReflection.h70
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleSurroundData.cpp47
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleSurroundData.h58
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.cpp49
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.h57
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleVisualData.cpp53
-rw-r--r--src/3rdparty/webkit/WebCore/rendering/style/StyleVisualData.h67
243 files changed, 66681 insertions, 0 deletions
diff --git a/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp b/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp
new file mode 100644
index 0000000..8f9feec
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.cpp
@@ -0,0 +1,785 @@
+/*
+ * Copyright (C) 2002 Lars Knoll (knoll@kde.org)
+ * (C) 2002 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006, 2008 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.
+ *
+ * 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 "AutoTableLayout.h"
+
+#include "RenderTable.h"
+#include "RenderTableCell.h"
+#include "RenderTableCol.h"
+#include "RenderTableSection.h"
+
+using namespace std;
+
+namespace WebCore {
+
+AutoTableLayout::AutoTableLayout(RenderTable* table)
+ : TableLayout(table)
+ , m_hasPercent(false)
+ , m_percentagesDirty(true)
+ , m_effWidthDirty(true)
+ , m_totalPercent(0)
+{
+}
+
+AutoTableLayout::~AutoTableLayout()
+{
+}
+
+/* recalculates the full structure needed to do layouting and minmax calculations.
+ This is usually calculated on the fly, but needs to be done fully when table cells change
+ dynamically
+*/
+void AutoTableLayout::recalcColumn(int effCol)
+{
+ Layout &l = m_layoutStruct[effCol];
+
+ RenderObject* child = m_table->firstChild();
+ // first we iterate over all rows.
+
+ RenderTableCell* fixedContributor = 0;
+ RenderTableCell* maxContributor = 0;
+
+ while (child) {
+ if (child->isTableSection()) {
+ RenderTableSection* section = static_cast<RenderTableSection*>(child);
+ int numRows = section->numRows();
+ RenderTableCell* last = 0;
+ for (int i = 0; i < numRows; i++) {
+ RenderTableSection::CellStruct current = section->cellAt(i, effCol);
+ RenderTableCell* cell = current.cell;
+
+ bool cellHasContent = cell && (cell->firstChild() || cell->style()->hasBorder() || cell->style()->hasPadding());
+ if (cellHasContent)
+ l.emptyCellsOnly = false;
+
+ if (current.inColSpan)
+ continue;
+ if (cell && cell->colSpan() == 1) {
+ // A cell originates in this column. Ensure we have
+ // a min/max width of at least 1px for this column now.
+ l.minWidth = max(l.minWidth, cellHasContent ? 1 : 0);
+ l.maxWidth = max(l.maxWidth, 1);
+ if (cell->prefWidthsDirty())
+ cell->calcPrefWidths();
+ l.minWidth = max(cell->minPrefWidth(), l.minWidth);
+ if (cell->maxPrefWidth() > l.maxWidth) {
+ l.maxWidth = cell->maxPrefWidth();
+ maxContributor = cell;
+ }
+
+ Length w = cell->styleOrColWidth();
+ // FIXME: What is this arbitrary value?
+ if (w.rawValue() > 32760)
+ w.setRawValue(32760);
+ if (w.isNegative())
+ w.setValue(0);
+ switch(w.type()) {
+ case Fixed:
+ // ignore width=0
+ if (w.value() > 0 && (int)l.width.type() != Percent) {
+ int wval = cell->calcBorderBoxWidth(w.value());
+ if (l.width.isFixed()) {
+ // Nav/IE weirdness
+ if ((wval > l.width.value()) ||
+ ((l.width.value() == wval) && (maxContributor == cell))) {
+ l.width.setValue(wval);
+ fixedContributor = cell;
+ }
+ } else {
+ l.width.setValue(Fixed, wval);
+ fixedContributor = cell;
+ }
+ }
+ break;
+ case Percent:
+ m_hasPercent = true;
+ if (w.isPositive() && (!l.width.isPercent() || w.rawValue() > l.width.rawValue()))
+ l.width = w;
+ break;
+ case Relative:
+ // FIXME: Need to understand this case and whether it makes sense to compare values
+ // which are not necessarily of the same type.
+ if (w.isAuto() || (w.isRelative() && w.value() > l.width.rawValue()))
+ l.width = w;
+ default:
+ break;
+ }
+ } else {
+ if (cell && (!effCol || section->cellAt(i, effCol-1).cell != cell)) {
+ // This spanning cell originates in this column. Ensure we have
+ // a min/max width of at least 1px for this column now.
+ l.minWidth = max(l.minWidth, cellHasContent ? 1 : 0);
+ l.maxWidth = max(l.maxWidth, 1);
+ insertSpanCell(cell);
+ }
+ last = cell;
+ }
+ }
+ }
+ child = child->nextSibling();
+ }
+
+ // Nav/IE weirdness
+ if (l.width.isFixed()) {
+ if (m_table->style()->htmlHacks() && l.maxWidth > l.width.value() && fixedContributor != maxContributor) {
+ l.width = Length();
+ fixedContributor = 0;
+ }
+ }
+
+ l.maxWidth = max(l.maxWidth, l.minWidth);
+
+ // ### we need to add col elements as well
+}
+
+void AutoTableLayout::fullRecalc()
+{
+ m_percentagesDirty = true;
+ m_hasPercent = false;
+ m_effWidthDirty = true;
+
+ int nEffCols = m_table->numEffCols();
+ m_layoutStruct.resize(nEffCols);
+ m_layoutStruct.fill(Layout());
+ m_spanCells.fill(0);
+
+ RenderObject *child = m_table->firstChild();
+ Length grpWidth;
+ int cCol = 0;
+ while (child) {
+ if (child->isTableCol()) {
+ RenderTableCol *col = static_cast<RenderTableCol*>(child);
+ int span = col->span();
+ if (col->firstChild()) {
+ grpWidth = col->style()->width();
+ } else {
+ Length w = col->style()->width();
+ if (w.isAuto())
+ w = grpWidth;
+ if ((w.isFixed() || w.isPercent()) && w.isZero())
+ w = Length();
+ int cEffCol = m_table->colToEffCol(cCol);
+ if (!w.isAuto() && span == 1 && cEffCol < nEffCols) {
+ if (m_table->spanOfEffCol(cEffCol) == 1) {
+ m_layoutStruct[cEffCol].width = w;
+ if (w.isFixed() && m_layoutStruct[cEffCol].maxWidth < w.value())
+ m_layoutStruct[cEffCol].maxWidth = w.value();
+ }
+ }
+ cCol += span;
+ }
+ } else {
+ break;
+ }
+
+ RenderObject *next = child->firstChild();
+ if (!next)
+ next = child->nextSibling();
+ if (!next && child->parent()->isTableCol()) {
+ next = child->parent()->nextSibling();
+ grpWidth = Length();
+ }
+ child = next;
+ }
+
+
+ for (int i = 0; i < nEffCols; i++)
+ recalcColumn(i);
+}
+
+static bool shouldScaleColumns(RenderTable* table)
+{
+ // A special case. If this table is not fixed width and contained inside
+ // a cell, then don't bloat the maxwidth by examining percentage growth.
+ bool scale = true;
+ while (table) {
+ Length tw = table->style()->width();
+ if ((tw.isAuto() || tw.isPercent()) && !table->isPositioned()) {
+ RenderBlock* cb = table->containingBlock();
+ while (cb && !cb->isRenderView() && !cb->isTableCell() &&
+ cb->style()->width().isAuto() && !cb->isPositioned())
+ cb = cb->containingBlock();
+
+ table = 0;
+ if (cb && cb->isTableCell() &&
+ (cb->style()->width().isAuto() || cb->style()->width().isPercent())) {
+ if (tw.isPercent())
+ scale = false;
+ else {
+ RenderTableCell* cell = static_cast<RenderTableCell*>(cb);
+ if (cell->colSpan() > 1 || cell->table()->style()->width().isAuto())
+ scale = false;
+ else
+ table = cell->table();
+ }
+ }
+ }
+ else
+ table = 0;
+ }
+ return scale;
+}
+
+void AutoTableLayout::calcPrefWidths(int& minWidth, int& maxWidth)
+{
+ fullRecalc();
+
+ int spanMaxWidth = calcEffectiveWidth();
+ minWidth = 0;
+ maxWidth = 0;
+ float maxPercent = 0;
+ float maxNonPercent = 0;
+ bool scaleColumns = shouldScaleColumns(m_table);
+
+ // We substitute 0 percent by (epsilon / percentScaleFactor) percent in two places below to avoid division by zero.
+ // FIXME: Handle the 0% cases properly.
+ const int epsilon = 1;
+
+ int remainingPercent = 100 * percentScaleFactor;
+ for (unsigned int i = 0; i < m_layoutStruct.size(); i++) {
+ minWidth += m_layoutStruct[i].effMinWidth;
+ maxWidth += m_layoutStruct[i].effMaxWidth;
+ if (scaleColumns) {
+ if (m_layoutStruct[i].effWidth.isPercent()) {
+ int percent = min(m_layoutStruct[i].effWidth.rawValue(), remainingPercent);
+ float pw = static_cast<float>(m_layoutStruct[i].effMaxWidth) * 100 * percentScaleFactor / max(percent, epsilon);
+ maxPercent = max(pw, maxPercent);
+ remainingPercent -= percent;
+ } else
+ maxNonPercent += m_layoutStruct[i].effMaxWidth;
+ }
+ }
+
+ if (scaleColumns) {
+ maxNonPercent = maxNonPercent * 100 * percentScaleFactor / max(remainingPercent, epsilon);
+ maxWidth = max(maxWidth, static_cast<int>(min(maxNonPercent, INT_MAX / 2.0f)));
+ maxWidth = max(maxWidth, static_cast<int>(min(maxPercent, INT_MAX / 2.0f)));
+ }
+
+ maxWidth = max(maxWidth, spanMaxWidth);
+
+ int bs = m_table->bordersPaddingAndSpacing();
+ minWidth += bs;
+ maxWidth += bs;
+
+ Length tw = m_table->style()->width();
+ if (tw.isFixed() && tw.value() > 0) {
+ minWidth = max(minWidth, tw.value());
+ maxWidth = minWidth;
+ }
+}
+
+/*
+ This method takes care of colspans.
+ effWidth is the same as width for cells without colspans. If we have colspans, they get modified.
+ */
+int AutoTableLayout::calcEffectiveWidth()
+{
+ float tMaxWidth = 0;
+
+ unsigned int nEffCols = m_layoutStruct.size();
+ int hspacing = m_table->hBorderSpacing();
+
+ for (unsigned int i = 0; i < nEffCols; i++) {
+ m_layoutStruct[i].effWidth = m_layoutStruct[i].width;
+ m_layoutStruct[i].effMinWidth = m_layoutStruct[i].minWidth;
+ m_layoutStruct[i].effMaxWidth = m_layoutStruct[i].maxWidth;
+ }
+
+ for (unsigned int i = 0; i < m_spanCells.size(); i++) {
+ RenderTableCell *cell = m_spanCells[i];
+ if (!cell)
+ break;
+ int span = cell->colSpan();
+
+ Length w = cell->styleOrColWidth();
+ if (!w.isRelative() && w.isZero())
+ w = Length(); // make it Auto
+
+ int col = m_table->colToEffCol(cell->col());
+ unsigned int lastCol = col;
+ int cMinWidth = cell->minPrefWidth() + hspacing;
+ float cMaxWidth = cell->maxPrefWidth() + hspacing;
+ int totalPercent = 0;
+ int minWidth = 0;
+ float maxWidth = 0;
+ bool allColsArePercent = true;
+ bool allColsAreFixed = true;
+ bool haveAuto = false;
+ bool spanHasEmptyCellsOnly = true;
+ int fixedWidth = 0;
+ while (lastCol < nEffCols && span > 0) {
+ switch (m_layoutStruct[lastCol].width.type()) {
+ case Percent:
+ totalPercent += m_layoutStruct[lastCol].width.rawValue();
+ allColsAreFixed = false;
+ break;
+ case Fixed:
+ if (m_layoutStruct[lastCol].width.value() > 0) {
+ fixedWidth += m_layoutStruct[lastCol].width.value();
+ allColsArePercent = false;
+ // IE resets effWidth to Auto here, but this breaks the konqueror about page and seems to be some bad
+ // legacy behaviour anyway. mozilla doesn't do this so I decided we don't neither.
+ break;
+ }
+ // fall through
+ case Auto:
+ haveAuto = true;
+ // fall through
+ default:
+ // If the column is a percentage width, do not let the spanning cell overwrite the
+ // width value. This caused a mis-rendering on amazon.com.
+ // Sample snippet:
+ // <table border=2 width=100%><
+ // <tr><td>1</td><td colspan=2>2-3</tr>
+ // <tr><td>1</td><td colspan=2 width=100%>2-3</td></tr>
+ // </table>
+ if (!m_layoutStruct[lastCol].effWidth.isPercent()) {
+ m_layoutStruct[lastCol].effWidth = Length();
+ allColsArePercent = false;
+ }
+ else
+ totalPercent += m_layoutStruct[lastCol].effWidth.rawValue();
+ allColsAreFixed = false;
+ }
+ if (!m_layoutStruct[lastCol].emptyCellsOnly)
+ spanHasEmptyCellsOnly = false;
+ span -= m_table->spanOfEffCol(lastCol);
+ minWidth += m_layoutStruct[lastCol].effMinWidth;
+ maxWidth += m_layoutStruct[lastCol].effMaxWidth;
+ lastCol++;
+ cMinWidth -= hspacing;
+ cMaxWidth -= hspacing;
+ }
+
+ // adjust table max width if needed
+ if (w.isPercent()) {
+ if (totalPercent > w.rawValue() || allColsArePercent) {
+ // can't satify this condition, treat as variable
+ w = Length();
+ } else {
+ 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.
+ int percentMissing = w.rawValue() - totalPercent;
+ float totalWidth = 0;
+ for (unsigned int pos = col; pos < lastCol; pos++) {
+ if (!(m_layoutStruct[pos].effWidth.isPercent()))
+ totalWidth += m_layoutStruct[pos].effMaxWidth;
+ }
+
+ for (unsigned int pos = col; pos < lastCol && totalWidth > 0; pos++) {
+ if (!(m_layoutStruct[pos].effWidth.isPercent())) {
+ int percent = static_cast<int>(percentMissing * static_cast<float>(m_layoutStruct[pos].effMaxWidth) / totalWidth);
+ totalWidth -= m_layoutStruct[pos].effMaxWidth;
+ percentMissing -= percent;
+ if (percent > 0)
+ m_layoutStruct[pos].effWidth.setRawValue(Percent, percent);
+ else
+ m_layoutStruct[pos].effWidth = Length();
+ }
+ }
+
+ }
+ }
+
+ // make sure minWidth and maxWidth of the spanning cell are honoured
+ if (cMinWidth > minWidth) {
+ if (allColsAreFixed) {
+ for (unsigned int pos = col; fixedWidth > 0 && pos < lastCol; pos++) {
+ int w = max(m_layoutStruct[pos].effMinWidth, cMinWidth * m_layoutStruct[pos].width.value() / fixedWidth);
+ fixedWidth -= m_layoutStruct[pos].width.value();
+ cMinWidth -= w;
+ m_layoutStruct[pos].effMinWidth = w;
+ }
+
+ } else {
+ float maxw = maxWidth;
+ int minw = minWidth;
+
+ // Give min to variable first, to fixed second, and to others third.
+ for (unsigned int pos = col; maxw >= 0 && pos < lastCol; pos++) {
+ if (m_layoutStruct[pos].width.isFixed() && haveAuto && fixedWidth <= cMinWidth) {
+ int w = max(m_layoutStruct[pos].effMinWidth, m_layoutStruct[pos].width.value());
+ fixedWidth -= m_layoutStruct[pos].width.value();
+ minw -= m_layoutStruct[pos].effMinWidth;
+ maxw -= m_layoutStruct[pos].effMaxWidth;
+ cMinWidth -= w;
+ m_layoutStruct[pos].effMinWidth = w;
+ }
+ }
+
+ for (unsigned int pos = col; maxw >= 0 && pos < lastCol && minw < cMinWidth; pos++) {
+ if (!(m_layoutStruct[pos].width.isFixed() && haveAuto && fixedWidth <= cMinWidth)) {
+ int w = max(m_layoutStruct[pos].effMinWidth, static_cast<int>(maxw ? cMinWidth * static_cast<float>(m_layoutStruct[pos].effMaxWidth) / maxw : cMinWidth));
+ w = min(m_layoutStruct[pos].effMinWidth+(cMinWidth-minw), w);
+
+ maxw -= m_layoutStruct[pos].effMaxWidth;
+ minw -= m_layoutStruct[pos].effMinWidth;
+ cMinWidth -= w;
+ m_layoutStruct[pos].effMinWidth = w;
+ }
+ }
+ }
+ }
+ if (!(w.isPercent())) {
+ if (cMaxWidth > maxWidth) {
+ for (unsigned int pos = col; maxWidth >= 0 && pos < lastCol; pos++) {
+ int w = max(m_layoutStruct[pos].effMaxWidth, static_cast<int>(maxWidth ? cMaxWidth * static_cast<float>(m_layoutStruct[pos].effMaxWidth) / maxWidth : cMaxWidth));
+ maxWidth -= m_layoutStruct[pos].effMaxWidth;
+ cMaxWidth -= w;
+ m_layoutStruct[pos].effMaxWidth = w;
+ }
+ }
+ } else {
+ for (unsigned int pos = col; pos < lastCol; pos++)
+ m_layoutStruct[pos].maxWidth = max(m_layoutStruct[pos].maxWidth, m_layoutStruct[pos].minWidth);
+ }
+ // treat span ranges consisting of empty cells only as if they had content
+ if (spanHasEmptyCellsOnly)
+ for (unsigned int pos = col; pos < lastCol; pos++)
+ m_layoutStruct[pos].emptyCellsOnly = false;
+ }
+ m_effWidthDirty = false;
+
+ return static_cast<int>(min(tMaxWidth, INT_MAX / 2.0f));
+}
+
+/* gets all cells that originate in a column and have a cellspan > 1
+ Sorts them by increasing cellspan
+*/
+void AutoTableLayout::insertSpanCell(RenderTableCell *cell)
+{
+ if (!cell || cell->colSpan() == 1)
+ return;
+
+ int size = m_spanCells.size();
+ if (!size || m_spanCells[size-1] != 0) {
+ m_spanCells.grow(size + 10);
+ for (int i = 0; i < 10; i++)
+ m_spanCells[size+i] = 0;
+ size += 10;
+ }
+
+ // add them in sort. This is a slow algorithm, and a binary search or a fast sorting after collection would be better
+ unsigned int pos = 0;
+ int span = cell->colSpan();
+ while (pos < m_spanCells.size() && m_spanCells[pos] && span > m_spanCells[pos]->colSpan())
+ pos++;
+ memmove(m_spanCells.data()+pos+1, m_spanCells.data()+pos, (size-pos-1)*sizeof(RenderTableCell *));
+ m_spanCells[pos] = cell;
+}
+
+
+void AutoTableLayout::layout()
+{
+ // table layout based on the values collected in the layout structure.
+ int tableWidth = m_table->width() - m_table->bordersPaddingAndSpacing();
+ int available = tableWidth;
+ int nEffCols = m_table->numEffCols();
+
+ if (nEffCols != (int)m_layoutStruct.size()) {
+ fullRecalc();
+ nEffCols = m_table->numEffCols();
+ }
+
+ if (m_effWidthDirty)
+ calcEffectiveWidth();
+
+ bool havePercent = false;
+ bool haveRelative = false;
+ int totalRelative = 0;
+ int numAuto = 0;
+ int numFixed = 0;
+ float totalAuto = 0;
+ float totalFixed = 0;
+ int totalPercent = 0;
+ int allocAuto = 0;
+ int numAutoEmptyCellsOnly = 0;
+
+ // fill up every cell with its minWidth
+ for (int i = 0; i < nEffCols; i++) {
+ int w = m_layoutStruct[i].effMinWidth;
+ m_layoutStruct[i].calcWidth = w;
+ available -= w;
+ Length& width = m_layoutStruct[i].effWidth;
+ switch (width.type()) {
+ case Percent:
+ havePercent = true;
+ totalPercent += width.rawValue();
+ break;
+ case Relative:
+ haveRelative = true;
+ totalRelative += width.value();
+ break;
+ case Fixed:
+ numFixed++;
+ totalFixed += m_layoutStruct[i].effMaxWidth;
+ // fall through
+ break;
+ case Auto:
+ case Static:
+ if (m_layoutStruct[i].emptyCellsOnly)
+ numAutoEmptyCellsOnly++;
+ else {
+ numAuto++;
+ totalAuto += m_layoutStruct[i].effMaxWidth;
+ allocAuto += w;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // allocate width to percent cols
+ if (available > 0 && havePercent) {
+ for (int i = 0; i < nEffCols; i++) {
+ Length &width = m_layoutStruct[i].effWidth;
+ if (width.isPercent()) {
+ int w = max(int(m_layoutStruct[i].effMinWidth), width.calcMinValue(tableWidth));
+ available += m_layoutStruct[i].calcWidth - w;
+ m_layoutStruct[i].calcWidth = w;
+ }
+ }
+ if (totalPercent > 100 * percentScaleFactor) {
+ // remove overallocated space from the last columns
+ int excess = tableWidth*(totalPercent - 100 * percentScaleFactor) / (100 * percentScaleFactor);
+ for (int i = nEffCols-1; i >= 0; i--) {
+ if (m_layoutStruct[i].effWidth.isPercent()) {
+ int w = m_layoutStruct[i].calcWidth;
+ int reduction = min(w, excess);
+ // the lines below might look inconsistent, but that's the way it's handled in mozilla
+ excess -= reduction;
+ int newWidth = max(int (m_layoutStruct[i].effMinWidth), w - reduction);
+ available += w - newWidth;
+ m_layoutStruct[i].calcWidth = newWidth;
+ }
+ }
+ }
+ }
+
+ // then allocate width to fixed cols
+ if (available > 0) {
+ for (int i = 0; i < nEffCols; ++i) {
+ Length &width = m_layoutStruct[i].effWidth;
+ if (width.isFixed() && width.value() > m_layoutStruct[i].calcWidth) {
+ available += m_layoutStruct[i].calcWidth - width.value();
+ m_layoutStruct[i].calcWidth = width.value();
+ }
+ }
+ }
+
+ // now satisfy relative
+ if (available > 0) {
+ for (int i = 0; i < nEffCols; i++) {
+ Length &width = m_layoutStruct[i].effWidth;
+ if (width.isRelative() && width.value() != 0) {
+ // width=0* gets effMinWidth.
+ int w = width.value() * tableWidth / totalRelative;
+ available += m_layoutStruct[i].calcWidth - w;
+ m_layoutStruct[i].calcWidth = w;
+ }
+ }
+ }
+
+ // now satisfy variable
+ if (available > 0 && numAuto) {
+ available += allocAuto; // this gets redistributed
+ for (int i = 0; i < nEffCols; i++) {
+ Length &width = m_layoutStruct[i].effWidth;
+ if (width.isAuto() && totalAuto != 0 && !m_layoutStruct[i].emptyCellsOnly) {
+ int w = max(m_layoutStruct[i].calcWidth, static_cast<int>(available * static_cast<float>(m_layoutStruct[i].effMaxWidth) / totalAuto));
+ available -= w;
+ totalAuto -= m_layoutStruct[i].effMaxWidth;
+ m_layoutStruct[i].calcWidth = w;
+ }
+ }
+ }
+
+ // spread over fixed columns
+ if (available > 0 && numFixed) {
+ // still have some width to spread, distribute to fixed columns
+ for (int i = 0; i < nEffCols; i++) {
+ Length &width = m_layoutStruct[i].effWidth;
+ if (width.isFixed()) {
+ int w = static_cast<int>(available * static_cast<float>(m_layoutStruct[i].effMaxWidth) / totalFixed);
+ available -= w;
+ totalFixed -= m_layoutStruct[i].effMaxWidth;
+ m_layoutStruct[i].calcWidth += w;
+ }
+ }
+ }
+
+ // spread over percent colums
+ if (available > 0 && m_hasPercent && totalPercent < 100 * percentScaleFactor) {
+ // still have some width to spread, distribute weighted to percent columns
+ for (int i = 0; i < nEffCols; i++) {
+ Length &width = m_layoutStruct[i].effWidth;
+ if (width.isPercent()) {
+ int w = available * width.rawValue() / totalPercent;
+ available -= w;
+ totalPercent -= width.rawValue();
+ m_layoutStruct[i].calcWidth += w;
+ if (!available || !totalPercent) break;
+ }
+ }
+ }
+
+ // spread over the rest
+ if (available > 0 && nEffCols > numAutoEmptyCellsOnly) {
+ int total = nEffCols - numAutoEmptyCellsOnly;
+ // still have some width to spread
+ int i = nEffCols;
+ while (i--) {
+ // variable columns with empty cells only don't get any width
+ if (m_layoutStruct[i].effWidth.isAuto() && m_layoutStruct[i].emptyCellsOnly)
+ continue;
+ int w = available / total;
+ available -= w;
+ total--;
+ m_layoutStruct[i].calcWidth += w;
+ }
+ }
+
+ // 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 (available < 0) {
+ // Need to reduce cells with the following prioritization:
+ // (1) Auto
+ // (2) Relative
+ // (3) Fixed
+ // (4) Percent
+ // This is basically the reverse of how we grew the cells.
+ if (available < 0) {
+ int mw = 0;
+ for (int i = nEffCols-1; i >= 0; i--) {
+ Length &width = m_layoutStruct[i].effWidth;
+ if (width.isAuto())
+ mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth;
+ }
+
+ for (int i = nEffCols-1; i >= 0 && mw > 0; i--) {
+ Length &width = m_layoutStruct[i].effWidth;
+ if (width.isAuto()) {
+ int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth;
+ int reduce = available * minMaxDiff / mw;
+ m_layoutStruct[i].calcWidth += reduce;
+ available -= reduce;
+ mw -= minMaxDiff;
+ if (available >= 0)
+ break;
+ }
+ }
+ }
+
+ if (available < 0) {
+ int mw = 0;
+ for (int i = nEffCols-1; i >= 0; i--) {
+ Length& width = m_layoutStruct[i].effWidth;
+ if (width.isRelative())
+ mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth;
+ }
+
+ for (int i = nEffCols-1; i >= 0 && mw > 0; i--) {
+ Length& width = m_layoutStruct[i].effWidth;
+ if (width.isRelative()) {
+ int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth;
+ int reduce = available * minMaxDiff / mw;
+ m_layoutStruct[i].calcWidth += reduce;
+ available -= reduce;
+ mw -= minMaxDiff;
+ if (available >= 0)
+ break;
+ }
+ }
+ }
+
+ if (available < 0) {
+ int mw = 0;
+ for (int i = nEffCols-1; i >= 0; i--) {
+ Length& width = m_layoutStruct[i].effWidth;
+ if (width.isFixed())
+ mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth;
+ }
+
+ for (int i = nEffCols-1; i >= 0 && mw > 0; i--) {
+ Length& width = m_layoutStruct[i].effWidth;
+ if (width.isFixed()) {
+ int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth;
+ int reduce = available * minMaxDiff / mw;
+ m_layoutStruct[i].calcWidth += reduce;
+ available -= reduce;
+ mw -= minMaxDiff;
+ if (available >= 0)
+ break;
+ }
+ }
+ }
+
+ if (available < 0) {
+ int mw = 0;
+ for (int i = nEffCols-1; i >= 0; i--) {
+ Length& width = m_layoutStruct[i].effWidth;
+ if (width.isPercent())
+ mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth;
+ }
+
+ for (int i = nEffCols-1; i >= 0 && mw > 0; i--) {
+ Length& width = m_layoutStruct[i].effWidth;
+ if (width.isPercent()) {
+ int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth;
+ int reduce = available * minMaxDiff / mw;
+ m_layoutStruct[i].calcWidth += reduce;
+ available -= reduce;
+ mw -= minMaxDiff;
+ if (available >= 0)
+ break;
+ }
+ }
+ }
+ }
+
+ int pos = 0;
+ for (int i = 0; i < nEffCols; i++) {
+ m_table->columnPositions()[i] = pos;
+ pos += m_layoutStruct[i].calcWidth + m_table->hBorderSpacing();
+ }
+ m_table->columnPositions()[m_table->columnPositions().size() - 1] = pos;
+}
+
+
+void AutoTableLayout::calcPercentages() const
+{
+ unsigned totalPercent = 0;
+ for (unsigned i = 0; i < m_layoutStruct.size(); i++) {
+ if (m_layoutStruct[i].width.isPercent())
+ totalPercent += m_layoutStruct[i].width.rawValue();
+ }
+ m_totalPercent = totalPercent / percentScaleFactor;
+ m_percentagesDirty = false;
+}
+
+#undef DEBUG_LAYOUT
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.h b/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.h
new file mode 100644
index 0000000..641a68b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/AutoTableLayout.h
@@ -0,0 +1,87 @@
+/*
+ * 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)
+ *
+ * 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.
+ *
+ * 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 AutoTableLayout_h
+#define AutoTableLayout_h
+
+#include "Length.h"
+#include "TableLayout.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class RenderTable;
+class RenderTableCell;
+
+class AutoTableLayout : public TableLayout {
+public:
+ AutoTableLayout(RenderTable*);
+ ~AutoTableLayout();
+
+ virtual void calcPrefWidths(int& minWidth, int& maxWidth);
+ virtual void layout();
+
+protected:
+ void fullRecalc();
+ void recalcColumn(int effCol);
+
+ void calcPercentages() const;
+ int totalPercent() const
+ {
+ if (m_percentagesDirty)
+ calcPercentages();
+ return m_totalPercent;
+ }
+
+ int calcEffectiveWidth();
+
+ void insertSpanCell(RenderTableCell*);
+
+ struct Layout {
+ Layout()
+ : minWidth(0)
+ , maxWidth(0)
+ , effMinWidth(0)
+ , effMaxWidth(0)
+ , calcWidth(0)
+ , emptyCellsOnly(true) {}
+ Length width;
+ Length effWidth;
+ int minWidth;
+ int maxWidth;
+ int effMinWidth;
+ int effMaxWidth;
+ int calcWidth;
+ bool emptyCellsOnly;
+ };
+
+ Vector<Layout, 4> m_layoutStruct;
+ Vector<RenderTableCell*, 4> m_spanCells;
+ bool m_hasPercent : 1;
+ mutable bool m_percentagesDirty : 1;
+ mutable bool m_effWidthDirty : 1;
+ mutable unsigned short m_totalPercent;
+};
+
+} // namespace WebCore
+
+#endif // AutoTableLayout_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/CounterNode.cpp b/src/3rdparty/webkit/WebCore/rendering/CounterNode.cpp
new file mode 100644
index 0000000..c30ca9a
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/CounterNode.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ *
+ * 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 "CounterNode.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)
+ , m_value(value)
+ , m_countInParent(0)
+ , m_renderer(o)
+ , m_parent(0)
+ , m_previousSibling(0)
+ , m_nextSibling(0)
+ , m_firstChild(0)
+ , m_lastChild(0)
+{
+}
+
+int CounterNode::computeCountInParent() const
+{
+ int increment = m_isReset ? 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()
+{
+ for (CounterNode* c = this; c; c = c->m_nextSibling) {
+ int oldCount = c->m_countInParent;
+ int newCount = c->computeCountInParent();
+ c->m_countInParent = newCount;
+ if (oldCount == newCount)
+ break;
+ if (c->m_renderer->isCounter())
+ c->m_renderer->setNeedsLayoutAndPrefWidthsRecalc();
+ }
+}
+
+void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild)
+{
+ ASSERT(newChild);
+ ASSERT(!newChild->m_parent);
+ ASSERT(!newChild->m_previousSibling);
+ ASSERT(!newChild->m_nextSibling);
+ ASSERT(!refChild || refChild->m_parent == this);
+
+ CounterNode* next;
+
+ if (refChild) {
+ next = refChild->m_nextSibling;
+ refChild->m_nextSibling = newChild;
+ } else {
+ next = m_firstChild;
+ 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 (next)
+ next->recount();
+}
+
+void CounterNode::removeChild(CounterNode* oldChild)
+{
+ ASSERT(oldChild);
+ ASSERT(!oldChild->m_firstChild);
+ ASSERT(!oldChild->m_lastChild);
+
+ CounterNode* next = oldChild->m_nextSibling;
+ CounterNode* prev = oldChild->m_previousSibling;
+
+ oldChild->m_nextSibling = 0;
+ oldChild->m_previousSibling = 0;
+ oldChild->m_parent = 0;
+
+ if (prev)
+ prev->m_nextSibling = next;
+ else {
+ ASSERT(m_firstChild == oldChild);
+ m_firstChild = next;
+ }
+
+ if (next)
+ next->m_previousSibling = prev;
+ else {
+ ASSERT(m_lastChild == oldChild);
+ m_lastChild = prev;
+ }
+
+ if (next)
+ next->recount();
+}
+
+#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());
+ }
+}
+
+#endif
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+
+void showTree(const WebCore::CounterNode* counter)
+{
+ if (counter)
+ showTreeAndMark(counter);
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/CounterNode.h b/src/3rdparty/webkit/WebCore/rendering/CounterNode.h
new file mode 100644
index 0000000..57f9563
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/CounterNode.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2006, 2007 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 CounterNode_h
+#define CounterNode_h
+
+#include <wtf/Noncopyable.h>
+
+// This implements a counter tree that is used for finding parents in counters() lookup,
+// and for propagating count changes when nodes are added or removed.
+
+// Parents represent unique counters and their scope, which are created either explicitly
+// by "counter-reset" style rules or implicitly by referring to a counter that is not in scope.
+// Such nodes are tagged as "reset" nodes, although they are not all due to "counter-reset".
+
+// Not that render tree children are often counter tree siblings due to counter scoping rules.
+
+namespace WebCore {
+
+class RenderObject;
+
+class CounterNode : Noncopyable {
+public:
+ CounterNode(RenderObject*, bool isReset, int value);
+
+ bool isReset() const { return m_isReset; }
+ int value() const { return m_value; }
+ int countInParent() const { return m_countInParent; }
+ RenderObject* renderer() const { return m_renderer; }
+
+ CounterNode* parent() const { return m_parent; }
+ CounterNode* previousSibling() const { return m_previousSibling; }
+ CounterNode* nextSibling() const { return m_nextSibling; }
+ CounterNode* firstChild() const { return m_firstChild; }
+ CounterNode* lastChild() const { return m_lastChild; }
+
+ void insertAfter(CounterNode* newChild, CounterNode* beforeChild);
+ void removeChild(CounterNode*);
+
+private:
+ int computeCountInParent() const;
+ void recount();
+
+ bool m_isReset;
+ int m_value;
+ int m_countInParent;
+ RenderObject* m_renderer;
+
+ CounterNode* m_parent;
+ CounterNode* m_previousSibling;
+ CounterNode* m_nextSibling;
+ CounterNode* m_firstChild;
+ CounterNode* m_lastChild;
+};
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showTree(const WebCore::CounterNode*);
+#endif
+
+#endif // CounterNode_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp
new file mode 100644
index 0000000..0bd1d1a
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.cpp
@@ -0,0 +1,85 @@
+/**
+* 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
+ * 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 "EllipsisBox.h"
+
+#include "Document.h"
+#include "GraphicsContext.h"
+#include "HitTestResult.h"
+
+namespace WebCore {
+
+void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
+{
+ GraphicsContext* context = paintInfo.context;
+ RenderStyle* style = m_object->style(m_firstLine);
+ if (style->font() != context->font())
+ context->setFont(style->font());
+
+ Color textColor = style->color();
+ if (textColor != context->fillColor())
+ context->setFillColor(textColor);
+ bool setShadow = false;
+ if (style->textShadow()) {
+ context->setShadow(IntSize(style->textShadow()->x, style->textShadow()->y),
+ style->textShadow()->blur, style->textShadow()->color);
+ setShadow = true;
+ }
+
+ const String& str = m_str;
+ context->drawText(TextRun(str.characters(), str.length(), false, 0, 0, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + m_baseline));
+
+ if (setShadow)
+ context->clearShadow();
+
+ if (m_markupBox) {
+ // Paint the markup box
+ tx += m_x + m_width - m_markupBox->xPos();
+ ty += m_y + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline());
+ m_markupBox->paint(paintInfo, tx, ty);
+ }
+}
+
+bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
+{
+ tx += m_x;
+ ty += m_y;
+
+ // Hit test the markup box.
+ if (m_markupBox) {
+ int mtx = tx + m_width - m_markupBox->xPos();
+ int mty = ty + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline());
+ if (m_markupBox->nodeAtPoint(request, result, x, y, mtx, mty)) {
+ object()->updateHitTestResult(result, IntPoint(x - mtx, y - mty));
+ return true;
+ }
+ }
+
+ if (visibleToHitTesting() && IntRect(tx, ty, m_width, m_height).contains(x, y)) {
+ object()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h
new file mode 100644
index 0000000..dbb30cd
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/EllipsisBox.h
@@ -0,0 +1,53 @@
+/**
+* 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
+ * 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 EllipsisBox_h
+#define EllipsisBox_h
+
+#include "InlineBox.h"
+
+namespace WebCore {
+
+class HitTestResult;
+
+struct HitTestRequest;
+
+class EllipsisBox : public InlineBox {
+public:
+ EllipsisBox(RenderObject* obj, const AtomicString& ellipsisStr, InlineFlowBox* parent,
+ int width, int y, int height, int baseline, bool firstLine, InlineBox* markupBox)
+ : InlineBox(obj, 0, y, width, height, baseline, firstLine, true, false, false, 0, 0, parent)
+ , m_str(ellipsisStr)
+ , m_markupBox(markupBox)
+ {
+ }
+
+ virtual void paint(RenderObject::PaintInfo&, int tx, int ty);
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty);
+
+private:
+ AtomicString m_str;
+ InlineBox* m_markupBox;
+};
+
+} // namespace WebCore
+
+#endif // EllipsisBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp b/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp
new file mode 100644
index 0000000..d7c1293
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.cpp
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ *
+ * 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.
+ *
+ * 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 "FixedTableLayout.h"
+
+#include "RenderTable.h"
+#include "RenderTableCell.h"
+#include "RenderTableCol.h"
+#include "RenderTableSection.h"
+
+/*
+ The text below is from the CSS 2.1 specs.
+
+ Fixed table layout
+
+ With this (fast) algorithm, the horizontal layout of the table does
+ not depend on the contents of the cells; it only depends on the
+ table's width, the width of the columns, and borders or cell
+ spacing.
+
+ The table's width may be specified explicitly with the 'width'
+ property. A value of 'auto' (for both 'display: table' and 'display:
+ inline-table') means use the automatic table layout algorithm.
+
+ In the fixed table layout algorithm, the width of each column is
+ determined as follows:
+
+ 1. A column element with a value other than 'auto' for the 'width'
+ property sets the width for that column.
+
+ 2. Otherwise, a cell in the first row with a value other than
+ 'auto' for the 'width' property sets the width for that column. If
+ the cell spans more than one column, the width is divided over the
+ columns.
+
+ 3. Any remaining columns equally divide the remaining horizontal
+ table space (minus borders or cell spacing).
+
+ The width of the table is then the greater of the value of the
+ 'width' property for the table element and the sum of the column
+ widths (plus cell spacing or borders). If the table is wider than
+ the columns, the extra space should be distributed over the columns.
+
+
+ In this manner, the user agent can begin to lay out the table once
+ the entire first row has been received. Cells in subsequent rows do
+ not affect column widths. Any cell that has content that overflows
+ uses the 'overflow' property to determine whether to clip the
+ overflow content.
+*/
+
+using namespace std;
+
+namespace WebCore {
+
+FixedTableLayout::FixedTableLayout(RenderTable* table)
+ : TableLayout(table)
+{
+}
+
+int FixedTableLayout::calcWidthArray(int)
+{
+ int usedWidth = 0;
+
+ // iterate over all <col> elements
+ RenderObject* child = m_table->firstChild();
+ int cCol = 0;
+ int nEffCols = m_table->numEffCols();
+ m_width.resize(nEffCols);
+ m_width.fill(Length(Auto));
+
+ Length grpWidth;
+ while (child) {
+ if (child->isTableCol()) {
+ RenderTableCol *col = static_cast<RenderTableCol *>(child);
+ int span = col->span();
+ if (col->firstChild())
+ grpWidth = col->style()->width();
+ else {
+ Length w = col->style()->width();
+ if (w.isAuto())
+ w = grpWidth;
+ int effWidth = 0;
+ if (w.isFixed() && w.value() > 0)
+ effWidth = w.value();
+
+ int usedSpan = 0;
+ int i = 0;
+ while (usedSpan < span) {
+ if(cCol + i >= nEffCols) {
+ m_table->appendColumn(span - usedSpan);
+ nEffCols++;
+ m_width.resize(nEffCols);
+ m_width[nEffCols-1] = Length();
+ }
+ int eSpan = m_table->spanOfEffCol(cCol+i);
+ if ((w.isFixed() || w.isPercent()) && w.isPositive()) {
+ m_width[cCol + i].setRawValue(w.type(), w.rawValue() * eSpan);
+ usedWidth += effWidth * eSpan;
+ }
+ usedSpan += eSpan;
+ i++;
+ }
+ cCol += i;
+ }
+ } else
+ break;
+
+ RenderObject *next = child->firstChild();
+ if (!next)
+ next = child->nextSibling();
+ if (!next && child->parent()->isTableCol()) {
+ next = child->parent()->nextSibling();
+ grpWidth = Length();
+ }
+ child = next;
+ }
+
+ // Iterate over the first row in case some are unspecified.
+ RenderTableSection* section = m_table->header();
+ if (!section)
+ section = m_table->firstBody();
+ if (!section)
+ section = m_table->footer();
+ if (section && !section->numRows())
+ section = m_table->sectionBelow(section, true);
+ if (section) {
+ cCol = 0;
+ RenderObject* firstRow = section->firstChild();
+ child = firstRow->firstChild();
+ while (child) {
+ if (child->isTableCell()) {
+ RenderTableCell* cell = static_cast<RenderTableCell*>(child);
+ if (cell->prefWidthsDirty())
+ cell->calcPrefWidths();
+
+ Length w = cell->styleOrColWidth();
+ int span = cell->colSpan();
+ int effWidth = 0;
+ if (w.isFixed() && w.isPositive())
+ effWidth = w.value();
+
+ int usedSpan = 0;
+ int i = 0;
+ while (usedSpan < span) {
+ ASSERT(cCol + i < nEffCols);
+ int eSpan = m_table->spanOfEffCol(cCol + i);
+ // Only set if no col element has already set it.
+ if (m_width[cCol + i].isAuto() && w.type() != Auto) {
+ m_width[cCol + i].setRawValue(w.type(), w.rawValue() * eSpan / span);
+ usedWidth += effWidth * eSpan / span;
+ }
+ usedSpan += eSpan;
+ i++;
+ }
+ cCol += i;
+ }
+ child = child->nextSibling();
+ }
+ }
+
+ return usedWidth;
+}
+
+void FixedTableLayout::calcPrefWidths(int& minWidth, int& maxWidth)
+{
+ // FIXME: This entire calculation is incorrect for both minwidth and maxwidth.
+
+ // we might want to wait until we have all of the first row before
+ // layouting for the first time.
+
+ // only need to calculate the minimum width as the sum of the
+ // cols/cells with a fixed width.
+ //
+ // The maximum width is max(minWidth, tableWidth).
+ int bs = m_table->bordersPaddingAndSpacing();
+
+ int tableWidth = m_table->style()->width().isFixed() ? m_table->style()->width().value() - bs : 0;
+ int mw = calcWidthArray(tableWidth) + bs;
+
+ minWidth = max(mw, tableWidth);
+ maxWidth = minWidth;
+}
+
+void FixedTableLayout::layout()
+{
+ int tableWidth = m_table->width() - m_table->bordersPaddingAndSpacing();
+ int nEffCols = m_table->numEffCols();
+ Vector<int> calcWidth(nEffCols, 0);
+
+ int numAuto = 0;
+ int autoSpan = 0;
+ int totalFixedWidth = 0;
+ int totalPercentWidth = 0;
+ int totalRawPercent = 0;
+
+ // Compute requirements and try to satisfy fixed and percent widths.
+ // Percentages are of the table's width, so for example
+ // for a table width of 100px with columns (40px, 10%), the 10% compute
+ // to 10px here, and will scale up to 20px in the final (80px, 20px).
+ for (int i = 0; i < nEffCols; i++) {
+ if (m_width[i].isFixed()) {
+ calcWidth[i] = m_width[i].value();
+ totalFixedWidth += calcWidth[i];
+ } else if (m_width[i].isPercent()) {
+ calcWidth[i] = m_width[i].calcValue(tableWidth);
+ totalPercentWidth += calcWidth[i];
+ totalRawPercent += m_width[i].rawValue();
+ } else if (m_width[i].isAuto()) {
+ numAuto++;
+ autoSpan += m_table->spanOfEffCol(i);
+ }
+ }
+
+ int hspacing = m_table->hBorderSpacing();
+ int totalWidth = totalFixedWidth + totalPercentWidth;
+ if (!numAuto || totalWidth > tableWidth) {
+ // If there are no auto columns, or if the total is too wide, take
+ // what we have and scale it to fit as necessary.
+ if (totalWidth != tableWidth) {
+ // Fixed widths only scale up
+ if (totalFixedWidth && totalWidth < tableWidth) {
+ totalFixedWidth = 0;
+ for (int i = 0; i < nEffCols; i++) {
+ if (m_width[i].isFixed()) {
+ calcWidth[i] = calcWidth[i] * tableWidth / totalWidth;
+ totalFixedWidth += calcWidth[i];
+ }
+ }
+ }
+ if (totalRawPercent) {
+ totalPercentWidth = 0;
+ for (int i = 0; i < nEffCols; i++) {
+ if (m_width[i].isPercent()) {
+ calcWidth[i] = m_width[i].rawValue() * (tableWidth - totalFixedWidth) / totalRawPercent;
+ totalPercentWidth += calcWidth[i];
+ }
+ }
+ }
+ totalWidth = totalFixedWidth + totalPercentWidth;
+ }
+ } else {
+ // Divide the remaining width among the auto columns.
+ int remainingWidth = tableWidth - totalFixedWidth - totalPercentWidth - hspacing * (autoSpan - numAuto);
+ int lastAuto = 0;
+ for (int i = 0; i < nEffCols; i++) {
+ if (m_width[i].isAuto()) {
+ int span = m_table->spanOfEffCol(i);
+ int w = remainingWidth * span / autoSpan;
+ calcWidth[i] = w + hspacing * (span - 1);
+ remainingWidth -= w;
+ if (!remainingWidth)
+ break;
+ lastAuto = i;
+ numAuto--;
+ autoSpan -= span;
+ }
+ }
+ // Last one gets the remainder.
+ if (remainingWidth)
+ calcWidth[lastAuto] += remainingWidth;
+ totalWidth = tableWidth;
+ }
+
+ if (totalWidth < tableWidth) {
+ // Spread extra space over columns.
+ int remainingWidth = tableWidth - totalWidth;
+ int total = nEffCols;
+ while (total) {
+ int w = remainingWidth / total;
+ remainingWidth -= w;
+ calcWidth[--total] += w;
+ }
+ if (nEffCols > 0)
+ calcWidth[nEffCols - 1] += remainingWidth;
+ }
+
+ int pos = 0;
+ for (int i = 0; i < nEffCols; i++) {
+ m_table->columnPositions()[i] = pos;
+ pos += calcWidth[i] + hspacing;
+ }
+ int colPositionsSize = m_table->columnPositions().size();
+ if (colPositionsSize > 0)
+ m_table->columnPositions()[colPositionsSize - 1] = pos;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.h b/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.h
new file mode 100644
index 0000000..ed7c089
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/FixedTableLayout.h
@@ -0,0 +1,49 @@
+/*
+ * 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)
+ *
+ * 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.
+ *
+ * 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 FixedTableLayout_h
+#define FixedTableLayout_h
+
+#include "Length.h"
+#include "TableLayout.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class RenderTable;
+
+class FixedTableLayout : public TableLayout {
+public:
+ FixedTableLayout(RenderTable*);
+
+ virtual void calcPrefWidths(int& minWidth, int& maxWidth);
+ virtual void layout();
+
+protected:
+ int calcWidthArray(int tableWidth);
+
+ Vector<Length> m_width;
+};
+
+} // namespace WebCore
+
+#endif // FixedTableLayout_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/GapRects.h b/src/3rdparty/webkit/WebCore/rendering/GapRects.h
new file mode 100644
index 0000000..a762ae5
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/GapRects.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2005, 2006 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.
+
+
+ Some useful definitions needed for laying out elements
+*/
+
+#ifndef GapRects_h
+#define GapRects_h
+
+#include "IntRect.h"
+
+namespace WebCore {
+
+ struct GapRects {
+ const IntRect& left() const { return m_left; }
+ const IntRect& center() const { return m_center; }
+ const IntRect& right() const { return m_right; }
+
+ void uniteLeft(const IntRect& r) { m_left.unite(r); }
+ void uniteCenter(const IntRect& r) { m_center.unite(r); }
+ void uniteRight(const IntRect& r) { m_right.unite(r); }
+ void unite(const GapRects& o) { uniteLeft(o.left()); uniteCenter(o.center()); uniteRight(o.right()); }
+
+ operator IntRect() const
+ {
+ IntRect result = m_left;
+ result.unite(m_center);
+ result.unite(m_right);
+ return result;
+ }
+
+ bool operator==(const GapRects& other)
+ {
+ return m_left == other.left() && m_center == other.center() && m_right == other.right();
+ }
+ bool operator!=(const GapRects& other) { return !(*this == other); }
+
+ private:
+ IntRect m_left;
+ IntRect m_center;
+ IntRect m_right;
+ };
+
+} // namespace WebCore
+
+#endif // GapRects_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h b/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h
new file mode 100644
index 0000000..11dca4b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/HitTestRequest.h
@@ -0,0 +1,44 @@
+/*
+ * 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
+ * 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 HitTestRequest_h
+#define HitTestRequest_h
+
+namespace WebCore {
+
+struct HitTestRequest {
+ HitTestRequest(bool r, bool a, bool m = false, bool u = false)
+ : readonly(r)
+ , active(a)
+ , mouseMove(m)
+ , mouseUp(u)
+ {
+ }
+
+ bool readonly;
+ bool active;
+ bool mouseMove;
+ bool mouseUp;
+};
+
+} // namespace WebCore
+
+#endif // HitTestRequest_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/HitTestResult.cpp b/src/3rdparty/webkit/WebCore/rendering/HitTestResult.cpp
new file mode 100644
index 0000000..5a041ed
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/HitTestResult.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2006, 2008 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 "HitTestResult.h"
+
+#include "Frame.h"
+#include "FrameTree.h"
+#include "HTMLAnchorElement.h"
+#include "HTMLImageElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "RenderImage.h"
+#include "Scrollbar.h"
+#include "SelectionController.h"
+
+#if ENABLE(SVG)
+#include "SVGNames.h"
+#include "XLinkNames.h"
+#endif
+
+#if ENABLE(WML)
+#include "WMLImageElement.h"
+#include "WMLNames.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+HitTestResult::HitTestResult(const IntPoint& point)
+ : m_point(point)
+ , m_isOverWidget(false)
+{
+}
+
+HitTestResult::HitTestResult(const HitTestResult& other)
+ : m_innerNode(other.innerNode())
+ , m_innerNonSharedNode(other.innerNonSharedNode())
+ , m_point(other.point())
+ , m_localPoint(other.localPoint())
+ , m_innerURLElement(other.URLElement())
+ , m_scrollbar(other.scrollbar())
+ , m_isOverWidget(other.isOverWidget())
+{
+}
+
+HitTestResult::~HitTestResult()
+{
+}
+
+HitTestResult& HitTestResult::operator=(const HitTestResult& other)
+{
+ m_innerNode = other.innerNode();
+ m_innerNonSharedNode = other.innerNonSharedNode();
+ m_point = other.point();
+ m_localPoint = other.localPoint();
+ m_innerURLElement = other.URLElement();
+ m_scrollbar = other.scrollbar();
+ m_isOverWidget = other.isOverWidget();
+ return *this;
+}
+
+void HitTestResult::setToNonShadowAncestor()
+{
+ Node* node = innerNode();
+ if (node)
+ node = node->shadowAncestorNode();
+ setInnerNode(node);
+ node = innerNonSharedNode();
+ if (node)
+ node = node->shadowAncestorNode();
+ setInnerNonSharedNode(node);
+}
+
+void HitTestResult::setInnerNode(Node* n)
+{
+ m_innerNode = n;
+}
+
+void HitTestResult::setInnerNonSharedNode(Node* n)
+{
+ m_innerNonSharedNode = n;
+}
+
+void HitTestResult::setURLElement(Element* n)
+{
+ m_innerURLElement = n;
+}
+
+void HitTestResult::setScrollbar(Scrollbar* s)
+{
+ m_scrollbar = s;
+}
+
+Frame* HitTestResult::targetFrame() const
+{
+ if (!m_innerURLElement)
+ return 0;
+
+ Frame* frame = m_innerURLElement->document()->frame();
+ if (!frame)
+ return 0;
+
+ 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)
+ return false;
+
+ Frame* frame = m_innerNonSharedNode->document()->frame();
+ if (!frame)
+ return false;
+
+ return frame->selection()->contains(m_point);
+}
+
+String HitTestResult::spellingToolTip() const
+{
+ // Return the tool tip string associated with this point, if any. Only markers associated with bad grammar
+ // currently supply strings, but maybe someday markers associated with misspelled words will also.
+ if (!m_innerNonSharedNode)
+ return String();
+
+ DocumentMarker* marker = m_innerNonSharedNode->document()->markerContainingPoint(m_point, DocumentMarker::Grammar);
+ if (!marker)
+ return String();
+
+ return marker->description;
+}
+
+String HitTestResult::title() const
+{
+ // Find the title in the nearest enclosing DOM node.
+ // For <area> tags in image maps, walk the tree for the <area>, not the <img> using it.
+ for (Node* titleNode = m_innerNode.get(); titleNode; titleNode = titleNode->parentNode()) {
+ if (titleNode->isElementNode()) {
+ String title = static_cast<Element*>(titleNode)->title();
+ if (!title.isEmpty())
+ return title;
+ }
+ }
+ return String();
+}
+
+String displayString(const String& string, const Node* node)
+{
+ if (!node)
+ return string;
+ String copy(string);
+ copy.replace('\\', node->document()->backslashAsCurrencySymbol());
+ return copy;
+}
+
+String HitTestResult::altDisplayString() const
+{
+ if (!m_innerNonSharedNode)
+ return String();
+
+ if (m_innerNonSharedNode->hasTagName(imgTag)) {
+ HTMLImageElement* image = static_cast<HTMLImageElement*>(m_innerNonSharedNode.get());
+ return displayString(image->alt(), m_innerNonSharedNode.get());
+ }
+
+ if (m_innerNonSharedNode->hasTagName(inputTag)) {
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(m_innerNonSharedNode.get());
+ return displayString(input->alt(), m_innerNonSharedNode.get());
+ }
+
+#if ENABLE(WML)
+ if (m_innerNonSharedNode->hasTagName(WMLNames::imgTag)) {
+ WMLImageElement* image = static_cast<WMLImageElement*>(m_innerNonSharedNode.get());
+ return displayString(image->altText(), m_innerNonSharedNode.get());
+ }
+#endif
+
+ return String();
+}
+
+Image* HitTestResult::image() const
+{
+ if (!m_innerNonSharedNode)
+ return 0;
+
+ RenderObject* renderer = m_innerNonSharedNode->renderer();
+ if (renderer && renderer->isImage()) {
+ RenderImage* image = static_cast<WebCore::RenderImage*>(renderer);
+ if (image->cachedImage() && !image->cachedImage()->errorOccurred())
+ return image->cachedImage()->image();
+ }
+
+ return 0;
+}
+
+IntRect HitTestResult::imageRect() const
+{
+ if (!image())
+ return IntRect();
+ return m_innerNonSharedNode->renderer()->absoluteContentBox();
+}
+
+KURL HitTestResult::absoluteImageURL() const
+{
+ if (!(m_innerNonSharedNode && m_innerNonSharedNode->document()))
+ return KURL();
+
+ if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isImage()))
+ return KURL();
+
+ AtomicString urlString;
+ if (m_innerNonSharedNode->hasTagName(embedTag)
+ || m_innerNonSharedNode->hasTagName(imgTag)
+ || m_innerNonSharedNode->hasTagName(inputTag)
+ || m_innerNonSharedNode->hasTagName(objectTag)
+#if ENABLE(SVG)
+ || m_innerNonSharedNode->hasTagName(SVGNames::imageTag)
+#endif
+#if ENABLE(WML)
+ || m_innerNonSharedNode->hasTagName(WMLNames::imgTag)
+#endif
+ ) {
+ Element* element = static_cast<Element*>(m_innerNonSharedNode.get());
+ urlString = element->getAttribute(element->imageSourceAttributeName());
+ } else
+ return KURL();
+
+ return m_innerNonSharedNode->document()->completeURL(parseURL(urlString));
+}
+
+KURL HitTestResult::absoluteLinkURL() const
+{
+ if (!(m_innerURLElement && m_innerURLElement->document()))
+ return KURL();
+
+ AtomicString urlString;
+ if (m_innerURLElement->hasTagName(aTag) || m_innerURLElement->hasTagName(areaTag) || m_innerURLElement->hasTagName(linkTag))
+ urlString = m_innerURLElement->getAttribute(hrefAttr);
+#if ENABLE(SVG)
+ else if (m_innerURLElement->hasTagName(SVGNames::aTag))
+ urlString = m_innerURLElement->getAttribute(XLinkNames::hrefAttr);
+#endif
+#if ENABLE(WML)
+ else if (m_innerURLElement->hasTagName(WMLNames::aTag))
+ urlString = m_innerURLElement->getAttribute(hrefAttr);
+#endif
+ else
+ return KURL();
+
+ return m_innerURLElement->document()->completeURL(parseURL(urlString));
+}
+
+bool HitTestResult::isLiveLink() const
+{
+ if (!(m_innerURLElement && m_innerURLElement->document()))
+ return false;
+
+ if (m_innerURLElement->hasTagName(aTag))
+ return static_cast<HTMLAnchorElement*>(m_innerURLElement.get())->isLiveLink();
+#if ENABLE(SVG)
+ if (m_innerURLElement->hasTagName(SVGNames::aTag))
+ return m_innerURLElement->isLink();
+#endif
+#if ENABLE(WML)
+ if (m_innerURLElement->hasTagName(WMLNames::aTag))
+ return m_innerURLElement->isLink();
+#endif
+
+ return false;
+}
+
+String HitTestResult::titleDisplayString() const
+{
+ if (!m_innerURLElement)
+ return String();
+
+ return displayString(m_innerURLElement->title(), m_innerURLElement.get());
+}
+
+String HitTestResult::textContent() const
+{
+ if (!m_innerURLElement)
+ return String();
+ return m_innerURLElement->textContent();
+}
+
+// FIXME: This function needs a better name and may belong in a different class. It's not
+// really isContentEditable(); it's more like needsEditingContextMenu(). In many ways, this
+// function would make more sense in the ContextMenu class, except that WebElementDictionary
+// hooks into it. Anyway, we should architect this better.
+bool HitTestResult::isContentEditable() const
+{
+ if (!m_innerNonSharedNode)
+ return false;
+
+ if (m_innerNonSharedNode->hasTagName(textareaTag) || m_innerNonSharedNode->hasTagName(isindexTag))
+ return true;
+
+ if (m_innerNonSharedNode->hasTagName(inputTag))
+ return static_cast<HTMLInputElement*>(m_innerNonSharedNode.get())->isTextField();
+
+ return m_innerNonSharedNode->isContentEditable();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h b/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h
new file mode 100644
index 0000000..5ed9b34
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/HitTestResult.h
@@ -0,0 +1,94 @@
+/*
+ * 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
+ * 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 HitTestResult_h
+#define HitTestResult_h
+
+#include "IntPoint.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Element;
+class Frame;
+class Image;
+class KURL;
+class IntRect;
+class Node;
+class Scrollbar;
+class String;
+
+class HitTestResult {
+public:
+ HitTestResult(const IntPoint&);
+ HitTestResult(const HitTestResult&);
+ ~HitTestResult();
+ HitTestResult& operator=(const HitTestResult&);
+
+ Node* innerNode() const { return m_innerNode.get(); }
+ Node* innerNonSharedNode() const { return m_innerNonSharedNode.get(); }
+ IntPoint point() const { return m_point; }
+ IntPoint localPoint() const { return m_localPoint; }
+ Element* URLElement() const { return m_innerURLElement.get(); }
+ Scrollbar* scrollbar() const { return m_scrollbar.get(); }
+ bool isOverWidget() const { return m_isOverWidget; }
+
+ void setToNonShadowAncestor();
+
+ void setInnerNode(Node*);
+ void setInnerNonSharedNode(Node*);
+ void setPoint(const IntPoint& p) { m_point = p; }
+ void setLocalPoint(const IntPoint& p) { m_localPoint = p; }
+ void setURLElement(Element*);
+ void setScrollbar(Scrollbar*);
+ void setIsOverWidget(bool b) { m_isOverWidget = b; }
+
+ Frame* targetFrame() const;
+ IntRect boundingBox() const;
+ bool isSelected() const;
+ String spellingToolTip() const;
+ String title() const;
+ String altDisplayString() const;
+ String titleDisplayString() const;
+ Image* image() const;
+ IntRect imageRect() const;
+ KURL absoluteImageURL() const;
+ KURL absoluteLinkURL() const;
+ String textContent() const;
+ bool isLiveLink() const;
+ bool isContentEditable() const;
+
+private:
+ RefPtr<Node> m_innerNode;
+ RefPtr<Node> m_innerNonSharedNode;
+ IntPoint m_point;
+ IntPoint m_localPoint; // A point in the local coordinate space of m_innerNonSharedNode's renderer. Allows us to efficiently
+ // determine where inside the renderer we hit on subsequent operations.
+ RefPtr<Element> m_innerURLElement;
+ RefPtr<Scrollbar> m_scrollbar;
+ bool m_isOverWidget; // Returns true if we are over a widget (and not in the border/padding area of a RenderWidget for example).
+};
+
+String displayString(const String&, const Node*);
+
+} // namespace WebCore
+
+#endif // HitTestResult_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineBox.cpp b/src/3rdparty/webkit/WebCore/rendering/InlineBox.cpp
new file mode 100644
index 0000000..f5d0de5
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/InlineBox.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "InlineBox.h"
+
+#include "HitTestResult.h"
+#include "InlineFlowBox.h"
+#include "RenderArena.h"
+#include "RootInlineBox.h"
+
+using namespace std;
+
+namespace WebCore {
+
+#ifndef NDEBUG
+static bool inInlineBoxDetach;
+#endif
+
+#ifndef NDEBUG
+
+InlineBox::~InlineBox()
+{
+ if (!m_hasBadParent && m_parent)
+ m_parent->setHasBadChildList();
+}
+
+#endif
+
+void InlineBox::remove()
+{
+ if (parent())
+ parent()->removeChild(this);
+}
+
+void InlineBox::destroy(RenderArena* renderArena)
+{
+#ifndef NDEBUG
+ inInlineBoxDetach = true;
+#endif
+ delete this;
+#ifndef NDEBUG
+ inInlineBoxDetach = false;
+#endif
+
+ // Recover the size left there for us by operator delete and free the memory.
+ renderArena->free(*(size_t *)this, this);
+}
+
+void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw()
+{
+ return renderArena->allocate(sz);
+}
+
+void InlineBox::operator delete(void* ptr, size_t sz)
+{
+ ASSERT(inInlineBoxDetach);
+
+ // Stash size where destroy can find it.
+ *(size_t *)ptr = sz;
+}
+
+#ifndef NDEBUG
+void InlineBox::showTreeForThis() const
+{
+ if (m_object)
+ m_object->showTreeForThis();
+}
+#endif
+
+int InlineBox::caretMinOffset() const
+{
+ return m_object->caretMinOffset();
+}
+
+int InlineBox::caretMaxOffset() const
+{
+ return m_object->caretMaxOffset();
+}
+
+unsigned InlineBox::caretMaxRenderedOffset() const
+{
+ return 1;
+}
+
+void InlineBox::dirtyLineBoxes()
+{
+ markDirty();
+ for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
+ curr->markDirty();
+}
+
+void InlineBox::deleteLine(RenderArena* arena)
+{
+ if (!m_extracted)
+ m_object->setInlineBoxWrapper(0);
+ destroy(arena);
+}
+
+void InlineBox::extractLine()
+{
+ m_extracted = true;
+ m_object->setInlineBoxWrapper(0);
+}
+
+void InlineBox::attachLine()
+{
+ m_extracted = false;
+ m_object->setInlineBoxWrapper(this);
+}
+
+void InlineBox::adjustPosition(int dx, int dy)
+{
+ m_x += dx;
+ m_y += dy;
+ if (m_object->isReplaced() || m_object->isBR())
+ m_object->setPos(m_object->xPos() + dx, m_object->yPos() + dy);
+}
+
+void InlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
+{
+ if (!object()->shouldPaintWithinRoot(paintInfo) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
+ return;
+
+ // Paint all phases of replaced elements atomically, as though the replaced element established its
+ // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
+ // specification.)
+ bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
+ RenderObject::PaintInfo info(paintInfo);
+ info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
+ object()->paint(info, tx, ty);
+ if (!preservePhase) {
+ info.phase = PaintPhaseChildBlockBackgrounds;
+ object()->paint(info, tx, ty);
+ info.phase = PaintPhaseFloat;
+ object()->paint(info, tx, ty);
+ info.phase = PaintPhaseForeground;
+ object()->paint(info, tx, ty);
+ info.phase = PaintPhaseOutline;
+ object()->paint(info, tx, ty);
+ }
+}
+
+bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
+{
+ // Hit test all phases of replaced elements atomically, as though the replaced element established its
+ // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
+ // specification.)
+ return object()->hitTest(request, result, IntPoint(x, y), tx, ty);
+}
+
+RootInlineBox* InlineBox::root()
+{
+ if (m_parent)
+ return m_parent->root();
+ ASSERT(isRootInlineBox());
+ return static_cast<RootInlineBox*>(this);
+}
+
+bool InlineBox::nextOnLineExists() const
+{
+ if (!m_determinedIfNextOnLineExists) {
+ m_determinedIfNextOnLineExists = true;
+
+ if (!parent())
+ m_nextOnLineExists = false;
+ else if (nextOnLine())
+ m_nextOnLineExists = true;
+ else
+ m_nextOnLineExists = parent()->nextOnLineExists();
+ }
+ return m_nextOnLineExists;
+}
+
+bool InlineBox::prevOnLineExists() const
+{
+ if (!m_determinedIfPrevOnLineExists) {
+ m_determinedIfPrevOnLineExists = true;
+
+ if (!parent())
+ m_prevOnLineExists = false;
+ else if (prevOnLine())
+ m_prevOnLineExists = true;
+ else
+ m_prevOnLineExists = parent()->prevOnLineExists();
+ }
+ return m_prevOnLineExists;
+}
+
+InlineBox* InlineBox::firstLeafChild()
+{
+ return this;
+}
+
+InlineBox* InlineBox::lastLeafChild()
+{
+ return this;
+}
+
+InlineBox* InlineBox::nextLeafChild()
+{
+ return parent() ? parent()->firstLeafChildAfterBox(this) : 0;
+}
+
+InlineBox* InlineBox::prevLeafChild()
+{
+ return parent() ? parent()->lastLeafChildBeforeBox(this) : 0;
+}
+
+RenderObject::SelectionState InlineBox::selectionState()
+{
+ return object()->selectionState();
+}
+
+bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
+{
+ // Non-replaced elements can always accommodate an ellipsis.
+ if (!m_object || !m_object->isReplaced())
+ return true;
+
+ IntRect boxRect(m_x, 0, m_width, 10);
+ IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
+ return !(boxRect.intersects(ellipsisRect));
+}
+
+int InlineBox::placeEllipsisBox(bool, int, int, bool&)
+{
+ // Use -1 to mean "we didn't set the position."
+ return -1;
+}
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+
+void showTree(const WebCore::InlineBox* b)
+{
+ if (b)
+ b->showTreeForThis();
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineBox.h b/src/3rdparty/webkit/WebCore/rendering/InlineBox.h
new file mode 100644
index 0000000..41ad72a
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/InlineBox.h
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 InlineBox_h
+#define InlineBox_h
+
+#include "RenderObject.h" // needed for RenderObject::PaintInfo
+#include "TextDirection.h"
+
+namespace WebCore {
+
+class HitTestResult;
+class RootInlineBox;
+
+struct HitTestRequest;
+
+// InlineBox represents a rectangle that occurs on a line. It corresponds to
+// some RenderObject (i.e., it represents a portion of that RenderObject).
+class InlineBox {
+public:
+ InlineBox(RenderObject* obj)
+ : m_object(obj)
+ , m_x(0)
+ , m_y(0)
+ , m_width(0)
+ , m_height(0)
+ , m_baseline(0)
+ , m_next(0)
+ , m_prev(0)
+ , m_parent(0)
+ , m_firstLine(false)
+ , m_constructed(false)
+ , m_bidiEmbeddingLevel(0)
+ , m_dirty(false)
+ , m_extracted(false)
+ , m_includeLeftEdge(false)
+ , m_includeRightEdge(false)
+ , m_hasTextChildren(true)
+ , m_endsWithBreak(false)
+ , m_hasSelectedChildren(false)
+ , m_hasEllipsisBox(false)
+ , m_dirOverride(false)
+ , m_treatAsText(true)
+ , m_determinedIfNextOnLineExists(false)
+ , m_determinedIfPrevOnLineExists(false)
+ , m_nextOnLineExists(false)
+ , m_prevOnLineExists(false)
+ , m_toAdd(0)
+#ifndef NDEBUG
+ , m_hasBadParent(false)
+#endif
+ {
+ }
+
+ InlineBox(RenderObject* obj, int x, int y, int width, int height, int baseline, bool firstLine, bool constructed,
+ bool dirty, bool extracted, InlineBox* next, InlineBox* prev, InlineFlowBox* parent)
+ : m_object(obj)
+ , m_x(x)
+ , m_y(y)
+ , m_width(width)
+ , m_height(height)
+ , m_baseline(baseline)
+ , m_next(next)
+ , m_prev(prev)
+ , m_parent(parent)
+ , m_firstLine(firstLine)
+ , m_constructed(constructed)
+ , m_bidiEmbeddingLevel(0)
+ , m_dirty(dirty)
+ , m_extracted(extracted)
+ , m_includeLeftEdge(false)
+ , m_includeRightEdge(false)
+ , m_hasTextChildren(true)
+ , m_endsWithBreak(false)
+ , m_hasSelectedChildren(false)
+ , m_hasEllipsisBox(false)
+ , m_dirOverride(false)
+ , m_treatAsText(true)
+ , m_determinedIfNextOnLineExists(false)
+ , m_determinedIfPrevOnLineExists(false)
+ , m_nextOnLineExists(false)
+ , m_prevOnLineExists(false)
+ , m_toAdd(0)
+#ifndef NDEBUG
+ , m_hasBadParent(false)
+#endif
+ {
+ }
+
+ virtual ~InlineBox();
+
+ virtual void destroy(RenderArena*);
+
+ virtual void deleteLine(RenderArena*);
+ virtual void extractLine();
+ virtual void attachLine();
+
+ virtual bool isLineBreak() const { return false; }
+
+ virtual void adjustPosition(int dx, int dy);
+
+ virtual void paint(RenderObject::PaintInfo&, int tx, int ty);
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty);
+
+ // 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);
+
+private:
+ // The normal operator new is disallowed.
+ void* operator new(size_t) throw();
+
+public:
+#ifndef NDEBUG
+ void showTreeForThis() const;
+#endif
+ virtual bool isInlineBox() { return false; }
+ virtual bool isInlineFlowBox() { return false; }
+ virtual bool isContainer() { return false; }
+ virtual bool isInlineTextBox() { return false; }
+ virtual bool isRootInlineBox() { return false; }
+#if ENABLE(SVG)
+ virtual bool isSVGRootInlineBox() { return false; }
+#endif
+ virtual bool isText() const { return false; }
+
+ bool isConstructed() { return m_constructed; }
+ virtual void setConstructed()
+ {
+ m_constructed = true;
+ if (m_next)
+ m_next->setConstructed();
+ }
+
+ void setExtracted(bool b = true) { m_extracted = b; }
+
+ void setFirstLineStyleBit(bool f) { m_firstLine = f; }
+ bool isFirstLineStyle() const { return m_firstLine; }
+
+ void remove();
+
+ InlineBox* nextOnLine() const { return m_next; }
+ InlineBox* prevOnLine() const { return m_prev; }
+ void setNextOnLine(InlineBox* next)
+ {
+ ASSERT(m_parent || !next);
+ m_next = next;
+ }
+ void setPrevOnLine(InlineBox* prev)
+ {
+ ASSERT(m_parent || !prev);
+ m_prev = prev;
+ }
+ bool nextOnLineExists() const;
+ bool prevOnLineExists() const;
+
+ virtual InlineBox* firstLeafChild();
+ virtual InlineBox* lastLeafChild();
+ InlineBox* nextLeafChild();
+ InlineBox* prevLeafChild();
+
+ RenderObject* object() const { return m_object; }
+
+ InlineFlowBox* parent() const
+ {
+ ASSERT(!m_hasBadParent);
+ return m_parent;
+ }
+ void setParent(InlineFlowBox* par) { m_parent = par; }
+
+ RootInlineBox* root();
+
+ void setWidth(int w) { m_width = w; }
+ int width() const { return m_width; }
+
+ void setXPos(int x) { m_x = x; }
+ int xPos() const { return m_x; }
+
+ void setYPos(int y) { m_y = y; }
+ int yPos() const { return m_y; }
+
+ void setHeight(int h) { m_height = h; }
+ int height() const { return m_height; }
+
+ void setBaseline(int b) { m_baseline = b; }
+ int baseline() const { return m_baseline; }
+
+ bool hasTextChildren() const { return m_hasTextChildren; }
+
+ virtual int topOverflow() { return yPos(); }
+ virtual int bottomOverflow() { return yPos() + height(); }
+ virtual int leftOverflow() { return xPos(); }
+ virtual int rightOverflow() { return xPos() + width(); }
+
+ virtual int caretMinOffset() const;
+ virtual int caretMaxOffset() const;
+ virtual unsigned caretMaxRenderedOffset() const;
+
+ unsigned char bidiLevel() const { return m_bidiEmbeddingLevel; }
+ void setBidiLevel(unsigned char level) { m_bidiEmbeddingLevel = level; }
+ TextDirection direction() const { return m_bidiEmbeddingLevel % 2 ? RTL : LTR; }
+ int caretLeftmostOffset() const { return direction() == LTR ? caretMinOffset() : caretMaxOffset(); }
+ int caretRightmostOffset() const { return direction() == LTR ? caretMaxOffset() : caretMinOffset(); }
+
+ virtual void clearTruncation() { }
+
+ bool isDirty() const { return m_dirty; }
+ void markDirty(bool dirty = true) { m_dirty = dirty; }
+
+ void dirtyLineBoxes();
+
+ virtual RenderObject::SelectionState selectionState();
+
+ virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth);
+ virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&);
+
+ void setHasBadParent();
+
+ int toAdd() const { return m_toAdd; }
+
+ bool visibleToHitTesting() const { return object()->style()->visibility() == VISIBLE && object()->style()->pointerEvents() != PE_NONE; }
+
+public:
+ RenderObject* m_object;
+
+ int m_x;
+ int m_y;
+ int m_width;
+ int m_height;
+ int m_baseline;
+
+private:
+ InlineBox* m_next; // The next element on the same line as us.
+ InlineBox* m_prev; // The previous element on the same line as us.
+
+ InlineFlowBox* m_parent; // The box that contains us.
+
+ // Some of these bits are actually for subclasses and moved here to compact the structures.
+
+ // for this class
+protected:
+ bool m_firstLine : 1;
+private:
+ bool m_constructed : 1;
+ unsigned char m_bidiEmbeddingLevel : 6;
+protected:
+ bool m_dirty : 1;
+ bool m_extracted : 1;
+
+ // for InlineFlowBox
+ bool m_includeLeftEdge : 1;
+ bool m_includeRightEdge : 1;
+ bool m_hasTextChildren : 1;
+
+ // for RootInlineBox
+ bool m_endsWithBreak : 1; // Whether the line ends with a <br>.
+ bool m_hasSelectedChildren : 1; // Whether we have any children selected (this bit will also be set if the <br> that terminates our line is selected).
+ bool m_hasEllipsisBox : 1;
+
+ // for InlineTextBox
+public:
+ bool m_dirOverride : 1;
+ bool m_treatAsText : 1; // Whether or not to treat a <br> as text for the purposes of line height.
+protected:
+ mutable bool m_determinedIfNextOnLineExists : 1;
+ mutable bool m_determinedIfPrevOnLineExists : 1;
+ mutable bool m_nextOnLineExists : 1;
+ mutable bool m_prevOnLineExists : 1;
+ int m_toAdd : 13; // for justified text
+
+#ifndef NDEBUG
+private:
+ bool m_hasBadParent;
+#endif
+};
+
+#ifdef NDEBUG
+inline InlineBox::~InlineBox()
+{
+}
+#endif
+
+inline void InlineBox::setHasBadParent()
+{
+#ifndef NDEBUG
+ m_hasBadParent = true;
+#endif
+}
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showTree(const WebCore::InlineBox*);
+#endif
+
+#endif // InlineBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp
new file mode 100644
index 0000000..b4d240e
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.cpp
@@ -0,0 +1,1064 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "InlineFlowBox.h"
+
+#include "CachedImage.h"
+#include "Document.h"
+#include "EllipsisBox.h"
+#include "GraphicsContext.h"
+#include "InlineTextBox.h"
+#include "HitTestResult.h"
+#include "RootInlineBox.h"
+#include "RenderBlock.h"
+#include "RenderFlow.h"
+#include "RenderListMarker.h"
+#include "RenderTableCell.h"
+#include "RootInlineBox.h"
+#include "Text.h"
+
+#include <math.h>
+
+using namespace std;
+
+namespace WebCore {
+
+#ifndef NDEBUG
+
+InlineFlowBox::~InlineFlowBox()
+{
+ if (!m_hasBadChildList)
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
+ child->setHasBadParent();
+}
+
+#endif
+
+RenderFlow* InlineFlowBox::flowObject()
+{
+ return static_cast<RenderFlow*>(m_object);
+}
+
+int InlineFlowBox::marginLeft()
+{
+ if (!includeLeftEdge())
+ return 0;
+
+ Length margin = object()->style()->marginLeft();
+ if (margin.isAuto())
+ return 0;
+ if (margin.isFixed())
+ return margin.value();
+ return object()->marginLeft();
+}
+
+int InlineFlowBox::marginRight()
+{
+ if (!includeRightEdge())
+ return 0;
+
+ Length margin = object()->style()->marginRight();
+ if (margin.isAuto())
+ return 0;
+ if (margin.isFixed())
+ return margin.value();
+ return object()->marginRight();
+}
+
+int InlineFlowBox::marginBorderPaddingLeft()
+{
+ return marginLeft() + borderLeft() + paddingLeft();
+}
+
+int InlineFlowBox::marginBorderPaddingRight()
+{
+ return marginRight() + borderRight() + paddingRight();
+}
+
+int InlineFlowBox::getFlowSpacingWidth()
+{
+ int totWidth = marginBorderPaddingLeft() + marginBorderPaddingRight();
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->isInlineFlowBox())
+ totWidth += static_cast<InlineFlowBox*>(curr)->getFlowSpacingWidth();
+ }
+ return totWidth;
+}
+
+void InlineFlowBox::addToLine(InlineBox* child)
+{
+ ASSERT(!child->parent());
+ ASSERT(!child->nextOnLine());
+ ASSERT(!child->prevOnLine());
+ checkConsistency();
+
+ child->setParent(this);
+ if (!m_firstChild) {
+ m_firstChild = child;
+ m_lastChild = child;
+ } else {
+ m_lastChild->setNextOnLine(child);
+ child->setPrevOnLine(m_lastChild);
+ m_lastChild = child;
+ }
+ child->setFirstLineStyleBit(m_firstLine);
+ if (child->isText())
+ m_hasTextChildren = true;
+ if (child->object()->selectionState() != RenderObject::SelectionNone)
+ root()->setHasSelectedChildren(true);
+
+ checkConsistency();
+}
+
+void InlineFlowBox::removeChild(InlineBox* child)
+{
+ checkConsistency();
+
+ if (!m_dirty)
+ dirtyLineBoxes();
+
+ root()->childRemoved(child);
+
+ if (child == m_firstChild)
+ m_firstChild = child->nextOnLine();
+ if (child == m_lastChild)
+ m_lastChild = child->prevOnLine();
+ if (child->nextOnLine())
+ child->nextOnLine()->setPrevOnLine(child->prevOnLine());
+ if (child->prevOnLine())
+ child->prevOnLine()->setNextOnLine(child->nextOnLine());
+
+ child->setParent(0);
+
+ checkConsistency();
+}
+
+void InlineFlowBox::deleteLine(RenderArena* arena)
+{
+ InlineBox* child = firstChild();
+ InlineBox* next = 0;
+ while (child) {
+ ASSERT(this == child->parent());
+ next = child->nextOnLine();
+#ifndef NDEBUG
+ child->setParent(0);
+#endif
+ child->deleteLine(arena);
+ child = next;
+ }
+#ifndef NDEBUG
+ m_firstChild = 0;
+ m_lastChild = 0;
+#endif
+
+ static_cast<RenderFlow*>(m_object)->removeLineBox(this);
+ destroy(arena);
+}
+
+void InlineFlowBox::extractLine()
+{
+ if (!m_extracted)
+ static_cast<RenderFlow*>(m_object)->extractLineBox(this);
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
+ child->extractLine();
+}
+
+void InlineFlowBox::attachLine()
+{
+ if (m_extracted)
+ static_cast<RenderFlow*>(m_object)->attachLineBox(this);
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
+ child->attachLine();
+}
+
+void InlineFlowBox::adjustPosition(int dx, int dy)
+{
+ InlineRunBox::adjustPosition(dx, dy);
+ for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
+ child->adjustPosition(dx, dy);
+}
+
+bool InlineFlowBox::onEndChain(RenderObject* endObject)
+{
+ if (!endObject)
+ return false;
+
+ if (endObject == object())
+ return true;
+
+ RenderObject* curr = endObject;
+ RenderObject* parent = curr->parent();
+ while (parent && !parent->isRenderBlock()) {
+ if (parent->lastChild() != curr || parent == object())
+ return false;
+
+ curr = parent;
+ parent = curr->parent();
+ }
+
+ return true;
+}
+
+void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject)
+{
+ // All boxes start off open. They will not apply any margins/border/padding on
+ // any side.
+ bool includeLeftEdge = false;
+ bool includeRightEdge = false;
+
+ RenderFlow* flow = static_cast<RenderFlow*>(object());
+
+ if (!flow->firstChild())
+ includeLeftEdge = includeRightEdge = true; // Empty inlines never split across lines.
+ else if (parent()) { // The root inline box never has borders/margins/padding.
+ bool ltr = flow->style()->direction() == LTR;
+
+ // Check to see if all initial lines are unconstructed. If so, then
+ // we know the inline began on this line.
+ if (!flow->firstLineBox()->isConstructed()) {
+ if (ltr && flow->firstLineBox() == this)
+ includeLeftEdge = true;
+ else if (!ltr && flow->lastLineBox() == this)
+ includeRightEdge = true;
+ }
+
+ // In order to determine if the inline ends on this line, we check three things:
+ // (1) If we are the last line and we don't have a continuation(), then we can
+ // close up.
+ // (2) If the last line box for the flow has an object following it on the line (ltr,
+ // reverse for rtl), then the inline has closed.
+ // (3) The line may end on the inline. If we are the last child (climbing up
+ // the end object's chain), then we just closed as well.
+ if (!flow->lastLineBox()->isConstructed()) {
+ if (ltr) {
+ if (!nextLineBox() &&
+ ((lastLine && !object()->continuation()) || nextOnLineExists() || onEndChain(endObject)))
+ includeRightEdge = true;
+ } else {
+ if ((!prevLineBox() || prevLineBox()->isConstructed()) &&
+ ((lastLine && !object()->continuation()) || prevOnLineExists() || onEndChain(endObject)))
+ includeLeftEdge = true;
+ }
+ }
+ }
+
+ setEdges(includeLeftEdge, includeRightEdge);
+
+ // Recur into our children.
+ for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) {
+ if (currChild->isInlineFlowBox()) {
+ InlineFlowBox* currFlow = static_cast<InlineFlowBox*>(currChild);
+ currFlow->determineSpacingForFlowBoxes(lastLine, endObject);
+ }
+ }
+}
+
+int InlineFlowBox::placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing)
+{
+ // Set our x position.
+ setXPos(x);
+
+ int boxShadowLeft = 0;
+ int boxShadowRight = 0;
+ for (ShadowData* boxShadow = object()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+ boxShadowLeft = min(boxShadow->x - boxShadow->blur, boxShadowLeft);
+ boxShadowRight = max(boxShadow->x + boxShadow->blur, boxShadowRight);
+ }
+ leftPosition = min(x + boxShadowLeft, leftPosition);
+
+ int startX = x;
+ x += borderLeft() + paddingLeft();
+
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->object()->isText()) {
+ InlineTextBox* text = static_cast<InlineTextBox*>(curr);
+ RenderText* rt = static_cast<RenderText*>(text->object());
+ if (rt->textLength()) {
+ if (needsWordSpacing && isSpaceOrNewline(rt->characters()[text->start()]))
+ x += rt->style(m_firstLine)->font().wordSpacing();
+ needsWordSpacing = !isSpaceOrNewline(rt->characters()[text->end()]);
+ }
+ text->setXPos(x);
+
+ 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
+ // applied to the right, so this is not an issue with left overflow.
+ int letterSpacing = min(0, (int)rt->style(m_firstLine)->font().letterSpacing());
+
+ int leftGlyphOverflow = -strokeOverflow;
+ int rightGlyphOverflow = strokeOverflow - letterSpacing;
+
+ int visualOverflowLeft = leftGlyphOverflow;
+ int visualOverflowRight = 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);
+ }
+
+ leftPosition = min(x + visualOverflowLeft, leftPosition);
+ rightPosition = max(x + text->width() + visualOverflowRight, rightPosition);
+ m_maxHorizontalVisualOverflow = max(max(visualOverflowRight, -visualOverflowLeft), m_maxHorizontalVisualOverflow);
+ x += text->width();
+ } else {
+ if (curr->object()->isPositioned()) {
+ if (curr->object()->parent()->style()->direction() == LTR)
+ curr->setXPos(x);
+ else
+ // Our offset that we cache needs to be from the edge of the right border box and
+ // not the left border box. We have to subtract |x| from the width of the block
+ // (which can be obtained from the root line box).
+ curr->setXPos(root()->object()->width()-x);
+ continue; // The positioned object has no effect on the width.
+ }
+ if (curr->object()->isInlineFlow()) {
+ InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
+ if (curr->object()->isCompact()) {
+ int ignoredX = x;
+ flow->placeBoxesHorizontally(ignoredX, leftPosition, rightPosition, needsWordSpacing);
+ } else {
+ x += flow->marginLeft();
+ x = flow->placeBoxesHorizontally(x, leftPosition, rightPosition, needsWordSpacing);
+ x += flow->marginRight();
+ }
+ } else if (!curr->object()->isCompact() && (!curr->object()->isListMarker() || static_cast<RenderListMarker*>(curr->object())->isInside())) {
+ x += curr->object()->marginLeft();
+ curr->setXPos(x);
+ leftPosition = min(x + curr->object()->overflowLeft(false), leftPosition);
+ rightPosition = max(x + curr->object()->overflowWidth(false), rightPosition);
+ x += curr->width() + curr->object()->marginRight();
+ }
+ }
+ }
+
+ x += borderRight() + paddingRight();
+ setWidth(x - startX);
+ rightPosition = max(xPos() + width() + boxShadowRight, rightPosition);
+
+ return x;
+}
+
+void 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 = object();
+ while (curr && !curr->element())
+ 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);
+
+ // Shrink boxes with no text children in quirks and almost strict mode.
+ if (!strictMode)
+ shrinkBoxesWithNoTextChildren(topPosition, bottomPosition);
+
+ heightOfBlock += maxHeight;
+}
+
+void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
+ int maxPositionTop, int maxPositionBottom)
+{
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ // The computed lineheight needs to be extended for the
+ // positioned elements
+ if (curr->object()->isPositioned())
+ continue; // Positioned placeholders don't affect calculations.
+ if (curr->yPos() == PositionTop || curr->yPos() == PositionBottom) {
+ if (curr->yPos() == PositionTop) {
+ if (maxAscent + maxDescent < curr->height())
+ maxDescent = curr->height() - maxAscent;
+ }
+ else {
+ if (maxAscent + maxDescent < curr->height())
+ maxAscent = curr->height() - maxDescent;
+ }
+
+ if (maxAscent + maxDescent >= max(maxPositionTop, maxPositionBottom))
+ break;
+ }
+
+ if (curr->isInlineFlowBox())
+ static_cast<InlineFlowBox*>(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
+ }
+}
+
+void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom,
+ int& maxAscent, int& maxDescent, bool strictMode)
+{
+ if (isRootInlineBox()) {
+ // Examine our root box.
+ setHeight(object()->lineHeight(m_firstLine, true));
+ bool isTableCell = object()->isTableCell();
+ if (isTableCell) {
+ RenderTableCell* tableCell = static_cast<RenderTableCell*>(object());
+ setBaseline(tableCell->RenderBlock::baselinePosition(m_firstLine, true));
+ }
+ else
+ setBaseline(object()->baselinePosition(m_firstLine, true));
+ if (hasTextChildren() || strictMode) {
+ int ascent = baseline();
+ int descent = height() - ascent;
+ if (maxAscent < ascent)
+ maxAscent = ascent;
+ if (maxDescent < descent)
+ maxDescent = descent;
+ }
+ }
+
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->object()->isPositioned())
+ continue; // Positioned placeholders don't affect calculations.
+
+ curr->setHeight(curr->object()->lineHeight(m_firstLine));
+ curr->setBaseline(curr->object()->baselinePosition(m_firstLine));
+ curr->setYPos(curr->object()->verticalPositionHint(m_firstLine));
+ if (curr->yPos() == PositionTop) {
+ if (maxPositionTop < curr->height())
+ maxPositionTop = curr->height();
+ }
+ else if (curr->yPos() == PositionBottom) {
+ if (maxPositionBottom < curr->height())
+ maxPositionBottom = curr->height();
+ }
+ else if (curr->hasTextChildren() || curr->object()->hasHorizontalBordersOrPadding() || strictMode) {
+ int ascent = curr->baseline() - curr->yPos();
+ int descent = curr->height() - ascent;
+ if (maxAscent < ascent)
+ maxAscent = ascent;
+ if (maxDescent < descent)
+ maxDescent = descent;
+ }
+
+ if (curr->isInlineFlowBox())
+ static_cast<InlineFlowBox*>(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode);
+ }
+}
+
+void InlineFlowBox::placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode,
+ int& topPosition, int& bottomPosition, int& selectionTop, int& selectionBottom)
+{
+ if (isRootInlineBox())
+ setYPos(y + maxAscent - baseline());// Place our root box.
+
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->object()->isPositioned())
+ continue; // Positioned placeholders don't affect calculations.
+
+ // Adjust boxes to use their real box y/height and not the logical height (as dictated by
+ // line-height).
+ if (curr->isInlineFlowBox())
+ static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(y, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom);
+
+ bool childAffectsTopBottomPos = true;
+ if (curr->yPos() == PositionTop)
+ curr->setYPos(y);
+ else if (curr->yPos() == PositionBottom)
+ curr->setYPos(y + maxHeight - curr->height());
+ else {
+ if (!curr->hasTextChildren() && !curr->object()->hasHorizontalBordersOrPadding() && !strictMode)
+ childAffectsTopBottomPos = false;
+ curr->setYPos(curr->yPos() + y + maxAscent - curr->baseline());
+ }
+
+ int newY = curr->yPos();
+ int newHeight = curr->height();
+ int newBaseline = curr->baseline();
+ int overflowTop = 0;
+ int overflowBottom = 0;
+ if (curr->isText() || curr->isInlineFlowBox()) {
+ const Font& font = curr->object()->style(m_firstLine)->font();
+ newBaseline = font.ascent();
+ newY += curr->baseline() - newBaseline;
+ newHeight = newBaseline + font.descent();
+ for (ShadowData* shadow = curr->object()->style()->textShadow(); shadow; shadow = shadow->next) {
+ overflowTop = min(overflowTop, shadow->y - shadow->blur);
+ overflowBottom = max(overflowBottom, shadow->y + shadow->blur);
+ }
+
+ for (ShadowData* boxShadow = curr->object()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+ overflowTop = min(overflowTop, boxShadow->y - boxShadow->blur);
+ overflowBottom = max(overflowBottom, boxShadow->y + boxShadow->blur);
+ }
+
+ for (ShadowData* textShadow = curr->object()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) {
+ overflowTop = min(overflowTop, textShadow->y - textShadow->blur);
+ overflowBottom = max(overflowBottom, textShadow->y + textShadow->blur);
+ }
+
+ if (curr->object()->hasReflection()) {
+ overflowTop = min(overflowTop, curr->object()->reflectionBox().y());
+ overflowBottom = max(overflowBottom, curr->object()->reflectionBox().bottom());
+ }
+
+ if (curr->isInlineFlowBox()) {
+ newHeight += curr->object()->borderTop() + curr->object()->paddingTop() +
+ curr->object()->borderBottom() + curr->object()->paddingBottom();
+ newY -= curr->object()->borderTop() + curr->object()->paddingTop();
+ newBaseline += curr->object()->borderTop() + curr->object()->paddingTop();
+ }
+ } else if (!curr->object()->isBR()) {
+ newY += curr->object()->marginTop();
+ newHeight = curr->height() - (curr->object()->marginTop() + curr->object()->marginBottom());
+ overflowTop = curr->object()->overflowTop(false);
+ overflowBottom = curr->object()->overflowHeight(false) - newHeight;
+ }
+
+ curr->setYPos(newY);
+ curr->setHeight(newHeight);
+ curr->setBaseline(newBaseline);
+
+ if (childAffectsTopBottomPos) {
+ selectionTop = min(selectionTop, newY);
+ selectionBottom = max(selectionBottom, newY + newHeight);
+ topPosition = min(topPosition, newY + overflowTop);
+ bottomPosition = max(bottomPosition, newY + newHeight + overflowBottom);
+ }
+ }
+
+ if (isRootInlineBox()) {
+ const Font& font = object()->style(m_firstLine)->font();
+ setHeight(font.ascent() + font.descent());
+ setYPos(yPos() + baseline() - font.ascent());
+ setBaseline(font.ascent());
+ if (hasTextChildren() || strictMode) {
+ selectionTop = min(selectionTop, yPos());
+ selectionBottom = max(selectionBottom, yPos() + height());
+ }
+ }
+}
+
+void InlineFlowBox::shrinkBoxesWithNoTextChildren(int topPos, int bottomPos)
+{
+ // First shrink our kids.
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->object()->isPositioned())
+ continue; // Positioned placeholders don't affect calculations.
+
+ if (curr->isInlineFlowBox())
+ static_cast<InlineFlowBox*>(curr)->shrinkBoxesWithNoTextChildren(topPos, bottomPos);
+ }
+
+ // See if we have text children. If not, then we need to shrink ourselves to fit on the line.
+ if (!hasTextChildren() && !object()->hasHorizontalBordersOrPadding()) {
+ if (yPos() < topPos)
+ setYPos(topPos);
+ if (yPos() + height() > bottomPos)
+ setHeight(bottomPos - yPos());
+ if (baseline() > height())
+ setBaseline(height());
+ }
+}
+
+bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
+{
+ // Check children first.
+ for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
+ if (!curr->object()->hasLayer() && curr->nodeAtPoint(request, result, x, y, tx, ty)) {
+ object()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+ }
+
+ // Now check ourselves.
+ IntRect rect(tx + m_x, ty + m_y, m_width, m_height);
+ if (visibleToHitTesting() && rect.contains(x, y)) {
+ object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); // Don't add in m_x or m_y here, we want coords in the containing block's space.
+ return true;
+ }
+
+ return false;
+}
+
+void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
+{
+ int xPos = tx + m_x - object()->maximalOutlineSize(paintInfo.phase);
+ int w = width() + 2 * object()->maximalOutlineSize(paintInfo.phase);
+ int shadowLeft = 0;
+ int shadowRight = 0;
+ for (ShadowData* boxShadow = object()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+ shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft);
+ shadowRight = max(boxShadow->x + boxShadow->blur, shadowRight);
+ }
+ for (ShadowData* textShadow = object()->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();
+
+ if (intersectsDamageRect && 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.
+ if (object()->style()->visibility() == VISIBLE && object()->hasOutline() && !isRootInlineBox()) {
+ if ((object()->continuation() || object()->isInlineContinuation()) && !object()->hasLayer()) {
+ // Add ourselves to the containing block of the entire continuation so that it can
+ // paint us atomically.
+ RenderBlock* block = object()->containingBlock()->containingBlock();
+ block->addContinuationWithOutline(static_cast<RenderFlow*>(object()->element()->renderer()));
+ } else if (!object()->isInlineContinuation())
+ paintInfo.outlineObjects->add(flowObject());
+ }
+ } else if (paintInfo.phase == PaintPhaseMask) {
+ paintMask(paintInfo, tx, ty);
+ return;
+ } else {
+ // 1. Paint our background, border and box-shadow.
+ paintBoxDecorations(paintInfo, tx, ty);
+
+ // 2. Paint our underline and overline.
+ paintTextDecorations(paintInfo, tx, ty, false);
+ }
+ }
+
+ if (paintInfo.phase == PaintPhaseMask)
+ return;
+
+ PaintPhase paintPhase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : paintInfo.phase;
+ RenderObject::PaintInfo childInfo(paintInfo);
+ childInfo.phase = paintPhase;
+ childInfo.paintingRoot = object()->paintingRootForChildren(paintInfo);
+
+ // 3. Paint our children.
+ if (paintPhase != PaintPhaseSelfOutline) {
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (!curr->object()->hasLayer())
+ curr->paint(childInfo, tx, ty);
+ }
+ }
+
+ // 4. Paint our strike-through
+ if (intersectsDamageRect && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
+ paintTextDecorations(paintInfo, tx, ty, true);
+}
+
+void InlineFlowBox::paintFillLayers(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer,
+ int my, int mh, int _tx, int _ty, int w, int h, CompositeOperator op)
+{
+ if (!fillLayer)
+ return;
+ paintFillLayers(paintInfo, c, fillLayer->next(), my, mh, _tx, _ty, w, h, op);
+ paintFillLayer(paintInfo, c, fillLayer, my, mh, _tx, _ty, w, h, op);
+}
+
+void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer,
+ int my, int mh, int tx, int ty, int w, int h, CompositeOperator op)
+{
+ StyleImage* img = fillLayer->image();
+ bool hasFillImage = img && img->canRender(object()->style()->effectiveZoom());
+ if ((!hasFillImage && !object()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent())
+ object()->paintFillLayerExtended(paintInfo, c, fillLayer, my, mh, tx, ty, w, h, this, op);
+ else {
+ // We have a fill image that spans multiple lines.
+ // We need to adjust _tx and _ty by the width of all previous lines.
+ // Think of background painting on inlines as though you had one long line, a single continuous
+ // strip. Even though that strip has been broken up across multiple lines, you still paint it
+ // as though you had one single line. This means each line has to pick up the background where
+ // the previous line left off.
+ // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right,
+ // but it isn't even clear how this should work at all.
+ int xOffsetOnLine = 0;
+ for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
+ xOffsetOnLine += curr->width();
+ int startX = tx - xOffsetOnLine;
+ int totalWidth = xOffsetOnLine;
+ for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
+ totalWidth += curr->width();
+ paintInfo.context->save();
+ paintInfo.context->clip(IntRect(tx, ty, width(), height()));
+ object()->paintFillLayerExtended(paintInfo, c, fillLayer, my, mh, startX, ty, totalWidth, h, this, op);
+ paintInfo.context->restore();
+ }
+}
+
+void InlineFlowBox::paintBoxShadow(GraphicsContext* context, RenderStyle* s, int tx, int ty, int w, int h)
+{
+ if ((!prevLineBox() && !nextLineBox()) || !parent())
+ object()->paintBoxShadow(context, tx, ty, w, h, s);
+ else {
+ // FIXME: We can do better here in the multi-line case. We want to push a clip so that the shadow doesn't
+ // protrude incorrectly at the edges, and we want to possibly include shadows cast from the previous/following lines
+ object()->paintBoxShadow(context, tx, ty, w, h, s, includeLeftEdge(), includeRightEdge());
+ }
+}
+
+void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int tx, int ty)
+{
+ if (!object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground)
+ return;
+
+ // Move x/y to our coordinates.
+ tx += m_x;
+ ty += m_y;
+
+ int w = width();
+ int h = height();
+
+ int my = max(ty, paintInfo.rect.y());
+ int mh;
+ if (ty < paintInfo.rect.y())
+ mh = max(0, h - (paintInfo.rect.y() - ty));
+ else
+ mh = min(paintInfo.rect.height(), h);
+
+ GraphicsContext* context = paintInfo.context;
+
+ // You can use p::first-line to specify a background. If so, the root line boxes for
+ // a line may actually have to paint a background.
+ RenderStyle* styleToUse = object()->style(m_firstLine);
+ if ((!parent() && m_firstLine && styleToUse != object()->style()) || (parent() && object()->hasBoxDecorations())) {
+ // Shadow comes first and is behind the background and border.
+ if (styleToUse->boxShadow())
+ paintBoxShadow(context, styleToUse, tx, ty, w, h);
+
+ Color c = styleToUse->backgroundColor();
+ paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), my, mh, tx, ty, w, h);
+
+ // :first-line cannot be used to put borders on a line. Always paint borders with our
+ // non-first-line style.
+ if (parent() && object()->style()->hasBorder()) {
+ StyleImage* borderImage = object()->style()->borderImage().image();
+ bool hasBorderImage = borderImage && borderImage->canRender(styleToUse->effectiveZoom());
+ if (hasBorderImage && !borderImage->isLoaded())
+ return; // Don't paint anything while we wait for the image to load.
+
+ // The simple case is where we either have no border image or we are the only box for this object. In those
+ // cases only a single call to draw is required.
+ if (!hasBorderImage || (!prevLineBox() && !nextLineBox()))
+ object()->paintBorder(context, tx, ty, w, h, object()->style(), includeLeftEdge(), includeRightEdge());
+ else {
+ // We have a border image that spans multiple lines.
+ // We need to adjust _tx and _ty by the width of all previous lines.
+ // Think of border image painting on inlines as though you had one long line, a single continuous
+ // strip. Even though that strip has been broken up across multiple lines, you still paint it
+ // as though you had one single line. This means each line has to pick up the image where
+ // the previous line left off.
+ // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right,
+ // but it isn't even clear how this should work at all.
+ int xOffsetOnLine = 0;
+ for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
+ xOffsetOnLine += curr->width();
+ int startX = tx - xOffsetOnLine;
+ int totalWidth = xOffsetOnLine;
+ for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
+ totalWidth += curr->width();
+ context->save();
+ context->clip(IntRect(tx, ty, width(), height()));
+ object()->paintBorder(context, startX, ty, totalWidth, h, object()->style());
+ context->restore();
+ }
+ }
+ }
+}
+
+void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty)
+{
+ if (!object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
+ return;
+
+ // Move x/y to our coordinates.
+ tx += m_x;
+ ty += m_y;
+
+ int w = width();
+ int h = height();
+
+ int my = max(ty, paintInfo.rect.y());
+ int mh;
+ if (ty < paintInfo.rect.y())
+ mh = max(0, h - (paintInfo.rect.y() - ty));
+ else
+ mh = min(paintInfo.rect.height(), h);
+
+
+ // Figure out if we need to push a transparency layer to render our mask.
+ bool pushTransparencyLayer = false;
+ const NinePieceImage& maskNinePieceImage = object()->style()->maskBoxImage();
+ StyleImage* maskBoxImage = object()->style()->maskBoxImage().image();
+ if ((maskBoxImage && object()->style()->maskLayers()->hasImage()) || object()->style()->maskLayers()->next())
+ pushTransparencyLayer = true;
+
+ CompositeOperator compositeOp = CompositeDestinationIn;
+ if (pushTransparencyLayer) {
+ paintInfo.context->setCompositeOperation(CompositeDestinationIn);
+ paintInfo.context->beginTransparencyLayer(1.0f);
+ compositeOp = CompositeSourceOver;
+ }
+
+ paintFillLayers(paintInfo, Color(), object()->style()->maskLayers(), my, mh, tx, ty, w, h, compositeOp);
+
+ bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(object()->style()->effectiveZoom());
+ if (!hasBoxImage || !maskBoxImage->isLoaded())
+ return; // Don't paint anything while we wait for the image to load.
+
+ // The simple case is where we are the only box for this object. In those
+ // cases only a single call to draw is required.
+ if (!prevLineBox() && !nextLineBox()) {
+ object()->paintNinePieceImage(paintInfo.context, tx, ty, w, h, object()->style(), maskNinePieceImage, compositeOp);
+ } else {
+ // We have a mask image that spans multiple lines.
+ // We need to adjust _tx and _ty by the width of all previous lines.
+ int xOffsetOnLine = 0;
+ for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
+ xOffsetOnLine += curr->width();
+ int startX = tx - xOffsetOnLine;
+ int totalWidth = xOffsetOnLine;
+ for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
+ totalWidth += curr->width();
+ paintInfo.context->save();
+ paintInfo.context->clip(IntRect(tx, ty, width(), height()));
+ object()->paintNinePieceImage(paintInfo.context, startX, ty, totalWidth, h, object()->style(), maskNinePieceImage, compositeOp);
+ paintInfo.context->restore();
+ }
+
+ if (pushTransparencyLayer)
+ paintInfo.context->endTransparencyLayer();
+}
+
+static bool shouldDrawTextDecoration(RenderObject* obj)
+{
+ for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) {
+ if (curr->isInlineFlow())
+ return true;
+ if (curr->isText() && !curr->isBR()) {
+ if (!curr->style()->collapseWhiteSpace())
+ return true;
+ Node* currElement = curr->element();
+ if (!currElement)
+ return true;
+ if (!currElement->isTextNode())
+ return true;
+ if (!static_cast<Text*>(currElement)->containsOnlyWhitespace())
+ return true;
+ }
+ }
+ return false;
+}
+
+void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int tx, int ty, bool paintedChildren)
+{
+ // Paint text decorations like underlines/overlines. We only do this if we aren't in quirks mode (i.e., in
+ // almost-strict mode or strict mode).
+ if (object()->style()->htmlHacks() || !object()->shouldPaintWithinRoot(paintInfo) ||
+ object()->style()->visibility() != VISIBLE)
+ return;
+
+ // We don't want underlines or other decorations when we're trying to draw nothing but the selection as white text.
+ if (paintInfo.phase == PaintPhaseSelection && paintInfo.forceBlackText)
+ return;
+
+ GraphicsContext* context = paintInfo.context;
+ tx += m_x;
+ ty += m_y;
+ RenderStyle* styleToUse = object()->style(m_firstLine);
+ int deco = parent() ? styleToUse->textDecoration() : styleToUse->textDecorationsInEffect();
+ if (deco != TDNONE &&
+ ((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) &&
+ shouldDrawTextDecoration(object())) {
+ int x = m_x + borderLeft() + paddingLeft();
+ int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight());
+ RootInlineBox* rootLine = root();
+ if (rootLine->ellipsisBox()) {
+ int ellipsisX = rootLine->ellipsisBox()->xPos();
+ int ellipsisWidth = rootLine->ellipsisBox()->width();
+
+ // FIXME: Will need to work with RTL
+ if (rootLine == this) {
+ if (x + w >= ellipsisX + ellipsisWidth)
+ w -= (x + w - ellipsisX - ellipsisWidth);
+ } else {
+ if (x >= ellipsisX)
+ return;
+ if (x + w >= ellipsisX)
+ w -= (x + w - ellipsisX);
+ }
+ }
+
+ // We must have child boxes and have decorations defined.
+ tx += borderLeft() + paddingLeft();
+
+ Color underline, overline, linethrough;
+ underline = overline = linethrough = styleToUse->color();
+ if (!parent())
+ object()->getTextDecorationColors(deco, underline, overline, linethrough);
+
+ bool isPrinting = object()->document()->printing();
+ context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1.
+
+ bool paintUnderline = deco & UNDERLINE && !paintedChildren;
+ bool paintOverline = deco & OVERLINE && !paintedChildren;
+ bool paintLineThrough = deco & LINE_THROUGH && paintedChildren;
+
+ bool linesAreOpaque = !isPrinting && (!paintUnderline || underline.alpha() == 255) && (!paintOverline || overline.alpha() == 255) && (!paintLineThrough || linethrough.alpha() == 255);
+
+ bool setClip = false;
+ int extraOffset = 0;
+ ShadowData* shadow = styleToUse->textShadow();
+ if (!linesAreOpaque && shadow && shadow->next) {
+ IntRect clipRect(tx, ty, w, m_baseline + 2);
+ for (ShadowData* s = shadow; s; s = s->next) {
+ IntRect shadowRect(tx, ty, w, m_baseline + 2);
+ shadowRect.inflate(s->blur);
+ shadowRect.move(s->x, s->y);
+ clipRect.unite(shadowRect);
+ extraOffset = max(extraOffset, max(0, s->y) + s->blur);
+ }
+ context->save();
+ context->clip(clipRect);
+ extraOffset += m_baseline + 2;
+ ty += extraOffset;
+ setClip = true;
+ }
+
+ bool setShadow = false;
+ do {
+ if (shadow) {
+ if (!shadow->next) {
+ // The last set of lines paints normally inside the clip.
+ ty -= extraOffset;
+ extraOffset = 0;
+ }
+ context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color);
+ setShadow = true;
+ shadow = shadow->next;
+ }
+
+ if (paintUnderline) {
+ context->setStrokeColor(underline);
+ // Leave one pixel of white between the baseline and the underline.
+ context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), w, isPrinting);
+ }
+ if (paintOverline) {
+ context->setStrokeColor(overline);
+ context->drawLineForText(IntPoint(tx, ty), w, isPrinting);
+ }
+ if (paintLineThrough) {
+ context->setStrokeColor(linethrough);
+ context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), w, isPrinting);
+ }
+ } while (shadow);
+
+ if (setClip)
+ context->restore();
+ else if (setShadow)
+ context->clearShadow();
+ }
+}
+
+InlineBox* InlineFlowBox::firstLeafChild()
+{
+ return firstLeafChildAfterBox();
+}
+
+InlineBox* InlineFlowBox::lastLeafChild()
+{
+ return lastLeafChildBeforeBox();
+}
+
+InlineBox* InlineFlowBox::firstLeafChildAfterBox(InlineBox* start)
+{
+ InlineBox* leaf = 0;
+ for (InlineBox* box = start ? start->nextOnLine() : firstChild(); box && !leaf; box = box->nextOnLine())
+ leaf = box->firstLeafChild();
+ if (start && !leaf && parent())
+ return parent()->firstLeafChildAfterBox(this);
+ return leaf;
+}
+
+InlineBox* InlineFlowBox::lastLeafChildBeforeBox(InlineBox* start)
+{
+ InlineBox* leaf = 0;
+ for (InlineBox* box = start ? start->prevOnLine() : lastChild(); box && !leaf; box = box->prevOnLine())
+ leaf = box->lastLeafChild();
+ if (start && !leaf && parent())
+ return parent()->lastLeafChildBeforeBox(this);
+ return leaf;
+}
+
+RenderObject::SelectionState InlineFlowBox::selectionState()
+{
+ return RenderObject::SelectionNone;
+}
+
+bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
+{
+ for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
+ if (!box->canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth))
+ return false;
+ }
+ return true;
+}
+
+int InlineFlowBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox)
+{
+ int result = -1;
+ for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
+ int currResult = box->placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
+ if (currResult != -1 && result == -1)
+ result = currResult;
+ }
+ return result;
+}
+
+void InlineFlowBox::clearTruncation()
+{
+ for (InlineBox *box = firstChild(); box; box = box->nextOnLine())
+ box->clearTruncation();
+}
+
+#ifndef NDEBUG
+
+void InlineFlowBox::checkConsistency() const
+{
+#ifdef CHECK_CONSISTENCY
+ ASSERT(!m_hasBadChildList);
+ const InlineBox* prev = 0;
+ for (const InlineBox* child = m_firstChild; child; child = child->nextOnLine()) {
+ ASSERT(child->parent() == this);
+ ASSERT(child->prevOnLine() == prev);
+ prev = child;
+ }
+ ASSERT(prev == m_lastChild);
+#endif
+}
+
+#endif
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h
new file mode 100644
index 0000000..30dad38
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/InlineFlowBox.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 InlineFlowBox_h
+#define InlineFlowBox_h
+
+#include "InlineRunBox.h"
+
+namespace WebCore {
+
+class HitTestResult;
+
+struct HitTestRequest;
+
+class InlineFlowBox : public InlineRunBox {
+public:
+ InlineFlowBox(RenderObject* obj)
+ : InlineRunBox(obj)
+ , m_firstChild(0)
+ , m_lastChild(0)
+ , m_maxHorizontalVisualOverflow(0)
+#ifndef NDEBUG
+ , m_hasBadChildList(false)
+#endif
+ {
+ // Internet Explorer and Firefox always create a marker for list items, even when the list-style-type is none. We do not make a marker
+ // in the list-style-type: none case, since it is wasteful to do so. However, in order to match other browsers we have to pretend like
+ // an invisible marker exists. The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no
+ // text children must not apply. This change also means that gaps will exist between image bullet list items. Even when the list bullet
+ // is an image, the line is still considered to be immune from the quirk.
+ m_hasTextChildren = obj->style()->display() == LIST_ITEM;
+ }
+
+#ifndef NDEBUG
+ virtual ~InlineFlowBox();
+#endif
+
+ RenderFlow* flowObject();
+
+ virtual bool isInlineFlowBox() { return true; }
+
+ InlineFlowBox* prevFlowBox() const { return static_cast<InlineFlowBox*>(m_prevLine); }
+ InlineFlowBox* nextFlowBox() const { return static_cast<InlineFlowBox*>(m_nextLine); }
+
+ InlineBox* firstChild() { checkConsistency(); return m_firstChild; }
+ InlineBox* lastChild() { checkConsistency(); return m_lastChild; }
+
+ virtual InlineBox* firstLeafChild();
+ virtual InlineBox* lastLeafChild();
+ InlineBox* firstLeafChildAfterBox(InlineBox* start = 0);
+ InlineBox* lastLeafChildBeforeBox(InlineBox* start = 0);
+
+ virtual void setConstructed()
+ {
+ InlineBox::setConstructed();
+ if (firstChild())
+ firstChild()->setConstructed();
+ }
+
+ void addToLine(InlineBox* child);
+ virtual void deleteLine(RenderArena*);
+ virtual void extractLine();
+ virtual void attachLine();
+ virtual void adjustPosition(int dx, int dy);
+
+ virtual void clearTruncation();
+
+ virtual void paintBoxDecorations(RenderObject::PaintInfo&, int tx, int ty);
+ virtual void paintMask(RenderObject::PaintInfo&, int tx, int ty);
+ void paintFillLayers(const RenderObject::PaintInfo&, const Color&, const FillLayer*,
+ int my, int mh, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver);
+ void paintFillLayer(const RenderObject::PaintInfo&, const Color&, const FillLayer*,
+ int my, int mh, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver);
+ void paintBoxShadow(GraphicsContext*, RenderStyle*, int tx, int ty, int w, int h);
+ virtual void paintTextDecorations(RenderObject::PaintInfo&, int tx, int ty, bool paintedChildren = false);
+ virtual void paint(RenderObject::PaintInfo&, int tx, int ty);
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty);
+
+ int marginBorderPaddingLeft();
+ int marginBorderPaddingRight();
+ int marginLeft();
+ int marginRight();
+ int borderLeft() { if (includeLeftEdge()) return object()->borderLeft(); return 0; }
+ int borderRight() { if (includeRightEdge()) return object()->borderRight(); return 0; }
+ int paddingLeft() { if (includeLeftEdge()) return object()->paddingLeft(); return 0; }
+ int paddingRight() { if (includeRightEdge()) return object()->paddingRight(); return 0; }
+
+ bool includeLeftEdge() { return m_includeLeftEdge; }
+ bool includeRightEdge() { return m_includeRightEdge; }
+ void setEdges(bool includeLeft, bool includeRight)
+ {
+ m_includeLeftEdge = includeLeft;
+ m_includeRightEdge = includeRight;
+ }
+
+ // Helper functions used during line construction and placement.
+ void determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject);
+ int getFlowSpacingWidth();
+ bool onEndChain(RenderObject* endObject);
+ virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing);
+ virtual void verticallyAlignBoxes(int& heightOfBlock);
+ 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);
+ void shrinkBoxesWithNoTextChildren(int topPosition, int bottomPosition);
+
+ virtual void setVerticalOverflowPositions(int /*top*/, int /*bottom*/) { }
+ virtual void setVerticalSelectionPositions(int /*top*/, int /*bottom*/) { }
+ int maxHorizontalVisualOverflow() const { return m_maxHorizontalVisualOverflow; }
+
+ void removeChild(InlineBox* child);
+
+ virtual RenderObject::SelectionState selectionState();
+
+ virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth);
+ virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&);
+
+ void checkConsistency() const;
+ void setHasBadChildList();
+
+private:
+ InlineBox* m_firstChild;
+ InlineBox* m_lastChild;
+ int m_maxHorizontalVisualOverflow;
+
+#ifndef NDEBUG
+ bool m_hasBadChildList;
+#endif
+};
+
+#ifdef NDEBUG
+inline void InlineFlowBox::checkConsistency() const
+{
+}
+#endif
+
+inline void InlineFlowBox::setHasBadChildList()
+{
+#ifndef NDEBUG
+ m_hasBadChildList = true;
+#endif
+}
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showTree(const WebCore::InlineBox*);
+#endif
+
+#endif // InlineFlowBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineRunBox.h b/src/3rdparty/webkit/WebCore/rendering/InlineRunBox.h
new file mode 100644
index 0000000..0f7c29b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/InlineRunBox.h
@@ -0,0 +1,54 @@
+/*
+ * 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
+ * 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 InlineRunBox_h
+#define InlineRunBox_h
+
+#include "InlineBox.h"
+
+namespace WebCore {
+
+class InlineRunBox : public InlineBox {
+public:
+ InlineRunBox(RenderObject* obj)
+ : InlineBox(obj)
+ , m_prevLine(0)
+ , m_nextLine(0)
+ {
+ }
+
+ InlineRunBox* prevLineBox() const { return m_prevLine; }
+ InlineRunBox* nextLineBox() const { return m_nextLine; }
+ void setNextLineBox(InlineRunBox* n) { m_nextLine = n; }
+ void setPreviousLineBox(InlineRunBox* p) { m_prevLine = p; }
+
+ virtual void paintBoxDecorations(RenderObject::PaintInfo&, int /*tx*/, int /*ty*/) { }
+ virtual void paintTextDecorations(RenderObject::PaintInfo&, int /*tx*/, int /*ty*/, bool /*paintedChildren*/ = false) { }
+
+protected:
+ InlineRunBox* m_prevLine; // The previous box that also uses our RenderObject
+ InlineRunBox* m_nextLine; // The next box that also uses our RenderObject
+};
+
+} // namespace WebCore
+
+#endif // InlineRunBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp
new file mode 100644
index 0000000..a5857e0
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.cpp
@@ -0,0 +1,909 @@
+/*
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "InlineTextBox.h"
+
+#include "ChromeClient.h"
+#include "Document.h"
+#include "Editor.h"
+#include "Frame.h"
+#include "GraphicsContext.h"
+#include "HitTestResult.h"
+#include "Page.h"
+#include "RenderArena.h"
+#include "RenderBlock.h"
+#include "RenderTheme.h"
+#include "Text.h"
+#include "break_lines.h"
+#include <wtf/AlwaysInline.h>
+
+using namespace std;
+
+namespace WebCore {
+
+int InlineTextBox::selectionTop()
+{
+ return root()->selectionTop();
+}
+
+int InlineTextBox::selectionHeight()
+{
+ return root()->selectionHeight();
+}
+
+bool InlineTextBox::isSelected(int startPos, int endPos) const
+{
+ int sPos = max(startPos - m_start, 0);
+ int ePos = min(endPos - m_start, (int)m_len);
+ return (sPos < ePos);
+}
+
+RenderObject::SelectionState InlineTextBox::selectionState()
+{
+ RenderObject::SelectionState state = object()->selectionState();
+ if (state == RenderObject::SelectionStart || state == RenderObject::SelectionEnd || state == RenderObject::SelectionBoth) {
+ int startPos, endPos;
+ object()->selectionStartEnd(startPos, endPos);
+ // The position after a hard line break is considered to be past its end.
+ int lastSelectable = start() + len() - (isLineBreak() ? 1 : 0);
+
+ bool start = (state != RenderObject::SelectionEnd && startPos >= m_start && startPos < m_start + m_len);
+ bool end = (state != RenderObject::SelectionStart && endPos > m_start && endPos <= lastSelectable);
+ if (start && end)
+ state = RenderObject::SelectionBoth;
+ else if (start)
+ state = RenderObject::SelectionStart;
+ else if (end)
+ state = RenderObject::SelectionEnd;
+ else if ((state == RenderObject::SelectionEnd || startPos < m_start) &&
+ (state == RenderObject::SelectionStart || endPos > lastSelectable))
+ state = RenderObject::SelectionInside;
+ else if (state == RenderObject::SelectionBoth)
+ state = RenderObject::SelectionNone;
+ }
+ return state;
+}
+
+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)
+ return IntRect();
+
+ RenderText* textObj = textObject();
+ int selTop = selectionTop();
+ int selHeight = selectionHeight();
+ const Font& f = textObj->style(m_firstLine)->font();
+
+ IntRect r = enclosingIntRect(f.selectionRectForText(TextRun(textObj->text()->characters() + m_start, m_len, textObj->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride),
+ IntPoint(tx + m_x, ty + selTop), selHeight, sPos, ePos));
+ if (r.x() > tx + m_x + m_width)
+ r.setWidth(0);
+ else if (r.right() - 1 > tx + m_x + m_width)
+ r.setWidth(tx + m_x + m_width - r.x());
+ return r;
+}
+
+void InlineTextBox::deleteLine(RenderArena* arena)
+{
+ static_cast<RenderText*>(m_object)->removeTextBox(this);
+ destroy(arena);
+}
+
+void InlineTextBox::extractLine()
+{
+ if (m_extracted)
+ return;
+
+ static_cast<RenderText*>(m_object)->extractTextBox(this);
+}
+
+void InlineTextBox::attachLine()
+{
+ if (!m_extracted)
+ return;
+
+ static_cast<RenderText*>(m_object)->attachTextBox(this);
+}
+
+int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox)
+{
+ if (foundBox) {
+ m_truncation = cFullTruncation;
+ return -1;
+ }
+
+ int ellipsisX = ltr ? blockEdge - ellipsisWidth : blockEdge + ellipsisWidth;
+
+ // For LTR, if the left edge of the ellipsis is to the left of our text run, then we are the run that will get truncated.
+ if (ltr) {
+ if (ellipsisX <= m_x) {
+ // Too far. Just set full truncation, but return -1 and let the ellipsis just be placed at the edge of the box.
+ m_truncation = cFullTruncation;
+ foundBox = true;
+ return -1;
+ }
+
+ if (ellipsisX < m_x + m_width) {
+ if (direction() == RTL)
+ return -1; // FIXME: Support LTR truncation when the last run is RTL someday.
+
+ foundBox = true;
+
+ int offset = offsetForPosition(ellipsisX, false);
+ if (offset == 0) {
+ // No characters should be rendered. Set ourselves to full truncation and place the ellipsis at the min of our start
+ // and the ellipsis edge.
+ m_truncation = cFullTruncation;
+ return min(ellipsisX, m_x);
+ }
+
+ // Set the truncation index on the text run. The ellipsis needs to be placed just after the last visible character.
+ m_truncation = offset;
+ return m_x + static_cast<RenderText*>(m_object)->width(m_start, offset, textPos(), m_firstLine);
+ }
+ }
+ else {
+ // FIXME: Support RTL truncation someday, including both modes (when the leftmost run on the line is either RTL or LTR)
+ }
+ return -1;
+}
+
+Color correctedTextColor(Color textColor, Color backgroundColor)
+{
+ // Adjust the text color if it is too close to the background color,
+ // by darkening or lightening it to move it further away.
+
+ int d = differenceSquared(textColor, backgroundColor);
+ // semi-arbitrarily chose 65025 (255^2) value here after a few tests;
+ if (d > 65025) {
+ return textColor;
+ }
+
+ int distanceFromWhite = differenceSquared(textColor, Color::white);
+ int distanceFromBlack = differenceSquared(textColor, Color::black);
+
+ if (distanceFromWhite < distanceFromBlack) {
+ return textColor.dark();
+ }
+
+ return textColor.light();
+}
+
+void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness)
+{
+ int mode = context->textDrawingMode();
+ if (strokeThickness > 0) {
+ int newMode = mode | cTextStroke;
+ if (mode != newMode) {
+ context->setTextDrawingMode(newMode);
+ mode = newMode;
+ }
+ }
+
+ if (mode & cTextFill && fillColor != context->fillColor())
+ context->setFillColor(fillColor);
+
+ if (mode & cTextStroke) {
+ if (strokeColor != context->strokeColor())
+ context->setStrokeColor(strokeColor);
+ if (strokeThickness != context->strokeThickness())
+ context->setStrokeThickness(strokeThickness);
+ }
+}
+
+bool InlineTextBox::isLineBreak() const
+{
+ return object()->isBR() || (object()->style()->preserveNewline() && len() == 1 && (*textObject()->text())[start()] == '\n');
+}
+
+bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int x, int y, int tx, int ty)
+{
+ if (isLineBreak())
+ return false;
+
+ IntRect rect(tx + m_x, ty + m_y, m_width, m_height);
+ if (m_truncation != cFullTruncation && visibleToHitTesting() && rect.contains(x, y)) {
+ object()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+ return false;
+}
+
+static void paintTextWithShadows(GraphicsContext* context, const TextRun& textRun, int startOffset, int endOffset, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked)
+{
+ do {
+ IntSize extraOffset;
+
+ if (shadow) {
+ IntSize shadowOffset(shadow->x, shadow->y);
+ int shadowBlur = shadow->blur;
+ const Color& shadowColor = shadow->color;
+
+ if (shadow->next || stroked) {
+ IntRect shadowRect(x, y, w, h);
+ shadowRect.inflate(shadowBlur);
+ shadowRect.move(shadowOffset);
+ context->save();
+ context->clip(shadowRect);
+
+ extraOffset = IntSize(0, 2 * h + max(0, shadowOffset.height()) + shadowBlur);
+ shadowOffset -= extraOffset;
+ }
+ context->setShadow(shadowOffset, shadowBlur, shadowColor);
+ }
+
+ if (startOffset <= endOffset)
+ context->drawText(textRun, textOrigin + extraOffset, startOffset, endOffset);
+ else {
+ if (endOffset > 0)
+ context->drawText(textRun, textOrigin + extraOffset, 0, endOffset);
+ if (startOffset < textRun.length())
+ context->drawText(textRun, textOrigin + extraOffset, startOffset);
+ }
+
+ if (!shadow)
+ break;
+
+ if (shadow->next || stroked)
+ context->restore();
+ else
+ context->clearShadow();
+
+ shadow = shadow->next;
+ } while (shadow || stroked);
+}
+
+void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
+{
+ if (isLineBreak() || !object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE ||
+ m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline)
+ return;
+
+ ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines);
+
+ int xPos = tx + m_x - parent()->maxHorizontalVisualOverflow();
+ int w = width() + 2 * parent()->maxHorizontalVisualOverflow();
+ if (xPos >= paintInfo.rect.right() || xPos + w <= paintInfo.rect.x())
+ return;
+
+ bool isPrinting = textObject()->document()->printing();
+
+ // Determine whether or not we're selected.
+ bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && selectionState() != RenderObject::SelectionNone;
+ if (!haveSelection && paintInfo.phase == PaintPhaseSelection)
+ // When only painting the selection, don't bother to paint if there is none.
+ return;
+
+ GraphicsContext* context = paintInfo.context;
+
+ // Determine whether or not we have composition underlines to draw.
+ bool containsComposition = object()->document()->frame()->editor()->compositionNode() == object()->node();
+ bool useCustomUnderlines = containsComposition && object()->document()->frame()->editor()->compositionUsesCustomUnderlines();
+
+ // Set our font.
+ RenderStyle* styleToUse = object()->style(m_firstLine);
+ int d = styleToUse->textDecorationsInEffect();
+ const Font* font = &styleToUse->font();
+ if (*font != context->font())
+ context->setFont(*font);
+
+ // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection
+ // and composition underlines.
+ if (paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && !isPrinting) {
+#if PLATFORM(MAC)
+ // Custom highlighters go behind everything else.
+ if (styleToUse->highlight() != nullAtom && !context->paintingDisabled())
+ paintCustomHighlight(tx, ty, styleToUse->highlight());
+#endif
+
+ if (containsComposition && !useCustomUnderlines)
+ paintCompositionBackground(context, tx, ty, styleToUse, font,
+ object()->document()->frame()->editor()->compositionStart(),
+ object()->document()->frame()->editor()->compositionEnd());
+
+ paintDocumentMarkers(context, tx, ty, styleToUse, font, true);
+
+ if (haveSelection && !useCustomUnderlines)
+ paintSelection(context, tx, ty, styleToUse, font);
+ }
+
+ // 2. Now paint the foreground, including text and decorations like underline/overline (in quirks mode only).
+ if (m_len <= 0)
+ return;
+
+ Color textFillColor;
+ Color textStrokeColor;
+ float textStrokeWidth = styleToUse->textStrokeWidth();
+ ShadowData* textShadow = paintInfo.forceBlackText ? 0 : styleToUse->textShadow();
+
+ if (paintInfo.forceBlackText) {
+ textFillColor = Color::black;
+ textStrokeColor = Color::black;
+ } else {
+ textFillColor = styleToUse->textFillColor();
+ if (!textFillColor.isValid())
+ textFillColor = styleToUse->color();
+
+ // Make the text fill color legible against a white background
+ if (styleToUse->forceBackgroundsToWhite())
+ textFillColor = correctedTextColor(textFillColor, Color::white);
+
+ textStrokeColor = styleToUse->textStrokeColor();
+ if (!textStrokeColor.isValid())
+ textStrokeColor = styleToUse->color();
+
+ // Make the text stroke color legible against a white background
+ if (styleToUse->forceBackgroundsToWhite())
+ textStrokeColor = correctedTextColor(textStrokeColor, Color::white);
+ }
+
+ bool paintSelectedTextOnly = (paintInfo.phase == PaintPhaseSelection);
+ bool paintSelectedTextSeparately = false;
+
+ Color selectionFillColor = textFillColor;
+ Color selectionStrokeColor = textStrokeColor;
+ float selectionStrokeWidth = textStrokeWidth;
+ ShadowData* selectionShadow = textShadow;
+ if (haveSelection) {
+ // Check foreground color first.
+ Color foreground = paintInfo.forceBlackText ? Color::black : object()->selectionForegroundColor();
+ if (foreground.isValid() && foreground != selectionFillColor) {
+ if (!paintSelectedTextOnly)
+ paintSelectedTextSeparately = true;
+ selectionFillColor = foreground;
+ }
+
+ if (RenderStyle* pseudoStyle = object()->getCachedPseudoStyle(RenderStyle::SELECTION)) {
+ ShadowData* shadow = paintInfo.forceBlackText ? 0 : pseudoStyle->textShadow();
+ if (shadow != selectionShadow) {
+ if (!paintSelectedTextOnly)
+ paintSelectedTextSeparately = true;
+ selectionShadow = shadow;
+ }
+
+ float strokeWidth = pseudoStyle->textStrokeWidth();
+ if (strokeWidth != selectionStrokeWidth) {
+ if (!paintSelectedTextOnly)
+ paintSelectedTextSeparately = true;
+ selectionStrokeWidth = strokeWidth;
+ }
+
+ Color stroke = paintInfo.forceBlackText ? Color::black : pseudoStyle->textStrokeColor();
+ if (!stroke.isValid())
+ stroke = pseudoStyle->color();
+ if (stroke != selectionStrokeColor) {
+ if (!paintSelectedTextOnly)
+ paintSelectedTextSeparately = true;
+ selectionStrokeColor = stroke;
+ }
+ }
+ }
+
+ IntPoint textOrigin(m_x + tx, m_y + ty + m_baseline);
+ TextRun textRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered());
+
+ int sPos = 0;
+ int ePos = 0;
+ if (paintSelectedTextOnly || paintSelectedTextSeparately)
+ selectionStartEnd(sPos, ePos);
+
+ 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);
+ if (!paintSelectedTextSeparately || ePos <= sPos) {
+ // FIXME: Truncate right-to-left text correctly.
+ paintTextWithShadows(context, textRun, 0, m_truncation == cNoTruncation ? m_len : m_truncation, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
+ } else
+ paintTextWithShadows(context, textRun, ePos, sPos, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
+
+ if (textStrokeWidth > 0)
+ context->restore();
+ }
+
+ if ((paintSelectedTextOnly || paintSelectedTextSeparately) && sPos < ePos) {
+ // paint only the text that is selected
+ if (selectionStrokeWidth > 0)
+ context->save();
+
+ updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth);
+ paintTextWithShadows(context, textRun, sPos, ePos, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0);
+
+ if (selectionStrokeWidth > 0)
+ context->restore();
+ }
+
+ // Paint decorations
+ if (d != TDNONE && paintInfo.phase != PaintPhaseSelection && styleToUse->htmlHacks()) {
+ context->setStrokeColor(styleToUse->color());
+ paintDecoration(context, tx, ty, d, textShadow);
+ }
+
+ if (paintInfo.phase == PaintPhaseForeground) {
+ paintDocumentMarkers(context, tx, ty, styleToUse, font, false);
+
+ if (useCustomUnderlines) {
+ const Vector<CompositionUnderline>& underlines = object()->document()->frame()->editor()->customCompositionUnderlines();
+ size_t numUnderlines = underlines.size();
+
+ for (size_t index = 0; index < numUnderlines; ++index) {
+ const CompositionUnderline& underline = underlines[index];
+
+ if (underline.endOffset <= start())
+ // underline is completely before this run. This might be an underline that sits
+ // before the first run we draw, or underlines that were within runs we skipped
+ // due to truncation.
+ continue;
+
+ if (underline.startOffset <= end()) {
+ // underline intersects this run. Paint it.
+ paintCompositionUnderline(context, tx, ty, underline);
+ if (underline.endOffset > end() + 1)
+ // underline also runs into the next run. Bail now, no more marker advancement.
+ break;
+ } else
+ // underline is completely after this run, bail. A later run will paint it.
+ break;
+ }
+ }
+ }
+}
+
+void InlineTextBox::selectionStartEnd(int& sPos, int& ePos)
+{
+ int startPos, endPos;
+ if (object()->selectionState() == RenderObject::SelectionInside) {
+ startPos = 0;
+ endPos = textObject()->textLength();
+ } else {
+ textObject()->selectionStartEnd(startPos, endPos);
+ if (object()->selectionState() == RenderObject::SelectionStart)
+ endPos = textObject()->textLength();
+ else if (object()->selectionState() == RenderObject::SelectionEnd)
+ startPos = 0;
+ }
+
+ sPos = max(startPos - m_start, 0);
+ ePos = min(endPos - m_start, (int)m_len);
+}
+
+void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font*)
+{
+ // See if we have a selection to paint at all.
+ int sPos, ePos;
+ selectionStartEnd(sPos, ePos);
+ if (sPos >= ePos)
+ return;
+
+ Color textColor = style->color();
+ Color c = object()->selectionBackgroundColor();
+ if (!c.isValid() || c.alpha() == 0)
+ return;
+
+ // If the text color ends up being the same as the selection background, invert the selection
+ // background. This should basically never happen, since the selection has transparency.
+ if (textColor == c)
+ c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue());
+
+ context->save();
+ updateGraphicsContext(context, c, c, 0); // Don't draw text at all!
+ int y = selectionTop();
+ int h = selectionHeight();
+ context->clip(IntRect(m_x + tx, y + ty, m_width, h));
+ context->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
+ IntPoint(m_x + tx, y + ty), h, c, sPos, ePos);
+ context->restore();
+}
+
+void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font*, int startPos, int endPos)
+{
+ int offset = m_start;
+ int sPos = max(startPos - offset, 0);
+ int ePos = min(endPos - offset, (int)m_len);
+
+ if (sPos >= ePos)
+ return;
+
+ context->save();
+
+ Color c = Color(225, 221, 85);
+
+ updateGraphicsContext(context, c, c, 0); // Don't draw text at all!
+
+ int y = selectionTop();
+ int h = selectionHeight();
+ context->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
+ IntPoint(m_x + tx, y + ty), h, c, sPos, ePos);
+ context->restore();
+}
+
+#if PLATFORM(MAC)
+
+void InlineTextBox::paintCustomHighlight(int tx, int ty, const AtomicString& type)
+{
+ Frame* frame = object()->document()->frame();
+ if (!frame)
+ return;
+ Page* page = frame->page();
+ if (!page)
+ return;
+
+ RootInlineBox* r = root();
+ FloatRect rootRect(tx + r->xPos(), ty + selectionTop(), r->width(), selectionHeight());
+ FloatRect textRect(tx + xPos(), rootRect.y(), width(), rootRect.height());
+
+ page->chrome()->client()->paintCustomHighlight(object()->node(), type, textRect, rootRect, true, false);
+}
+
+#endif
+
+void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, int deco, ShadowData* shadow)
+{
+ tx += m_x;
+ ty += m_y;
+
+ if (m_truncation == cFullTruncation)
+ return;
+
+ int width = (m_truncation == cNoTruncation) ? m_width
+ : static_cast<RenderText*>(m_object)->width(m_start, m_truncation, textPos(), m_firstLine);
+
+ // Get the text decoration colors.
+ Color underline, overline, linethrough;
+ object()->getTextDecorationColors(deco, underline, overline, linethrough, true);
+
+ // Use a special function for underlines to get the positioning exactly right.
+ bool isPrinting = textObject()->document()->printing();
+ context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1.
+
+ bool linesAreOpaque = !isPrinting && (!(deco & UNDERLINE) || underline.alpha() == 255) && (!(deco & OVERLINE) || overline.alpha() == 255) && (!(deco & LINE_THROUGH) || linethrough.alpha() == 255);
+
+ bool setClip = false;
+ int extraOffset = 0;
+ if (!linesAreOpaque && shadow && shadow->next) {
+ context->save();
+ IntRect clipRect(tx, ty, width, m_baseline + 2);
+ for (ShadowData* s = shadow; s; s = s->next) {
+ IntRect shadowRect(tx, ty, width, m_baseline + 2);
+ shadowRect.inflate(s->blur);
+ shadowRect.move(s->x, s->y);
+ clipRect.unite(shadowRect);
+ extraOffset = max(extraOffset, max(0, s->y) + s->blur);
+ }
+ context->save();
+ context->clip(clipRect);
+ extraOffset += m_baseline + 2;
+ ty += extraOffset;
+ setClip = true;
+ }
+
+ bool setShadow = false;
+ do {
+ if (shadow) {
+ if (!shadow->next) {
+ // The last set of lines paints normally inside the clip.
+ ty -= extraOffset;
+ extraOffset = 0;
+ }
+ context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color);
+ setShadow = true;
+ shadow = shadow->next;
+ }
+
+ if (deco & UNDERLINE) {
+ context->setStrokeColor(underline);
+ // Leave one pixel of white between the baseline and the underline.
+ context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), width, isPrinting);
+ }
+ if (deco & OVERLINE) {
+ context->setStrokeColor(overline);
+ context->drawLineForText(IntPoint(tx, ty), width, isPrinting);
+ }
+ if (deco & LINE_THROUGH) {
+ context->setStrokeColor(linethrough);
+ context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), width, isPrinting);
+ }
+ } while (shadow);
+
+ if (setClip)
+ context->restore();
+ else if (setShadow)
+ context->clearShadow();
+}
+
+void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font* f, bool grammar)
+{
+ // Never print spelling/grammar markers (5327887)
+ if (textObject()->document()->printing())
+ return;
+
+ if (m_truncation == cFullTruncation)
+ return;
+
+ int start = 0; // start of line to draw, relative to tx
+ int width = m_width; // how much line to draw
+
+ // Determine whether we need to measure text
+ bool markerSpansWholeBox = true;
+ if (m_start <= (int)marker.startOffset)
+ markerSpansWholeBox = false;
+ if ((end() + 1) != marker.endOffset) // end points at the last char, not past it
+ markerSpansWholeBox = false;
+ if (m_truncation != cNoTruncation)
+ markerSpansWholeBox = false;
+
+ if (!markerSpansWholeBox || grammar) {
+ int startPosition = max<int>(marker.startOffset - m_start, 0);
+ int endPosition = min<int>(marker.endOffset - m_start, m_len);
+
+ if (m_truncation != cNoTruncation)
+ endPosition = min<int>(endPosition, m_truncation);
+
+ // Calculate start & width
+ IntPoint startPoint(tx + m_x, ty + selectionTop());
+ TextRun run(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered());
+ int h = selectionHeight();
+
+ IntRect markerRect = enclosingIntRect(f->selectionRectForText(run, startPoint, h, startPosition, endPosition));
+ start = markerRect.x() - startPoint.x();
+ width = markerRect.width();
+
+ // 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)
+ object()->document()->setRenderedRectForMarker(object()->node(), marker, markerRect);
+ }
+
+ // IMPORTANT: The misspelling underline is not considered when calculating the text bounds, so we have to
+ // make sure to fit within those bounds. This means the top pixel(s) of the underline will overlap the
+ // bottom pixel(s) of the glyphs in smaller font sizes. The alternatives are to increase the line spacing (bad!!)
+ // or decrease the underline thickness. The overlap is actually the most useful, and matches what AppKit does.
+ // So, we generally place the underline at the bottom of the text, but in larger fonts that's not so good so
+ // we pin to two pixels under the baseline.
+ int lineThickness = cMisspellingLineThickness;
+ int descent = m_height - m_baseline;
+ int underlineOffset;
+ if (descent <= (2 + lineThickness)) {
+ // place the underline at the very bottom of the text in small/medium fonts
+ underlineOffset = m_height - lineThickness;
+ } else {
+ // in larger fonts, tho, place the underline up near the baseline to prevent big gap
+ underlineOffset = m_baseline + 2;
+ }
+ 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* f)
+{
+ // 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.
+ int y = selectionTop();
+ int h = selectionHeight();
+
+ int sPos = max(marker.startOffset - m_start, (unsigned)0);
+ int ePos = min(marker.endOffset - m_start, (unsigned)m_len);
+ TextRun run(textObject()->text()->characters() + m_start, m_len, textObject()->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(f->selectionRectForText(run, startPoint, h, sPos, ePos));
+ object()->document()->setRenderedRectForMarker(object()->node(), marker, markerRect);
+
+ // Optionally highlight the text
+ if (object()->document()->frame()->markedTextMatchesAreHighlighted()) {
+ Color color = theme()->platformTextSearchHighlightColor();
+ pt->save();
+ updateGraphicsContext(pt, color, color, 0); // Don't draw text at all!
+ pt->clip(IntRect(tx + m_x, ty + y, m_width, h));
+ pt->drawHighlightForText(run, startPoint, h, color, sPos, ePos);
+ pt->restore();
+ }
+}
+
+void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, RenderStyle* style, const Font* f, bool background)
+{
+ Vector<DocumentMarker> markers = object()->document()->markersForNode(object()->node());
+ Vector<DocumentMarker>::iterator markerIt = markers.begin();
+
+ // 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;
+
+ // Paint either the background markers or the foreground markers, but not both
+ switch (marker.type) {
+ case DocumentMarker::Grammar:
+ case DocumentMarker::Spelling:
+ if (background)
+ continue;
+ break;
+
+ case DocumentMarker::TextMatch:
+ if (!background)
+ continue;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ if (marker.endOffset <= start())
+ // marker is completely before this run. This might be a marker that sits before the
+ // first run we draw, or markers that were within runs we skipped due to truncation.
+ continue;
+
+ if (marker.startOffset > end())
+ // marker is completely after this run, bail. A later run will paint it.
+ break;
+
+ // marker intersects this run. Paint it.
+ switch (marker.type) {
+ case DocumentMarker::Spelling:
+ paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, f, false);
+ break;
+ case DocumentMarker::Grammar:
+ paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, f, true);
+ break;
+ case DocumentMarker::TextMatch:
+ paintTextMatchMarker(pt, tx, ty, marker, style, f);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ }
+}
+
+
+void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int ty, const CompositionUnderline& underline)
+{
+ tx += m_x;
+ ty += m_y;
+
+ if (m_truncation == cFullTruncation)
+ return;
+
+ int start = 0; // start of line to draw, relative to tx
+ int width = m_width; // how much line to draw
+ bool useWholeWidth = true;
+ unsigned paintStart = m_start;
+ unsigned paintEnd = end() + 1; // end points at the last char, not past it
+ if (paintStart <= underline.startOffset) {
+ paintStart = underline.startOffset;
+ useWholeWidth = false;
+ start = static_cast<RenderText*>(m_object)->width(m_start, paintStart - m_start, textPos(), m_firstLine);
+ }
+ if (paintEnd != underline.endOffset) { // end points at the last char, not past it
+ paintEnd = min(paintEnd, (unsigned)underline.endOffset);
+ useWholeWidth = false;
+ }
+ if (m_truncation != cNoTruncation) {
+ paintEnd = min(paintEnd, (unsigned)m_start + m_truncation);
+ useWholeWidth = false;
+ }
+ if (!useWholeWidth) {
+ width = static_cast<RenderText*>(m_object)->width(paintStart, paintEnd - paintStart, textPos() + start, m_firstLine);
+ }
+
+ // Thick marked text underlines are 2px thick as long as there is room for the 2px line under the baseline.
+ // All other marked text underlines are 1px thick.
+ // If there's not enough space the underline will touch or overlap characters.
+ int lineThickness = 1;
+ if (underline.thick && m_height - m_baseline >= 2)
+ lineThickness = 2;
+
+ // We need to have some space between underlines of subsequent clauses, because some input methods do not use different underline styles for those.
+ // We make each line shorter, which has a harmless side effect of shortening the first and last clauses, too.
+ start += 1;
+ width -= 2;
+
+ ctx->setStrokeColor(underline.color);
+ ctx->setStrokeThickness(lineThickness);
+ ctx->drawLineForText(IntPoint(tx + start, ty + m_height - lineThickness), width, textObject()->document()->printing());
+}
+
+int InlineTextBox::caretMinOffset() const
+{
+ return m_start;
+}
+
+int InlineTextBox::caretMaxOffset() const
+{
+ return m_start + m_len;
+}
+
+unsigned InlineTextBox::caretMaxRenderedOffset() const
+{
+ return m_start + m_len;
+}
+
+int InlineTextBox::textPos() const
+{
+ if (xPos() == 0)
+ return 0;
+
+ RenderBlock *blockElement = object()->containingBlock();
+ return direction() == RTL ? xPos() - blockElement->borderRight() - blockElement->paddingRight()
+ : xPos() - blockElement->borderLeft() - blockElement->paddingLeft();
+}
+
+int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const
+{
+ if (isLineBreak())
+ return 0;
+
+ RenderText* text = static_cast<RenderText*>(m_object);
+ RenderStyle *style = text->style(m_firstLine);
+ const Font* f = &style->font();
+ return f->offsetForPosition(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
+ _x - m_x, includePartialGlyphs);
+}
+
+int InlineTextBox::positionForOffset(int offset) const
+{
+ ASSERT(offset >= m_start);
+ ASSERT(offset <= m_start + m_len);
+
+ if (isLineBreak())
+ return m_x;
+
+ RenderText* text = static_cast<RenderText*>(m_object);
+ const Font& f = text->style(m_firstLine)->font();
+ int from = direction() == RTL ? offset - m_start : 0;
+ int to = direction() == RTL ? m_len : offset - m_start;
+ // FIXME: Do we need to add rightBearing here?
+ return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride),
+ IntPoint(m_x, 0), 0, from, to)).right();
+}
+
+bool InlineTextBox::containsCaretOffset(int offset) const
+{
+ // Offsets before the box are never "in".
+ if (offset < m_start)
+ return false;
+
+ int pastEnd = m_start + m_len;
+
+ // Offsets inside the box (not at either edge) are always "in".
+ if (offset < pastEnd)
+ return true;
+
+ // Offsets outside the box are always "out".
+ if (offset > pastEnd)
+ return false;
+
+ // Offsets at the end are "out" for line breaks (they are on the next line).
+ if (isLineBreak())
+ return false;
+
+ // Offsets at the end are "in" for normal boxes (but the caller has to check affinity).
+ return true;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h
new file mode 100644
index 0000000..d8a250b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/InlineTextBox.h
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006 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
+ * 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 InlineTextBox_h
+#define InlineTextBox_h
+
+#include "DocumentMarker.h"
+#include "InlineRunBox.h"
+#include "RenderText.h"
+
+namespace WebCore {
+
+const unsigned short cNoTruncation = USHRT_MAX;
+const unsigned short cFullTruncation = USHRT_MAX - 1;
+
+class String;
+class StringImpl;
+class HitTestResult;
+class Position;
+
+struct CompositionUnderline;
+
+// Helper functions shared by InlineTextBox / SVGRootInlineBox
+void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness);
+Color correctedTextColor(Color textColor, Color backgroundColor);
+
+class InlineTextBox : public InlineRunBox {
+public:
+ InlineTextBox(RenderObject* obj)
+ : InlineRunBox(obj)
+ , m_start(0)
+ , m_len(0)
+ , m_truncation(cNoTruncation)
+ {
+ }
+
+ InlineTextBox* nextTextBox() const { return static_cast<InlineTextBox*>(nextLineBox()); }
+ InlineTextBox* prevTextBox() const { return static_cast<InlineTextBox*>(prevLineBox()); }
+
+ unsigned start() const { return m_start; }
+ unsigned end() const { return m_len ? m_start + m_len - 1 : m_start; }
+ unsigned len() const { return m_len; }
+
+ void setStart(unsigned start) { m_start = start; }
+ void setLen(unsigned len) { m_len = len; }
+
+ void offsetRun(int d) { m_start += d; }
+
+ virtual int selectionTop();
+ virtual int selectionHeight();
+
+ virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos);
+ bool isSelected(int startPos, int endPos) const;
+ void selectionStartEnd(int& sPos, int& ePos);
+
+ virtual void paint(RenderObject::PaintInfo&, int tx, int ty);
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty);
+
+ RenderText* textObject() const;
+
+ virtual void deleteLine(RenderArena*);
+ virtual void extractLine();
+ virtual void attachLine();
+
+ virtual RenderObject::SelectionState selectionState();
+
+ virtual void clearTruncation() { m_truncation = cNoTruncation; }
+ virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox);
+
+ virtual bool isLineBreak() const;
+
+ void setSpaceAdd(int add) { m_width -= m_toAdd; m_toAdd = add; m_width += m_toAdd; }
+ int spaceAdd() { return m_toAdd; }
+
+ virtual bool isInlineTextBox() { return true; }
+ virtual bool isText() const { return m_treatAsText; }
+ void setIsText(bool b) { m_treatAsText = b; }
+
+ virtual int caretMinOffset() const;
+ virtual int caretMaxOffset() const;
+ virtual unsigned caretMaxRenderedOffset() const;
+
+ int textPos() const;
+ virtual int offsetForPosition(int x, bool includePartialGlyphs = true) const;
+ virtual int positionForOffset(int offset) const;
+
+ bool containsCaretOffset(int offset) const; // false for offset after line break
+
+ int m_start;
+ unsigned short m_len;
+
+ unsigned short m_truncation; // Where to truncate when text overflow is applied. We use special constants to
+ // denote no truncation (the whole run paints) and full truncation (nothing paints at all).
+
+protected:
+ void paintCompositionBackground(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, int startPos, int endPos);
+ void paintDocumentMarkers(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, bool background);
+ void paintCompositionUnderline(GraphicsContext*, int tx, int ty, const CompositionUnderline&);
+#if PLATFORM(MAC)
+ void paintCustomHighlight(int tx, int ty, const AtomicString& type);
+#endif
+
+private:
+ void paintDecoration(GraphicsContext*, int tx, int ty, int decoration, ShadowData* shadow);
+ 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*);
+ friend class RenderText;
+};
+
+inline RenderText* InlineTextBox::textObject() const
+{
+ return static_cast<RenderText*>(m_object);
+}
+
+} // namespace WebCore
+
+#endif // InlineTextBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp b/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp
new file mode 100644
index 0000000..20d0b99
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/LayoutState.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include "config.h"
+#include "LayoutState.h"
+
+#include "RenderArena.h"
+#include "RenderLayer.h"
+#include "RenderView.h"
+
+namespace WebCore {
+
+LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& offset)
+{
+ ASSERT(prev);
+
+ m_next = prev;
+
+ bool fixed = renderer->isPositioned() && renderer->style()->position() == FixedPosition;
+ if (fixed) {
+ // FIXME: This doesn't work correctly with transforms.
+ FloatPoint fixedOffset = renderer->view()->localToAbsolute(FloatPoint(), true);
+ m_offset = IntSize(fixedOffset.x(), fixedOffset.y()) + offset;
+ } else
+ m_offset = prev->m_offset + offset;
+
+ if (renderer->isRelPositioned()) {
+ if (renderer->hasLayer())
+ m_offset += renderer->layer()->relativePositionOffset();
+ } else if (renderer->isPositioned() && !fixed) {
+ if (RenderObject* container = renderer->container())
+ m_offset += renderer->offsetForPositionedInContainer(container);
+ }
+
+ m_clipped = !fixed && prev->m_clipped;
+ if (m_clipped)
+ m_clipRect = prev->m_clipRect;
+ if (renderer->hasOverflowClip()) {
+ int x = m_offset.width();
+ int y = m_offset.height();
+ RenderLayer* layer = renderer->layer();
+ IntRect clipRect(x, y, layer->width(), layer->height());
+ clipRect.move(renderer->view()->layoutDelta());
+ if (m_clipped)
+ m_clipRect.intersect(clipRect);
+ else {
+ m_clipRect = clipRect;
+ m_clipped = true;
+ }
+ layer->subtractScrolledContentOffset(x, y);
+ m_offset = IntSize(x, y);
+ }
+ // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present.
+}
+
+LayoutState::LayoutState(RenderObject* root)
+ : m_clipped(false)
+{
+ RenderObject* container = root->container();
+ FloatPoint absContentPoint = container->localToAbsoluteForContent(FloatPoint(), false, true);
+ m_offset = IntSize(absContentPoint.x(), absContentPoint.y());
+ m_next = 0;
+}
+
+#ifndef NDEBUG
+static bool inLayoutStateDestroy;
+#endif
+
+void LayoutState::destroy(RenderArena* renderArena)
+{
+#ifndef NDEBUG
+ inLayoutStateDestroy = true;
+#endif
+ delete this;
+#ifndef NDEBUG
+ inLayoutStateDestroy = false;
+#endif
+ renderArena->free(*(size_t*)this, this);
+}
+
+void* LayoutState::operator new(size_t sz, RenderArena* renderArena) throw()
+{
+ return renderArena->allocate(sz);
+}
+
+void LayoutState::operator delete(void* ptr, size_t sz)
+{
+ ASSERT(inLayoutStateDestroy);
+ *(size_t*)ptr = sz;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/LayoutState.h b/src/3rdparty/webkit/WebCore/rendering/LayoutState.h
new file mode 100644
index 0000000..551c74a
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/LayoutState.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 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 LayoutState_h
+#define LayoutState_h
+
+#include "IntRect.h"
+#include "IntSize.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class RenderArena;
+class RenderBox;
+class RenderObject;
+
+class LayoutState : Noncopyable {
+public:
+ LayoutState()
+ : m_clipped(false)
+ , m_next(0)
+ {
+ }
+
+ LayoutState(LayoutState*, RenderBox*, const IntSize& offset);
+ LayoutState(RenderObject*);
+
+ void destroy(RenderArena*);
+
+ // 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);
+
+private:
+ // The normal operator new is disallowed.
+ void* operator new(size_t) throw();
+
+public:
+ bool m_clipped;
+ IntRect m_clipRect;
+ IntSize m_offset;
+ LayoutState* m_next;
+};
+
+} // namespace WebCore
+
+#endif // LayoutState_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.cpp b/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.cpp
new file mode 100644
index 0000000..0455eae
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.cpp
@@ -0,0 +1,45 @@
+/**
+ * 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) 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 "ListMarkerBox.h"
+
+#include "InlineFlowBox.h"
+#include "RenderArena.h"
+#include "RenderListMarker.h"
+
+namespace WebCore {
+
+ListMarkerBox::ListMarkerBox(RenderObject* obj)
+ : InlineBox(obj)
+{
+}
+
+bool ListMarkerBox::isText() const
+{
+ return static_cast<RenderListMarker*>(object())->isText();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.h b/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.h
new file mode 100644
index 0000000..47ae256
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/ListMarkerBox.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ *
+ * 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 ListMarkerBox_h
+#define ListMarkerBox_h
+
+#include "InlineBox.h"
+
+namespace WebCore {
+
+class ListMarkerBox : public InlineBox {
+public:
+ ListMarkerBox(RenderObject*);
+
+ virtual bool isText() const;
+};
+
+} // namespace WebCore
+
+#endif // ListMarkerBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp
new file mode 100644
index 0000000..48ea3ab
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2008 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO)
+
+#include "MediaControlElements.h"
+
+#include "Event.h"
+#include "EventNames.h"
+#include "EventHandler.h"
+#include "FloatConversion.h"
+#include "Frame.h"
+#include "HTMLNames.h"
+#include "RenderSlider.h"
+#include "RenderTheme.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// FIXME: These constants may need to be tweaked to better match the seeking in the QT plugin
+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)
+ , m_mediaElement(mediaElement)
+{
+ RefPtr<RenderStyle> rootStyle = RenderStyle::create();
+ rootStyle->inheritFrom(mediaElement->renderer()->style());
+ rootStyle->setDisplay(BLOCK);
+ rootStyle->setPosition(RelativePosition);
+ RenderMediaControlShadowRoot* renderer = new (mediaElement->renderer()->renderArena()) RenderMediaControlShadowRoot(this);
+ renderer->setParent(mediaElement->renderer());
+ renderer->setStyle(rootStyle.release());
+ setRenderer(renderer);
+ setAttached();
+ setInDocument(true);
+}
+
+// ----------------------------
+
+MediaControlInputElement::MediaControlInputElement(Document* doc, RenderStyle::PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement)
+ : HTMLInputElement(inputTag, doc)
+ , m_mediaElement(mediaElement)
+{
+ setInputType(type);
+ RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(pseudo);
+ RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style);
+ if (renderer) {
+ setRenderer(renderer);
+ renderer->setStyle(style);
+ }
+ setAttached();
+ setInDocument(true);
+}
+
+void MediaControlInputElement::attachToParent(Element* parent)
+{
+ parent->addChild(this);
+ parent->renderer()->addChild(renderer());
+}
+
+void MediaControlInputElement::update()
+{
+ if (renderer())
+ renderer()->updateFromElement();
+}
+
+bool MediaControlInputElement::hitTest(const IntPoint& absPoint)
+{
+ if (renderer() && renderer()->style()->hasAppearance())
+ return theme()->hitTestMediaControlPart(renderer(), absPoint);
+
+ return false;
+}
+
+// ----------------------------
+
+MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* doc, HTMLMediaElement* element)
+ : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_MUTE_BUTTON, "button", element)
+{
+}
+
+void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
+{
+ if (event->type() == eventNames().clickEvent) {
+ m_mediaElement->setMuted(!m_mediaElement->muted());
+ event->setDefaultHandled();
+ }
+ HTMLInputElement::defaultEventHandler(event);
+}
+
+// ----------------------------
+
+MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* doc, HTMLMediaElement* element)
+ : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_PLAY_BUTTON, "button", element)
+{
+}
+
+void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
+{
+ if (event->type() == eventNames().clickEvent) {
+ ExceptionCode ec;
+ if (m_mediaElement->canPlay())
+ m_mediaElement->play(ec);
+ else
+ m_mediaElement->pause(ec);
+ event->setDefaultHandled();
+ }
+ HTMLInputElement::defaultEventHandler(event);
+}
+
+// ----------------------------
+
+MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* doc, HTMLMediaElement* element, bool forward)
+ : MediaControlInputElement(doc, forward ? RenderStyle::MEDIA_CONTROLS_SEEK_FORWARD_BUTTON : RenderStyle::MEDIA_CONTROLS_SEEK_BACK_BUTTON, "button", element)
+ , m_forward(forward)
+ , m_seeking(false)
+ , m_capturing(false)
+ , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
+{
+}
+
+void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
+{
+ if (event->type() == eventNames().mousedownEvent) {
+ if (Frame* frame = document()->frame()) {
+ m_capturing = true;
+ frame->eventHandler()->setCapturingMouseEventsNode(this);
+ }
+ ExceptionCode ec;
+ m_mediaElement->pause(ec);
+ m_seekTimer.startRepeating(cSeekRepeatDelay);
+ event->setDefaultHandled();
+ } else if (event->type() == eventNames().mouseupEvent) {
+ if (m_capturing)
+ if (Frame* frame = document()->frame()) {
+ m_capturing = false;
+ frame->eventHandler()->setCapturingMouseEventsNode(0);
+ }
+ ExceptionCode ec;
+ if (m_seeking || m_seekTimer.isActive()) {
+ if (!m_seeking) {
+ float stepTime = m_forward ? cStepTime : -cStepTime;
+ m_mediaElement->setCurrentTime(m_mediaElement->currentTime() + stepTime, ec);
+ }
+ m_seekTimer.stop();
+ m_seeking = false;
+ event->setDefaultHandled();
+ }
+ }
+ HTMLInputElement::defaultEventHandler(event);
+}
+
+void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
+{
+ ExceptionCode ec;
+ m_seeking = true;
+ float seekTime = m_forward ? cSeekTime : -cSeekTime;
+ m_mediaElement->setCurrentTime(m_mediaElement->currentTime() + seekTime, ec);
+}
+
+// ----------------------------
+
+MediaControlTimelineElement::MediaControlTimelineElement(Document* doc, HTMLMediaElement* element)
+ : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_TIMELINE, "range", element)
+{
+ setAttribute(precisionAttr, "float");
+}
+
+void MediaControlTimelineElement::defaultEventHandler(Event* event)
+{
+ RenderSlider* slider = static_cast<RenderSlider*>(renderer());
+ bool oldInDragMode = slider && slider->inDragMode();
+ float oldTime = narrowPrecisionToFloat(value().toDouble());
+ bool oldEnded = m_mediaElement->ended();
+
+ HTMLInputElement::defaultEventHandler(event);
+
+ float time = narrowPrecisionToFloat(value().toDouble());
+ if (oldTime != time || event->type() == eventNames().inputEvent) {
+ ExceptionCode ec;
+ m_mediaElement->setCurrentTime(time, ec);
+ }
+ // Media element stays in non-paused state when it reaches end. If the slider is now dragged
+ // to some other position the playback resumes which does not match usual media player UIs.
+ // Get the expected behavior by pausing explicitly in this case.
+ if (oldEnded && !m_mediaElement->ended() && !m_mediaElement->paused()) {
+ ExceptionCode ec;
+ m_mediaElement->pause(ec);
+ }
+ // Pause playback during drag, but do it without using DOM API which would generate events
+ bool inDragMode = slider && slider->inDragMode();
+ if (inDragMode != oldInDragMode)
+ m_mediaElement->setPausedInternal(inDragMode);
+}
+
+void MediaControlTimelineElement::update(bool updateDuration)
+{
+ if (updateDuration) {
+ float dur = m_mediaElement->duration();
+ setAttribute(maxAttr, String::number(isfinite(dur) ? dur : 0));
+ }
+ setValue(String::number(m_mediaElement->currentTime()));
+}
+
+// ----------------------------
+
+MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* doc, HTMLMediaElement* element)
+ : MediaControlInputElement(doc, RenderStyle::MEDIA_CONTROLS_FULLSCREEN_BUTTON, "button", element)
+{
+}
+
+void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
+{
+ if (event->type() == eventNames().clickEvent) {
+ event->setDefaultHandled();
+ }
+ HTMLInputElement::defaultEventHandler(event);
+}
+
+// ----------------------------
+
+} //namespace WebCore
+#endif // enable(video)
diff --git a/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h
new file mode 100644
index 0000000..4741534
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/MediaControlElements.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaControlElements_h
+#define MediaControlElements_h
+
+#if ENABLE(VIDEO)
+
+#include "HTMLDivElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLMediaElement.h"
+#include "RenderBlock.h"
+
+// These are the shadow elements used in RenderMedia
+
+namespace WebCore {
+
+class Event;
+class Frame;
+
+enum MediaControlElements {
+ MediaFullscreenButton, MediaMuteButton, MediaPlayButton,
+ MediaSeekBackButton, MediaSeekForwardButton, MediaSlider, MediaSliderThumb,
+ MediaUnMuteButton, MediaPauseButton, MediaTimelineContainer, MediaCurrentTimeDisplay,
+ MediaTimeRemainingDisplay, MediaControlsPanel
+};
+
+class MediaControlShadowRootElement : public HTMLDivElement {
+public:
+ MediaControlShadowRootElement(Document*, HTMLMediaElement*);
+
+ virtual bool isShadowNode() const { return true; }
+ virtual Node* shadowParentNode() { return m_mediaElement; }
+
+private:
+ HTMLMediaElement* m_mediaElement;
+};
+
+// ----------------------------
+
+class MediaControlInputElement : public HTMLInputElement {
+public:
+ MediaControlInputElement(Document*, RenderStyle::PseudoId, const String& type, HTMLMediaElement*);
+ void attachToParent(Element*);
+ void update();
+ bool hitTest(const IntPoint& absPoint);
+protected:
+ HTMLMediaElement* m_mediaElement;
+};
+
+// ----------------------------
+
+class MediaControlMuteButtonElement : public MediaControlInputElement {
+public:
+ MediaControlMuteButtonElement(Document*, HTMLMediaElement*);
+ virtual void defaultEventHandler(Event*);
+};
+
+// ----------------------------
+
+class MediaControlPlayButtonElement : public MediaControlInputElement {
+public:
+ MediaControlPlayButtonElement(Document*, HTMLMediaElement*);
+ virtual void defaultEventHandler(Event*);
+};
+
+// ----------------------------
+
+class MediaControlSeekButtonElement : public MediaControlInputElement {
+public:
+ MediaControlSeekButtonElement(Document*, HTMLMediaElement*, bool forward);
+ virtual void defaultEventHandler(Event*);
+ void seekTimerFired(Timer<MediaControlSeekButtonElement>*);
+
+private:
+ bool m_forward;
+ bool m_seeking;
+ bool m_capturing;
+ Timer<MediaControlSeekButtonElement> m_seekTimer;
+};
+
+// ----------------------------
+
+class MediaControlTimelineElement : public MediaControlInputElement {
+public:
+ MediaControlTimelineElement(Document*, HTMLMediaElement*);
+ virtual void defaultEventHandler(Event*);
+ void update(bool updateDuration = true);
+};
+
+// ----------------------------
+
+class MediaControlFullscreenButtonElement : public MediaControlInputElement {
+public:
+ MediaControlFullscreenButtonElement(Document*, HTMLMediaElement*);
+ virtual void defaultEventHandler(Event*);
+};
+
+// ----------------------------
+
+class RenderMediaControlShadowRoot : public RenderBlock {
+public:
+ RenderMediaControlShadowRoot(Element* e) : RenderBlock(e) { }
+ void setParent(RenderObject* p) { RenderObject::setParent(p); }
+};
+
+// ----------------------------
+
+} //namespace WebCore
+#endif // enable(video)
+#endif // MediaControlElements_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.cpp b/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.cpp
new file mode 100644
index 0000000..214fb09
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.cpp
@@ -0,0 +1,110 @@
+/*
+ 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
+ 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"
+#include "PointerEventsHitRules.h"
+
+namespace WebCore {
+
+PointerEventsHitRules::PointerEventsHitRules(EHitTesting hitTesting, EPointerEvents pointerEvents)
+ : requireVisible(false)
+ , requireFill(false)
+ , requireStroke(false)
+ , canHitStroke(false)
+ , canHitFill(false)
+{
+ if (hitTesting == SVG_PATH_HITTESTING) {
+ switch (pointerEvents)
+ {
+ case PE_VISIBLE_PAINTED:
+ case PE_AUTO: // "auto" is like "visiblePainted" when in SVG content
+ requireFill = true;
+ requireStroke = true;
+ case PE_VISIBLE:
+ requireVisible = true;
+ canHitFill = true;
+ canHitStroke = true;
+ break;
+ case PE_VISIBLE_FILL:
+ requireVisible = true;
+ canHitFill = true;
+ break;
+ case PE_VISIBLE_STROKE:
+ requireVisible = true;
+ canHitStroke = true;
+ break;
+ case PE_PAINTED:
+ requireFill = true;
+ requireStroke = true;
+ case PE_ALL:
+ canHitFill = true;
+ canHitStroke = true;
+ break;
+ case PE_FILL:
+ canHitFill = true;
+ break;
+ case PE_STROKE:
+ canHitStroke = true;
+ break;
+ case PE_NONE:
+ // nothing to do here, defaults are all false.
+ break;
+ }
+ } else {
+ switch (pointerEvents)
+ {
+ case PE_VISIBLE_PAINTED:
+ case PE_AUTO: // "auto" is like "visiblePainted" when in SVG content
+ requireVisible = true;
+ requireFill = true;
+ requireStroke = true;
+ canHitFill = true;
+ canHitStroke = true;
+ break;
+ case PE_VISIBLE_FILL:
+ case PE_VISIBLE_STROKE:
+ case PE_VISIBLE:
+ requireVisible = true;
+ canHitFill = true;
+ canHitStroke = true;
+ break;
+ case PE_PAINTED:
+ requireFill = true;
+ requireStroke = true;
+ canHitFill = true;
+ canHitStroke = true;
+ break;
+ case PE_FILL:
+ case PE_STROKE:
+ case PE_ALL:
+ canHitFill = true;
+ canHitStroke = true;
+ break;
+ case PE_NONE:
+ // nothing to do here, defaults are all false.
+ break;
+ }
+ }
+}
+
+}
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h b/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h
new file mode 100644
index 0000000..e2dae3b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/PointerEventsHitRules.h
@@ -0,0 +1,50 @@
+/*
+ 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
+ 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 PointerEventsHitRules_h
+#define PointerEventsHitRules_h
+
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+class PointerEventsHitRules {
+public:
+ enum EHitTesting {
+ SVG_IMAGE_HITTESTING,
+ SVG_PATH_HITTESTING,
+ SVG_TEXT_HITTESTING
+ };
+
+ PointerEventsHitRules(EHitTesting, EPointerEvents);
+
+ bool requireVisible;
+ bool requireFill;
+ bool requireStroke;
+ bool canHitStroke;
+ bool canHitFill;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderApplet.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderApplet.cpp
new file mode 100644
index 0000000..7483943
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderApplet.cpp
@@ -0,0 +1,98 @@
+/**
+ * This file is part of the HTML widget for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2003, 2006 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
+ * 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 "RenderApplet.h"
+
+#include "Document.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "HTMLAppletElement.h"
+#include "HTMLNames.h"
+#include "HTMLParamElement.h"
+#include "Widget.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderApplet::RenderApplet(HTMLAppletElement* applet, const HashMap<String, String>& args)
+ : RenderWidget(applet)
+ , m_args(args)
+{
+ setInline(true);
+}
+
+RenderApplet::~RenderApplet()
+{
+}
+
+IntSize RenderApplet::intrinsicSize() const
+{
+ // FIXME: This doesn't make sense. We can't just start returning
+ // a different size once we've created the widget and expect
+ // layout and sizing to be correct. We should remove this and
+ // pass the appropriate intrinsic size in the constructor.
+ return m_widget ? IntSize(50, 50) : IntSize(150, 150);
+}
+
+void RenderApplet::createWidgetIfNecessary()
+{
+ HTMLAppletElement* element = static_cast<HTMLAppletElement*>(node());
+ if (m_widget || !element->isFinishedParsingChildren())
+ return;
+
+ // FIXME: Java applets can't be resized (this is a bug in Apple's Java implementation).
+ // In order to work around this problem and have a correct size from the start, we will
+ // use fixed widths/heights from the style system when we can, since the widget might
+ // not have an accurate m_width/m_height.
+ int width = style()->width().isFixed() ? style()->width().value() :
+ m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight();
+ int height = style()->height().isFixed() ? style()->height().value() :
+ m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom();
+ for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
+ if (child->hasTagName(paramTag)) {
+ HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
+ if (!p->name().isEmpty())
+ m_args.set(p->name(), p->value());
+ }
+ }
+
+ Frame* frame = document()->frame();
+ ASSERT(frame);
+ setWidget(frame->loader()->createJavaAppletWidget(IntSize(width, height), element, m_args));
+}
+
+void RenderApplet::layout()
+{
+ ASSERT(needsLayout());
+
+ calcWidth();
+ calcHeight();
+
+ // The applet's widget gets created lazily upon first layout.
+ createWidgetIfNecessary();
+ setNeedsLayout(false);
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderApplet.h b/src/3rdparty/webkit/WebCore/rendering/RenderApplet.h
new file mode 100644
index 0000000..6746c22
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderApplet.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2006, 2007 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 RenderApplet_h
+#define RenderApplet_h
+
+#include "RenderWidget.h"
+#include "StringHash.h"
+
+namespace WebCore {
+
+ class HTMLAppletElement;
+
+ class RenderApplet : public RenderWidget {
+ public:
+ RenderApplet(HTMLAppletElement*, const HashMap<String, String>& args);
+ virtual ~RenderApplet();
+
+ virtual const char* renderName() const { return "RenderApplet"; }
+
+ virtual bool isApplet() const { return true; }
+
+ virtual void layout();
+ virtual IntSize intrinsicSize() const;
+
+ void createWidgetIfNecessary();
+
+ private:
+ HashMap<String, String> m_args;
+ };
+
+} // namespace WebCore
+
+#endif // RenderApplet_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp
new file mode 100644
index 0000000..69d08a5
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderArena.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * Portions are Copyright (C) 1998 Netscape Communications Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+ */
+
+#include "config.h"
+#include "RenderArena.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <wtf/Assertions.h>
+
+#define ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y))
+
+namespace WebCore {
+
+#ifndef NDEBUG
+
+const int signature = 0xDBA00AEA;
+const int signatureDead = 0xDBA00AED;
+
+typedef struct {
+ RenderArena* arena;
+ size_t size;
+ int signature;
+} RenderArenaDebugHeader;
+
+#endif
+
+RenderArena::RenderArena(unsigned arenaSize)
+{
+ // Initialize the arena pool
+ INIT_ARENA_POOL(&m_pool, "RenderArena", arenaSize);
+
+ // Zero out the recyclers array
+ memset(m_recyclers, 0, sizeof(m_recyclers));
+}
+
+RenderArena::~RenderArena()
+{
+ FinishArenaPool(&m_pool);
+}
+
+void* RenderArena::allocate(size_t size)
+{
+#ifndef NDEBUG
+ // Use standard malloc so that memory debugging tools work.
+ ASSERT(this);
+ void* block = ::malloc(sizeof(RenderArenaDebugHeader) + size);
+ RenderArenaDebugHeader* header = (RenderArenaDebugHeader*)block;
+ header->arena = this;
+ header->size = size;
+ header->signature = signature;
+ return header + 1;
+#else
+ void* result = 0;
+
+ // Ensure we have correct alignment for pointers. Important for Tru64
+ size = ROUNDUP(size, sizeof(void*));
+
+ // Check recyclers first
+ if (size < gMaxRecycledSize) {
+ const int index = size >> 2;
+
+ result = m_recyclers[index];
+ if (result) {
+ // Need to move to the next object
+ void* next = *((void**)result);
+ m_recyclers[index] = next;
+ }
+ }
+
+ if (!result) {
+ // Allocate a new chunk from the arena
+ ARENA_ALLOCATE(result, &m_pool, size);
+ }
+
+ return result;
+#endif
+}
+
+void RenderArena::free(size_t size, void* ptr)
+{
+#ifndef NDEBUG
+ // Use standard free so that memory debugging tools work.
+ RenderArenaDebugHeader* header = (RenderArenaDebugHeader*)ptr - 1;
+ ASSERT(header->signature == signature);
+ ASSERT(header->size == size);
+ ASSERT(header->arena == this);
+ header->signature = signatureDead;
+ ::free(header);
+#else
+ // Ensure we have correct alignment for pointers. Important for Tru64
+ size = ROUNDUP(size, sizeof(void*));
+
+ // See if it's a size that we recycle
+ if (size < gMaxRecycledSize) {
+ const int index = size >> 2;
+ void* currentTop = m_recyclers[index];
+ m_recyclers[index] = ptr;
+ *((void**)ptr) = currentTop;
+ }
+#endif
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderArena.h b/src/3rdparty/webkit/WebCore/rendering/RenderArena.h
new file mode 100644
index 0000000..3c27d15
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderArena.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * Portions are Copyright (C) 1998 Netscape Communications Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+ */
+
+#ifndef RenderArena_h
+#define RenderArena_h
+
+#include "Arena.h"
+
+namespace WebCore {
+
+static const size_t gMaxRecycledSize = 400;
+
+class RenderArena {
+public:
+ RenderArena(unsigned arenaSize = 4096);
+ ~RenderArena();
+
+ // Memory management functions
+ void* allocate(size_t);
+ void free(size_t, void*);
+
+private:
+ // Underlying arena pool
+ ArenaPool m_pool;
+
+ // The recycler array is sparse with the indices being multiples of 4,
+ // i.e., 0, 4, 8, 12, 16, 20, ...
+ void* m_recyclers[gMaxRecycledSize >> 2];
+};
+
+} // namespace WebCore
+
+#endif // RenderArena_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp
new file mode 100644
index 0000000..2532c5b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderBR.cpp
@@ -0,0 +1,111 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2006 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
+ * 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 "RenderBR.h"
+
+#include "Document.h"
+#include "InlineTextBox.h"
+#include "VisiblePosition.h"
+
+namespace WebCore {
+
+RenderBR::RenderBR(Node* node)
+ : RenderText(node, StringImpl::create("\n"))
+ , m_lineHeight(-1)
+{
+}
+
+RenderBR::~RenderBR()
+{
+}
+
+InlineBox* RenderBR::createInlineBox(bool makePlaceholder, bool isRootLineBox, bool isOnlyRun)
+{
+ // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode
+ // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.)
+ InlineTextBox* box = static_cast<InlineTextBox*>(RenderText::createInlineBox(makePlaceholder, isRootLineBox, isOnlyRun));
+ box->setIsText(isOnlyRun || document()->inStrictMode());
+ return box;
+}
+
+int RenderBR::baselinePosition(bool firstLine, bool isRootLineBox) const
+{
+ if (firstTextBox() && !firstTextBox()->isText())
+ return 0;
+ return RenderText::baselinePosition(firstLine, isRootLineBox);
+}
+
+int RenderBR::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
+{
+ if (firstTextBox() && !firstTextBox()->isText())
+ return 0;
+
+ if (firstLine) {
+ RenderStyle* s = style(firstLine);
+ Length lh = s->lineHeight();
+ if (lh.isNegative()) {
+ if (s == style()) {
+ if (m_lineHeight == -1)
+ m_lineHeight = RenderObject::lineHeight(false);
+ return m_lineHeight;
+ }
+ return s->font().lineSpacing();
+ }
+ if (lh.isPercent())
+ return lh.calcMinValue(s->fontSize());
+ return lh.value();
+ }
+
+ if (m_lineHeight == -1)
+ m_lineHeight = RenderObject::lineHeight(false);
+ return m_lineHeight;
+}
+
+void RenderBR::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderText::styleDidChange(diff, oldStyle);
+ m_lineHeight = -1;
+}
+
+int RenderBR::caretMinOffset() const
+{
+ return 0;
+}
+
+int RenderBR::caretMaxOffset() const
+{
+ return 1;
+}
+
+unsigned RenderBR::caretMaxRenderedOffset() const
+{
+ return 1;
+}
+
+VisiblePosition RenderBR::positionForCoordinates(int /*x*/, int /*y*/)
+{
+ return VisiblePosition(element(), 0, DOWNSTREAM);
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBR.h b/src/3rdparty/webkit/WebCore/rendering/RenderBR.h
new file mode 100644
index 0000000..b65bb58
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderBR.h
@@ -0,0 +1,71 @@
+/*
+ * 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
+ * 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 RenderBR_h
+#define RenderBR_h
+
+#include "RenderText.h"
+
+/*
+ * The whole class here is a hack to get <br> working, as long as we don't have support for
+ * CSS2 :before and :after pseudo elements
+ */
+namespace WebCore {
+
+class Position;
+
+class RenderBR : public RenderText {
+public:
+ RenderBR(Node*);
+ virtual ~RenderBR();
+
+ virtual const char* renderName() const { return "RenderBR"; }
+
+ virtual IntRect selectionRect(bool) { return IntRect(); }
+
+ virtual unsigned width(unsigned /*from*/, unsigned /*len*/, const Font&, int /*xpos*/) const { return 0; }
+ virtual unsigned width(unsigned /*from*/, unsigned /*len*/, int /*xpos*/, bool /*firstLine = false*/) const { return 0; }
+
+ virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
+ virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const;
+
+ // overrides
+ virtual InlineBox* createInlineBox(bool, bool, bool isOnlyRun = false);
+
+ virtual bool isBR() const { return true; }
+
+ virtual int caretMinOffset() const;
+ virtual int caretMaxOffset() const;
+ virtual unsigned caretMaxRenderedOffset() const;
+
+ virtual VisiblePosition positionForCoordinates(int x, int y);
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+private:
+ mutable int m_lineHeight;
+};
+
+} // namespace WebCore
+
+#endif // RenderBR_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp
new file mode 100644
index 0000000..0aa58da
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp
@@ -0,0 +1,4671 @@
+/*
+ * 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.
+ *
+ * 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 "RenderBlock.h"
+
+#include "Document.h"
+#include "Element.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HitTestResult.h"
+#include "InlineTextBox.h"
+#include "RenderImage.h"
+#include "RenderMarquee.h"
+#include "RenderReplica.h"
+#include "RenderTableCell.h"
+#include "RenderTextFragment.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "SelectionController.h"
+#include <wtf/StdLibExtras.h>
+
+using namespace std;
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+// Number of pixels to allow as a fudge factor when clicking above or below a line.
+// clicking up to verticalLineClickFudgeFactor pixels above a line will correspond to the closest point on the line.
+const int verticalLineClickFudgeFactor= 3;
+
+using namespace HTMLNames;
+
+struct ColumnInfo {
+ ColumnInfo()
+ : m_desiredColumnWidth(0)
+ , m_desiredColumnCount(1)
+ { }
+ int m_desiredColumnWidth;
+ unsigned m_desiredColumnCount;
+ Vector<IntRect> m_columnRects;
+};
+
+typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
+static ColumnInfoMap* gColumnInfoMap = 0;
+
+typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
+static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
+
+typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
+static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
+
+typedef WTF::HashMap<RenderBlock*, RenderFlowSequencedSet*> ContinuationOutlineTableMap;
+
+// Our MarginInfo state used when laying out block children.
+RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom)
+{
+ // Whether or not we can collapse our own margins with our children. We don't do this
+ // if we had any border/padding (obviously), if we're the root or HTML elements, or if
+ // we're positioned, floating, a table cell.
+ m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned() &&
+ !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable();
+
+ m_canCollapseTopWithChildren = m_canCollapseWithChildren && (top == 0) && block->style()->marginTopCollapse() != MSEPARATE;
+
+ // If any height other than auto is specified in CSS, then we don't collapse our bottom
+ // margins with our children's margins. To do otherwise would be to risk odd visual
+ // effects when the children overflow out of the parent block and yet still collapse
+ // with it. We also don't collapse if we have any bottom border/padding.
+ m_canCollapseBottomWithChildren = m_canCollapseWithChildren && (bottom == 0) &&
+ (block->style()->height().isAuto() && block->style()->height().value() == 0) && block->style()->marginBottomCollapse() != MSEPARATE;
+
+ m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginTopCollapse() == MDISCARD ||
+ block->style()->marginBottomCollapse() == MDISCARD;
+
+ m_atTopOfBlock = true;
+ m_atBottomOfBlock = false;
+
+ 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;
+}
+
+// -------------------------------------------------------------------------------------------------------
+
+RenderBlock::RenderBlock(Node* node)
+ : RenderFlow(node)
+ , m_floatingObjects(0)
+ , m_positionedObjects(0)
+ , m_maxMargin(0)
+ , m_overflowHeight(0)
+ , m_overflowWidth(0)
+ , m_overflowLeft(0)
+ , m_overflowTop(0)
+{
+}
+
+RenderBlock::~RenderBlock()
+{
+ delete m_floatingObjects;
+ delete m_positionedObjects;
+ delete m_maxMargin;
+
+ if (m_hasColumns)
+ delete gColumnInfoMap->take(this);
+
+ if (gPercentHeightDescendantsMap) {
+ if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) {
+ HashSet<RenderBox*>::iterator end = descendantSet->end();
+ for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
+ HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant);
+ ASSERT(containerSet);
+ if (!containerSet)
+ continue;
+ ASSERT(containerSet->contains(this));
+ containerSet->remove(this);
+ if (containerSet->isEmpty()) {
+ gPercentHeightContainerMap->remove(*descendant);
+ delete containerSet;
+ }
+ }
+ delete descendantSet;
+ }
+ }
+}
+
+void RenderBlock::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
+{
+ setReplaced(newStyle->isDisplayReplacedType());
+ RenderFlow::styleWillChange(diff, newStyle);
+}
+
+void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderFlow::styleDidChange(diff, oldStyle);
+
+ // FIXME: We could save this call when the change only affected non-inherited properties
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isAnonymousBlock()) {
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(style());
+ newStyle->setDisplay(BLOCK);
+ child->setStyle(newStyle.release());
+ }
+ }
+
+ m_lineHeight = -1;
+
+ // Update pseudos for :before and :after now.
+ if (!isAnonymous() && canHaveChildren()) {
+ updateBeforeAfterContent(RenderStyle::BEFORE);
+ updateBeforeAfterContent(RenderStyle::AFTER);
+ }
+ updateFirstLetter();
+}
+
+void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild)
+{
+ // Make sure we don't append things after :after-generated content if we have it.
+ if (!beforeChild && isAfterContent(lastChild()))
+ beforeChild = lastChild();
+
+ bool madeBoxesNonInline = false;
+
+ // If the requested beforeChild is not one of our children, then this is because
+ // there is an anonymous container within this object that contains the beforeChild.
+ if (beforeChild && beforeChild->parent() != this) {
+ RenderObject* anonymousChild = beforeChild->parent();
+ ASSERT(anonymousChild);
+
+ while (anonymousChild->parent() != this)
+ anonymousChild = anonymousChild->parent();
+
+ ASSERT(anonymousChild->isAnonymous());
+
+ if (anonymousChild->isAnonymousBlock()) {
+ // Insert the child into the anonymous block box instead of here.
+ if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
+ beforeChild->parent()->addChild(newChild, beforeChild);
+ else
+ addChildToFlow(newChild, beforeChild->parent());
+ return;
+ }
+
+ ASSERT(anonymousChild->isTable());
+ if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP
+ || newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION
+ || newChild->isTableSection()
+ || newChild->isTableRow()
+ || newChild->isTableCell()) {
+ // Insert into the anonymous table.
+ anonymousChild->addChild(newChild, beforeChild);
+ return;
+ }
+
+ // Go on to insert before the anonymous table.
+ beforeChild = anonymousChild;
+ }
+
+ // A block has to either have all of its children inline, or all of its children as blocks.
+ // So, if our children are currently inline and a block child has to be inserted, we move all our
+ // inline children into anonymous block boxes.
+ if (m_childrenInline && !newChild->isInline() && !newChild->isFloatingOrPositioned()) {
+ // This is a block with inline content. Wrap the inline content in anonymous blocks.
+ makeChildrenNonInline(beforeChild);
+ madeBoxesNonInline = true;
+
+ if (beforeChild && beforeChild->parent() != this) {
+ beforeChild = beforeChild->parent();
+ ASSERT(beforeChild->isAnonymousBlock());
+ ASSERT(beforeChild->parent() == this);
+ }
+ } else if (!m_childrenInline && (newChild->isFloatingOrPositioned() || newChild->isInline())) {
+ // If we're inserting an inline child but all of our children are blocks, then we have to make sure
+ // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
+ // a new one is created and inserted into our list of children in the appropriate position.
+ RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
+
+ if (afterChild && afterChild->isAnonymousBlock()) {
+ afterChild->addChild(newChild);
+ return;
+ }
+
+ if (newChild->isInline()) {
+ // No suitable existing anonymous box - create a new one.
+ RenderBlock* newBox = createAnonymousBlock();
+ RenderContainer::addChild(newBox, beforeChild);
+ newBox->addChild(newChild);
+ return;
+ }
+ }
+
+ RenderContainer::addChild(newChild, beforeChild);
+ // ### care about aligned stuff
+
+ if (madeBoxesNonInline && parent() && isAnonymousBlock())
+ parent()->removeLeftoverAnonymousBlock(this);
+ // this object may be dead here
+}
+
+static void getInlineRun(RenderObject* start, RenderObject* boundary,
+ RenderObject*& inlineRunStart,
+ RenderObject*& inlineRunEnd)
+{
+ // Beginning at |start| we find the largest contiguous run of inlines that
+ // we can. We denote the run with start and end points, |inlineRunStart|
+ // and |inlineRunEnd|. Note that these two values may be the same if
+ // we encounter only one inline.
+ //
+ // We skip any non-inlines we encounter as long as we haven't found any
+ // inlines yet.
+ //
+ // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
+ // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
+ // a non-inline.
+
+ // Start by skipping as many non-inlines as we can.
+ RenderObject * curr = start;
+ bool sawInline;
+ do {
+ while (curr && !(curr->isInline() || curr->isFloatingOrPositioned()))
+ curr = curr->nextSibling();
+
+ inlineRunStart = inlineRunEnd = curr;
+
+ if (!curr)
+ return; // No more inline children to be found.
+
+ sawInline = curr->isInline();
+
+ curr = curr->nextSibling();
+ while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) {
+ inlineRunEnd = curr;
+ if (curr->isInline())
+ sawInline = true;
+ curr = curr->nextSibling();
+ }
+ } while (!sawInline);
+}
+
+void RenderBlock::deleteLineBoxTree()
+{
+ InlineFlowBox* line = m_firstLineBox;
+ InlineFlowBox* nextLine;
+ while (line) {
+ nextLine = line->nextFlowBox();
+ line->deleteLine(renderArena());
+ line = nextLine;
+ }
+ m_firstLineBox = m_lastLineBox = 0;
+}
+
+void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
+{
+ // makeChildrenNonInline takes a block whose children are *all* inline and it
+ // makes sure that inline children are coalesced under anonymous
+ // blocks. If |insertionPoint| is defined, then it represents the insertion point for
+ // the new block child that is causing us to have to wrap all the inlines. This
+ // means that we cannot coalesce inlines before |insertionPoint| with inlines following
+ // |insertionPoint|, because the new child is going to be inserted in between the inlines,
+ // splitting them.
+ ASSERT(isInlineBlockOrInlineTable() || !isInline());
+ ASSERT(!insertionPoint || insertionPoint->parent() == this);
+
+ m_childrenInline = false;
+
+ RenderObject *child = firstChild();
+ if (!child)
+ return;
+
+ deleteLineBoxTree();
+
+ while (child) {
+ RenderObject *inlineRunStart, *inlineRunEnd;
+ getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
+
+ if (!inlineRunStart)
+ break;
+
+ child = inlineRunEnd->nextSibling();
+
+ RenderBlock* box = createAnonymousBlock();
+ insertChildNode(box, inlineRunStart);
+ RenderObject* o = inlineRunStart;
+ while(o != inlineRunEnd)
+ {
+ RenderObject* no = o;
+ o = no->nextSibling();
+ box->moveChildNode(no);
+ }
+ box->moveChildNode(inlineRunEnd);
+ }
+
+#ifndef NDEBUG
+ for (RenderObject *c = firstChild(); c; c = c->nextSibling())
+ ASSERT(!c->isInline());
+#endif
+
+ repaint();
+}
+
+void RenderBlock::removeChild(RenderObject *oldChild)
+{
+ // If this child is a block, and if our previous and next siblings are
+ // both anonymous blocks with inline content, then we can go ahead and
+ // fold the inline content back together.
+ RenderObject* prev = oldChild->previousSibling();
+ RenderObject* next = oldChild->nextSibling();
+ bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() &&
+ !oldChild->continuation() &&
+ (!prev || (prev->isAnonymousBlock() && prev->childrenInline())) &&
+ (!next || (next->isAnonymousBlock() && next->childrenInline()));
+ if (canDeleteAnonymousBlocks && prev && next) {
+ // Take all the children out of the |next| block and put them in
+ // the |prev| block.
+ prev->setNeedsLayoutAndPrefWidthsRecalc();
+ RenderObject* o = next->firstChild();
+ while (o) {
+ RenderObject* no = o;
+ o = no->nextSibling();
+ prev->moveChildNode(no);
+ }
+
+ RenderBlock* nextBlock = static_cast<RenderBlock*>(next);
+ nextBlock->deleteLineBoxTree();
+
+ // Nuke the now-empty block.
+ next->destroy();
+ }
+
+ RenderFlow::removeChild(oldChild);
+
+ RenderObject* child = prev ? prev : next;
+ if (canDeleteAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) {
+ // The removal has knocked us down to containing only a single anonymous
+ // box. We can go ahead and pull the content right back up into our
+ // box.
+ setNeedsLayoutAndPrefWidthsRecalc();
+ RenderBlock* anonBlock = static_cast<RenderBlock*>(removeChildNode(child, false));
+ m_childrenInline = true;
+ RenderObject* o = anonBlock->firstChild();
+ while (o) {
+ RenderObject* no = o;
+ o = no->nextSibling();
+ moveChildNode(no);
+ }
+
+ // Delete the now-empty block's lines and nuke it.
+ anonBlock->deleteLineBoxTree();
+ anonBlock->destroy();
+ }
+}
+
+int RenderBlock::overflowHeight(bool includeInterior) const
+{
+ if (!includeInterior && hasOverflowClip()) {
+ int shadowHeight = 0;
+ for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
+ shadowHeight = max(boxShadow->y + boxShadow->blur, shadowHeight);
+ int height = m_height + shadowHeight;
+ if (hasReflection())
+ height = max(height, reflectionBox().bottom());
+ return height;
+ }
+ return m_overflowHeight;
+}
+
+int RenderBlock::overflowWidth(bool includeInterior) const
+{
+ if (!includeInterior && hasOverflowClip()) {
+ int shadowWidth = 0;
+ for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
+ shadowWidth = max(boxShadow->x + boxShadow->blur, shadowWidth);
+ int width = m_width + shadowWidth;
+ if (hasReflection())
+ width = max(width, reflectionBox().right());
+ return width;
+ }
+ return m_overflowWidth;
+}
+
+int RenderBlock::overflowLeft(bool includeInterior) const
+{
+ if (!includeInterior && hasOverflowClip()) {
+ int shadowLeft = 0;
+ for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
+ shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft);
+ 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 = 0;
+ for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
+ shadowTop = min(boxShadow->y - boxShadow->blur, shadowTop);
+ 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 = borderBox();
+ int shadowLeft = 0;
+ int shadowRight = 0;
+ int shadowTop = 0;
+ int shadowBottom = 0;
+
+ for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+ shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft);
+ shadowRight = max(boxShadow->x + boxShadow->blur, shadowRight);
+ shadowTop = min(boxShadow->y - boxShadow->blur, shadowTop);
+ shadowBottom = max(boxShadow->y + boxShadow->blur, shadowBottom);
+ }
+
+ 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 borderBox();
+ int l = overflowLeft(includeInterior);
+ int t = min(overflowTop(includeInterior), -borderTopExtra());
+ return IntRect(l, t, overflowWidth(includeInterior) - l, max(overflowHeight(includeInterior), height() + borderBottomExtra()) - t);
+}
+
+bool RenderBlock::isSelfCollapsingBlock() const
+{
+ // We are not self-collapsing if we
+ // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
+ // (b) are a table,
+ // (c) have border/padding,
+ // (d) have a min-height
+ // (e) have specified that one of our margins can't collapse using a CSS extension
+ if (m_height > 0 ||
+ isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 ||
+ style()->minHeight().isPositive() ||
+ style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE)
+ return false;
+
+ bool hasAutoHeight = style()->height().isAuto();
+ if (style()->height().isPercent() && !style()->htmlHacks()) {
+ hasAutoHeight = true;
+ for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
+ if (cb->style()->height().isFixed() || cb->isTableCell())
+ hasAutoHeight = false;
+ }
+ }
+
+ // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
+ // on whether we have content that is all self-collapsing or not.
+ if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().isZero())) {
+ // If the block has inline children, see if we generated any line boxes. If we have any
+ // line boxes, then we can't be self-collapsing, since we have content.
+ if (childrenInline())
+ return !firstLineBox();
+
+ // Whether or not we collapse is dependent on whether all our normal flow children
+ // are also self-collapsing.
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isFloatingOrPositioned())
+ continue;
+ if (!child->isSelfCollapsingBlock())
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+void RenderBlock::layout()
+{
+ // Update our first letter info now.
+ updateFirstLetter();
+
+ // Table cells call layoutBlock directly, so don't add any logic here. Put code into
+ // layoutBlock().
+ 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 = m_width;
+ m_overflowHeight = m_height;
+ m_overflowLeft = 0;
+ m_overflowTop = 0;
+ }
+}
+
+void RenderBlock::layoutBlock(bool relayoutChildren)
+{
+ ASSERT(needsLayout());
+
+ if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
+ return; // cause us to come in here. Just bail.
+
+ if (!relayoutChildren && layoutOnlyPositionedObjects())
+ return;
+
+ IntRect oldBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = m_everHadLayout && checkForRepaintDuringLayout();
+ if (checkForRepaint) {
+ oldBounds = absoluteClippedOverflowRect();
+ oldOutlineBox = absoluteOutlineBounds();
+ }
+
+ LayoutStateMaintainer statePusher(view(), this, IntSize(xPos(), yPos()), !m_hasColumns && !hasReflection());
+
+ int oldWidth = m_width;
+ int oldColumnWidth = desiredColumnWidth();
+
+ calcWidth();
+ calcColumnWidth();
+
+ m_overflowWidth = m_width;
+ m_overflowLeft = 0;
+
+ if (oldWidth != m_width || oldColumnWidth != desiredColumnWidth())
+ relayoutChildren = true;
+
+ clearFloats();
+
+ int previousHeight = m_height;
+ m_height = 0;
+ m_overflowHeight = 0;
+
+ // We use four values, maxTopPos, maxPosNeg, 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
+ // collapsing together, then you'd take the maximal positive margin from both A and B
+ // and subtract it from the maximal negative margin from both A and B to get the
+ // true collapsed margin. This algorithm is recursive, so when we finish layout()
+ // our block knows its current maximal positive/negative values.
+ //
+ // Start out by setting our margin values to our current margins. Table cells have
+ // no margins, so we don't fill in the values for table cells.
+ bool isCell = isTableCell();
+ if (!isCell) {
+ initMaxMarginValues();
+
+ m_topMarginQuirk = style()->marginTop().quirk();
+ m_bottomMarginQuirk = style()->marginBottom().quirk();
+
+ Node* node = element();
+ if (node && node->hasTagName(formTag) && static_cast<HTMLFormElement*>(node)->isMalformed()) {
+ // See if this form is malformed (i.e., unclosed). If so, don't give the form
+ // a bottom margin.
+ setMaxBottomMargins(0, 0);
+ }
+ }
+
+ // For overflow:scroll blocks, ensure we have both scrollbars in place always.
+ if (scrollsOverflow()) {
+ if (style()->overflowX() == OSCROLL)
+ m_layer->setHasHorizontalScrollbar(true);
+ if (style()->overflowY() == OSCROLL)
+ m_layer->setHasVerticalScrollbar(true);
+ }
+
+ int repaintTop = 0;
+ int repaintBottom = 0;
+ int maxFloatBottom = 0;
+ if (childrenInline())
+ layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom);
+ else
+ layoutBlockChildren(relayoutChildren, maxFloatBottom);
+
+ // Expand our intrinsic height to encompass floats.
+ int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
+ if (floatBottom() > (m_height - toAdd) && (isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() ||
+ (parent() && parent()->isFlexibleBox() || m_hasColumns)))
+ m_height = floatBottom() + toAdd;
+
+ // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as
+ // we adjust for clean column breaks.
+ int singleColumnBottom = layoutColumns();
+
+ // Calculate our new height.
+ int oldHeight = m_height;
+ calcHeight();
+ if (oldHeight != m_height) {
+ if (oldHeight > m_height && maxFloatBottom > m_height && !childrenInline()) {
+ // One of our children's floats may have become an overhanging float for us. We need to look for it.
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isBlockFlow() && !child->isFloatingOrPositioned()) {
+ RenderBlock* block = static_cast<RenderBlock*>(child);
+ if (block->floatBottom() + block->yPos() > m_height)
+ addOverhangingFloats(block, -block->xPos(), -block->yPos(), false);
+ }
+ }
+ }
+ // 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 > m_height)
+ m_overflowHeight -= toAdd;
+ if (m_overflowHeight < m_height)
+ m_overflowHeight = m_height;
+ }
+ if (previousHeight != m_height)
+ relayoutChildren = true;
+
+ // Some classes of objects (floats and fieldsets with no specified heights and table cells) expand to encompass
+ // overhanging floats.
+ if (hasOverhangingFloats() && expandsToEncloseOverhangingFloats()) {
+ m_height = floatBottom();
+ m_height += borderBottom() + paddingBottom();
+ }
+
+ if ((isCell || isInline() || isFloatingOrPositioned() || isRoot()) && !hasOverflowClip() && !hasControlClip())
+ addVisualOverflow(floatRect());
+
+ layoutPositionedObjects(relayoutChildren || isRoot());
+
+ positionListMarker();
+
+ // Always ensure our overflow width/height are at least as large as our width/height.
+ m_overflowWidth = max(m_overflowWidth, m_width);
+ m_overflowHeight = max(m_overflowHeight, m_height);
+
+ if (!hasOverflowClip()) {
+ for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+ m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur);
+ m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur);
+ m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur);
+ m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur);
+ }
+
+ if (hasReflection()) {
+ m_overflowTop = min(m_overflowTop, reflectionBox().y());
+ m_overflowHeight = max(m_overflowHeight, reflectionBox().bottom());
+ }
+ }
+
+ statePusher.pop();
+
+ // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
+ // we overflow or not.
+ if (hasOverflowClip())
+ m_layer->updateScrollInfoAfterLayout();
+
+ // Repaint with our new bounds if they are different from our old bounds.
+ bool didFullRepaint = false;
+ if (checkForRepaint)
+ didFullRepaint = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+ if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
+ IntRect repaintRect(m_overflowLeft, repaintTop, m_overflowWidth - m_overflowLeft, repaintBottom - repaintTop);
+
+ // FIXME: Deal with multiple column repainting. We have to split the repaint
+ // rect up into multiple rects if it spans columns.
+
+ repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
+
+ if (hasOverflowClip()) {
+ // Adjust repaint rect for scroll offset
+ int x = repaintRect.x();
+ int y = repaintRect.y();
+ layer()->subtractScrolledContentOffset(x, y);
+ repaintRect.setX(x);
+ repaintRect.setY(y);
+
+ // Don't allow this rect to spill out of our overflow box.
+ repaintRect.intersect(IntRect(0, 0, m_width, m_height));
+ }
+
+ // Make sure the rect is still non-empty after intersecting for overflow above
+ if (!repaintRect.isEmpty()) {
+ repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
+ if (hasReflection())
+ layer()->reflection()->repaintRectangle(repaintRect);
+ }
+ }
+ setNeedsLayout(false);
+}
+
+void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo)
+{
+ if (child->hasStaticX()) {
+ if (style()->direction() == LTR)
+ child->setStaticX(borderLeft() + paddingLeft());
+ else
+ child->setStaticX(borderRight() + paddingRight());
+ }
+
+ if (child->hasStaticY()) {
+ int y = m_height;
+ if (!marginInfo.canCollapseWithTop()) {
+ child->calcVerticalMargins();
+ int marginTop = child->marginTop();
+ int collapsedTopPos = marginInfo.posMargin();
+ int collapsedTopNeg = marginInfo.negMargin();
+ if (marginTop > 0) {
+ if (marginTop > collapsedTopPos)
+ collapsedTopPos = marginTop;
+ } else {
+ if (-marginTop > collapsedTopNeg)
+ collapsedTopNeg = -marginTop;
+ }
+ y += (collapsedTopPos - collapsedTopNeg) - marginTop;
+ }
+ child->setStaticY(y);
+ }
+}
+
+void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
+{
+ // The float should be positioned taking into account the bottom margin
+ // of the previous flow. We add that margin into the height, get the
+ // float positioned properly, and then subtract the margin out of the
+ // height again. In the case of self-collapsing blocks, we always just
+ // use the top margins, since the self-collapsing block collapsed its
+ // own bottom margin into its top margin.
+ //
+ // Note also that the previous flow may collapse its margin into the top of
+ // our block. If this is the case, then we do not add the margin in to our
+ // height when computing the position of the float. This condition can be tested
+ // for by simply calling canCollapseWithTop. See
+ // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
+ // an example of this scenario.
+ int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin();
+ m_height += marginOffset;
+ positionNewFloats();
+ m_height -= marginOffset;
+}
+
+RenderObject* RenderBlock::handleSpecialChild(RenderObject* child, const MarginInfo& marginInfo, CompactInfo& compactInfo, bool& handled)
+{
+ // Handle positioned children first.
+ RenderObject* next = handlePositionedChild(child, marginInfo, handled);
+ if (handled) return next;
+
+ // Handle floating children next.
+ next = handleFloatingChild(child, marginInfo, handled);
+ if (handled) return next;
+
+ // See if we have a compact element. If we do, then try to tuck the compact element into the margin space of the next block.
+ next = handleCompactChild(child, compactInfo, handled);
+ if (handled) return next;
+
+ // Finally, see if we have a run-in element.
+ return handleRunInChild(child, handled);
+}
+
+
+RenderObject* RenderBlock::handlePositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled)
+{
+ if (child->isPositioned()) {
+ handled = true;
+ child->containingBlock()->insertPositionedObject(child);
+ adjustPositionedBlock(child, marginInfo);
+ return child->nextSibling();
+ }
+
+ return 0;
+}
+
+RenderObject* RenderBlock::handleFloatingChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled)
+{
+ if (child->isFloating()) {
+ handled = true;
+ insertFloatingObject(child);
+ adjustFloatingBlock(marginInfo);
+ return child->nextSibling();
+ }
+
+ return 0;
+}
+
+RenderObject* RenderBlock::handleCompactChild(RenderObject* child, CompactInfo& compactInfo, bool& handled)
+{
+ // FIXME: We only deal with one compact at a time. It is unclear what should be
+ // done if multiple contiguous compacts are encountered. For now we assume that
+ // compact A followed by another compact B should simply be treated as block A.
+ if (child->isCompact() && !compactInfo.compact() && (child->childrenInline() || child->isReplaced())) {
+ // Get the next non-positioned/non-floating RenderBlock.
+ RenderObject* next = child->nextSibling();
+ RenderObject* curr = next;
+ while (curr && curr->isFloatingOrPositioned())
+ curr = curr->nextSibling();
+ if (curr && curr->isRenderBlock() && !curr->isCompact() && !curr->isRunIn()) {
+ curr->calcWidth(); // So that horizontal margins are correct.
+
+ child->setInline(true); // Need to compute the margins/width for the child as though it is an inline, so that it won't try to puff up the margins to
+ // fill the containing block width.
+ child->calcWidth();
+ int childMargins = child->marginLeft() + child->marginRight();
+ int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight();
+ if (margin >= (childMargins + child->maxPrefWidth())) {
+ // The compact will fit in the margin.
+ handled = true;
+ compactInfo.set(child, curr);
+ child->setPos(0,0); // This position will be updated to reflect the compact's
+ // desired position and the line box for the compact will
+ // pick that position up.
+
+ // Remove the child.
+ RenderObject* next = child->nextSibling();
+ removeChildNode(child);
+
+ // Now insert the child under |curr|.
+ curr->insertChildNode(child, curr->firstChild());
+ return next;
+ }
+ else
+ child->setInline(false); // We didn't fit, so we remain a block-level element.
+ }
+ }
+ return 0;
+}
+
+void RenderBlock::insertCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo)
+{
+ if (compactInfo.matches(child)) {
+ // We have a compact child to squeeze in.
+ RenderObject* compactChild = compactInfo.compact();
+ int compactXPos = borderLeft() + paddingLeft() + compactChild->marginLeft();
+ if (style()->direction() == RTL) {
+ compactChild->calcWidth(); // have to do this because of the capped maxwidth
+ compactXPos = width() - borderRight() - paddingRight() - marginRight() -
+ compactChild->width() - compactChild->marginRight();
+ }
+ compactXPos -= child->xPos(); // Put compactXPos into the child's coordinate space.
+ compactChild->setPos(compactXPos, compactChild->yPos()); // Set the x position.
+ compactInfo.clear();
+ }
+}
+
+RenderObject* RenderBlock::handleRunInChild(RenderObject* child, bool& handled)
+{
+ // 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())) {
+ // Get the next non-positioned/non-floating RenderBlock.
+ RenderObject* curr = child->nextSibling();
+ while (curr && curr->isFloatingOrPositioned())
+ curr = curr->nextSibling();
+ if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isCompact() && !curr->isRunIn())) {
+ // The block acts like an inline, so just null out its
+ // position.
+ handled = true;
+ child->setInline(true);
+ child->setPos(0,0);
+
+ // Remove the child.
+ RenderObject* next = child->nextSibling();
+ removeChildNode(child);
+
+ // Now insert the child under |curr|.
+ curr->insertChildNode(child, curr->firstChild());
+ return next;
+ }
+ }
+ return 0;
+}
+
+void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate)
+{
+ // Get our max pos and neg top margins.
+ int posTop = child->maxTopMargin(true);
+ int negTop = child->maxTopMargin(false);
+
+ // For self-collapsing blocks, collapse our bottom margins into our
+ // top to get new posTop and negTop values.
+ if (child->isSelfCollapsingBlock()) {
+ posTop = max(posTop, child->maxBottomMargin(true));
+ negTop = max(negTop, child->maxBottomMargin(false));
+ }
+
+ // See if the top margin is quirky. We only care if this child has
+ // margins that will collapse with us.
+ bool topQuirk = child->isTopMarginQuirk() || style()->marginTopCollapse() == MDISCARD;
+
+ if (marginInfo.canCollapseWithTop()) {
+ // This child is collapsing with the top of the
+ // block. If it has larger margin values, then we need to update
+ // our own maximal values.
+ if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk)
+ setMaxTopMargins(max(posTop, maxTopPosMargin()), max(negTop, maxTopNegMargin()));
+
+ // The minute any of the margins involved isn't a quirk, don't
+ // collapse it away, even if the margin is smaller (www.webreference.com
+ // has an example of this, a <dt> with 0.8em author-specified inside
+ // a <dl> inside a <td>.
+ if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) {
+ m_topMarginQuirk = false;
+ marginInfo.setDeterminedTopQuirk(true);
+ }
+
+ if (!marginInfo.determinedTopQuirk() && topQuirk && marginTop() == 0)
+ // We have no top margin and our top child has a quirky margin.
+ // We will pick up this quirky margin and pass it through.
+ // This deals with the <td><div><p> case.
+ // Don't do this for a block that split two inlines though. You do
+ // still apply margins in this case.
+ m_topMarginQuirk = true;
+ }
+
+ if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop))
+ marginInfo.setTopQuirk(topQuirk);
+
+ int ypos = m_height;
+ if (child->isSelfCollapsingBlock()) {
+ // This child has no height. We need to compute our
+ // position before we collapse the child's margins together,
+ // so that we can get an accurate position for the zero-height block.
+ int collapsedTopPos = max(marginInfo.posMargin(), child->maxTopMargin(true));
+ int collapsedTopNeg = max(marginInfo.negMargin(), child->maxTopMargin(false));
+ marginInfo.setMargin(collapsedTopPos, collapsedTopNeg);
+
+ // Now collapse the child's margins together, which means examining our
+ // bottom margin values as well.
+ marginInfo.setPosMarginIfLarger(child->maxBottomMargin(true));
+ marginInfo.setNegMarginIfLarger(child->maxBottomMargin(false));
+
+ if (!marginInfo.canCollapseWithTop())
+ // We need to make sure that the position of the self-collapsing block
+ // is correct, since it could have overflowing content
+ // that needs to be positioned correctly (e.g., a block that
+ // had a specified height of 0 but that actually had subcontent).
+ ypos = m_height + collapsedTopPos - collapsedTopNeg;
+ }
+ else {
+ if (child->style()->marginTopCollapse() == MSEPARATE) {
+ m_height += marginInfo.margin() + child->marginTop();
+ ypos = m_height;
+ }
+ else if (!marginInfo.atTopOfBlock() ||
+ (!marginInfo.canCollapseTopWithChildren()
+ && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) {
+ // We're collapsing with a previous sibling's margins and not
+ // with the top of the block.
+ m_height += max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop);
+ ypos = m_height;
+ }
+
+ marginInfo.setPosMargin(child->maxBottomMargin(true));
+ marginInfo.setNegMargin(child->maxBottomMargin(false));
+
+ if (marginInfo.margin())
+ marginInfo.setBottomQuirk(child->isBottomMarginQuirk() || style()->marginBottomCollapse() == MDISCARD);
+
+ marginInfo.setSelfCollapsingBlockClearedFloat(false);
+ }
+
+ view()->addLayoutDelta(IntSize(0, yPosEstimate - ypos));
+ child->setPos(child->xPos(), ypos);
+ if (ypos != 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->containsFloats())
+ child->markAllDescendantsWithFloatsForLayout();
+
+ // Our guess was wrong. Make the child lay itself out again.
+ child->layoutIfNeeded();
+ }
+}
+
+void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin)
+{
+ int heightIncrease = getClearDelta(child);
+ if (!heightIncrease)
+ return;
+
+ // The child needs to be lowered. Move the child so that it just clears the float.
+ view()->addLayoutDelta(IntSize(0, -heightIncrease));
+ child->setPos(child->xPos(), child->yPos() + heightIncrease);
+
+ if (child->isSelfCollapsingBlock()) {
+ // 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)));
+
+ // Adjust our height such that we are ready to be collapsed with subsequent siblings.
+ m_height = child->yPos() - 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.
+ m_height += heightIncrease;
+
+ if (marginInfo.canCollapseWithTop()) {
+ // We can no longer collapse with the top of the block since a clear
+ // occurred. The empty blocks collapse into the cleared block.
+ // FIXME: This isn't quite correct. Need clarification for what to do
+ // if the height the cleared block is offset by is smaller than the
+ // margins involved.
+ setMaxTopMargins(oldTopPosMargin, oldTopNegMargin);
+ marginInfo.setAtTopOfBlock(false);
+ }
+
+ // If our value of clear caused us to be repositioned vertically to be
+ // underneath a float, we might have to do another layout to take into account
+ // the extra space we now have available.
+ 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->containsFloats())
+ child->markAllDescendantsWithFloatsForLayout();
+ child->layoutIfNeeded();
+}
+
+int RenderBlock::estimateVerticalPosition(RenderObject* child, const MarginInfo& marginInfo)
+{
+ // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
+ // relayout if there are intruding floats.
+ int yPosEstimate = m_height;
+ if (!marginInfo.canCollapseWithTop()) {
+ int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop();
+ yPosEstimate += max(marginInfo.margin(), childMarginTop);
+ }
+ return yPosEstimate;
+}
+
+void RenderBlock::determineHorizontalPosition(RenderObject* child)
+{
+ if (style()->direction() == LTR) {
+ int xPos = borderLeft() + paddingLeft();
+
+ // Add in our left margin.
+ int chPos = xPos + child->marginLeft();
+
+ // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
+ // to shift over as necessary to dodge any floats that might get in the way.
+ if (child->avoidsFloats()) {
+ int leftOff = leftOffset(m_height);
+ if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) {
+ if (child->marginLeft() < 0)
+ leftOff += child->marginLeft();
+ chPos = max(chPos, leftOff); // Let the float sit in the child's margin if it can fit.
+ }
+ else if (leftOff != xPos) {
+ // The object is shifting right. The object might be centered, so we need to
+ // recalculate our horizontal margins. Note that the containing block content
+ // width computation will take into account the delta between |leftOff| and |xPos|
+ // so that we can just pass the content width in directly to the |calcHorizontalMargins|
+ // function.
+ static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos()));
+ chPos = leftOff + child->marginLeft();
+ }
+ }
+ view()->addLayoutDelta(IntSize(child->xPos() - chPos, 0));
+ child->setPos(chPos, child->yPos());
+ } else {
+ int xPos = m_width - borderRight() - paddingRight() - verticalScrollbarWidth();
+ int chPos = xPos - (child->width() + child->marginRight());
+ if (child->avoidsFloats()) {
+ int rightOff = rightOffset(m_height);
+ if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) {
+ if (child->marginRight() < 0)
+ rightOff -= child->marginRight();
+ chPos = min(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit.
+ } else if (rightOff != xPos) {
+ // The object is shifting left. The object might be centered, so we need to
+ // recalculate our horizontal margins. Note that the containing block content
+ // width computation will take into account the delta between |rightOff| and |xPos|
+ // so that we can just pass the content width in directly to the |calcHorizontalMargins|
+ // function.
+ static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos()));
+ chPos = rightOff - child->marginRight() - child->width();
+ }
+ }
+ view()->addLayoutDelta(IntSize(child->xPos() - chPos, 0));
+ child->setPos(chPos, child->yPos());
+ }
+}
+
+void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
+{
+ if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) {
+ // Update our max pos/neg bottom margins, since we collapsed our bottom margins
+ // with our children.
+ setMaxBottomMargins(max(maxBottomPosMargin(), marginInfo.posMargin()), max(maxBottomNegMargin(), marginInfo.negMargin()));
+
+ if (!marginInfo.bottomQuirk())
+ m_bottomMarginQuirk = false;
+
+ if (marginInfo.bottomQuirk() && marginBottom() == 0)
+ // We have no bottom margin and our last child has a quirky margin.
+ // We will pick up this quirky margin and pass it through.
+ // This deals with the <td><div><p> case.
+ m_bottomMarginQuirk = true;
+ }
+}
+
+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();
+ }
+
+ // If we can't collapse with children then go ahead and add in the bottom margin.
+ if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()
+ && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk()))
+ m_height += marginInfo.margin();
+
+ // Now add in our bottom border/padding.
+ m_height += bottom;
+
+ // Negative margins can cause our height to shrink below our minimal height (border/padding).
+ // If this happens, ensure that the computed height is increased to the minimal height.
+ m_height = max(m_height, top + bottom);
+
+ // Always make sure our overflow height is at least our height.
+ m_overflowHeight = max(m_height, m_overflowHeight);
+
+ // Update our bottom collapsed margin info.
+ setCollapsedBottomMargin(marginInfo);
+}
+
+void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom)
+{
+ if (gPercentHeightDescendantsMap) {
+ if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) {
+ HashSet<RenderBox*>::iterator end = descendants->end();
+ for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) {
+ RenderBox* box = *it;
+ while (box != this) {
+ if (box->normalChildNeedsLayout())
+ break;
+ box->setChildNeedsLayout(true, false);
+ box = box->containingBlock();
+ ASSERT(box);
+ if (!box)
+ break;
+ }
+ }
+ }
+ }
+
+ int top = borderTop() + paddingTop();
+ int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
+
+ m_height = m_overflowHeight = 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);
+ CompactInfo compactInfo;
+
+ // Fieldsets need to find their legend and position it inside the border of the object.
+ // The legend then gets skipped during normal layout.
+ RenderObject* legend = layoutLegend(relayoutChildren);
+
+ int previousFloatBottom = 0;
+ maxFloatBottom = 0;
+
+ RenderObject* child = firstChild();
+ while (child) {
+ if (legend == child) {
+ child = child->nextSibling();
+ 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.
+ if (relayoutChildren || ((child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent()) && !isRenderView()))
+ child->setChildNeedsLayout(true, false);
+
+ // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
+ if (relayoutChildren && (child->style()->paddingLeft().isPercent() || child->style()->paddingRight().isPercent()))
+ child->setPrefWidthsDirty(true, false);
+
+ // Handle the four types of special elements first. These include positioned content, floating content, compacts and
+ // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
+ bool handled = false;
+ RenderObject* next = handleSpecialChild(child, marginInfo, compactInfo, handled);
+ if (handled) {
+ child = next;
+ continue;
+ }
+
+ // The child is a normal flow object. Compute its vertical margins now.
+ child->calcVerticalMargins();
+
+ // 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->xPos(), child->yPos() , child->width(), child->height());
+
+ // Go ahead and position the child as though it didn't collapse with the top.
+ view()->addLayoutDelta(IntSize(0, child->yPos() - yPosEstimate));
+ child->setPos(child->xPos(), yPosEstimate);
+
+ bool markDescendantsWithFloats = false;
+ if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && 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 > m_height || fb > yPosEstimate)
+ markDescendantsWithFloats = true;
+ }
+
+ if (markDescendantsWithFloats)
+ child->markAllDescendantsWithFloatsForLayout();
+
+ if (child->isRenderBlock())
+ previousFloatBottom = max(previousFloatBottom, oldRect.y() + static_cast<RenderBlock*>(child)->floatBottom());
+
+ 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.
+ collapseMargins(child, marginInfo, yPosEstimate);
+
+ // Now check for clear.
+ clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin);
+
+ // 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);
+
+ // Update our height now that the child has been placed in the correct position.
+ m_height += child->height();
+ if (child->style()->marginBottomCollapse() == MSEPARATE) {
+ m_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.
+ maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(static_cast<RenderBlock *>(child), -child->xPos(), -child->yPos(), !childNeededLayout));
+
+ // Update our overflow in case the child spills out the block.
+ m_overflowTop = min(m_overflowTop, child->yPos() + child->overflowTop(false));
+ m_overflowHeight = max(m_overflowHeight, m_height + child->overflowHeight(false) - child->height());
+ m_overflowWidth = max(child->xPos() + child->overflowWidth(false), m_overflowWidth);
+ m_overflowLeft = min(child->xPos() + child->overflowLeft(false), m_overflowLeft);
+
+ // Insert our compact into the block margin if we have one.
+ insertCompactIfNeeded(child, compactInfo);
+
+ IntSize childOffset(child->xPos() - oldRect.x(), child->yPos() - oldRect.y());
+ if (childOffset.width() || childOffset.height()) {
+ view()->addLayoutDelta(childOffset);
+
+ // 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);
+ }
+
+ if (!childHadLayout && child->checkForRepaintDuringLayout())
+ child->repaint();
+
+ child = child->nextSibling();
+ }
+
+ // 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);
+}
+
+bool RenderBlock::layoutOnlyPositionedObjects()
+{
+ if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout())
+ return false;
+
+ LayoutStateMaintainer statePusher(view(), this, IntSize(xPos(), yPos()), !m_hasColumns);
+
+ if (needsPositionedMovementLayout()) {
+ tryLayoutDoingPositionedMovementOnly();
+ if (needsLayout())
+ return false;
+ }
+
+ // All we have to is lay out our positioned objects.
+ layoutPositionedObjects(false);
+
+ statePusher.pop();
+
+ if (hasOverflowClip())
+ m_layer->updateScrollInfoAfterLayout();
+
+ setNeedsLayout(false);
+ return true;
+}
+
+void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
+{
+ if (m_positionedObjects) {
+ RenderObject* r;
+ Iterator end = m_positionedObjects->end();
+ for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
+ r = *it;
+ // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
+ // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
+ // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
+ // positioned explicitly) this should not incur a performance penalty.
+ if (relayoutChildren || (r->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow()))
+ r->setChildNeedsLayout(true, false);
+
+ // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
+ if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent()))
+ r->setPrefWidthsDirty(true, false);
+
+ // We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width
+ // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
+ if (r->needsPositionedMovementLayoutOnly())
+ r->tryLayoutDoingPositionedMovementOnly();
+ r->layoutIfNeeded();
+ }
+ }
+}
+
+void RenderBlock::markPositionedObjectsForLayout()
+{
+ if (m_positionedObjects) {
+ RenderObject* r;
+ Iterator end = m_positionedObjects->end();
+ for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
+ r = *it;
+ r->setChildNeedsLayout(true);
+ }
+ }
+}
+
+void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
+{
+ // Repaint any overhanging floats (if we know we're the one to paint them).
+ if (hasOverhangingFloats()) {
+ // We think that we must be in a bad state if m_floatingObjects is nil at this point, so
+ // we assert on Debug builds and nil-check Release builds.
+ ASSERT(m_floatingObjects);
+ if (!m_floatingObjects)
+ return;
+
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+
+ // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
+ // in this block. Better yet would be to push extra state for the containers of other floats.
+ view()->disableLayoutState();
+ for ( ; (r = it.current()); ++it) {
+ // Only repaint the object if it is overhanging, is not in its own layer, and
+ // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
+ // condition is replaced with being a descendant of us.
+ if (r->m_bottom > m_height && (paintAllDescendants && r->m_renderer->isDescendantOf(this) || r->m_shouldPaint) && !r->m_renderer->hasLayer()) {
+ r->m_renderer->repaint();
+ r->m_renderer->repaintOverhangingFloats();
+ }
+ }
+ view()->enableLayoutState();
+ }
+}
+
+void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ tx += m_x;
+ ty += m_y;
+
+ PaintPhase phase = paintInfo.phase;
+
+ // Check if we need to do anything at all.
+ // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
+ // paints the root's background.
+ if (!isInlineFlow() && !isRoot()) {
+ IntRect overflowBox = overflowRect(false);
+ overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
+ overflowBox.move(tx, ty);
+ if (!overflowBox.intersects(paintInfo.rect))
+ return;
+ }
+
+ bool useControlClip = phase != PaintPhaseBlockBackground && phase != PaintPhaseSelfOutline && phase != PaintPhaseMask && hasControlClip();
+
+ // Push a clip.
+ if (useControlClip) {
+ if (phase == PaintPhaseOutline)
+ paintInfo.phase = PaintPhaseChildOutlines;
+ else if (phase == PaintPhaseChildBlockBackground) {
+ paintInfo.phase = PaintPhaseBlockBackground;
+ paintObject(paintInfo, tx, ty);
+ paintInfo.phase = PaintPhaseChildBlockBackgrounds;
+ }
+ IntRect clipRect(controlClipRect(tx, ty));
+ if (clipRect.isEmpty())
+ return;
+ paintInfo.context->save();
+ paintInfo.context->clip(clipRect);
+ }
+
+ paintObject(paintInfo, tx, ty);
+
+ // Pop the clip.
+ if (useControlClip) {
+ paintInfo.context->restore();
+ if (phase == PaintPhaseOutline) {
+ paintInfo.phase = PaintPhaseSelfOutline;
+ paintObject(paintInfo, tx, ty);
+ paintInfo.phase = phase;
+ } else if (phase == PaintPhaseChildBlockBackground)
+ paintInfo.phase = phase;
+ }
+}
+
+void RenderBlock::paintColumns(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats)
+{
+ // We need to do multiple passes, breaking up our child painting into strips.
+ GraphicsContext* context = paintInfo.context;
+ int currXOffset = 0;
+ int currYOffset = 0;
+ int ruleAdd = borderLeft() + paddingLeft();
+ int ruleX = 0;
+ int colGap = columnGap();
+ const Color& ruleColor = style()->columnRuleColor();
+ bool ruleTransparent = style()->columnRuleIsTransparent();
+ EBorderStyle ruleStyle = style()->columnRuleStyle();
+ int ruleWidth = style()->columnRuleWidth();
+ bool renderRule = !paintingFloats && ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap;
+ Vector<IntRect>* colRects = columnRects();
+ unsigned colCount = colRects->size();
+ for (unsigned i = 0; i < colCount; i++) {
+ // For each rect, we clip to the rect, and then we adjust our coords.
+ IntRect colRect = colRects->at(i);
+ colRect.move(tx, ty);
+ context->save();
+
+ // Each strip pushes a clip, since column boxes are specified as being
+ // like overflow:hidden.
+ context->clip(colRect);
+
+ // Adjust tx and ty to change where we paint.
+ PaintInfo info(paintInfo);
+ info.rect.intersect(colRect);
+
+ // Adjust our x and y when painting.
+ int finalX = tx + currXOffset;
+ int finalY = ty + currYOffset;
+ if (paintingFloats)
+ paintFloats(info, finalX, finalY, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
+ else
+ paintContents(info, finalX, finalY);
+
+ // Move to the next position.
+ if (style()->direction() == LTR) {
+ ruleX += colRect.width() + colGap / 2;
+ currXOffset += colRect.width() + colGap;
+ } else {
+ ruleX -= (colRect.width() + colGap / 2);
+ currXOffset -= (colRect.width() + colGap);
+ }
+
+ currYOffset -= colRect.height();
+
+ context->restore();
+
+ // Now paint the column rule.
+ if (renderRule && paintInfo.phase == PaintPhaseForeground && i < colCount - 1) {
+ int ruleStart = ruleX - ruleWidth / 2 + ruleAdd;
+ int ruleEnd = ruleStart + ruleWidth;
+ drawBorder(paintInfo.context, tx + ruleStart, ty + borderTop() + paddingTop(), tx + ruleEnd, ty + borderTop() + paddingTop() + contentHeight(),
+ style()->direction() == LTR ? BSLeft : BSRight, ruleColor, style()->color(), ruleStyle, 0, 0);
+ }
+
+ ruleX = currXOffset;
+ }
+}
+
+void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty)
+{
+ // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
+ // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
+ // will do a full repaint().
+ if (document()->didLayoutWithPendingStylesheets() && !isRenderView())
+ return;
+
+ if (childrenInline())
+ paintLines(paintInfo, tx, ty);
+ else
+ paintChildren(paintInfo, tx, ty);
+}
+
+void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
+{
+ PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
+ newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
+
+ // We don't paint our own background, but we do let the kids paint their backgrounds.
+ PaintInfo info(paintInfo);
+ info.phase = newPhase;
+ info.paintingRoot = paintingRootForChildren(paintInfo);
+ bool isPrinting = document()->printing();
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ // Check for page-break-before: always, and if it's set, break and bail.
+ if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS &&
+ inRootBlockContext() && (ty + child->yPos()) > paintInfo.rect.y() &&
+ (ty + child->yPos()) < paintInfo.rect.bottom()) {
+ view()->setBestTruncatedAt(ty + child->yPos(), this, true);
+ return;
+ }
+
+ if (!child->hasLayer() && !child->isFloating())
+ child->paint(info, tx, ty);
+
+ // Check for page-break-after: always, and if it's set, break and bail.
+ if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS &&
+ inRootBlockContext() && (ty + child->yPos() + child->height()) > paintInfo.rect.y() &&
+ (ty + child->yPos() + child->height()) < paintInfo.rect.bottom()) {
+ view()->setBestTruncatedAt(ty + child->yPos() + child->height() + max(0, child->collapsedMarginBottom()), this, true);
+ return;
+ }
+ }
+}
+
+void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type)
+{
+ SelectionController* selection = type == CursorCaret ? document()->frame()->selection() : document()->frame()->dragCaretController();
+
+ // Ask the SelectionController if the caret should be painted by this block
+ RenderObject* caretPainter = selection->caretRenderer();
+ if (caretPainter == this && selection->isContentEditable()) {
+ // Convert the painting offset into the local coordinate system of this renderer,
+ // to match the localCaretRect computed by the SelectionController
+ offsetForContents(tx, ty);
+
+ if (type == CursorCaret)
+ document()->frame()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect);
+ else
+ document()->frame()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect);
+ }
+}
+
+void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty)
+{
+ PaintPhase paintPhase = paintInfo.phase;
+
+ // If we're a repositioned run-in or a compact, don't paint background/borders.
+ bool inlineFlow = isInlineFlow();
+
+ // 1. paint background, borders etc
+ if (!inlineFlow &&
+ (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) &&
+ hasBoxDecorations() && style()->visibility() == VISIBLE) {
+ paintBoxDecorations(paintInfo, tx, ty);
+ }
+
+ if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
+ paintMask(paintInfo, tx, ty);
+ return;
+ }
+
+ // We're done. We don't bother painting any children.
+ if (paintPhase == PaintPhaseBlockBackground)
+ return;
+
+ // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).s
+ int scrolledX = tx;
+ int scrolledY = ty;
+ if (hasOverflowClip())
+ m_layer->subtractScrolledContentOffset(scrolledX, scrolledY);
+
+ // 2. paint contents
+ if (paintPhase != PaintPhaseSelfOutline) {
+ if (m_hasColumns)
+ paintColumns(paintInfo, scrolledX, scrolledY);
+ else
+ paintContents(paintInfo, scrolledX, scrolledY);
+ }
+
+ // 3. paint selection
+ // FIXME: Make this work with multi column layouts. For now don't fill gaps.
+ bool isPrinting = document()->printing();
+ if (!inlineFlow && !isPrinting && !m_hasColumns)
+ paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
+
+ // 4. paint floats.
+ if (!inlineFlow && (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip)) {
+ if (m_hasColumns)
+ paintColumns(paintInfo, scrolledX, scrolledY, true);
+ else
+ paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
+ }
+
+ // 5. paint outline.
+ if (!inlineFlow && (paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
+ RenderObject::paintOutline(paintInfo.context, tx, ty, width(), height(), style());
+
+ // 6. paint continuation outlines.
+ if (!inlineFlow && (paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
+ if (continuation() && continuation()->hasOutline() && continuation()->style()->visibility() == VISIBLE) {
+ RenderFlow* inlineFlow = static_cast<RenderFlow*>(continuation()->element()->renderer());
+ if (!inlineFlow->hasLayer())
+ containingBlock()->addContinuationWithOutline(inlineFlow);
+ else if (!inlineFlow->firstLineBox())
+ inlineFlow->paintOutline(paintInfo.context, tx - xPos() + inlineFlow->containingBlock()->xPos(),
+ ty - yPos() + inlineFlow->containingBlock()->yPos());
+ }
+ paintContinuationOutlines(paintInfo, tx, ty);
+ }
+
+ // 7. paint caret.
+ // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
+ // then paint the caret.
+ if (!inlineFlow && paintPhase == PaintPhaseForeground) {
+ paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret);
+ paintCaret(paintInfo, scrolledX, scrolledY, DragCaret);
+ }
+}
+
+void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preservePhase)
+{
+ if (!m_floatingObjects)
+ return;
+
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for (; (r = it.current()); ++it) {
+ // Only paint the object if our m_shouldPaint flag is set.
+ if (r->m_shouldPaint && !r->m_renderer->hasLayer()) {
+ PaintInfo currentPaintInfo(paintInfo);
+ currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
+ int currentTX = tx + r->m_left - r->m_renderer->xPos() + r->m_renderer->marginLeft();
+ int currentTY = ty + r->m_top - r->m_renderer->yPos() + r->m_renderer->marginTop();
+ r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
+ if (!preservePhase) {
+ currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
+ r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
+ currentPaintInfo.phase = PaintPhaseFloat;
+ r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
+ currentPaintInfo.phase = PaintPhaseForeground;
+ r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
+ currentPaintInfo.phase = PaintPhaseOutline;
+ r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
+ }
+ }
+ }
+}
+
+void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (!shouldPaintWithinRoot(paintInfo) || !firstLineBox())
+ return;
+
+ if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) {
+ // We can check the first box and last box and avoid painting if we don't
+ // intersect.
+ int yPos = ty + firstLineBox()->yPos();
+ int h = lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos();
+ if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y())
+ return;
+
+ // See if our boxes intersect with the dirty rect. If so, then we paint
+ // them. 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 (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
+ yPos = ty + curr->yPos();
+ h = curr->height();
+ if (curr->ellipsisBox() && yPos < paintInfo.rect.bottom() && yPos + h > paintInfo.rect.y())
+ curr->paintEllipsisBox(paintInfo, tx, ty);
+ }
+ }
+}
+
+ContinuationOutlineTableMap* continuationOutlineTable()
+{
+ DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
+ return &table;
+}
+
+void RenderBlock::addContinuationWithOutline(RenderFlow* flow)
+{
+ // We can't make this work if the inline is in a layer. We'll just rely on the broken
+ // way of painting.
+ ASSERT(!flow->layer());
+
+ ContinuationOutlineTableMap* table = continuationOutlineTable();
+ RenderFlowSequencedSet* continuations = table->get(this);
+ if (!continuations) {
+ continuations = new RenderFlowSequencedSet;
+ table->set(this, continuations);
+ }
+
+ continuations->add(flow);
+}
+
+void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty)
+{
+ ContinuationOutlineTableMap* table = continuationOutlineTable();
+ if (table->isEmpty())
+ return;
+
+ RenderFlowSequencedSet* continuations = table->get(this);
+ if (!continuations)
+ return;
+
+ // Paint each continuation outline.
+ RenderFlowSequencedSet::iterator end = continuations->end();
+ for (RenderFlowSequencedSet::iterator it = continuations->begin(); it != end; ++it) {
+ // Need to add in the coordinates of the intervening blocks.
+ RenderFlow* flow = *it;
+ RenderBlock* block = flow->containingBlock();
+ for ( ; block && block != this; block = block->containingBlock()) {
+ tx += block->xPos();
+ ty += block->yPos();
+ }
+ ASSERT(block);
+ flow->paintOutline(info.context, tx, ty);
+ }
+
+ // Delete
+ delete continuations;
+ table->remove(this);
+}
+
+void RenderBlock::setSelectionState(SelectionState s)
+{
+ if (selectionState() == s)
+ return;
+
+ if (s == SelectionInside && selectionState() != SelectionNone)
+ return;
+
+ if ((s == SelectionStart && selectionState() == SelectionEnd) ||
+ (s == SelectionEnd && selectionState() == SelectionStart))
+ m_selectionState = SelectionBoth;
+ else
+ m_selectionState = s;
+
+ RenderBlock* cb = containingBlock();
+ if (cb && !cb->isRenderView())
+ cb->setSelectionState(s);
+}
+
+bool RenderBlock::shouldPaintSelectionGaps() const
+{
+ return m_selectionState != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
+}
+
+bool RenderBlock::isSelectionRoot() const
+{
+ if (!element())
+ return false;
+
+ // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
+ if (isTable())
+ return false;
+
+ if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() ||
+ isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() ||
+ hasReflection() || hasMask())
+ return true;
+
+ if (view() && view()->selectionStart()) {
+ Node* startElement = view()->selectionStart()->element();
+ if (startElement && startElement->rootEditableElement() == element())
+ return true;
+ }
+
+ return false;
+}
+
+GapRects RenderBlock::selectionGapRects()
+{
+ ASSERT(!needsLayout());
+
+ if (!shouldPaintSelectionGaps())
+ return GapRects();
+
+ // FIXME: this is broken with transforms
+ FloatPoint absContentPoint = localToAbsoluteForContent(FloatPoint());
+ if (hasOverflowClip())
+ absContentPoint -= layer()->scrolledContentOffset();
+
+ int lastTop = -borderTopExtra();
+ int lastLeft = leftSelectionOffset(this, lastTop);
+ int lastRight = rightSelectionOffset(this, lastTop);
+
+ return fillSelectionGaps(this, absContentPoint.x(), absContentPoint.y(), absContentPoint.x(), absContentPoint.y(), lastTop, lastLeft, lastRight);
+}
+
+void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
+ int lastTop = -borderTopExtra();
+ int lastLeft = leftSelectionOffset(this, lastTop);
+ int lastRight = rightSelectionOffset(this, lastTop);
+ paintInfo.context->save();
+ fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &paintInfo);
+ paintInfo.context->restore();
+ }
+}
+
+static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderObject*>* positionedObjects)
+{
+ if (!positionedObjects)
+ return;
+
+ ListHashSet<RenderObject*>::const_iterator end = positionedObjects->end();
+ for (ListHashSet<RenderObject*>::const_iterator it = positionedObjects->begin(); it != end; ++it) {
+ RenderObject* r = *it;
+ paintInfo->context->clipOut(IntRect(tx + r->xPos(), ty + r->yPos(), r->width(), r->height()));
+ }
+}
+
+GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
+ int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo)
+{
+ // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
+ // Clip out floating and positioned objects when painting selection gaps.
+ if (paintInfo) {
+ // Note that we don't clip out overflow for positioned objects. We just stick to the border box.
+ clipOutPositionedObjects(paintInfo, tx, ty, m_positionedObjects);
+ if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
+ for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
+ clipOutPositionedObjects(paintInfo, cb->xPos(), cb->yPos(), cb->m_positionedObjects);
+ if (m_floatingObjects) {
+ for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) {
+ FloatingObject* r = it.current();
+ paintInfo->context->clipOut(IntRect(tx + r->m_left + r->m_renderer->marginLeft(),
+ ty + r->m_top + r->m_renderer->marginTop(),
+ r->m_renderer->width(), r->m_renderer->height()));
+ }
+ }
+ }
+
+ // FIXME: overflow: auto/scroll regions need more math here, since painting in the border box is different from painting in the padding box (one is scrolled, the other is
+ // fixed).
+ GapRects result;
+ if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
+ return result;
+
+ if (m_hasColumns || hasTransform()) {
+ // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
+ lastTop = (ty - blockY) + height();
+ lastLeft = leftSelectionOffset(rootBlock, height());
+ lastRight = rightSelectionOffset(rootBlock, height());
+ return result;
+ }
+
+ if (childrenInline())
+ result = fillInlineSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo);
+ else
+ result = fillBlockSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo);
+
+ // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
+ if (rootBlock == this && (m_selectionState != SelectionBoth && m_selectionState != SelectionEnd))
+ result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height() + borderBottomExtra(),
+ rootBlock, blockX, blockY, paintInfo));
+ return result;
+}
+
+GapRects RenderBlock::fillInlineSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
+ int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo)
+{
+ GapRects result;
+
+ bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
+
+ if (!firstLineBox()) {
+ if (containsStart) {
+ // Go ahead and update our lastY to be the bottom of the block. <hr>s or empty blocks with height can trip this
+ // case.
+ lastTop = (ty - blockY) + height();
+ lastLeft = leftSelectionOffset(rootBlock, height());
+ lastRight = rightSelectionOffset(rootBlock, height());
+ }
+ return result;
+ }
+
+ RootInlineBox* lastSelectedLine = 0;
+ RootInlineBox* curr;
+ for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
+
+ // Now paint the gaps for the lines.
+ for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
+ int selTop = curr->selectionTop();
+ int selHeight = curr->selectionHeight();
+
+ if (!containsStart && !lastSelectedLine &&
+ selectionState() != SelectionStart && selectionState() != SelectionBoth)
+ result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + selTop,
+ rootBlock, blockX, blockY, paintInfo));
+
+ if (!paintInfo || ty + selTop < paintInfo->rect.bottom() && ty + selTop + selHeight > paintInfo->rect.y())
+ result.unite(curr->fillLineSelectionGap(selTop, selHeight, rootBlock, blockX, blockY, tx, ty, paintInfo));
+
+ lastSelectedLine = curr;
+ }
+
+ if (containsStart && !lastSelectedLine)
+ // Selection must start just after our last line.
+ lastSelectedLine = lastRootBox();
+
+ 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());
+ }
+ return result;
+}
+
+GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
+ int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo)
+{
+ GapRects result;
+
+ // Go ahead and jump right to the first block child that contains some selected objects.
+ RenderObject* curr;
+ for (curr = firstChild(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSibling()) { }
+
+ for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSibling()) {
+ SelectionState childState = curr->selectionState();
+ if (childState == SelectionBoth || childState == SelectionEnd)
+ sawSelectionEnd = true;
+
+ if (curr->isFloatingOrPositioned())
+ continue; // We must be a normal flow object in order to even be considered.
+
+ if (curr->isRelPositioned() && curr->hasLayer()) {
+ // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
+ // Just disregard it completely.
+ IntSize relOffset = curr->layer()->relativePositionOffset();
+ if (relOffset.width() || relOffset.height())
+ continue;
+ }
+
+ bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
+ bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
+ if (fillBlockGaps) {
+ // We need to fill the vertical gap above this object.
+ if (childState == SelectionEnd || childState == SelectionInside)
+ // Fill the gap above the object.
+ result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight,
+ ty + curr->yPos(), rootBlock, blockX, blockY, paintInfo));
+
+ // Only fill side gaps for objects that paint their own selection if we know for sure the selection is going to extend all the way *past*
+ // our object. We know this if the selection did not end inside our object.
+ if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
+ childState = SelectionNone;
+
+ // Fill side gaps on this object based off its state.
+ bool leftGap, rightGap;
+ getHorizontalSelectionGapInfo(childState, leftGap, rightGap);
+
+ if (leftGap)
+ result.uniteLeft(fillLeftSelectionGap(this, curr->xPos(), curr->yPos(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo));
+ if (rightGap)
+ result.uniteRight(fillRightSelectionGap(this, curr->xPos() + curr->width(), curr->yPos(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo));
+
+ // Update lastTop to be just underneath the object. lastLeft and lastRight extend as far as
+ // they can without bumping into floating or positioned objects. Ideally they will go right up
+ // to the border of the root selection block.
+ lastTop = (ty - blockY) + (curr->yPos() + curr->height());
+ lastLeft = leftSelectionOffset(rootBlock, curr->yPos() + curr->height());
+ lastRight = rightSelectionOffset(rootBlock, curr->yPos() + curr->height());
+ } else if (childState != SelectionNone)
+ // We must be a block that has some selected object inside it. Go ahead and recur.
+ result.unite(static_cast<RenderBlock*>(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->xPos(), ty + curr->yPos(),
+ lastTop, lastLeft, lastRight, paintInfo));
+ }
+ return result;
+}
+
+IntRect RenderBlock::fillHorizontalSelectionGap(RenderObject* selObj, int xPos, int yPos, int width, int height, const PaintInfo* paintInfo)
+{
+ if (width <= 0 || height <= 0)
+ return IntRect();
+ IntRect gapRect(xPos, yPos, width, height);
+ if (paintInfo && selObj->style()->visibility() == VISIBLE)
+ paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor());
+ return gapRect;
+}
+
+IntRect RenderBlock::fillVerticalSelectionGap(int lastTop, int lastLeft, int lastRight, int bottomY, RenderBlock* rootBlock,
+ int blockX, int blockY, const PaintInfo* paintInfo)
+{
+ int top = blockY + lastTop;
+ int height = bottomY - top;
+ if (height <= 0)
+ return IntRect();
+
+ // Get the selection offsets for the bottom of the gap
+ int left = blockX + max(lastLeft, leftSelectionOffset(rootBlock, bottomY));
+ int right = blockX + min(lastRight, rightSelectionOffset(rootBlock, bottomY));
+ int width = right - left;
+ if (width <= 0)
+ return IntRect();
+
+ IntRect gapRect(left, top, width, height);
+ if (paintInfo)
+ paintInfo->context->fillRect(gapRect, selectionBackgroundColor());
+ return gapRect;
+}
+
+IntRect RenderBlock::fillLeftSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock,
+ int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo)
+{
+ int top = yPos + ty;
+ int left = blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height));
+ int right = min(xPos + tx, blockX + min(rightSelectionOffset(rootBlock, yPos), rightSelectionOffset(rootBlock, yPos + height)));
+ int width = right - left;
+ if (width <= 0)
+ return IntRect();
+
+ IntRect gapRect(left, top, width, height);
+ if (paintInfo)
+ paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor());
+ return gapRect;
+}
+
+IntRect RenderBlock::fillRightSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock,
+ int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo)
+{
+ int left = max(xPos + tx, blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height)));
+ int top = yPos + ty;
+ int right = blockX + min(rightSelectionOffset(rootBlock, yPos), rightSelectionOffset(rootBlock, yPos + height));
+ int width = right - left;
+ if (width <= 0)
+ return IntRect();
+
+ IntRect gapRect(left, top, width, height);
+ if (paintInfo)
+ paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor());
+ return gapRect;
+}
+
+void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
+{
+ bool ltr = style()->direction() == LTR;
+ leftGap = (state == RenderObject::SelectionInside) ||
+ (state == RenderObject::SelectionEnd && ltr) ||
+ (state == RenderObject::SelectionStart && !ltr);
+ rightGap = (state == RenderObject::SelectionInside) ||
+ (state == RenderObject::SelectionStart && ltr) ||
+ (state == RenderObject::SelectionEnd && !ltr);
+}
+
+int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int y)
+{
+ int left = leftOffset(y);
+ if (left == borderLeft() + paddingLeft()) {
+ if (rootBlock != this)
+ // The border can potentially be further extended by our containingBlock().
+ return containingBlock()->leftSelectionOffset(rootBlock, y + yPos());
+ return left;
+ }
+ else {
+ RenderBlock* cb = this;
+ while (cb != rootBlock) {
+ left += cb->xPos();
+ cb = cb->containingBlock();
+ }
+ }
+
+ return left;
+}
+
+int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int y)
+{
+ int right = rightOffset(y);
+ if (right == (contentWidth() + (borderLeft() + paddingLeft()))) {
+ if (rootBlock != this)
+ // The border can potentially be further extended by our containingBlock().
+ return containingBlock()->rightSelectionOffset(rootBlock, y + yPos());
+ return right;
+ }
+ else {
+ RenderBlock* cb = this;
+ while (cb != rootBlock) {
+ right += cb->xPos();
+ cb = cb->containingBlock();
+ }
+ }
+ return right;
+}
+
+void RenderBlock::insertPositionedObject(RenderObject *o)
+{
+ // Create the list of special objects if we don't aleady have one
+ if (!m_positionedObjects)
+ m_positionedObjects = new ListHashSet<RenderObject*>;
+
+ m_positionedObjects->add(o);
+}
+
+void RenderBlock::removePositionedObject(RenderObject *o)
+{
+ if (m_positionedObjects)
+ m_positionedObjects->remove(o);
+}
+
+void RenderBlock::removePositionedObjects(RenderBlock* o)
+{
+ if (!m_positionedObjects)
+ return;
+
+ RenderObject* r;
+
+ Iterator end = m_positionedObjects->end();
+
+ Vector<RenderObject*, 16> deadObjects;
+
+ for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
+ r = *it;
+ if (!o || r->isDescendantOf(o)) {
+ if (o)
+ r->setChildNeedsLayout(true, false);
+
+ // It is parent blocks job to add positioned child to positioned objects list of its containing block
+ // Parent layout needs to be invalidated to ensure this happens.
+ RenderObject* p = r->parent();
+ while (p && !p->isRenderBlock())
+ p = p->parent();
+ if (p)
+ p->setChildNeedsLayout(true);
+
+ deadObjects.append(r);
+ }
+ }
+
+ for (unsigned i = 0; i < deadObjects.size(); i++)
+ m_positionedObjects->remove(deadObjects.at(i));
+}
+
+void RenderBlock::insertFloatingObject(RenderObject *o)
+{
+ ASSERT(o->isFloating());
+
+ // Create the list of special objects if we don't aleady have one
+ if (!m_floatingObjects) {
+ m_floatingObjects = new DeprecatedPtrList<FloatingObject>;
+ m_floatingObjects->setAutoDelete(true);
+ } else {
+ // Don't insert the object again if it's already in the list
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ FloatingObject* f;
+ while ( (f = it.current()) ) {
+ if (f->m_renderer == o) return;
+ ++it;
+ }
+ }
+
+ // Create the special object entry & append it to the list
+
+ o->layoutIfNeeded();
+
+ FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight);
+
+ newObj->m_top = -1;
+ newObj->m_bottom = -1;
+ newObj->m_width = o->width() + o->marginLeft() + o->marginRight();
+ newObj->m_shouldPaint = !o->hasLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will.
+ newObj->m_isDescendant = true;
+ newObj->m_renderer = o;
+
+ m_floatingObjects->append(newObj);
+}
+
+void RenderBlock::removeFloatingObject(RenderObject *o)
+{
+ if (m_floatingObjects) {
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ while (it.current()) {
+ if (it.current()->m_renderer == o) {
+ if (childrenInline())
+ markLinesDirtyInVerticalRange(0, it.current()->m_bottom);
+ m_floatingObjects->removeRef(it.current());
+ }
+ ++it;
+ }
+ }
+}
+
+bool RenderBlock::positionNewFloats()
+{
+ if (!m_floatingObjects)
+ return false;
+
+ FloatingObject* f = m_floatingObjects->last();
+
+ // If all floats have already been positioned, then we have no work to do.
+ if (!f || f->m_top != -1)
+ return false;
+
+ // Move backwards through our floating object list until we find a float that has
+ // already been positioned. Then we'll be able to move forward, positioning all of
+ // the new floats that need it.
+ FloatingObject* lastFloat = m_floatingObjects->getPrev();
+ while (lastFloat && lastFloat->m_top == -1) {
+ f = m_floatingObjects->prev();
+ lastFloat = m_floatingObjects->getPrev();
+ }
+
+ int y = m_height;
+
+ // The float cannot start above the y position of the last positioned float.
+ if (lastFloat)
+ y = max(lastFloat->m_top, y);
+
+ // Now walk through the set of unpositioned floats and place them.
+ while (f) {
+ // The containing block is responsible for positioning floats, so if we have floats in our
+ // list that come from somewhere else, do not attempt to position them.
+ if (f->m_renderer->containingBlock() != this) {
+ f = m_floatingObjects->next();
+ continue;
+ }
+
+ RenderObject* o = f->m_renderer;
+ int _height = o->height() + o->marginTop() + o->marginBottom();
+
+ int ro = rightOffset(); // Constant part of right offset.
+ int lo = leftOffset(); // Constat part of left offset.
+ int fwidth = f->m_width; // The width we look for.
+ if (ro - lo < fwidth)
+ fwidth = ro - lo; // Never look for more than what will be available.
+
+ IntRect oldRect(o->xPos(), o->yPos() , o->width(), o->height());
+
+ if (o->style()->clear() & CLEFT)
+ y = max(leftBottom(), y);
+ if (o->style()->clear() & CRIGHT)
+ y = max(rightBottom(), y);
+
+ if (o->style()->floating() == FLEFT) {
+ int heightRemainingLeft = 1;
+ int heightRemainingRight = 1;
+ int fx = leftRelOffset(y,lo, false, &heightRemainingLeft);
+ while (rightRelOffset(y,ro, false, &heightRemainingRight)-fx < fwidth) {
+ y += min(heightRemainingLeft, heightRemainingRight);
+ fx = leftRelOffset(y,lo, false, &heightRemainingLeft);
+ }
+ fx = max(0, fx);
+ f->m_left = fx;
+ o->setPos(fx + o->marginLeft(), y + o->marginTop());
+ } else {
+ int heightRemainingLeft = 1;
+ int heightRemainingRight = 1;
+ int fx = rightRelOffset(y,ro, false, &heightRemainingRight);
+ while (fx - leftRelOffset(y,lo, false, &heightRemainingLeft) < fwidth) {
+ y += min(heightRemainingLeft, heightRemainingRight);
+ fx = rightRelOffset(y, ro, false, &heightRemainingRight);
+ }
+ f->m_left = fx - f->m_width;
+ o->setPos(fx - o->marginRight() - o->width(), y + o->marginTop());
+ }
+
+ f->m_top = y;
+ f->m_bottom = f->m_top + _height;
+
+ // If the child moved, we have to repaint it.
+ if (o->checkForRepaintDuringLayout())
+ o->repaintDuringLayoutIfMoved(oldRect);
+
+ f = m_floatingObjects->next();
+ }
+ return true;
+}
+
+void RenderBlock::newLine(EClear clear)
+{
+ positionNewFloats();
+ // set y position
+ int newY = 0;
+ switch(clear)
+ {
+ case CLEFT:
+ newY = leftBottom();
+ break;
+ case CRIGHT:
+ newY = rightBottom();
+ break;
+ case CBOTH:
+ newY = floatBottom();
+ default:
+ break;
+ }
+ if (m_height < newY)
+ m_height = newY;
+}
+
+void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
+{
+ if (!gPercentHeightDescendantsMap) {
+ gPercentHeightDescendantsMap = new PercentHeightDescendantsMap;
+ gPercentHeightContainerMap = new PercentHeightContainerMap;
+ }
+
+ HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this);
+ if (!descendantSet) {
+ descendantSet = new HashSet<RenderBox*>;
+ gPercentHeightDescendantsMap->set(this, descendantSet);
+ }
+ bool added = descendantSet->add(descendant).second;
+ if (!added) {
+ ASSERT(gPercentHeightContainerMap->get(descendant));
+ ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this));
+ return;
+ }
+
+ HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant);
+ if (!containerSet) {
+ containerSet = new HashSet<RenderBlock*>;
+ gPercentHeightContainerMap->set(descendant, containerSet);
+ }
+ ASSERT(!containerSet->contains(this));
+ containerSet->add(this);
+}
+
+void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
+{
+ if (!gPercentHeightContainerMap)
+ return;
+
+ HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant);
+ if (!containerSet)
+ return;
+
+ HashSet<RenderBlock*>::iterator end = containerSet->end();
+ for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
+ RenderBlock* container = *it;
+ HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container);
+ ASSERT(descendantSet);
+ if (!descendantSet)
+ continue;
+ ASSERT(descendantSet->contains(descendant));
+ descendantSet->remove(descendant);
+ if (descendantSet->isEmpty()) {
+ gPercentHeightDescendantsMap->remove(container);
+ delete descendantSet;
+ }
+ }
+
+ delete containerSet;
+}
+
+int
+RenderBlock::leftOffset() const
+{
+ return borderLeft()+paddingLeft();
+}
+
+int
+RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent,
+ int *heightRemaining ) const
+{
+ int left = fixedOffset;
+ if (m_floatingObjects) {
+ if ( heightRemaining ) *heightRemaining = 1;
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it )
+ {
+ if (r->m_top <= y && r->m_bottom > y &&
+ r->type() == FloatingObject::FloatLeft &&
+ r->m_left + r->m_width > left) {
+ left = r->m_left + r->m_width;
+ if ( heightRemaining ) *heightRemaining = r->m_bottom - y;
+ }
+ }
+ }
+
+ if (applyTextIndent && m_firstLine && style()->direction() == LTR) {
+ int cw = 0;
+ if (style()->textIndent().isPercent())
+ cw = containingBlock()->availableWidth();
+ left += style()->textIndent().calcMinValue(cw);
+ }
+
+ return left;
+}
+
+int
+RenderBlock::rightOffset() const
+{
+ return borderLeft() + paddingLeft() + availableWidth();
+}
+
+int
+RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent,
+ int *heightRemaining ) const
+{
+ int right = fixedOffset;
+
+ if (m_floatingObjects) {
+ if (heightRemaining) *heightRemaining = 1;
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it )
+ {
+ if (r->m_top <= y && r->m_bottom > y &&
+ r->type() == FloatingObject::FloatRight &&
+ r->m_left < right) {
+ right = r->m_left;
+ if ( heightRemaining ) *heightRemaining = r->m_bottom - y;
+ }
+ }
+ }
+
+ if (applyTextIndent && m_firstLine && style()->direction() == RTL) {
+ int cw = 0;
+ if (style()->textIndent().isPercent())
+ cw = containingBlock()->availableWidth();
+ right -= style()->textIndent().calcMinValue(cw);
+ }
+
+ return right;
+}
+
+int
+RenderBlock::lineWidth(int y) const
+{
+ int result = rightOffset(y) - leftOffset(y);
+ return (result < 0) ? 0 : result;
+}
+
+int RenderBlock::nextFloatBottomBelow(int height) const
+{
+ if (!m_floatingObjects)
+ return 0;
+
+ int bottom = INT_MAX;
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it) {
+ if (r->m_bottom > height)
+ bottom = min(r->m_bottom, bottom);
+ }
+
+ return bottom == INT_MAX ? 0 : bottom;
+}
+
+int
+RenderBlock::floatBottom() const
+{
+ if (!m_floatingObjects) return 0;
+ int bottom=0;
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it )
+ if (r->m_bottom>bottom)
+ bottom=r->m_bottom;
+ return bottom;
+}
+
+IntRect RenderBlock::floatRect() const
+{
+ IntRect result;
+ if (!m_floatingObjects || hasOverflowClip())
+ return result;
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for (; (r = it.current()); ++it) {
+ if (r->m_shouldPaint && !r->m_renderer->hasLayer()) {
+ IntRect childRect = r->m_renderer->overflowRect(false);
+ childRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop());
+ result.unite(childRect);
+ }
+ }
+
+ return result;
+}
+
+int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int bottom = RenderFlow::lowestPosition(includeOverflowInterior, includeSelf);
+ if (!includeOverflowInterior && hasOverflowClip())
+ return bottom;
+
+ int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetY() : 0;
+
+ if (includeSelf)
+ bottom = max(bottom, m_overflowHeight + relativeOffset);
+
+ if (m_positionedObjects) {
+ RenderObject* r;
+ Iterator end = m_positionedObjects->end();
+ for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
+ r = *it;
+ // Fixed positioned objects do not scroll and thus should not constitute
+ // part of the lowest position.
+ if (r->style()->position() != FixedPosition) {
+ // FIXME: Should work for overflow sections too.
+ // If a positioned object lies completely to the left of the root it will be unreachable via scrolling.
+ // Therefore we should not allow it to contribute to the lowest position.
+ if (!isRenderView() || r->xPos() + r->width() > 0 || r->xPos() + r->rightmostPosition(false) > 0) {
+ int lp = r->yPos() + r->lowestPosition(false);
+ bottom = max(bottom, lp + relativeOffset);
+ }
+ }
+ }
+ }
+
+ if (m_hasColumns) {
+ Vector<IntRect>* colRects = columnRects();
+ for (unsigned i = 0; i < colRects->size(); i++)
+ bottom = max(bottom, colRects->at(i).bottom() + relativeOffset);
+ return bottom;
+ }
+
+ if (m_floatingObjects) {
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it ) {
+ if (r->m_shouldPaint || r->m_renderer->hasLayer()) {
+ int lp = r->m_top + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false);
+ bottom = max(bottom, lp + relativeOffset);
+ }
+ }
+ }
+
+
+ if (!includeSelf && lastLineBox()) {
+ int lp = lastLineBox()->yPos() + lastLineBox()->height();
+ bottom = max(bottom, lp);
+ }
+
+ return bottom;
+}
+
+int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int right = RenderFlow::rightmostPosition(includeOverflowInterior, includeSelf);
+ if (!includeOverflowInterior && hasOverflowClip())
+ return right;
+
+ int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetX() : 0;
+
+ if (includeSelf)
+ right = max(right, m_overflowWidth + relativeOffset);
+
+ if (m_positionedObjects) {
+ RenderObject* r;
+ Iterator end = m_positionedObjects->end();
+ for (Iterator it = m_positionedObjects->begin() ; it != end; ++it) {
+ r = *it;
+ // Fixed positioned objects do not scroll and thus should not constitute
+ // part of the rightmost position.
+ if (r->style()->position() != FixedPosition) {
+ // FIXME: Should work for overflow sections too.
+ // If a positioned object lies completely above the root it will be unreachable via scrolling.
+ // Therefore we should not allow it to contribute to the rightmost position.
+ if (!isRenderView() || r->yPos() + r->height() > 0 || r->yPos() + r->lowestPosition(false) > 0) {
+ int rp = r->xPos() + r->rightmostPosition(false);
+ right = max(right, rp + relativeOffset);
+ }
+ }
+ }
+ }
+
+ if (m_hasColumns) {
+ // This only matters for LTR
+ if (style()->direction() == LTR)
+ right = max(columnRects()->last().right() + relativeOffset, right);
+ return right;
+ }
+
+ if (m_floatingObjects) {
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it ) {
+ if (r->m_shouldPaint || r->m_renderer->hasLayer()) {
+ int rp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->rightmostPosition(false);
+ right = max(right, rp + relativeOffset);
+ }
+ }
+ }
+
+ if (!includeSelf && firstLineBox()) {
+ for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) {
+ int rp = currBox->xPos() + currBox->width();
+ // If this node is a root editable element, then the rightmostPosition should account for a caret at the end.
+ // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to.
+ if (node()->isContentEditable() && node() == node()->rootEditableElement() && style()->direction() == LTR)
+ rp += 1;
+ right = max(right, rp);
+ }
+ }
+
+ return right;
+}
+
+int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int left = RenderFlow::leftmostPosition(includeOverflowInterior, includeSelf);
+ if (!includeOverflowInterior && hasOverflowClip())
+ return left;
+
+ int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetX() : 0;
+
+ if (includeSelf)
+ left = min(left, m_overflowLeft + relativeOffset);
+
+ if (m_positionedObjects) {
+ RenderObject* r;
+ Iterator end = m_positionedObjects->end();
+ for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
+ r = *it;
+ // Fixed positioned objects do not scroll and thus should not constitute
+ // part of the leftmost position.
+ if (r->style()->position() != FixedPosition) {
+ // FIXME: Should work for overflow sections too.
+ // If a positioned object lies completely above the root it will be unreachable via scrolling.
+ // Therefore we should not allow it to contribute to the leftmost position.
+ if (!isRenderView() || r->yPos() + r->height() > 0 || r->yPos() + r->lowestPosition(false) > 0) {
+ int lp = r->xPos() + r->leftmostPosition(false);
+ left = min(left, lp + relativeOffset);
+ }
+ }
+ }
+ }
+
+ if (m_hasColumns) {
+ // This only matters for RTL
+ if (style()->direction() == RTL)
+ left = min(columnRects()->last().x() + relativeOffset, left);
+ return left;
+ }
+
+ if (m_floatingObjects) {
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it ) {
+ if (r->m_shouldPaint || r->m_renderer->hasLayer()) {
+ int lp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->leftmostPosition(false);
+ left = min(left, lp + relativeOffset);
+ }
+ }
+ }
+
+ if (!includeSelf && firstLineBox()) {
+ for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox())
+ left = min(left, (int)currBox->xPos());
+ }
+
+ return left;
+}
+
+int
+RenderBlock::leftBottom()
+{
+ if (!m_floatingObjects) return 0;
+ int bottom=0;
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it )
+ if (r->m_bottom > bottom && r->type() == FloatingObject::FloatLeft)
+ bottom=r->m_bottom;
+
+ return bottom;
+}
+
+int
+RenderBlock::rightBottom()
+{
+ if (!m_floatingObjects) return 0;
+ int bottom=0;
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it )
+ if (r->m_bottom>bottom && r->type() == FloatingObject::FloatRight)
+ bottom=r->m_bottom;
+
+ return bottom;
+}
+
+void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom)
+{
+ if (top >= bottom)
+ return;
+
+ RootInlineBox* lowestDirtyLine = lastRootBox();
+ RootInlineBox* afterLowest = lowestDirtyLine;
+ while (lowestDirtyLine && lowestDirtyLine->blockHeight() >= bottom) {
+ afterLowest = lowestDirtyLine;
+ lowestDirtyLine = lowestDirtyLine->prevRootBox();
+ }
+
+ while (afterLowest && afterLowest->blockHeight() >= top) {
+ afterLowest->markDirty();
+ afterLowest = afterLowest->prevRootBox();
+ }
+}
+
+void RenderBlock::clearFloats()
+{
+ // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
+ if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrPositioned() || isTableCell()) {
+ if (m_floatingObjects)
+ m_floatingObjects->clear();
+ return;
+ }
+
+ typedef HashMap<RenderObject*, FloatingObject*> RendererToFloatInfoMap;
+ RendererToFloatInfoMap floatMap;
+
+ if (m_floatingObjects) {
+ if (childrenInline()) {
+ m_floatingObjects->first();
+ while (FloatingObject* f = m_floatingObjects->take())
+ floatMap.add(f->m_renderer, f);
+ } else
+ m_floatingObjects->clear();
+ }
+
+ // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
+ // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
+ // to avoid floats.
+ bool parentHasFloats = false;
+ RenderObject *prev = previousSibling();
+ while (prev && (!prev->isRenderBlock() || prev->avoidsFloats() || prev->isFloatingOrPositioned())) {
+ if (prev->isFloating())
+ parentHasFloats = true;
+ prev = prev->previousSibling();
+ }
+
+ // First add in floats from the parent.
+ int offset = m_y;
+ if (parentHasFloats)
+ addIntrudingFloats(static_cast<RenderBlock *>(parent()),
+ parent()->borderLeft() + parent()->paddingLeft(), offset);
+
+ int xoffset = 0;
+ if (prev)
+ offset -= prev->yPos();
+ else {
+ prev = parent();
+ xoffset += prev->borderLeft() + prev->paddingLeft();
+ }
+
+ // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
+ if (!prev->isRenderBlock()) return;
+ RenderBlock* block = static_cast<RenderBlock *>(prev);
+
+ if (block->m_floatingObjects && block->floatBottom() > offset)
+ addIntrudingFloats(block, xoffset, offset);
+
+ if (childrenInline()) {
+ int changeTop = INT_MAX;
+ int changeBottom = INT_MIN;
+ if (m_floatingObjects) {
+ for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) {
+ FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer);
+ if (oldFloatingObject) {
+ if (f->m_width != oldFloatingObject->m_width || f->m_left != oldFloatingObject->m_left) {
+ changeTop = 0;
+ changeBottom = max(changeBottom, max(f->m_bottom, oldFloatingObject->m_bottom));
+ } else if (f->m_bottom != oldFloatingObject->m_bottom) {
+ changeTop = min(changeTop, min(f->m_bottom, oldFloatingObject->m_bottom));
+ changeBottom = max(changeBottom, max(f->m_bottom, oldFloatingObject->m_bottom));
+ }
+
+ floatMap.remove(f->m_renderer);
+ delete oldFloatingObject;
+ } else {
+ changeTop = 0;
+ changeBottom = max(changeBottom, f->m_bottom);
+ }
+ }
+ }
+
+ RendererToFloatInfoMap::iterator end = floatMap.end();
+ for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) {
+ FloatingObject* floatingObject = (*it).second;
+ if (!floatingObject->m_isDescendant) {
+ changeTop = 0;
+ changeBottom = max(changeBottom, floatingObject->m_bottom);
+ }
+ }
+ deleteAllValues(floatMap);
+
+ markLinesDirtyInVerticalRange(changeTop, changeBottom);
+ }
+}
+
+int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bool makeChildPaintOtherFloats)
+{
+ // Prevent floats from being added to the canvas by the root element, e.g., <html>.
+ if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot())
+ return 0;
+
+ int lowestFloatBottom = 0;
+
+ // Floats that will remain the child's responsiblity to paint should factor into its
+ // visual overflow.
+ IntRect floatsOverflowRect;
+ DeprecatedPtrListIterator<FloatingObject> it(*child->m_floatingObjects);
+ for (FloatingObject* r; (r = it.current()); ++it) {
+ int bottom = child->yPos() + r->m_bottom;
+ lowestFloatBottom = max(lowestFloatBottom, bottom);
+
+ if (bottom > height()) {
+ // If the object is not in the list, we add it now.
+ if (!containsFloat(r->m_renderer)) {
+ FloatingObject *floatingObj = new FloatingObject(r->type());
+ floatingObj->m_top = r->m_top - yoff;
+ floatingObj->m_bottom = r->m_bottom - yoff;
+ floatingObj->m_left = r->m_left - xoff;
+ floatingObj->m_width = r->m_width;
+ floatingObj->m_renderer = r->m_renderer;
+
+ // The nearest enclosing layer always paints the float (so that zindex and stacking
+ // behaves properly). We always want to propagate the desire to paint the float as
+ // far out as we can, to the outermost block that overlaps the float, stopping only
+ // if we hit a layer boundary.
+ if (r->m_renderer->enclosingLayer() == enclosingLayer())
+ r->m_shouldPaint = false;
+ else
+ floatingObj->m_shouldPaint = false;
+
+ // We create the floating object list lazily.
+ if (!m_floatingObjects) {
+ m_floatingObjects = new DeprecatedPtrList<FloatingObject>;
+ m_floatingObjects->setAutoDelete(true);
+ }
+ m_floatingObjects->append(floatingObj);
+ }
+ } else if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasLayer() && r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingLayer() == child->enclosingLayer())
+ // The float is not overhanging from this block, so if it is a descendant of the child, the child should
+ // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
+ // layer.
+ // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
+ // it should paint.
+ r->m_shouldPaint = true;
+
+ if (r->m_shouldPaint && !r->m_renderer->hasLayer()) {
+ 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);
+ }
+ }
+ child->addVisualOverflow(floatsOverflowRect);
+ return lowestFloatBottom;
+}
+
+void RenderBlock::addIntrudingFloats(RenderBlock* prev, int xoff, int yoff)
+{
+ // If the parent or previous sibling doesn't have any floats to add, don't bother.
+ if (!prev->m_floatingObjects)
+ return;
+
+ DeprecatedPtrListIterator<FloatingObject> it(*prev->m_floatingObjects);
+ for (FloatingObject *r; (r = it.current()); ++it) {
+ if (r->m_bottom > yoff) {
+ // The object may already be in our list. Check for it up front to avoid
+ // creating duplicate entries.
+ FloatingObject* f = 0;
+ if (m_floatingObjects) {
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ while ((f = it.current())) {
+ if (f->m_renderer == r->m_renderer) break;
+ ++it;
+ }
+ }
+ if (!f) {
+ FloatingObject *floatingObj = new FloatingObject(r->type());
+ floatingObj->m_top = r->m_top - yoff;
+ floatingObj->m_bottom = r->m_bottom - yoff;
+ floatingObj->m_left = r->m_left - xoff;
+ // Applying the child's margin makes no sense in the case where the child was passed in.
+ // since his own margin was added already through the subtraction of the |xoff| variable
+ // above. |xoff| will equal -flow->marginLeft() in this case, so it's already been taken
+ // into account. Only apply this code if |child| is false, since otherwise the left margin
+ // will get applied twice.
+ if (prev != parent())
+ floatingObj->m_left += prev->marginLeft();
+ floatingObj->m_left -= marginLeft();
+ floatingObj->m_shouldPaint = false; // We are not in the direct inheritance chain for this float. We will never paint it.
+ floatingObj->m_width = r->m_width;
+ floatingObj->m_renderer = r->m_renderer;
+
+ // We create the floating object list lazily.
+ if (!m_floatingObjects) {
+ m_floatingObjects = new DeprecatedPtrList<FloatingObject>;
+ m_floatingObjects->setAutoDelete(true);
+ }
+ m_floatingObjects->append(floatingObj);
+ }
+ }
+ }
+}
+
+bool RenderBlock::avoidsFloats() const
+{
+ // Floats can't intrude into our box if we have a non-auto column count or width.
+ return RenderFlow::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth();
+}
+
+bool RenderBlock::containsFloat(RenderObject* o)
+{
+ if (m_floatingObjects) {
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ while (it.current()) {
+ if (it.current()->m_renderer == o)
+ return true;
+ ++it;
+ }
+ }
+ return false;
+}
+
+void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove)
+{
+ setChildNeedsLayout(true);
+
+ if (floatToRemove)
+ removeFloatingObject(floatToRemove);
+
+ // Iterate over our children and mark them as needed.
+ if (!childrenInline()) {
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (isBlockFlow() && !child->isFloatingOrPositioned() &&
+ ((floatToRemove ? child->containsFloat(floatToRemove) : child->containsFloats()) || child->shrinkToAvoidFloats()))
+ child->markAllDescendantsWithFloatsForLayout(floatToRemove);
+ }
+ }
+}
+
+int RenderBlock::getClearDelta(RenderObject *child)
+{
+ // There is no need to compute clearance if we have no floats.
+ if (!containsFloats())
+ return 0;
+
+ // At least one float is present. We need to perform the clearance computation.
+ bool clearSet = child->style()->clear() != CNONE;
+ int bottom = 0;
+ switch (child->style()->clear()) {
+ case CNONE:
+ break;
+ case CLEFT:
+ bottom = leftBottom();
+ break;
+ case CRIGHT:
+ bottom = rightBottom();
+ break;
+ case CBOTH:
+ bottom = floatBottom();
+ break;
+ }
+
+ // 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 - child->yPos()) : 0;
+ if (!result && child->avoidsFloats() && child->style()->width().isFixed() &&
+ child->minPrefWidth() > lineWidth(child->yPos()) && child->minPrefWidth() <= availableWidth() &&
+ document()->inStrictMode())
+ result = max(0, floatBottom() - child->yPos());
+ 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, int, int, int)
+{
+ if (!scrollsOverflow())
+ return false;
+
+ return layer()->hitTestOverflowControls(result);
+}
+
+bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
+{
+ bool inlineFlow = isInlineFlow();
+
+ int tx = _tx + m_x;
+ int ty = _ty + m_y + borderTopExtra();
+
+ if (!inlineFlow && !isRenderView()) {
+ // Check if we need to do anything at all.
+ IntRect overflowBox = overflowRect(false);
+ overflowBox.move(tx, ty);
+ if (!overflowBox.contains(_x, _y))
+ return false;
+ }
+
+ if (isPointInOverflowControl(result, _x, _y, tx, ty)) {
+ if (hitTestAction == HitTestBlockBackground) {
+ updateHitTestResult(result, IntPoint(_x - tx, _y - ty));
+ return true;
+ }
+ return false;
+ }
+
+ // If we have lightweight control clipping, then we can't have any spillout.
+ if (!hasControlClip() || controlClipRect(tx, ty).contains(_x, _y)) {
+ // Hit test descendants first.
+ int scrolledX = tx;
+ int scrolledY = ty;
+ if (hasOverflowClip())
+ m_layer->subtractScrolledContentOffset(scrolledX, scrolledY);
+
+ // Hit test contents if we don't have columns.
+ if (!m_hasColumns && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
+ return true;
+
+ // Hit test our columns if we do have them.
+ if (m_hasColumns && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
+ return true;
+
+ // Hit test floats.
+ if (hitTestAction == HitTestFloat && m_floatingObjects) {
+ if (isRenderView()) {
+ scrolledX += static_cast<RenderView*>(this)->frameView()->scrollX();
+ scrolledY += static_cast<RenderView*>(this)->frameView()->scrollY();
+ }
+
+ FloatingObject* o;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for (it.toLast(); (o = it.current()); --it) {
+ if (o->m_shouldPaint && !o->m_renderer->hasLayer()) {
+ int xoffset = scrolledX + o->m_left + o->m_renderer->marginLeft() - o->m_renderer->xPos();
+ int yoffset = scrolledY + o->m_top + o->m_renderer->marginTop() - o->m_renderer->yPos();
+ if (o->m_renderer->hitTest(request, result, IntPoint(_x, _y), xoffset, yoffset)) {
+ updateHitTestResult(result, IntPoint(_x - xoffset, _y - yoffset));
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ // Now hit test our background
+ if (!inlineFlow && (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground)) {
+ int topExtra = borderTopExtra();
+ IntRect boundsRect(tx, ty - topExtra, m_width, m_height + topExtra + borderBottomExtra());
+ if (visibleToHitTesting() && boundsRect.contains(_x, _y)) {
+ updateHitTestResult(result, IntPoint(_x - tx, _y - ty + topExtra));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
+{
+ // We need to do multiple passes, breaking up our hit testing into strips.
+ // We can always go left to right, since column contents are clipped (meaning that there
+ // can't be any overlap).
+ int currXOffset = 0;
+ int currYOffset = 0;
+ int colGap = columnGap();
+ Vector<IntRect>* colRects = columnRects();
+ for (unsigned i = 0; i < colRects->size(); i++) {
+ IntRect colRect = colRects->at(i);
+ colRect.move(tx, ty);
+
+ if (colRect.contains(x, y)) {
+ // The point is inside this column.
+ // Adjust tx and ty to change where we hit test.
+
+ int finalX = tx + currXOffset;
+ int finalY = ty + currYOffset;
+ return hitTestContents(request, result, x, y, finalX, finalY, hitTestAction);
+ }
+
+ // Move to the next position.
+ if (style()->direction() == LTR)
+ currXOffset += colRect.width() + colGap;
+ else
+ currXOffset -= (colRect.width() + colGap);
+
+ currYOffset -= colRect.height();
+ }
+
+ return false;
+}
+
+bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
+{
+ if (childrenInline() && !isTable()) {
+ // We have to hit-test our line boxes.
+ if (hitTestLines(request, result, x, y, tx, ty, hitTestAction)) {
+ updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+ } else {
+ // Hit test our children.
+ HitTestAction childHitTest = hitTestAction;
+ if (hitTestAction == HitTestChildBlockBackgrounds)
+ childHitTest = HitTestChildBlockBackground;
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
+ // FIXME: We have to skip over inline flows, since they can show up inside RenderTables at the moment (a demoted inline <form> for example). If we ever implement a
+ // table-specific hit-test method (which we should do for performance reasons anyway), then we can remove this check.
+ if (!child->hasLayer() && !child->isFloating() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) {
+ updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+Position RenderBlock::positionForBox(InlineBox *box, bool start) const
+{
+ if (!box)
+ return Position();
+
+ if (!box->object()->element())
+ return Position(element(), start ? caretMinOffset() : caretMaxOffset());
+
+ if (!box->isInlineTextBox())
+ return Position(box->object()->element(), start ? box->object()->caretMinOffset() : box->object()->caretMaxOffset());
+
+ InlineTextBox *textBox = static_cast<InlineTextBox *>(box);
+ return Position(box->object()->element(), start ? textBox->start() : textBox->start() + textBox->len());
+}
+
+Position RenderBlock::positionForRenderer(RenderObject* renderer, bool start) const
+{
+ if (!renderer)
+ return Position(element(), 0);
+
+ Node* node = renderer->element() ? renderer->element() : element();
+ if (!node)
+ return Position();
+
+ ASSERT(renderer == node->renderer());
+
+ int offset = start ? renderer->caretMinOffset() : renderer->caretMaxOffset();
+
+ // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
+ ASSERT(!node->isCharacterDataNode() || renderer->isText());
+
+ return Position(node, offset);
+}
+
+VisiblePosition RenderBlock::positionForCoordinates(int x, int y)
+{
+ if (isTable())
+ return RenderFlow::positionForCoordinates(x, y);
+
+ int top = borderTop();
+ int bottom = top + borderTopExtra() + paddingTop() + contentHeight() + paddingBottom() + borderBottomExtra();
+
+ int left = borderLeft();
+ int right = left + paddingLeft() + contentWidth() + paddingRight();
+
+ Node* n = element();
+
+ int contentsX = x;
+ int contentsY = y;
+ offsetForContents(contentsX, contentsY);
+
+ if (isReplaced()) {
+ if (y < 0 || y < height() && x < 0)
+ return VisiblePosition(n, caretMinOffset(), DOWNSTREAM);
+ if (y >= height() || y >= 0 && x >= width())
+ return VisiblePosition(n, caretMaxOffset(), DOWNSTREAM);
+ }
+
+ // If we start inside the shadow tree, we will stay inside (even if the point is above or below).
+ if (!(n && n->isShadowNode()) && !childrenInline()) {
+ // Don't return positions inside editable roots for coordinates outside those roots, except for coordinates outside
+ // a document that is entirely editable.
+ bool isEditableRoot = n && n->rootEditableElement() == n && !n->hasTagName(bodyTag) && !n->hasTagName(htmlTag);
+
+ if (y < top || (isEditableRoot && (y < bottom && x < left))) {
+ if (!isEditableRoot)
+ if (RenderObject* c = firstChild()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float or a compact, etc.
+ VisiblePosition p = c->positionForCoordinates(contentsX - c->xPos(), contentsY - c->yPos());
+ if (p.isNotNull())
+ return p;
+ }
+ if (n) {
+ if (Node* sp = n->shadowParentNode())
+ n = sp;
+ if (Node* p = n->parent())
+ return VisiblePosition(p, n->nodeIndex(), DOWNSTREAM);
+ }
+ return VisiblePosition(n, 0, DOWNSTREAM);
+ }
+
+ if (y >= bottom || (isEditableRoot && (y >= top && x >= right))) {
+ if (!isEditableRoot)
+ if (RenderObject* c = lastChild()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float or a compact, ect.
+ VisiblePosition p = c->positionForCoordinates(contentsX - c->xPos(), contentsY - c->yPos());
+ if (p.isNotNull())
+ return p;
+ }
+ if (n) {
+ if (Node* sp = n->shadowParentNode())
+ n = sp;
+ if (Node* p = n->parent())
+ return VisiblePosition(p, n->nodeIndex() + 1, DOWNSTREAM);
+ }
+ return VisiblePosition(n, 0, DOWNSTREAM);
+ }
+ }
+
+ if (childrenInline()) {
+ if (!firstRootBox())
+ return VisiblePosition(n, 0, DOWNSTREAM);
+
+ if (contentsY < firstRootBox()->topOverflow() - verticalLineClickFudgeFactor)
+ // y coordinate is above first root line box
+ return VisiblePosition(positionForBox(firstRootBox()->firstLeafChild(), true), DOWNSTREAM);
+
+ // look for the closest line box in the root box which is at the passed-in y coordinate
+ for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
+ // set the bottom based on whether there is a next root box
+ if (root->nextRootBox())
+ // FIXME: 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();
+ else
+ bottom = root->bottomOverflow() + verticalLineClickFudgeFactor;
+ // check if this root line box is located at this y coordinate
+ if (contentsY < bottom && root->firstChild()) {
+ InlineBox* closestBox = root->closestLeafChildForXPos(x);
+ if (closestBox)
+ // pass the box a y position that is inside it
+ return closestBox->object()->positionForCoordinates(contentsX, closestBox->m_y);
+ }
+ }
+
+ if (lastRootBox())
+ // y coordinate is below last root line box
+ return VisiblePosition(positionForBox(lastRootBox()->lastLeafChild(), false), DOWNSTREAM);
+
+ return VisiblePosition(n, 0, DOWNSTREAM);
+ }
+
+ // See if any child blocks exist at this y coordinate.
+ if (firstChild() && contentsY < firstChild()->yPos())
+ return VisiblePosition(n, 0, DOWNSTREAM);
+ for (RenderObject* renderer = firstChild(); renderer; renderer = renderer->nextSibling()) {
+ if (renderer->height() == 0 || renderer->style()->visibility() != VISIBLE || renderer->isFloatingOrPositioned())
+ continue;
+ RenderObject* next = renderer->nextSibling();
+ while (next && next->isFloatingOrPositioned())
+ next = next->nextSibling();
+ if (next)
+ bottom = next->yPos();
+ else
+ bottom = top + scrollHeight();
+ if (contentsY >= renderer->yPos() && contentsY < bottom)
+ return renderer->positionForCoordinates(contentsX - renderer->xPos(), contentsY - renderer->yPos());
+ }
+
+ return RenderFlow::positionForCoordinates(x, y);
+}
+
+void RenderBlock::offsetForContents(int& tx, int& ty) const
+{
+ ty -= borderTopExtra();
+
+ if (hasOverflowClip())
+ m_layer->addScrolledContentOffset(tx, ty);
+
+ if (m_hasColumns) {
+ IntPoint contentsPoint(tx, ty);
+ adjustPointToColumnContents(contentsPoint);
+ tx = contentsPoint.x();
+ ty = contentsPoint.y();
+ }
+}
+
+int RenderBlock::availableWidth() const
+{
+ // If we have multiple columns, then the available width is reduced to our column width.
+ if (m_hasColumns)
+ return desiredColumnWidth();
+ return contentWidth();
+}
+
+int RenderBlock::columnGap() const
+{
+ if (style()->hasNormalColumnGap())
+ return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
+ return static_cast<int>(style()->columnGap());
+}
+
+void RenderBlock::calcColumnWidth()
+{
+ // Calculate our column width and column count.
+ unsigned desiredColumnCount = 1;
+ int desiredColumnWidth = contentWidth();
+
+ // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
+ if (document()->printing() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth())) {
+ setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
+ return;
+ }
+
+ int availWidth = desiredColumnWidth;
+ int colGap = columnGap();
+ int colWidth = max(1, static_cast<int>(style()->columnWidth()));
+ int colCount = max(1, static_cast<int>(style()->columnCount()));
+
+ if (style()->hasAutoColumnWidth()) {
+ if ((colCount - 1) * colGap < availWidth) {
+ desiredColumnCount = colCount;
+ desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
+ } else if (colGap < availWidth) {
+ desiredColumnCount = availWidth / colGap;
+ desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
+ }
+ } else if (style()->hasAutoColumnCount()) {
+ if (colWidth < availWidth) {
+ desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
+ desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
+ }
+ } else {
+ // Both are set.
+ if (colCount * colWidth + (colCount - 1) * colGap <= availWidth) {
+ desiredColumnCount = colCount;
+ desiredColumnWidth = colWidth;
+ } else if (colWidth < availWidth) {
+ desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
+ desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
+ }
+ }
+ setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
+}
+
+void RenderBlock::setDesiredColumnCountAndWidth(int count, int width)
+{
+ if (count == 1) {
+ if (m_hasColumns) {
+ delete gColumnInfoMap->take(this);
+ m_hasColumns = false;
+ }
+ } else {
+ ColumnInfo* info;
+ if (m_hasColumns)
+ info = gColumnInfoMap->get(this);
+ else {
+ if (!gColumnInfoMap)
+ gColumnInfoMap = new ColumnInfoMap;
+ info = new ColumnInfo;
+ gColumnInfoMap->add(this, info);
+ m_hasColumns = true;
+ }
+ info->m_desiredColumnCount = count;
+ info->m_desiredColumnWidth = width;
+ }
+}
+
+int RenderBlock::desiredColumnWidth() const
+{
+ if (!m_hasColumns)
+ return contentWidth();
+ return gColumnInfoMap->get(this)->m_desiredColumnWidth;
+}
+
+unsigned RenderBlock::desiredColumnCount() const
+{
+ if (!m_hasColumns)
+ return 1;
+ return gColumnInfoMap->get(this)->m_desiredColumnCount;
+}
+
+Vector<IntRect>* RenderBlock::columnRects() const
+{
+ if (!m_hasColumns)
+ return 0;
+ return &gColumnInfoMap->get(this)->m_columnRects;
+}
+
+int RenderBlock::layoutColumns(int endOfContent)
+{
+ // Don't do anything if we have no columns
+ if (!m_hasColumns)
+ return -1;
+
+ ColumnInfo* info = gColumnInfoMap->get(this);
+ int desiredColumnWidth = info->m_desiredColumnWidth;
+ int desiredColumnCount = info->m_desiredColumnCount;
+ Vector<IntRect>* columnRects = &info->m_columnRects;
+
+ 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;
+
+ // Add in half our line-height to help with best-guess initial balancing.
+ int columnSlop = lineHeight(false) / 2;
+ int remainingSlopSpace = columnSlop * desiredColumnCount;
+
+ if (computeIntrinsicHeight)
+ colHeight += columnSlop;
+
+ int colGap = columnGap();
+
+ // Compute a collection of column rects.
+ columnRects->clear();
+
+ // Then we do a simulated "paint" into the column slices and allow the content to slightly adjust our individual column rects.
+ // FIXME: We need to take into account layers that are affected by the columns as well here so that they can have an opportunity
+ // to adjust column rects also.
+ RenderView* v = view();
+ int left = borderLeft() + paddingLeft();
+ int top = borderTop() + paddingTop();
+ int currX = style()->direction() == LTR ? borderLeft() + paddingLeft() : borderLeft() + paddingLeft() + contentWidth() - desiredColumnWidth;
+ int currY = top;
+ unsigned colCount = desiredColumnCount;
+ int maxColBottom = borderTop() + paddingTop();
+ int contentBottom = top + availableHeight;
+ 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)
+ colHeight = availableHeight;
+
+ // This represents the real column position.
+ IntRect colRect(currX, top, desiredColumnWidth, colHeight);
+
+ // For the simulated paint, we pretend like everything is in one long strip.
+ IntRect pageRect(left, currY, desiredColumnWidth, colHeight);
+ v->setPrintRect(pageRect);
+ v->setTruncatedAt(currY + colHeight);
+ GraphicsContext context((PlatformGraphicsContext*)0);
+ RenderObject::PaintInfo paintInfo(&context, pageRect, PaintPhaseForeground, false, 0, 0);
+
+ m_hasColumns = false;
+ paintObject(paintInfo, 0, 0);
+ m_hasColumns = true;
+
+ int adjustedBottom = v->bestTruncatedAt();
+ if (adjustedBottom <= currY)
+ adjustedBottom = currY + colHeight;
+
+ colRect.setHeight(adjustedBottom - currY);
+
+ // Add in the lost space to the subsequent columns.
+ // FIXME: This will create a "staircase" effect if there are enough columns, but the effect should be pretty subtle.
+ if (computeIntrinsicHeight) {
+ int lostSpace = colHeight - colRect.height();
+ if (lostSpace > remainingSlopSpace) {
+ // Redestribute the space among the remaining columns.
+ int spaceToRedistribute = lostSpace - remainingSlopSpace;
+ int remainingColumns = colCount - i + 1;
+ colHeight += spaceToRedistribute / remainingColumns;
+ }
+ remainingSlopSpace = max(0, remainingSlopSpace - lostSpace);
+ }
+
+ if (style()->direction() == LTR)
+ currX += desiredColumnWidth + colGap;
+ else
+ currX -= (desiredColumnWidth + colGap);
+
+ currY += colRect.height();
+ availableHeight -= colRect.height();
+
+ maxColBottom = max(colRect.bottom(), maxColBottom);
+
+ columnRects->append(colRect);
+
+ // Start adding in more columns as long as there's still content left.
+ if (currY < endOfContent && i == colCount - 1 && (computeIntrinsicHeight || contentHeight()))
+ colCount++;
+ }
+
+ m_overflowWidth = max(m_width, currX - colGap);
+ m_overflowLeft = min(0, currX + desiredColumnWidth + colGap);
+
+ m_overflowHeight = maxColBottom;
+ int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
+
+ if (computeIntrinsicHeight)
+ m_height = m_overflowHeight + toAdd;
+
+ v->setPrintRect(IntRect());
+ v->setTruncatedAt(0);
+
+ ASSERT(colCount == columnRects->size());
+
+ return contentBottom;
+}
+
+void RenderBlock::adjustPointToColumnContents(IntPoint& point) const
+{
+ // Just bail if we have no columns.
+ if (!m_hasColumns)
+ return;
+
+ Vector<IntRect>* colRects = columnRects();
+
+ // Determine which columns we intersect.
+ int colGap = columnGap();
+ int leftGap = colGap / 2;
+ IntPoint columnPoint(colRects->at(0).location());
+ int yOffset = 0;
+ for (unsigned i = 0; i < colRects->size(); i++) {
+ // Add in half the column gap to the left and right of the rect.
+ IntRect colRect = colRects->at(i);
+ IntRect gapAndColumnRect(colRect.x() - leftGap, colRect.y(), colRect.width() + colGap, colRect.height());
+
+ if (gapAndColumnRect.contains(point)) {
+ // We're inside the column. Translate the x and y into our column coordinate space.
+ point.move(columnPoint.x() - colRect.x(), yOffset);
+ return;
+ }
+
+ // Move to the next position.
+ yOffset += colRect.height();
+ }
+}
+
+void RenderBlock::adjustRectForColumns(IntRect& r) const
+{
+ // Just bail if we have no columns.
+ if (!m_hasColumns)
+ return;
+
+ Vector<IntRect>* colRects = columnRects();
+
+ // Begin with a result rect that is empty.
+ IntRect result;
+
+ // Determine which columns we intersect.
+ int currXOffset = 0;
+ int currYOffset = 0;
+ int colGap = columnGap();
+ for (unsigned i = 0; i < colRects->size(); i++) {
+ IntRect colRect = colRects->at(i);
+
+ IntRect repaintRect = r;
+ repaintRect.move(currXOffset, currYOffset);
+
+ repaintRect.intersect(colRect);
+
+ result.unite(repaintRect);
+
+ // Move to the next position.
+ if (style()->direction() == LTR)
+ currXOffset += colRect.width() + colGap;
+ else
+ currXOffset -= (colRect.width() + colGap);
+
+ currYOffset -= colRect.height();
+ }
+
+ r = result;
+}
+
+void RenderBlock::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ updateFirstLetter();
+
+ if (!isTableCell() && style()->width().isFixed() && style()->width().value() > 0)
+ m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
+ else {
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = 0;
+
+ if (childrenInline())
+ calcInlinePrefWidths();
+ else
+ calcBlockPrefWidths();
+
+ m_maxPrefWidth = max(m_minPrefWidth, m_maxPrefWidth);
+
+ if (!style()->autoWrap() && childrenInline()) {
+ m_minPrefWidth = m_maxPrefWidth;
+
+ // A horizontal marquee with inline children has no minimum width.
+ if (m_layer && m_layer->marquee() && m_layer->marquee()->isHorizontal())
+ m_minPrefWidth = 0;
+ }
+
+ if (isTableCell()) {
+ Length w = static_cast<const RenderTableCell*>(this)->styleOrColWidth();
+ if (w.isFixed() && w.value() > 0)
+ m_maxPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(w.value()));
+ }
+ }
+
+ if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
+ m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ }
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
+ m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ }
+
+ int toAdd = 0;
+ toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight();
+
+ m_minPrefWidth += toAdd;
+ m_maxPrefWidth += toAdd;
+
+ setPrefWidthsDirty(false);
+}
+
+struct InlineMinMaxIterator
+{
+/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
+ inline min/max width calculations. Note the following about the way it walks:
+ (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
+ (2) We do not drill into the children of floats or replaced elements, since you can't break
+ in the middle of such an element.
+ (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
+ distinct borders/margin/padding that contribute to the min/max width.
+*/
+ RenderObject* parent;
+ RenderObject* current;
+ bool endOfInline;
+
+ InlineMinMaxIterator(RenderObject* p, bool end = false)
+ :parent(p), current(p), endOfInline(end) {}
+
+ RenderObject* next();
+};
+
+RenderObject* InlineMinMaxIterator::next()
+{
+ RenderObject* result = 0;
+ bool oldEndOfInline = endOfInline;
+ endOfInline = false;
+ while (current || current == parent) {
+ if (!oldEndOfInline &&
+ (current == parent ||
+ (!current->isFloating() && !current->isReplaced() && !current->isPositioned())))
+ result = current->firstChild();
+ if (!result) {
+ // We hit the end of our inline. (It was empty, e.g., <span></span>.)
+ if (!oldEndOfInline && current->isInlineFlow()) {
+ result = current;
+ endOfInline = true;
+ break;
+ }
+
+ while (current && current != parent) {
+ result = current->nextSibling();
+ if (result) break;
+ current = current->parent();
+ if (current && current != parent && current->isInlineFlow()) {
+ result = current;
+ endOfInline = true;
+ break;
+ }
+ }
+ }
+
+ if (!result)
+ break;
+
+ if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isInlineFlow()))
+ break;
+
+ current = result;
+ result = 0;
+ }
+
+ // Update our position.
+ current = result;
+ return current;
+}
+
+static int getBPMWidth(int childValue, Length cssUnit)
+{
+ if (cssUnit.type() != Auto)
+ return (cssUnit.isFixed() ? cssUnit.value() : childValue);
+ return 0;
+}
+
+static int getBorderPaddingMargin(const RenderObject* child, bool endOfInline)
+{
+ RenderStyle* cstyle = child->style();
+ int result = 0;
+ bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline;
+ result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()),
+ (leftSide ? cstyle->marginLeft() :
+ cstyle->marginRight()));
+ result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()),
+ (leftSide ? cstyle->paddingLeft() :
+ cstyle->paddingRight()));
+ result += leftSide ? child->borderLeft() : child->borderRight();
+ return result;
+}
+
+static inline void stripTrailingSpace(int& inlineMax, int& inlineMin,
+ RenderObject* trailingSpaceChild)
+{
+ if (trailingSpaceChild && trailingSpaceChild->isText()) {
+ // Collapse away the trailing space at the end of a block.
+ RenderText* t = static_cast<RenderText*>(trailingSpaceChild);
+ const UChar space = ' ';
+ const Font& font = t->style()->font(); // FIXME: This ignores first-line.
+ int spaceWidth = font.width(TextRun(&space, 1));
+ inlineMax -= spaceWidth + font.wordSpacing();
+ if (inlineMin > inlineMax)
+ inlineMin = inlineMax;
+ }
+}
+
+void RenderBlock::calcInlinePrefWidths()
+{
+ int inlineMax = 0;
+ int inlineMin = 0;
+
+ int cw = containingBlock()->contentWidth();
+
+ // If we are at the start of a line, we want to ignore all white-space.
+ // Also strip spaces if we previously had text that ended in a trailing space.
+ bool stripFrontSpaces = true;
+ RenderObject* trailingSpaceChild = 0;
+
+ // Firefox and Opera will allow a table cell to grow to fit an image inside it under
+ // very specific cirucumstances (in order to match common WinIE renderings).
+ // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
+ bool allowImagesToBreak = !style()->htmlHacks() || !isTableCell() || !style()->width().isIntrinsicOrAuto();
+
+ bool autoWrap, oldAutoWrap;
+ autoWrap = oldAutoWrap = style()->autoWrap();
+
+ InlineMinMaxIterator childIterator(this);
+ bool addedTextIndent = false; // Only gets added in once.
+ RenderObject* prevFloat = 0;
+ RenderObject* previousLeaf = 0;
+ while (RenderObject* child = childIterator.next()) {
+ autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
+ child->style()->autoWrap();
+
+ if (!child->isBR()) {
+ // Step One: determine whether or not we need to go ahead and
+ // terminate our current line. Each discrete chunk can become
+ // the new min-width, if it is the widest chunk seen so far, and
+ // it can also become the max-width.
+
+ // Children fall into three categories:
+ // (1) An inline flow object. These objects always have a min/max of 0,
+ // and are included in the iteration solely so that their margins can
+ // be added in.
+ //
+ // (2) An inline non-text non-flow object, e.g., an inline replaced element.
+ // These objects can always be on a line by themselves, so in this situation
+ // we need to go ahead and break the current line, and then add in our own
+ // margins and min/max width on its own line, and then terminate the line.
+ //
+ // (3) A text object. Text runs can have breakable characters at the start,
+ // the middle or the end. They may also lose whitespace off the front if
+ // we're already ignoring whitespace. In order to compute accurate min-width
+ // information, we need three pieces of information.
+ // (a) the min-width of the first non-breakable run. Should be 0 if the text string
+ // starts with whitespace.
+ // (b) the min-width of the last non-breakable run. Should be 0 if the text string
+ // ends with whitespace.
+ // (c) the min/max width of the string (trimmed for whitespace).
+ //
+ // If the text string starts with whitespace, then we need to go ahead and
+ // terminate our current line (unless we're already in a whitespace stripping
+ // mode.
+ //
+ // If the text string has a breakable character in the middle, but didn't start
+ // with whitespace, then we add the width of the first non-breakable run and
+ // then end the current line. We then need to use the intermediate min/max width
+ // values (if any of them are larger than our current min/max). We then look at
+ // the width of the last non-breakable run and use that to start a new line
+ // (unless we end in whitespace).
+ RenderStyle* cstyle = child->style();
+ int childMin = 0;
+ int childMax = 0;
+
+ if (!child->isText()) {
+ // Case (1) and (2). Inline replaced and inline flow elements.
+ if (child->isInlineFlow()) {
+ // Add in padding/border/margin from the appropriate side of
+ // the element.
+ int bpm = getBorderPaddingMargin(child, childIterator.endOfInline);
+ childMin += bpm;
+ childMax += bpm;
+
+ inlineMin += childMin;
+ inlineMax += childMax;
+
+ child->setPrefWidthsDirty(false);
+ } else {
+ // Inline replaced elts add in their margins to their min/max values.
+ int margins = 0;
+ Length leftMargin = cstyle->marginLeft();
+ Length rightMargin = cstyle->marginRight();
+ if (leftMargin.isFixed())
+ margins += leftMargin.value();
+ if (rightMargin.isFixed())
+ margins += rightMargin.value();
+ childMin += margins;
+ childMax += margins;
+ }
+ }
+
+ if (!child->isRenderInline() && !child->isText()) {
+ // Case (2). Inline replaced elements and floats.
+ // Go ahead and terminate the current line as far as
+ // minwidth is concerned.
+ childMin += child->minPrefWidth();
+ childMax += child->maxPrefWidth();
+
+ bool clearPreviousFloat;
+ if (child->isFloating()) {
+ clearPreviousFloat = (prevFloat
+ && (prevFloat->style()->floating() == FLEFT && (child->style()->clear() & CLEFT)
+ || prevFloat->style()->floating() == FRIGHT && (child->style()->clear() & CRIGHT)));
+ prevFloat = child;
+ } else
+ clearPreviousFloat = false;
+
+ bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
+ if (canBreakReplacedElement && (autoWrap || oldAutoWrap) || clearPreviousFloat) {
+ m_minPrefWidth = max(inlineMin, m_minPrefWidth);
+ inlineMin = 0;
+ }
+
+ // If we're supposed to clear the previous float, then terminate maxwidth as well.
+ if (clearPreviousFloat) {
+ m_maxPrefWidth = max(inlineMax, m_maxPrefWidth);
+ inlineMax = 0;
+ }
+
+ // Add in text-indent. This is added in only once.
+ int ti = 0;
+ if (!addedTextIndent) {
+ addedTextIndent = true;
+ ti = style()->textIndent().calcMinValue(cw);
+ childMin+=ti;
+ childMax+=ti;
+ }
+
+ // Add our width to the max.
+ inlineMax += childMax;
+
+ if (!autoWrap || !canBreakReplacedElement) {
+ if (child->isFloating())
+ m_minPrefWidth = max(childMin, m_minPrefWidth);
+ else
+ inlineMin += childMin;
+ } else {
+ // Now check our line.
+ m_minPrefWidth = max(childMin, m_minPrefWidth);
+
+ // Now start a new line.
+ inlineMin = 0;
+ }
+
+ // We are no longer stripping whitespace at the start of
+ // a line.
+ if (!child->isFloating()) {
+ stripFrontSpaces = false;
+ trailingSpaceChild = 0;
+ }
+ } else if (child->isText()) {
+ // Case (3). Text.
+ RenderText* t = static_cast<RenderText *>(child);
+
+ if (t->isWordBreak()) {
+ m_minPrefWidth = max(inlineMin, m_minPrefWidth);
+ inlineMin = 0;
+ continue;
+ }
+
+ // Determine if we have a breakable character. Pass in
+ // whether or not we should ignore any spaces at the front
+ // of the string. If those are going to be stripped out,
+ // then they shouldn't be considered in the breakable char
+ // check.
+ bool hasBreakableChar, hasBreak;
+ int beginMin, endMin;
+ bool beginWS, endWS;
+ int beginMax, endMax;
+ t->trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
+ hasBreakableChar, hasBreak, beginMax, endMax,
+ childMin, childMax, stripFrontSpaces);
+
+ // This text object will not be rendered, but it may still provide a breaking opportunity.
+ if (!hasBreak && childMax == 0) {
+ if (autoWrap && (beginWS || endWS)) {
+ m_minPrefWidth = max(inlineMin, m_minPrefWidth);
+ inlineMin = 0;
+ }
+ continue;
+ }
+
+ if (stripFrontSpaces)
+ trailingSpaceChild = child;
+ else
+ trailingSpaceChild = 0;
+
+ // Add in text-indent. This is added in only once.
+ int ti = 0;
+ if (!addedTextIndent) {
+ addedTextIndent = true;
+ ti = style()->textIndent().calcMinValue(cw);
+ childMin+=ti; beginMin += ti;
+ childMax+=ti; beginMax += ti;
+ }
+
+ // If we have no breakable characters at all,
+ // then this is the easy case. We add ourselves to the current
+ // min and max and continue.
+ if (!hasBreakableChar) {
+ inlineMin += childMin;
+ } else {
+ // We have a breakable character. Now we need to know if
+ // we start and end with whitespace.
+ if (beginWS)
+ // Go ahead and end the current line.
+ m_minPrefWidth = max(inlineMin, m_minPrefWidth);
+ else {
+ inlineMin += beginMin;
+ m_minPrefWidth = max(inlineMin, m_minPrefWidth);
+ childMin -= ti;
+ }
+
+ inlineMin = childMin;
+
+ if (endWS) {
+ // We end in whitespace, which means we can go ahead
+ // and end our current line.
+ m_minPrefWidth = max(inlineMin, m_minPrefWidth);
+ inlineMin = 0;
+ } else {
+ m_minPrefWidth = max(inlineMin, m_minPrefWidth);
+ inlineMin = endMin;
+ }
+ }
+
+ if (hasBreak) {
+ inlineMax += beginMax;
+ m_maxPrefWidth = max(inlineMax, m_maxPrefWidth);
+ m_maxPrefWidth = max(childMax, m_maxPrefWidth);
+ inlineMax = endMax;
+ } else
+ inlineMax += childMax;
+ }
+ } else {
+ m_minPrefWidth = max(inlineMin, m_minPrefWidth);
+ m_maxPrefWidth = max(inlineMax, m_maxPrefWidth);
+ inlineMin = inlineMax = 0;
+ stripFrontSpaces = true;
+ trailingSpaceChild = 0;
+ }
+
+ oldAutoWrap = autoWrap;
+ if (!child->isInlineFlow())
+ previousLeaf = child;
+ }
+
+ if (style()->collapseWhiteSpace())
+ stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
+
+ m_minPrefWidth = max(inlineMin, m_minPrefWidth);
+ m_maxPrefWidth = max(inlineMax, m_maxPrefWidth);
+}
+
+// Use a very large value (in effect infinite).
+#define BLOCK_MAX_WIDTH 15000
+
+void RenderBlock::calcBlockPrefWidths()
+{
+ bool nowrap = style()->whiteSpace() == NOWRAP;
+
+ RenderObject *child = firstChild();
+ int floatLeftWidth = 0, floatRightWidth = 0;
+ while (child) {
+ // Positioned children don't affect the min/max width
+ if (child->isPositioned()) {
+ child = child->nextSibling();
+ continue;
+ }
+
+ if (child->isFloating() || child->avoidsFloats()) {
+ int floatTotalWidth = floatLeftWidth + floatRightWidth;
+ if (child->style()->clear() & CLEFT) {
+ m_maxPrefWidth = max(floatTotalWidth, m_maxPrefWidth);
+ floatLeftWidth = 0;
+ }
+ if (child->style()->clear() & CRIGHT) {
+ m_maxPrefWidth = max(floatTotalWidth, m_maxPrefWidth);
+ floatRightWidth = 0;
+ }
+ }
+
+ // A margin basically has three types: fixed, percentage, and auto (variable).
+ // Auto and percentage margins simply become 0 when computing min/max width.
+ // Fixed margins can be added in as is.
+ Length ml = child->style()->marginLeft();
+ Length mr = child->style()->marginRight();
+ int margin = 0, marginLeft = 0, marginRight = 0;
+ if (ml.isFixed())
+ marginLeft += ml.value();
+ if (mr.isFixed())
+ marginRight += mr.value();
+ margin = marginLeft + marginRight;
+
+ int w = child->minPrefWidth() + margin;
+ m_minPrefWidth = max(w, m_minPrefWidth);
+
+ // IE ignores tables for calculation of nowrap. Makes some sense.
+ if (nowrap && !child->isTable())
+ m_maxPrefWidth = max(w, m_maxPrefWidth);
+
+ w = child->maxPrefWidth() + margin;
+
+ if (!child->isFloating()) {
+ if (child->avoidsFloats()) {
+ // Determine a left and right max value based off whether or not the floats can fit in the
+ // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin
+ // is smaller than the float width.
+ int maxLeft = marginLeft > 0 ? max(floatLeftWidth, marginLeft) : floatLeftWidth + marginLeft;
+ int maxRight = marginRight > 0 ? max(floatRightWidth, marginRight) : floatRightWidth + marginRight;
+ w = child->maxPrefWidth() + maxLeft + maxRight;
+ w = max(w, floatLeftWidth + floatRightWidth);
+ }
+ else
+ m_maxPrefWidth = max(floatLeftWidth + floatRightWidth, m_maxPrefWidth);
+ floatLeftWidth = floatRightWidth = 0;
+ }
+
+ if (child->isFloating()) {
+ if (style()->floating() == FLEFT)
+ floatLeftWidth += w;
+ else
+ floatRightWidth += w;
+ } else
+ m_maxPrefWidth = max(w, m_maxPrefWidth);
+
+ // A very specific WinIE quirk.
+ // Example:
+ /*
+ <div style="position:absolute; width:100px; top:50px;">
+ <div style="position:absolute;left:0px;top:50px;height:50px;background-color:green">
+ <table style="width:100%"><tr><td></table>
+ </div>
+ </div>
+ */
+ // In the above example, the inner absolute positioned block should have a computed width
+ // of 100px because of the table.
+ // We can achieve this effect by making the maxwidth of blocks that contain tables
+ // with percentage widths be infinite (as long as they are not inside a table cell).
+ if (style()->htmlHacks() && child->style()->width().isPercent() &&
+ !isTableCell() && child->isTable() && m_maxPrefWidth < BLOCK_MAX_WIDTH) {
+ RenderBlock* cb = containingBlock();
+ while (!cb->isRenderView() && !cb->isTableCell())
+ cb = cb->containingBlock();
+ if (!cb->isTableCell())
+ m_maxPrefWidth = BLOCK_MAX_WIDTH;
+ }
+
+ child = child->nextSibling();
+ }
+
+ // Always make sure these values are non-negative.
+ m_minPrefWidth = max(0, m_minPrefWidth);
+ m_maxPrefWidth = max(0, m_maxPrefWidth);
+
+ m_maxPrefWidth = max(floatLeftWidth + floatRightWidth, m_maxPrefWidth);
+}
+
+bool RenderBlock::hasLineIfEmpty() const
+{
+ return element() && (element()->isContentEditable() && element()->rootEditableElement() == element() ||
+ element()->isShadowNode() && element()->shadowParentNode()->hasTagName(inputTag));
+}
+
+int RenderBlock::lineHeight(bool b, bool isRootLineBox) const
+{
+ // Inline blocks are replaced elements. Otherwise, just pass off to
+ // the base class. If we're being queried as though we're the root line
+ // box, then the fact that we're an inline-block is irrelevant, and we behave
+ // just like a block.
+ if (isReplaced() && !isRootLineBox)
+ return height() + marginTop() + marginBottom();
+ return RenderFlow::lineHeight(b, isRootLineBox);
+}
+
+int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const
+{
+ // Inline blocks are replaced elements. Otherwise, just pass off to
+ // the base class. If we're being queried as though we're the root line
+ // box, then the fact that we're an inline-block is irrelevant, and we behave
+ // just like a block.
+ if (isReplaced() && !isRootLineBox) {
+ // For "leaf" theme objects, let the theme decide what the baseline position is.
+ // FIXME: Might be better to have a custom CSS property instead, so that if the theme
+ // is turned off, checkboxes/radios will still have decent baselines.
+ if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance()))
+ return theme()->baselinePosition(this);
+
+ // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in
+ // the normal flow. We make an exception for marquees, since their baselines are meaningless
+ // (the content inside them moves). This matches WinIE as well, which just bottom-aligns them.
+ // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
+ // vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside
+ // of our content box.
+ int baselinePos = (m_layer && (m_layer->marquee() || m_layer->verticalScrollbar() || m_layer->scrollYOffset() != 0)) ? -1 : getBaselineOfLastLineBox();
+ if (baselinePos != -1 && baselinePos <= borderTop() + paddingTop() + contentHeight())
+ return marginTop() + baselinePos;
+ return height() + marginTop() + marginBottom();
+ }
+ return RenderFlow::baselinePosition(b, isRootLineBox);
+}
+
+int RenderBlock::getBaselineOfFirstLineBox() const
+{
+ if (!isBlockFlow())
+ return RenderFlow::getBaselineOfFirstLineBox();
+
+ if (childrenInline()) {
+ if (firstLineBox())
+ return firstLineBox()->yPos() + firstLineBox()->baseline();
+ else
+ return -1;
+ }
+ else {
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+ if (!curr->isFloatingOrPositioned()) {
+ int result = curr->getBaselineOfFirstLineBox();
+ if (result != -1)
+ return curr->yPos() + result; // Translate to our coordinate space.
+ }
+ }
+ }
+
+ return -1;
+}
+
+int RenderBlock::getBaselineOfLastLineBox() const
+{
+ if (!isBlockFlow())
+ return RenderFlow::getBaselineOfLastLineBox();
+
+ if (childrenInline()) {
+ if (!firstLineBox() && hasLineIfEmpty())
+ return RenderFlow::baselinePosition(true, true) + borderTop() + paddingTop();
+ if (lastLineBox())
+ return lastLineBox()->yPos() + lastLineBox()->baseline();
+ return -1;
+ }
+ else {
+ bool haveNormalFlowChild = false;
+ for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
+ if (!curr->isFloatingOrPositioned()) {
+ haveNormalFlowChild = true;
+ int result = curr->getBaselineOfLastLineBox();
+ if (result != -1)
+ return curr->yPos() + result; // Translate to our coordinate space.
+ }
+ }
+ if (!haveNormalFlowChild && hasLineIfEmpty())
+ return RenderFlow::baselinePosition(true, true) + borderTop() + paddingTop();
+ }
+
+ return -1;
+}
+
+bool RenderBlock::containsNonZeroBidiLevel() const
+{
+ for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
+ for (InlineBox* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
+ if (box->bidiLevel())
+ return true;
+ }
+ }
+ return false;
+}
+
+RenderBlock* RenderBlock::firstLineBlock() const
+{
+ const RenderObject* firstLineBlock = this;
+ bool hasPseudo = false;
+ while (true) {
+ hasPseudo = firstLineBlock->style()->hasPseudoStyle(RenderStyle::FIRST_LINE);
+ if (hasPseudo)
+ break;
+ RenderObject* parentBlock = firstLineBlock->parent();
+ if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() ||
+ !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow())
+ break;
+ firstLineBlock = parentBlock;
+ }
+
+ if (!hasPseudo)
+ return 0;
+
+ return (RenderBlock*)(firstLineBlock);
+}
+
+void RenderBlock::updateFirstLetter()
+{
+ if (!document()->usesFirstLetterRules())
+ return;
+ // Don't recurse
+ if (style()->styleType() == RenderStyle::FIRST_LETTER)
+ return;
+
+ // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find
+ // an efficient way to check for that situation though before implementing anything.
+ RenderObject* firstLetterBlock = this;
+ bool hasPseudoStyle = false;
+ while (true) {
+ // We only honor first-letter if the firstLetterBlock can have children in the DOM. This correctly
+ // prevents form controls from honoring first-letter.
+ hasPseudoStyle = firstLetterBlock->style()->hasPseudoStyle(RenderStyle::FIRST_LETTER)
+ && firstLetterBlock->canHaveChildren();
+ if (hasPseudoStyle)
+ break;
+ RenderObject* parentBlock = firstLetterBlock->parent();
+ if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
+ !parentBlock->isBlockFlow())
+ break;
+ firstLetterBlock = parentBlock;
+ }
+
+ if (!hasPseudoStyle)
+ return;
+
+ // Drill into inlines looking for our first text child.
+ RenderObject* currChild = firstLetterBlock->firstChild();
+ while (currChild && currChild->needsLayout() && (!currChild->isReplaced() || currChild->isFloatingOrPositioned()) && !currChild->isText()) {
+ if (currChild->isFloatingOrPositioned()) {
+ if (currChild->style()->styleType() == RenderStyle::FIRST_LETTER)
+ break;
+ currChild = currChild->nextSibling();
+ } else
+ currChild = currChild->firstChild();
+ }
+
+ // Get list markers out of the way.
+ while (currChild && currChild->isListMarker())
+ currChild = currChild->nextSibling();
+
+ if (!currChild)
+ return;
+
+ RenderObject* firstLetterContainer = currChild->parent();
+
+ // If the child already has style, then it has already been created, so we just want
+ // to update it.
+ if (currChild->style()->styleType() == RenderStyle::FIRST_LETTER) {
+ RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(RenderStyle::FIRST_LETTER,
+ firstLetterContainer->firstLineStyle());
+ currChild->setStyle(pseudo);
+ for (RenderObject* genChild = currChild->firstChild(); genChild; genChild = genChild->nextSibling()) {
+ if (genChild->isText())
+ genChild->setStyle(pseudo);
+ }
+ return;
+ }
+
+ // If the child does not already have style, we create it here.
+ if (currChild->isText() && !currChild->isBR() && currChild->parent()->style()->styleType() != RenderStyle::FIRST_LETTER) {
+ // Our layout state is not valid for the repaints we are going to trigger by
+ // adding and removing children of firstLetterContainer.
+ view()->disableLayoutState();
+
+ RenderText* textObj = static_cast<RenderText*>(currChild);
+
+ // Create our pseudo style now that we have our firstLetterContainer determined.
+ RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(RenderStyle::FIRST_LETTER,
+ firstLetterContainer->firstLineStyle());
+
+ // Force inline display (except for floating first-letters)
+ pseudoStyle->setDisplay( pseudoStyle->isFloating() ? BLOCK : INLINE);
+ pseudoStyle->setPosition( StaticPosition ); // CSS2 says first-letter can't be positioned.
+
+ RenderObject* firstLetter = RenderFlow::createAnonymousFlow(document(), pseudoStyle); // anonymous box
+ firstLetterContainer->addChild(firstLetter, currChild);
+
+ // The original string is going to be either a generated content string or a DOM node's
+ // string. We want the original string before it got transformed in case first-letter has
+ // no text-transform or a different text-transform applied to it.
+ RefPtr<StringImpl> oldText = textObj->originalText();
+ ASSERT(oldText);
+
+ if (oldText && oldText->length() > 0) {
+ unsigned int length = 0;
+
+ // account for leading spaces and punctuation
+ while (length < oldText->length() && (isSpaceOrNewline((*oldText)[length]) || Unicode::isPunct((*oldText)[length])))
+ length++;
+
+ // account for first letter
+ length++;
+
+ // construct text fragment for the text after the first letter
+ // NOTE: this might empty
+ RenderTextFragment* remainingText =
+ new (renderArena()) RenderTextFragment(textObj->node(), oldText.get(), length, oldText->length() - length);
+ remainingText->setStyle(textObj->style());
+ if (remainingText->element())
+ remainingText->element()->setRenderer(remainingText);
+
+ RenderObject* nextObj = textObj->nextSibling();
+ firstLetterContainer->removeChild(textObj);
+ firstLetterContainer->addChild(remainingText, nextObj);
+ remainingText->setFirstLetter(firstLetter);
+
+ // construct text fragment for the first letter
+ RenderTextFragment* letter =
+ new (renderArena()) RenderTextFragment(remainingText->node(), oldText.get(), 0, length);
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(pseudoStyle);
+ letter->setStyle(newStyle.release());
+ firstLetter->addChild(letter);
+
+ textObj->destroy();
+ }
+ view()->enableLayoutState();
+ }
+}
+
+bool RenderBlock::inRootBlockContext() const
+{
+ if (isTableCell() || isFloatingOrPositioned() || hasOverflowClip())
+ return false;
+
+ if (isRoot() || isRenderView())
+ return true;
+
+ return containingBlock()->inRootBlockContext();
+}
+
+// Helper methods for obtaining the last line, computing line counts and heights for line counts
+// (crawling into blocks).
+static bool shouldCheckLines(RenderObject* obj)
+{
+ return !obj->isFloatingOrPositioned() && !obj->isCompact() && !obj->isRunIn() &&
+ obj->isBlockFlow() && obj->style()->height().isAuto() &&
+ (!obj->isFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
+}
+
+static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count)
+{
+ if (block->style()->visibility() == VISIBLE) {
+ if (block->childrenInline()) {
+ for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
+ if (count++ == i)
+ return box;
+ }
+ }
+ else {
+ for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) {
+ if (shouldCheckLines(obj)) {
+ RootInlineBox *box = getLineAtIndex(static_cast<RenderBlock*>(obj), i, count);
+ if (box)
+ return box;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
+{
+ if (block->style()->visibility() == VISIBLE) {
+ if (block->childrenInline()) {
+ for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
+ if (++count == l)
+ return box->bottomOverflow() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
+ }
+ }
+ else {
+ RenderObject* normalFlowChildWithoutLines = 0;
+ for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) {
+ if (shouldCheckLines(obj)) {
+ int result = getHeightForLineCount(static_cast<RenderBlock*>(obj), l, false, count);
+ if (result != -1)
+ return result + obj->yPos() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
+ }
+ else if (!obj->isFloatingOrPositioned() && !obj->isCompact() && !obj->isRunIn())
+ normalFlowChildWithoutLines = obj;
+ }
+ if (normalFlowChildWithoutLines && l == 0)
+ return normalFlowChildWithoutLines->yPos() + normalFlowChildWithoutLines->height();
+ }
+ }
+
+ return -1;
+}
+
+RootInlineBox* RenderBlock::lineAtIndex(int i)
+{
+ int count = 0;
+ return getLineAtIndex(this, i, count);
+}
+
+int RenderBlock::lineCount()
+{
+ int count = 0;
+ if (style()->visibility() == VISIBLE) {
+ if (childrenInline())
+ for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
+ count++;
+ else
+ for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
+ if (shouldCheckLines(obj))
+ count += static_cast<RenderBlock*>(obj)->lineCount();
+ }
+ return count;
+}
+
+int RenderBlock::heightForLineCount(int l)
+{
+ int count = 0;
+ return getHeightForLineCount(this, l, true, count);
+}
+
+void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const
+{
+ // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
+ // for either overflow or translations via relative positioning.
+ if (style()->visibility() == VISIBLE) {
+ if (childrenInline()) {
+ for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
+ if (box->firstChild())
+ left = min(left, x + box->firstChild()->xPos());
+ if (box->lastChild())
+ right = max(right, x + box->lastChild()->xPos() + box->lastChild()->width());
+ }
+ }
+ else {
+ for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) {
+ if (!obj->isFloatingOrPositioned()) {
+ if (obj->isBlockFlow() && !obj->hasOverflowClip())
+ static_cast<RenderBlock*>(obj)->adjustForBorderFit(x + obj->xPos(), left, right);
+ else if (obj->style()->visibility() == VISIBLE) {
+ // We are a replaced element or some kind of non-block-flow object.
+ left = min(left, x + obj->xPos());
+ right = max(right, x + obj->xPos() + obj->width());
+ }
+ }
+ }
+ }
+
+ if (m_floatingObjects) {
+ FloatingObject* r;
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for (; (r = it.current()); ++it) {
+ // Only examine the object if our m_shouldPaint flag is set.
+ if (r->m_shouldPaint) {
+ int floatLeft = r->m_left - r->m_renderer->xPos() + r->m_renderer->marginLeft();
+ int floatRight = floatLeft + r->m_renderer->width();
+ left = min(left, floatLeft);
+ right = max(right, floatRight);
+ }
+ }
+ }
+ }
+}
+
+void RenderBlock::borderFitAdjust(int& x, int& w) const
+{
+ if (style()->borderFit() == BorderFitBorder)
+ return;
+
+ // Walk any normal flow lines to snugly fit.
+ int left = INT_MAX;
+ int right = INT_MIN;
+ int oldWidth = w;
+ adjustForBorderFit(0, left, right);
+ if (left != INT_MAX) {
+ left -= (borderLeft() + paddingLeft());
+ if (left > 0) {
+ x += left;
+ w -= left;
+ }
+ }
+ if (right != INT_MIN) {
+ right += (borderRight() + paddingRight());
+ if (right < oldWidth)
+ w -= (oldWidth - right);
+ }
+}
+
+void RenderBlock::clearTruncation()
+{
+ if (style()->visibility() == VISIBLE) {
+ if (childrenInline() && hasMarkupTruncation()) {
+ setHasMarkupTruncation(false);
+ for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
+ box->clearTruncation();
+ }
+ else
+ for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
+ if (shouldCheckLines(obj))
+ static_cast<RenderBlock*>(obj)->clearTruncation();
+ }
+}
+
+void RenderBlock::setMaxTopMargins(int pos, int neg)
+{
+ if (!m_maxMargin) {
+ if (pos == MaxMargin::topPosDefault(this) && neg == MaxMargin::topNegDefault(this))
+ return;
+ m_maxMargin = new MaxMargin(this);
+ }
+ m_maxMargin->m_topPos = pos;
+ m_maxMargin->m_topNeg = neg;
+}
+
+void RenderBlock::setMaxBottomMargins(int pos, int neg)
+{
+ if (!m_maxMargin) {
+ if (pos == MaxMargin::bottomPosDefault(this) && neg == MaxMargin::bottomNegDefault(this))
+ return;
+ m_maxMargin = new MaxMargin(this);
+ }
+ m_maxMargin->m_bottomPos = pos;
+ m_maxMargin->m_bottomNeg = neg;
+}
+
+const char* RenderBlock::renderName() const
+{
+ if (isBody())
+ return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass.
+
+ if (isFloating())
+ return "RenderBlock (floating)";
+ if (isPositioned())
+ return "RenderBlock (positioned)";
+ if (isAnonymousBlock())
+ return "RenderBlock (anonymous)";
+ else if (isAnonymous())
+ return "RenderBlock (generated)";
+ if (isRelPositioned())
+ return "RenderBlock (relative positioned)";
+ if (isCompact())
+ return "RenderBlock (compact)";
+ if (isRunIn())
+ return "RenderBlock (run-in)";
+ return "RenderBlock";
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h
new file mode 100644
index 0000000..902460d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.h
@@ -0,0 +1,504 @@
+/*
+ * This file is part of the render object implementation for KHTML.
+ *
+ * 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.
+ *
+ * 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 RenderBlock_h
+#define RenderBlock_h
+
+#include "DeprecatedPtrList.h"
+#include "GapRects.h"
+#include "RenderFlow.h"
+#include "RootInlineBox.h"
+#include <wtf/ListHashSet.h>
+
+namespace WebCore {
+
+class InlineIterator;
+class BidiRun;
+class Position;
+class RootInlineBox;
+
+template <class Iterator, class Run> class BidiResolver;
+typedef BidiResolver<InlineIterator, BidiRun> InlineBidiResolver;
+
+enum CaretType { CursorCaret, DragCaret };
+
+class RenderBlock : public RenderFlow {
+public:
+ RenderBlock(Node*);
+ virtual ~RenderBlock();
+
+ virtual const char* renderName() const;
+
+ // These two functions are overridden for inline-block.
+ virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
+ virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const;
+
+ virtual bool isRenderBlock() const { return true; }
+ virtual bool isBlockFlow() const { return (!isInline() || isReplaced()) && !isTable(); }
+ virtual bool isInlineFlow() const { return isInline() && !isReplaced(); }
+ virtual bool isInlineBlockOrInlineTable() const { return isInline() && isReplaced(); }
+
+ virtual bool childrenInline() const { return m_childrenInline; }
+ virtual void setChildrenInline(bool b) { m_childrenInline = b; }
+ void makeChildrenNonInline(RenderObject* insertionPoint = 0);
+ 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;
+ virtual void setOverflowHeight(int h) { m_overflowHeight = h; }
+ virtual void setOverflowWidth(int w) { m_overflowWidth = w; }
+
+ void addVisualOverflow(const IntRect&);
+
+ virtual bool isSelfCollapsingBlock() const;
+ virtual bool isTopMarginQuirk() const { return m_topMarginQuirk; }
+ virtual bool isBottomMarginQuirk() const { return m_bottomMarginQuirk; }
+
+ virtual int maxTopMargin(bool positive) const { return positive ? maxTopPosMargin() : maxTopNegMargin(); }
+ virtual int maxBottomMargin(bool positive) const { return positive ? maxBottomPosMargin() : maxBottomNegMargin(); }
+
+ 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); }
+ int maxBottomPosMargin() const { return m_maxMargin ? m_maxMargin->m_bottomPos : MaxMargin::bottomPosDefault(this); }
+ int maxBottomNegMargin() const { return m_maxMargin ? m_maxMargin->m_bottomNeg : MaxMargin::bottomNegDefault(this); }
+ void setMaxTopMargins(int pos, int neg);
+ void setMaxBottomMargins(int pos, int neg);
+
+ void initMaxMarginValues()
+ {
+ if (m_maxMargin) {
+ m_maxMargin->m_topPos = MaxMargin::topPosDefault(this);
+ m_maxMargin->m_topNeg = MaxMargin::topNegDefault(this);
+ m_maxMargin->m_bottomPos = MaxMargin::bottomPosDefault(this);
+ m_maxMargin->m_bottomNeg = MaxMargin::bottomNegDefault(this);
+ }
+ }
+
+ virtual void addChildToFlow(RenderObject* newChild, RenderObject* beforeChild);
+ virtual void removeChild(RenderObject*);
+
+ virtual void repaintOverhangingFloats(bool paintAllDescendants);
+
+ virtual void layout();
+ virtual void layoutBlock(bool relayoutChildren);
+ void layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom);
+ void layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom);
+
+ void layoutPositionedObjects(bool relayoutChildren);
+ void insertPositionedObject(RenderObject*);
+ void removePositionedObject(RenderObject*);
+ virtual void removePositionedObjects(RenderBlock*);
+
+ void addPercentHeightDescendant(RenderBox*);
+ static void removePercentHeightDescendant(RenderBox*);
+
+ virtual void positionListMarker() { }
+
+ virtual void borderFitAdjust(int& x, int& w) const; // Shrink the box in which the border paints if border-fit is set.
+
+ // Called to lay out the legend for a fieldset.
+ virtual RenderObject* layoutLegend(bool /*relayoutChildren*/) { return 0; }
+
+ // the implementation of the following functions is in bidi.cpp
+ struct FloatWithRect {
+ FloatWithRect(RenderObject* f)
+ : object(f)
+ , rect(IntRect(f->xPos() - f->marginLeft(), f->yPos() - f->marginTop(), f->width() + f->marginLeft() + f->marginRight(), f->height() + f->marginTop() + f->marginBottom()))
+ {
+ }
+
+ RenderObject* object;
+ IntRect rect;
+ };
+
+ void bidiReorderLine(InlineBidiResolver&, const InlineIterator& end);
+ RootInlineBox* determineStartPosition(bool& fullLayout, InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats);
+ RootInlineBox* determineEndPosition(RootInlineBox* startBox, InlineIterator& cleanLineStart,
+ BidiStatus& cleanLineBidiStatus,
+ int& yPos);
+ bool matchedEndLine(const InlineBidiResolver&, const InlineIterator& endLineStart, const BidiStatus& endLineStatus,
+ RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop);
+ bool generatesLineBoxesForInlineChild(RenderObject*);
+ void skipTrailingWhitespace(InlineIterator&);
+ int skipLeadingWhitespace(InlineBidiResolver&);
+ void fitBelowFloats(int widthToFit, int& availableWidth);
+ InlineIterator findNextLineBreak(InlineBidiResolver&, EClear* clear = 0);
+ RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool lastLine, RenderObject* endObject);
+ InlineFlowBox* createLineBoxes(RenderObject*);
+ void computeHorizontalPositionsForLine(RootInlineBox*, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd);
+ void computeVerticalPositionsForLine(RootInlineBox*, BidiRun*);
+ void checkLinesForOverflow();
+ void deleteEllipsisLineBoxes();
+ void checkLinesForTextOverflow();
+ // end bidi.cpp functions
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void paintObject(PaintInfo&, int tx, int ty);
+ void paintFloats(PaintInfo&, int tx, int ty, bool preservePhase = false);
+ void paintContents(PaintInfo&, int tx, int ty);
+ void paintColumns(PaintInfo&, int tx, int ty, bool paintFloats = false);
+ void paintChildren(PaintInfo&, int tx, int ty);
+ void paintEllipsisBoxes(PaintInfo&, int tx, int ty);
+ void paintSelection(PaintInfo&, int tx, int ty);
+ void paintCaret(PaintInfo&, int tx, int ty, CaretType);
+
+ void insertFloatingObject(RenderObject*);
+ void removeFloatingObject(RenderObject*);
+
+ // Called from lineWidth, to position the floats added in the last line.
+ // Returns ture if and only if it has positioned any floats.
+ bool positionNewFloats();
+ void clearFloats();
+ int getClearDelta(RenderObject* child);
+ virtual void markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove = 0);
+ void markPositionedObjectsForLayout();
+
+ virtual bool containsFloats() { return m_floatingObjects && !m_floatingObjects->isEmpty(); }
+ virtual bool containsFloat(RenderObject*);
+
+ virtual bool avoidsFloats() const;
+
+ virtual bool hasOverhangingFloats() { return !hasColumns() && floatBottom() > m_height; }
+ void addIntrudingFloats(RenderBlock* prev, int xoffset, int yoffset);
+ int addOverhangingFloats(RenderBlock* child, int xoffset, int yoffset, bool makeChildPaintOtherFloats);
+
+ int nextFloatBottomBelow(int) const;
+ int floatBottom() const;
+ inline int leftBottom();
+ inline int rightBottom();
+ IntRect floatRect() const;
+
+ virtual int lineWidth(int) 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;
+
+ int rightOffset() const;
+ int rightRelOffset(int y, int fixedOffset, bool applyTextIndent = true, int* heightRemaining = 0) const;
+ int rightOffset(int y) const { return rightRelOffset(y, rightOffset(), true); }
+
+ int leftOffset() const;
+ int leftRelOffset(int y, int fixedOffset, bool applyTextIndent = true, int* heightRemaining = 0) const;
+ int leftOffset(int y) const { return leftRelOffset(y, leftOffset(), true); }
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+ virtual bool hitTestColumns(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+ virtual bool hitTestContents(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ virtual bool isPointInOverflowControl(HitTestResult&, int x, int y, int tx, int ty);
+
+ virtual VisiblePosition positionForCoordinates(int x, int y);
+
+ // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.)
+ virtual int availableWidth() const;
+
+ virtual void calcPrefWidths();
+ void calcInlinePrefWidths();
+ void calcBlockPrefWidths();
+
+ virtual int getBaselineOfFirstLineBox() const;
+ virtual int getBaselineOfLastLineBox() const;
+
+ RootInlineBox* firstRootBox() const { return static_cast<RootInlineBox*>(firstLineBox()); }
+ RootInlineBox* lastRootBox() const { return static_cast<RootInlineBox*>(lastLineBox()); }
+
+ bool containsNonZeroBidiLevel() const;
+
+ // Obtains the nearest enclosing block (including this block) that contributes a first-line style to our inline
+ // children.
+ virtual RenderBlock* firstLineBlock() const;
+ virtual void updateFirstLetter();
+
+ bool inRootBlockContext() const;
+
+ void setHasMarkupTruncation(bool b = true) { m_hasMarkupTruncation = b; }
+ bool hasMarkupTruncation() const { return m_hasMarkupTruncation; }
+
+ virtual bool hasSelectedChildren() const { return m_selectionState != SelectionNone; }
+ virtual SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState); }
+ virtual void setSelectionState(SelectionState s);
+
+ struct BlockSelectionInfo {
+ RenderBlock* m_block;
+ GapRects m_rects;
+ SelectionState m_state;
+
+ BlockSelectionInfo()
+ : m_block(0)
+ , m_state(SelectionNone)
+ {
+ }
+
+ BlockSelectionInfo(RenderBlock* b)
+ : m_block(b)
+ , m_rects(b->needsLayout() ? GapRects() : b->selectionGapRects())
+ , m_state(b->selectionState())
+ {
+ }
+
+ RenderBlock* block() const { return m_block; }
+ GapRects rects() const { return m_rects; }
+ SelectionState state() const { return m_state; }
+ };
+
+ virtual IntRect selectionRect(bool) { return selectionGapRects(); }
+ GapRects selectionGapRects();
+ virtual bool shouldPaintSelectionGaps() const;
+ bool isSelectionRoot() const;
+ GapRects fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
+ int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* = 0);
+ GapRects fillInlineSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
+ int& lastTop, int& lastLeft, int& lastRight, const PaintInfo*);
+ GapRects fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
+ int& lastTop, int& lastLeft, int& lastRight, const PaintInfo*);
+ IntRect fillVerticalSelectionGap(int lastTop, int lastLeft, int lastRight, int bottomY, RenderBlock* rootBlock,
+ int blockX, int blockY, const PaintInfo*);
+ IntRect fillLeftSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock,
+ int blockX, int blockY, int tx, int ty, const PaintInfo*);
+ IntRect fillRightSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock,
+ int blockX, int blockY, int tx, int ty, const PaintInfo*);
+ IntRect fillHorizontalSelectionGap(RenderObject* selObj, int xPos, int yPos, int width, int height, const PaintInfo*);
+
+ void getHorizontalSelectionGapInfo(SelectionState, bool& leftGap, bool& rightGap);
+ int leftSelectionOffset(RenderBlock* rootBlock, int y);
+ int rightSelectionOffset(RenderBlock* rootBlock, int y);
+
+ // Helper methods for computing line counts and heights for line counts.
+ RootInlineBox* lineAtIndex(int);
+ int lineCount();
+ int heightForLineCount(int);
+ void clearTruncation();
+
+ int desiredColumnWidth() const;
+ unsigned desiredColumnCount() const;
+ Vector<IntRect>* columnRects() const;
+ void setDesiredColumnCountAndWidth(int count, int width);
+
+ void adjustRectForColumns(IntRect&) const;
+
+ void addContinuationWithOutline(RenderFlow*);
+ void paintContinuationOutlines(PaintInfo&, int tx, int ty);
+
+private:
+ void adjustPointToColumnContents(IntPoint&) const;
+ void adjustForBorderFit(int x, int& left, int& right) const; // Helper function for borderFitAdjust
+
+ void markLinesDirtyInVerticalRange(int top, int bottom);
+
+protected:
+ virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle);
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ void newLine(EClear);
+ virtual bool hasLineIfEmpty() const;
+ bool layoutOnlyPositionedObjects();
+
+private:
+ Position positionForBox(InlineBox*, bool start = true) const;
+ Position positionForRenderer(RenderObject*, bool start = true) const;
+
+ // Adjust tx and ty from painting offsets to the local coords of this renderer
+ void offsetForContents(int& tx, int& ty) const;
+
+ int columnGap() const;
+ void calcColumnWidth();
+ int layoutColumns(int endOfContent = -1);
+
+protected:
+ struct FloatingObject {
+ enum Type {
+ FloatLeft,
+ FloatRight
+ };
+
+ FloatingObject(Type type)
+ : m_renderer(0)
+ , m_top(0)
+ , m_bottom(0)
+ , m_left(0)
+ , m_width(0)
+ , m_type(type)
+ , m_shouldPaint(true)
+ , m_isDescendant(false)
+ {
+ }
+
+ Type type() { return static_cast<Type>(m_type); }
+
+ RenderObject* m_renderer;
+ int m_top;
+ int m_bottom;
+ int m_left;
+ int m_width;
+ unsigned m_type : 1; // Type (left or right aligned)
+ bool m_shouldPaint : 1;
+ bool m_isDescendant : 1;
+ };
+
+ // The following helper functions and structs are used by layoutBlockChildren.
+ class CompactInfo {
+ // A compact child that needs to be collapsed into the margin of the following block.
+ RenderObject* m_compact;
+
+ // The block with the open margin that the compact child is going to place itself within.
+ RenderObject* m_block;
+
+ public:
+ RenderObject* compact() const { return m_compact; }
+ RenderObject* block() const { return m_block; }
+ bool matches(RenderObject* child) const { return m_compact && m_block == child; }
+
+ void clear() { set(0, 0); }
+ void set(RenderObject* c, RenderObject* b) { m_compact = c; m_block = b; }
+
+ CompactInfo() { clear(); }
+ };
+
+ class MarginInfo {
+ // Collapsing flags for whether we can collapse our margins with our children's margins.
+ bool m_canCollapseWithChildren : 1;
+ bool m_canCollapseTopWithChildren : 1;
+ bool m_canCollapseBottomWithChildren : 1;
+
+ // Whether or not we are a quirky container, i.e., do we collapse away top and bottom
+ // margins in our container. Table cells and the body are the common examples. We
+ // also have a custom style property for Safari RSS to deal with TypePad blog articles.
+ bool m_quirkContainer : 1;
+
+ // This flag tracks whether we are still looking at child margins that can all collapse together at the beginning of a block.
+ // They may or may not collapse with the top margin of the block (|m_canCollapseTopWithChildren| tells us that), but they will
+ // always be collapsing with one another. This variable can remain set to true through multiple iterations
+ // as long as we keep encountering self-collapsing blocks.
+ bool m_atTopOfBlock : 1;
+
+ // 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;
+ bool m_bottomQuirk : 1;
+ bool m_determinedTopQuirk : 1;
+
+ // These flags track the previous maximal positive and negative margins.
+ int m_posMargin;
+ int m_negMargin;
+
+ public:
+ MarginInfo(RenderBlock* b, int top, int bottom);
+
+ 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; }
+ void setPosMargin(int p) { m_posMargin = p; }
+ void setNegMargin(int n) { m_negMargin = n; }
+ void setPosMarginIfLarger(int p) { if (p > m_posMargin) m_posMargin = p; }
+ void setNegMarginIfLarger(int n) { if (n > m_negMargin) m_negMargin = n; }
+
+ void setMargin(int p, int n) { m_posMargin = p; m_negMargin = n; }
+
+ bool atTopOfBlock() const { return m_atTopOfBlock; }
+ bool canCollapseWithTop() const { return m_atTopOfBlock && m_canCollapseTopWithChildren; }
+ 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; }
+ bool bottomQuirk() const { return m_bottomQuirk; }
+ int posMargin() const { return m_posMargin; }
+ int negMargin() const { return m_negMargin; }
+ int margin() const { return m_posMargin - m_negMargin; }
+ };
+
+ void adjustPositionedBlock(RenderObject* child, const MarginInfo&);
+ void adjustFloatingBlock(const MarginInfo&);
+ RenderObject* handleSpecialChild(RenderObject* child, const MarginInfo&, CompactInfo&, bool& handled);
+ RenderObject* handleFloatingChild(RenderObject* child, const MarginInfo&, bool& handled);
+ RenderObject* handlePositionedChild(RenderObject* child, const MarginInfo&, bool& handled);
+ RenderObject* handleCompactChild(RenderObject* child, CompactInfo&, bool& handled);
+ RenderObject* handleRunInChild(RenderObject* child, bool& handled);
+ void collapseMargins(RenderObject* child, MarginInfo&, int yPosEstimate);
+ void clearFloatsIfNeeded(RenderObject* child, MarginInfo&, int oldTopPosMargin, int oldTopNegMargin);
+ void insertCompactIfNeeded(RenderObject* child, CompactInfo&);
+ int estimateVerticalPosition(RenderObject* child, const MarginInfo&);
+ void determineHorizontalPosition(RenderObject* child);
+ void handleBottomOfBlock(int top, int bottom, MarginInfo&);
+ void setCollapsedBottomMargin(const MarginInfo&);
+ // End helper functions and structs used by layoutBlockChildren.
+
+private:
+ typedef ListHashSet<RenderObject*>::const_iterator Iterator;
+ DeprecatedPtrList<FloatingObject>* m_floatingObjects;
+ ListHashSet<RenderObject*>* m_positionedObjects;
+
+ // Allocated only when some of these fields have non-default values
+ struct MaxMargin {
+ MaxMargin(const RenderBlock* o)
+ : m_topPos(topPosDefault(o))
+ , m_topNeg(topNegDefault(o))
+ , m_bottomPos(bottomPosDefault(o))
+ , m_bottomNeg(bottomNegDefault(o))
+ {
+ }
+
+ static int topPosDefault(const RenderBlock* o) { return o->marginTop() > 0 ? o->marginTop() : 0; }
+ static int topNegDefault(const RenderBlock* o) { return o->marginTop() < 0 ? -o->marginTop() : 0; }
+ static int bottomPosDefault(const RenderBlock* o) { return o->marginBottom() > 0 ? o->marginBottom() : 0; }
+ static int bottomNegDefault(const RenderBlock* o) { return o->marginBottom() < 0 ? -o->marginBottom() : 0; }
+
+ int m_topPos;
+ int m_topNeg;
+ int m_bottomPos;
+ int m_bottomNeg;
+ };
+
+ MaxMargin* m_maxMargin;
+
+protected:
+ // How much content overflows out of our block vertically or horizontally.
+ int m_overflowHeight;
+ int m_overflowWidth;
+ int m_overflowLeft;
+ int m_overflowTop;
+};
+
+} // namespace WebCore
+
+#endif // RenderBlock_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp
new file mode 100644
index 0000000..78691de
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderBox.cpp
@@ -0,0 +1,2768 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2005, 2006, 2007, 2008 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 "RenderBox.h"
+
+#include "CachedImage.h"
+#include "ChromeClient.h"
+#include "Document.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLElement.h"
+#include "HTMLNames.h"
+#include "ImageBuffer.h"
+#include "Frame.h"
+#include "Page.h"
+#include "RenderArena.h"
+#include "RenderFlexibleBox.h"
+#include "RenderLayer.h"
+#include "RenderReplica.h"
+#include "RenderTableCell.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include <algorithm>
+#include <math.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// Used by flexible boxes when flexing this element.
+typedef WTF::HashMap<const RenderBox*, int> OverrideSizeMap;
+static OverrideSizeMap* gOverrideSizeMap = 0;
+
+bool RenderBox::s_wasFloating = false;
+bool RenderBox::s_hadOverflowClip = false;
+
+RenderBox::RenderBox(Node* node)
+ : RenderObject(node)
+ , m_width(0)
+ , m_height(0)
+ , m_x(0)
+ , m_y(0)
+ , m_marginLeft(0)
+ , m_marginRight(0)
+ , m_marginTop(0)
+ , m_marginBottom(0)
+ , m_minPrefWidth(-1)
+ , m_maxPrefWidth(-1)
+ , m_layer(0)
+ , m_inlineBoxWrapper(0)
+{
+}
+
+RenderBox::~RenderBox()
+{
+}
+
+void RenderBox::destroy()
+{
+ // A lot of the code in this function is just pasted into
+ // RenderWidget::destroy. If anything in this function changes,
+ // be sure to fix RenderWidget::destroy() as well.
+ if (hasOverrideSize())
+ gOverrideSizeMap->remove(this);
+
+ // This must be done before we destroy the RenderObject.
+ if (m_layer)
+ m_layer->clearClipRects();
+
+ if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent()))
+ RenderBlock::removePercentHeightDescendant(this);
+
+ RenderObject::destroy();
+}
+
+void RenderBox::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
+{
+ s_wasFloating = isFloating();
+ s_hadOverflowClip = hasOverflowClip();
+
+ RenderObject::styleWillChange(diff, newStyle);
+}
+
+void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen
+ // during the style change (it's used by absoluteClippedOverflowRect()).
+ if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintPhaseOutline))
+ static_cast<RenderView*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize());
+
+ RenderObject::styleDidChange(diff, oldStyle);
+
+ if (needsLayout() && oldStyle && (oldStyle->height().isPercent() || oldStyle->minHeight().isPercent() || oldStyle->maxHeight().isPercent()))
+ RenderBlock::removePercentHeightDescendant(this);
+
+ // The root and the RenderView always paint their backgrounds/borders.
+ if (isRoot() || isRenderView())
+ setHasBoxDecorations(true);
+
+ setInline(style()->isDisplayInlineType());
+
+ switch (style()->position()) {
+ case AbsolutePosition:
+ case FixedPosition:
+ setPositioned(true);
+ break;
+ default:
+ setPositioned(false);
+
+ if (style()->isFloating())
+ setFloating(true);
+
+ if (style()->position() == RelativePosition)
+ setRelPositioned(true);
+ break;
+ }
+
+ // We also handle <body> and <html>, whose overflow applies to the viewport.
+ if (!isRoot() && (isRenderBlock() || isTableRow() || isTableSection()) && style()->overflowX() != OVISIBLE) {
+ bool boxHasOverflowClip = true;
+ if (isBody()) {
+ // Overflow on the body can propagate to the viewport under the following conditions.
+ // (1) The root element is <html>.
+ // (2) We are the primary <body> (can be checked by looking at document.body).
+ // (3) The root element has visible overflow.
+ if (document()->documentElement()->hasTagName(htmlTag) &&
+ document()->body() == element() &&
+ document()->documentElement()->renderer()->style()->overflowX() == OVISIBLE)
+ boxHasOverflowClip = false;
+ }
+
+ // Check for overflow clip.
+ // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value.
+ if (boxHasOverflowClip) {
+ if (!s_hadOverflowClip)
+ // Erase the overflow
+ repaint();
+ setHasOverflowClip();
+ }
+ }
+
+ setHasTransform(style()->hasTransform());
+ setHasReflection(style()->boxReflect());
+
+ if (requiresLayer()) {
+ if (!m_layer) {
+ if (s_wasFloating && isFloating())
+ setChildNeedsLayout(true);
+ m_layer = new (renderArena()) RenderLayer(this);
+ setHasLayer(true);
+ m_layer->insertOnlyThisLayer();
+ if (parent() && !needsLayout() && containingBlock())
+ m_layer->updateLayerPositions();
+ }
+ } else if (m_layer && !isRoot() && !isRenderView()) {
+ ASSERT(m_layer->parent());
+ RenderLayer* layer = m_layer;
+ m_layer = 0;
+ setHasLayer(false);
+ setHasTransform(false); // Either a transform wasn't specified or the object doesn't support transforms, so just null out the bit.
+ setHasReflection(false);
+ layer->removeOnlyThisLayer();
+ if (s_wasFloating && isFloating())
+ setChildNeedsLayout(true);
+ }
+
+ // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
+ // new zoomed coordinate space.
+ if (hasOverflowClip() && oldStyle && style() && oldStyle->effectiveZoom() != style()->effectiveZoom()) {
+ int left = scrollLeft();
+ if (left) {
+ left = (left / oldStyle->effectiveZoom()) * style()->effectiveZoom();
+ setScrollLeft(left);
+ }
+ int top = scrollTop();
+ if (top) {
+ top = (top / oldStyle->effectiveZoom()) * style()->effectiveZoom();
+ setScrollTop(top);
+ }
+ }
+
+ if (m_layer)
+ m_layer->styleChanged(diff, oldStyle);
+
+ // Set the text color if we're the body.
+ if (isBody())
+ document()->setTextColor(style()->color());
+}
+
+int RenderBox::minPrefWidth() const
+{
+ if (prefWidthsDirty())
+ const_cast<RenderBox*>(this)->calcPrefWidths();
+
+ return m_minPrefWidth;
+}
+
+int RenderBox::maxPrefWidth() const
+{
+ if (prefWidthsDirty())
+ const_cast<RenderBox*>(this)->calcPrefWidths();
+
+ return m_maxPrefWidth;
+}
+
+int RenderBox::overrideSize() const
+{
+ if (!hasOverrideSize())
+ return -1;
+ return gOverrideSizeMap->get(this);
+}
+
+void RenderBox::setOverrideSize(int s)
+{
+ if (s == -1) {
+ if (hasOverrideSize()) {
+ setHasOverrideSize(false);
+ gOverrideSizeMap->remove(this);
+ }
+ } else {
+ if (!gOverrideSizeMap)
+ gOverrideSizeMap = new OverrideSizeMap();
+ setHasOverrideSize(true);
+ gOverrideSizeMap->set(this, s);
+ }
+}
+
+int RenderBox::overrideWidth() const
+{
+ return hasOverrideSize() ? overrideSize() : m_width;
+}
+
+int RenderBox::overrideHeight() const
+{
+ return hasOverrideSize() ? overrideSize() : m_height;
+}
+
+void RenderBox::setPos(int xPos, int yPos)
+{
+ // Optimize for the case where we don't move at all.
+ if (xPos == m_x && yPos == m_y)
+ return;
+
+ m_x = xPos;
+ m_y = yPos;
+}
+
+int RenderBox::calcBorderBoxWidth(int width) const
+{
+ int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
+ if (style()->boxSizing() == CONTENT_BOX)
+ return width + bordersPlusPadding;
+ return max(width, bordersPlusPadding);
+}
+
+int RenderBox::calcBorderBoxHeight(int height) const
+{
+ int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
+ if (style()->boxSizing() == CONTENT_BOX)
+ return height + bordersPlusPadding;
+ return max(height, bordersPlusPadding);
+}
+
+int RenderBox::calcContentBoxWidth(int width) const
+{
+ if (style()->boxSizing() == BORDER_BOX)
+ width -= (borderLeft() + borderRight() + paddingLeft() + paddingRight());
+ return max(0, width);
+}
+
+int RenderBox::calcContentBoxHeight(int height) const
+{
+ if (style()->boxSizing() == BORDER_BOX)
+ height -= (borderTop() + borderBottom() + paddingTop() + paddingBottom());
+ return max(0, height);
+}
+
+// Hit Testing
+bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action)
+{
+ tx += m_x;
+ ty += m_y;
+
+ // Check kids first.
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
+ // FIXME: We have to skip over inline flows, since they can show up inside table rows
+ // at the moment (a demoted inline <form> for example). If we ever implement a
+ // table-specific hit-test method (which we should do for performance reasons anyway),
+ // then we can remove this check.
+ if (!child->hasLayer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) {
+ updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+ }
+
+ // Check our bounds next. For this purpose always assume that we can only be hit in the
+ // foreground phase (which is true for replaced elements like images).
+ if (visibleToHitTesting() && action == HitTestForeground && IntRect(tx, ty, m_width, m_height).contains(x, y)) {
+ updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+
+ return false;
+}
+
+// --------------------- painting stuff -------------------------------
+
+void RenderBox::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ tx += m_x;
+ ty += m_y;
+
+ // default implementation. Just pass paint through to the children
+ PaintInfo childInfo(paintInfo);
+ childInfo.paintingRoot = paintingRootForChildren(paintInfo);
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling())
+ child->paint(childInfo, tx, ty);
+}
+
+void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
+{
+ const FillLayer* bgLayer = style()->backgroundLayers();
+ Color bgColor = style()->backgroundColor();
+ if (!style()->hasBackground() && element() && element()->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;
+ if (bodyObject) {
+ bgLayer = bodyObject->style()->backgroundLayers();
+ bgColor = bodyObject->style()->backgroundColor();
+ }
+ }
+
+ int w = width();
+ int h = height();
+
+ int rw;
+ int rh;
+ if (view()->frameView()) {
+ rw = view()->frameView()->contentsWidth();
+ rh = view()->frameView()->contentsHeight();
+ } else {
+ rw = view()->width();
+ rh = view()->height();
+ }
+
+ // CSS2 14.2:
+ // The background of the box generated by the root element covers the entire canvas including
+ // its margins.
+ int bx = tx - marginLeft();
+ int by = ty - marginTop();
+ int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
+ int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
+
+ int my = max(by, paintInfo.rect.y());
+
+ paintFillLayers(paintInfo, bgColor, bgLayer, my, paintInfo.rect.height(), bx, by, bw, bh);
+
+ if (style()->hasBorder() && style()->display() != INLINE)
+ paintBorder(paintInfo.context, tx, ty, w, h, style());
+}
+
+void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (!shouldPaintWithinRoot(paintInfo))
+ return;
+
+ if (isRoot()) {
+ paintRootBoxDecorations(paintInfo, tx, ty);
+ return;
+ }
+
+ int w = width();
+ int h = height() + borderTopExtra() + borderBottomExtra();
+ ty -= borderTopExtra();
+
+ // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat
+ // balloon layout is an example of this).
+ borderFitAdjust(tx, w);
+
+ int my = max(ty, paintInfo.rect.y());
+ int mh;
+ if (ty < paintInfo.rect.y())
+ mh = max(0, h - (paintInfo.rect.y() - ty));
+ else
+ mh = min(paintInfo.rect.height(), h);
+
+ // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
+ // custom shadows of their own.
+ paintBoxShadow(paintInfo.context, tx, ty, w, h, style());
+
+ // If we have a native theme appearance, paint that before painting our background.
+ // The theme will tell us whether or not we should also paint the CSS background.
+ bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, IntRect(tx, ty, w, h));
+ if (!themePainted) {
+ // The <body> only paints its background if the root element has defined a background
+ // independent of the body. Go through the DOM to get to the root element's render object,
+ // since the root could be inline and wrapped in an anonymous block.
+ if (!isBody() || document()->documentElement()->renderer()->style()->hasBackground())
+ paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h);
+ if (style()->hasAppearance())
+ theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, w, h));
+ }
+
+ // The theme will tell us whether or not we should also paint the CSS border.
+ if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, IntRect(tx, ty, w, h)))) && style()->hasBorder())
+ paintBorder(paintInfo.context, tx, ty, w, h, style());
+}
+
+void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (!shouldPaintWithinRoot(paintInfo) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
+ return;
+
+ int w = width();
+ int h = height() + borderTopExtra() + borderBottomExtra();
+ ty -= borderTopExtra();
+
+ // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat
+ // balloon layout is an example of this).
+ borderFitAdjust(tx, w);
+
+ int my = max(ty, paintInfo.rect.y());
+ int mh;
+ if (ty < paintInfo.rect.y())
+ mh = max(0, h - (paintInfo.rect.y() - ty));
+ else
+ mh = min(paintInfo.rect.height(), h);
+
+ paintMaskImages(paintInfo, my, mh, tx, ty, w, h);
+}
+
+void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int my, int mh, int tx, int ty, int w, int h)
+{
+ // 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()) || style()->maskLayers()->next())
+ // 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.
+ pushTransparencyLayer = true;
+
+ CompositeOperator compositeOp = CompositeDestinationIn;
+ if (pushTransparencyLayer) {
+ paintInfo.context->setCompositeOperation(CompositeDestinationIn);
+ paintInfo.context->beginTransparencyLayer(1.0f);
+ compositeOp = CompositeSourceOver;
+ }
+
+ paintFillLayers(paintInfo, Color(), style()->maskLayers(), my, mh, tx, ty, w, h, compositeOp);
+ paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp);
+
+ if (pushTransparencyLayer)
+ paintInfo.context->endTransparencyLayer();
+}
+
+IntRect RenderBox::maskClipRect()
+{
+ IntRect bbox = borderBox();
+ if (style()->maskBoxImage().image())
+ return bbox;
+
+ IntRect result;
+ for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
+ if (maskLayer->image()) {
+ IntRect maskRect;
+ IntPoint phase;
+ IntSize tileSize;
+ calculateBackgroundImageGeometry(maskLayer, bbox.x(), bbox.y(), bbox.width(), bbox.height(), maskRect, phase, tileSize);
+ result.unite(maskRect);
+ }
+ }
+ return result;
+}
+
+void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer,
+ int clipY, int clipH, int tx, int ty, int width, int height, CompositeOperator op)
+{
+ if (!fillLayer)
+ return;
+
+ paintFillLayers(paintInfo, c, fillLayer->next(), clipY, clipH, tx, ty, width, height, op);
+ paintFillLayer(paintInfo, c, fillLayer, clipY, clipH, tx, ty, width, height, op);
+}
+
+void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer,
+ int clipY, int clipH, int tx, int ty, int width, int height, CompositeOperator op)
+{
+ paintFillLayerExtended(paintInfo, c, fillLayer, clipY, clipH, tx, ty, width, height, 0, op);
+}
+
+IntSize RenderBox::calculateBackgroundSize(const FillLayer* bgLayer, int scaledWidth, int scaledHeight) 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();
+ }
+
+ return IntSize(max(1, w), max(1, h));
+ } else
+ return bg->imageSize(this, style()->effectiveZoom());
+}
+
+void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
+{
+ if (isInlineFlow() ||
+ style()->borderImage().image() && style()->borderImage().image()->data() == image ||
+ style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image) {
+ repaint();
+ return;
+ }
+
+ bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
+ if (!didFullRepaint) {
+ repaintLayerRectsForImage(image, style()->maskLayers(), false);
+ }
+}
+
+bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
+{
+ IntRect absoluteRect;
+ RenderBox* layerRenderer = 0;
+
+ for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
+ if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(style()->effectiveZoom())) {
+ // Now that we know this image is being used, compute the renderer and the rect
+ // if we haven't already
+ if (!layerRenderer) {
+ bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document()->documentElement()->renderer()->style()->hasBackground()));
+ if (drawingRootBackground) {
+ layerRenderer = view();
+
+ int rw;
+ int rh;
+
+ if (FrameView* frameView = static_cast<RenderView*>(layerRenderer)->frameView()) {
+ rw = frameView->contentsWidth();
+ rh = frameView->contentsHeight();
+ } else {
+ rw = layerRenderer->width();
+ rh = layerRenderer->height();
+ }
+ absoluteRect = IntRect(-layerRenderer->marginLeft(),
+ -layerRenderer->marginTop(),
+ max(layerRenderer->width() + layerRenderer->marginLeft() + layerRenderer->marginRight() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
+ max(layerRenderer->height() + layerRenderer->marginTop() + layerRenderer->marginBottom() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
+ } else {
+ layerRenderer = this;
+ absoluteRect = borderBox();
+ }
+
+ layerRenderer->computeAbsoluteRepaintRect(absoluteRect);
+ }
+
+ IntRect repaintRect;
+ IntPoint phase;
+ IntSize tileSize;
+ layerRenderer->calculateBackgroundImageGeometry(curLayer, absoluteRect.x(), absoluteRect.y(), absoluteRect.width(), absoluteRect.height(), repaintRect, phase, tileSize);
+ view()->repaintViewRectangle(repaintRect);
+ if (repaintRect == absoluteRect)
+ return true;
+ }
+ }
+ return false;
+}
+
+void RenderBox::calculateBackgroundImageGeometry(const FillLayer* bgLayer, 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
+
+ if (bgLayer->attachment()) {
+ // Scroll
+ if (bgLayer->origin() != BorderFillBox) {
+ left = borderLeft();
+ right = borderRight();
+ top = borderTop();
+ bottom = borderBottom();
+ if (bgLayer->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.
+ if (isRoot()) {
+ rw = width() - left - right;
+ rh = height() - top - bottom;
+ left += marginLeft();
+ right += marginRight();
+ top += marginTop();
+ bottom += marginBottom();
+ }
+ cx = tx;
+ cy = ty;
+ pw = w - left - right;
+ ph = h - top - bottom;
+ } else {
+ // Fixed
+ IntRect vr = viewRect();
+ cx = vr.x();
+ cy = vr.y();
+ pw = vr.width();
+ ph = vr.height();
+ }
+
+ int sx = 0;
+ int sy = 0;
+ int cw;
+ int ch;
+
+ IntSize scaledImageSize;
+ if (isRoot() && bgLayer->attachment())
+ scaledImageSize = calculateBackgroundSize(bgLayer, rw, rh);
+ else
+ scaledImageSize = calculateBackgroundSize(bgLayer, pw, ph);
+
+ int scaledImageWidth = scaledImageSize.width();
+ int scaledImageHeight = scaledImageSize.height();
+
+ EFillRepeat backgroundRepeat = bgLayer->repeat();
+
+ int xPosition;
+ if (isRoot() && bgLayer->attachment())
+ 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() && bgLayer->attachment())
+ 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);
+ }
+
+ if (!bgLayer->attachment()) {
+ sx += max(tx - cx, 0);
+ sy += max(ty - cy, 0);
+ }
+
+ destRect = IntRect(cx, cy, cw, ch);
+ destRect.intersect(IntRect(tx, ty, w, h));
+ phase = IntPoint(sx, sy);
+ tileSize = IntSize(scaledImageWidth, scaledImageHeight);
+}
+
+void RenderBox::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int clipY, int clipH,
+ int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op)
+{
+ GraphicsContext* context = paintInfo.context;
+ bool includeLeftEdge = box ? box->includeLeftEdge() : true;
+ bool includeRightEdge = box ? box->includeRightEdge() : true;
+ int bLeft = includeLeftEdge ? borderLeft() : 0;
+ int bRight = includeRightEdge ? borderRight() : 0;
+ int pLeft = includeLeftEdge ? paddingLeft() : 0;
+ int pRight = includeRightEdge ? paddingRight() : 0;
+
+ bool clippedToBorderRadius = false;
+ if (style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge)) {
+ context->save();
+ context->addRoundedRectClip(IntRect(tx, ty, w, h),
+ includeLeftEdge ? style()->borderTopLeftRadius() : IntSize(),
+ includeRightEdge ? style()->borderTopRightRadius() : IntSize(),
+ includeLeftEdge ? style()->borderBottomLeftRadius() : IntSize(),
+ includeRightEdge ? style()->borderBottomRightRadius() : IntSize());
+ clippedToBorderRadius = true;
+ }
+
+ if (bgLayer->clip() == PaddingFillBox || bgLayer->clip() == ContentFillBox) {
+ // Clip to the padding or content boxes as necessary.
+ bool includePadding = bgLayer->clip() == ContentFillBox;
+ int x = tx + bLeft + (includePadding ? pLeft : 0);
+ int y = ty + borderTop() + (includePadding ? paddingTop() : 0);
+ int width = w - bLeft - bRight - (includePadding ? pLeft + pRight : 0);
+ int height = h - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : 0);
+ context->save();
+ context->clip(IntRect(x, y, width, height));
+ } else if (bgLayer->clip() == TextFillBox) {
+ // We have to draw our text into a mask that can then be used to clip background drawing.
+ // First figure out how big the mask has to be. It should be no bigger than what we need
+ // to actually render, so we should intersect the dirty rect with the border box of the background.
+ IntRect maskRect(tx, ty, w, h);
+ maskRect.intersect(paintInfo.rect);
+
+ // Now create the mask.
+ auto_ptr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false);
+ if (!maskImage.get())
+ return;
+
+ GraphicsContext* maskImageContext = maskImage->context();
+ maskImageContext->translate(-maskRect.x(), -maskRect.y());
+
+ // Now add the text to the clip. We do this by painting using a special paint phase that signals to
+ // InlineTextBoxes that they should just add their contents to the clip.
+ PaintInfo info(maskImageContext, maskRect, PaintPhaseTextClip, true, 0, 0);
+ if (box)
+ box->paint(info, tx - box->xPos(), ty - box->yPos());
+ else
+ paint(info, tx, ty);
+
+ // The mask has been created. Now we just need to clip to it.
+ context->save();
+ context->clipToImageBuffer(maskRect, maskImage.get());
+ }
+
+ StyleImage* bg = bgLayer->image();
+ bool shouldPaintBackgroundImage = bg && bg->canRender(style()->effectiveZoom());
+ Color bgColor = c;
+
+ // When this style flag is set, change existing background colors and images to a solid white background.
+ // If there's no bg color or image, leave it untouched to avoid affecting transparency.
+ // We don't try to avoid loading the background images, because this style flag is only set
+ // when printing, and at that point we've already loaded the background images anyway. (To avoid
+ // loading the background images we'd have to do this check when applying styles rather than
+ // while rendering.)
+ if (style()->forceBackgroundsToWhite()) {
+ // Note that we can't reuse this variable below because the bgColor might be changed
+ bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0;
+ if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) {
+ bgColor = Color::white;
+ shouldPaintBackgroundImage = false;
+ }
+ }
+
+ // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
+ // no background in the child document should show the parent's background.
+ bool isTransparent = false;
+ if (!bgLayer->next() && isRoot() && !(bgColor.isValid() && bgColor.alpha() > 0) && view()->frameView()) {
+ Node* elt = document()->ownerElement();
+ if (elt) {
+ if (!elt->hasTagName(frameTag)) {
+ // 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();
+ isTransparent = !body || !body->hasLocalName(framesetTag); // Can't scroll a frameset document anyway.
+ }
+ } else
+ isTransparent = view()->frameView()->isTransparent();
+
+ // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent.
+ if (isTransparent)
+ view()->frameView()->setUseSlowRepaints(); // The parent must show behind the child.
+ }
+
+ // Paint the color first underneath all images.
+ if (!bgLayer->next()) {
+ IntRect rect(tx, clipY, w, clipH);
+ // If we have an alpha and we are painting the root element, go ahead and blend with the base background color.
+ if (isRoot() && (!bgColor.isValid() || bgColor.alpha() < 0xFF) && !isTransparent) {
+ Color baseColor = view()->frameView()->baseBackgroundColor();
+ if (baseColor.alpha() > 0) {
+ context->save();
+ context->setCompositeOperation(CompositeCopy);
+ context->fillRect(rect, baseColor);
+ context->restore();
+ } else
+ context->clearRect(rect);
+ }
+
+ if (bgColor.isValid() && bgColor.alpha() > 0)
+ context->fillRect(rect, bgColor);
+ }
+
+ // no progressive loading of the background image
+ if (shouldPaintBackgroundImage) {
+ IntRect destRect;
+ IntPoint phase;
+ IntSize tileSize;
+
+ calculateBackgroundImageGeometry(bgLayer, tx, ty, w, h, destRect, phase, tileSize);
+ if (!destRect.isEmpty()) {
+ CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op;
+ context->drawTiledImage(bg->image(this, tileSize), destRect, phase, tileSize, compositeOp);
+ }
+ }
+
+ if (bgLayer->clip() != BorderFillBox)
+ // Undo the background clip
+ context->restore();
+
+ if (clippedToBorderRadius)
+ // Undo the border radius clip
+ context->restore();
+}
+
+#if PLATFORM(MAC)
+
+void RenderBox::paintCustomHighlight(int tx, int ty, const AtomicString& type, bool behindText)
+{
+ Frame* frame = document()->frame();
+ if (!frame)
+ return;
+ Page* page = frame->page();
+ if (!page)
+ return;
+
+ InlineBox* boxWrap = inlineBoxWrapper();
+ RootInlineBox* r = boxWrap ? boxWrap->root() : 0;
+ if (r) {
+ FloatRect rootRect(tx + r->xPos(), ty + r->selectionTop(), r->width(), r->selectionHeight());
+ FloatRect imageRect(tx + m_x, rootRect.y(), width(), rootRect.height());
+ page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false);
+ } else {
+ FloatRect imageRect(tx + m_x, ty + m_y, width(), height());
+ page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false);
+ }
+}
+
+#endif
+
+IntRect RenderBox::getOverflowClipRect(int tx, int ty)
+{
+ // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
+ // here.
+
+ int bLeft = borderLeft();
+ int bTop = borderTop();
+
+ int clipX = tx + bLeft;
+ int clipY = ty + bTop;
+ int clipWidth = m_width - bLeft - borderRight();
+ int clipHeight = m_height - bTop - borderBottom() + borderTopExtra() + borderBottomExtra();
+
+ // Subtract out scrollbars if we have them.
+ if (m_layer) {
+ clipWidth -= m_layer->verticalScrollbarWidth();
+ clipHeight -= m_layer->horizontalScrollbarHeight();
+ }
+
+ return IntRect(clipX, clipY, clipWidth, clipHeight);
+}
+
+IntRect RenderBox::getClipRect(int tx, int ty)
+{
+ int clipX = tx;
+ int clipY = ty;
+ int clipWidth = m_width;
+ int clipHeight = m_height;
+
+ if (!style()->clipLeft().isAuto()) {
+ int c = style()->clipLeft().calcValue(m_width);
+ clipX += c;
+ clipWidth -= c;
+ }
+
+ if (!style()->clipRight().isAuto())
+ clipWidth -= m_width - style()->clipRight().calcValue(m_width);
+
+ if (!style()->clipTop().isAuto()) {
+ int c = style()->clipTop().calcValue(m_height);
+ clipY += c;
+ clipHeight -= c;
+ }
+
+ if (!style()->clipBottom().isAuto())
+ clipHeight -= m_height - style()->clipBottom().calcValue(m_height);
+
+ return IntRect(clipX, clipY, clipWidth, clipHeight);
+}
+
+int RenderBox::containingBlockWidth() const
+{
+ RenderBlock* cb = containingBlock();
+ if (!cb)
+ return 0;
+ if (shrinkToAvoidFloats())
+ return cb->lineWidth(m_y);
+ return cb->availableWidth();
+}
+
+IntSize RenderBox::offsetForPositionedInContainer(RenderObject* container) const
+{
+ if (!container->isRelPositioned() || !container->isInlineFlow())
+ return IntSize();
+
+ // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
+ // box from the rest of the content, but only in the cases where we know we're positioned
+ // relative to the inline itself.
+
+ IntSize offset;
+ RenderFlow* flow = static_cast<RenderFlow*>(container);
+ int sx;
+ int sy;
+ if (flow->firstLineBox()) {
+ sx = flow->firstLineBox()->xPos();
+ sy = flow->firstLineBox()->yPos();
+ } else {
+ sx = flow->staticX();
+ sy = flow->staticY();
+ }
+
+ if (!hasStaticX())
+ offset.setWidth(sx);
+ // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside
+ // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct
+ // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
+ // do.
+ else if (!style()->isOriginalDisplayInlineType())
+ // Avoid adding in the left border/padding of the containing block twice. Subtract it out.
+ offset.setWidth(sx - (containingBlock()->borderLeft() + containingBlock()->paddingLeft()));
+
+ if (!hasStaticY())
+ offset.setHeight(sy);
+
+ return offset;
+}
+
+FloatPoint RenderBox::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const
+{
+ if (RenderView* v = view()) {
+ if (LayoutState* layoutState = v->layoutState()) {
+ IntSize offset = layoutState->m_offset;
+ offset.expand(m_x, m_y);
+ localPoint += offset;
+ if (style()->position() == RelativePosition && m_layer)
+ localPoint += m_layer->relativePositionOffset();
+ return localPoint;
+ }
+ }
+
+ if (style()->position() == FixedPosition)
+ fixed = true;
+
+ RenderObject* o = container();
+ if (o) {
+ if (useTransforms && m_layer && m_layer->transform()) {
+ fixed = false; // Elements with transforms act as a containing block for fixed position descendants
+ localPoint = m_layer->transform()->mapPoint(localPoint);
+ }
+
+ localPoint += offsetFromContainer(o);
+
+ return o->localToAbsoluteForContent(localPoint, fixed, useTransforms);
+ }
+
+ return FloatPoint();
+}
+
+FloatPoint RenderBox::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const
+{
+ // We don't expect absoluteToLocal() to be called during layout (yet)
+ ASSERT(!view() || !view()->layoutState());
+
+ if (style()->position() == FixedPosition)
+ fixed = true;
+
+ if (useTransforms && m_layer && m_layer->transform())
+ fixed = false;
+
+ RenderObject* o = container();
+ if (o) {
+ FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms);
+
+ // Take into account space above a vertically aligned table cell
+ // (see localToAbsoluteForContent())
+ localPoint.move(0.0f, -static_cast<float>(borderTopExtra()));
+
+ localPoint -= offsetFromContainer(o);
+
+ if (useTransforms && m_layer && m_layer->transform())
+ localPoint = m_layer->transform()->inverse().mapPoint(localPoint);
+
+ return localPoint;
+ }
+
+ return FloatPoint();
+}
+
+FloatQuad RenderBox::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const
+{
+ if (style()->position() == FixedPosition)
+ fixed = true;
+
+ RenderObject* o = container();
+ if (o) {
+ FloatQuad quad = localQuad;
+ if (m_layer && m_layer->transform()) {
+ fixed = false; // Elements with transforms act as a containing block for fixed position descendants
+ quad = m_layer->transform()->mapQuad(quad);
+ }
+
+ quad += offsetFromContainer(o);
+
+ // Take into account space above a vertically aligned table cell
+ // (see localToAbsoluteForContent())
+ quad.move(0.0f, static_cast<float>(o->borderTopExtra()));
+
+ return o->localToAbsoluteQuad(quad, fixed);
+ }
+
+ return FloatQuad();
+}
+
+IntSize RenderBox::offsetFromContainer(RenderObject* o) const
+{
+ ASSERT(o == container());
+
+ IntSize offset;
+ if (isRelPositioned())
+ offset += relativePositionOffset();
+
+ if (!isInline() || isReplaced()) {
+ RenderBlock* cb;
+ if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition
+ && (cb = static_cast<RenderBlock*>(o))->hasColumns()) {
+ IntRect rect(m_x, m_y, 1, 1);
+ cb->adjustRectForColumns(rect);
+ offset.expand(rect.x(), rect.y());
+ } else
+ offset.expand(m_x, m_y);
+ }
+
+ if (o->hasOverflowClip())
+ offset -= o->layer()->scrolledContentOffset();
+
+ if (style()->position() == AbsolutePosition)
+ offset += offsetForPositionedInContainer(o);
+
+ return offset;
+}
+
+void RenderBox::dirtyLineBoxes(bool fullLayout, bool /*isRootLineBox*/)
+{
+ if (m_inlineBoxWrapper) {
+ if (fullLayout) {
+ m_inlineBoxWrapper->destroy(renderArena());
+ m_inlineBoxWrapper = 0;
+ } else
+ m_inlineBoxWrapper->dirtyLineBoxes();
+ }
+}
+
+void RenderBox::position(InlineBox* box)
+{
+ if (isPositioned()) {
+ // Cache the x position only if we were an INLINE type originally.
+ bool wasInline = style()->isOriginalDisplayInlineType();
+ if (wasInline && hasStaticX()) {
+ // The value is cached in the xPos of the box. We only need this value if
+ // our object was inline originally, since otherwise it would have ended up underneath
+ // the inlines.
+ setStaticX(box->xPos());
+ setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
+ } else if (!wasInline && hasStaticY()) {
+ // Our object was a block originally, so we make our normal flow position be
+ // just below the line box (as though all the inlines that came before us got
+ // wrapped in an anonymous block, which is what would have happened had we been
+ // in flow). This value was cached in the yPos() of the box.
+ setStaticY(box->yPos());
+ setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
+ }
+
+ // Nuke the box.
+ box->remove();
+ box->destroy(renderArena());
+ } else if (isReplaced()) {
+ m_x = box->xPos();
+ m_y = box->yPos();
+ m_inlineBoxWrapper = box;
+ }
+}
+
+void RenderBox::deleteLineBoxWrapper()
+{
+ if (m_inlineBoxWrapper) {
+ if (!documentBeingDestroyed())
+ m_inlineBoxWrapper->remove();
+ m_inlineBoxWrapper->destroy(renderArena());
+ m_inlineBoxWrapper = 0;
+ }
+}
+
+IntRect RenderBox::absoluteClippedOverflowRect()
+{
+ if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
+ return IntRect();
+
+ IntRect r = overflowRect(false);
+
+ RenderView* v = view();
+ if (v)
+ r.move(v->layoutDelta());
+
+ if (style()) {
+ if (style()->hasAppearance())
+ // The theme may wish to inflate the rect used when repainting.
+ theme()->adjustRepaintRect(this, r);
+
+ // We have to use maximalOutlineSize() because a child might have an outline
+ // that projects outside of our overflowRect.
+ if (v) {
+ ASSERT(style()->outlineSize() <= v->maximalOutlineSize());
+ r.inflate(v->maximalOutlineSize());
+ }
+ }
+ computeAbsoluteRepaintRect(r);
+ return r;
+}
+
+void RenderBox::computeAbsoluteRepaintRect(IntRect& rect, bool fixed)
+{
+ if (RenderView* v = view()) {
+ if (LayoutState* layoutState = v->layoutState()) {
+ if (style()->position() == RelativePosition && m_layer)
+ rect.move(m_layer->relativePositionOffset());
+
+ rect.move(m_x, m_y);
+ rect.move(layoutState->m_offset);
+ if (layoutState->m_clipped)
+ rect.intersect(layoutState->m_clipRect);
+ return;
+ }
+ }
+
+ if (hasReflection())
+ rect.unite(reflectedRect(rect));
+
+ RenderObject* o = container();
+ if (!o)
+ return;
+
+ IntPoint topLeft = rect.location();
+ topLeft.move(m_x, m_y);
+
+ if (style()->position() == FixedPosition)
+ fixed = true;
+
+ if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
+ RenderBlock* cb = static_cast<RenderBlock*>(o);
+ if (cb->hasColumns()) {
+ IntRect repaintRect(topLeft, rect.size());
+ cb->adjustRectForColumns(repaintRect);
+ topLeft = repaintRect.location();
+ rect = repaintRect;
+ }
+ }
+
+ // We are now in our parent container's coordinate space. Apply our transform to obtain a bounding box
+ // in the parent's coordinate space that encloses us.
+ if (m_layer && m_layer->transform()) {
+ fixed = false;
+ rect = m_layer->transform()->mapRect(rect);
+ // FIXME: this clobbers topLeft adjustment done for multicol above
+ topLeft = rect.location();
+ topLeft.move(m_x, m_y);
+ }
+
+ if (style()->position() == AbsolutePosition)
+ topLeft += offsetForPositionedInContainer(o);
+ else if (style()->position() == RelativePosition && m_layer) {
+ // Apply the relative position offset when invalidating a rectangle. The layer
+ // is translated, but the render box isn't, so we need to do this to get the
+ // right dirty rect. Since this is called from RenderObject::setStyle, the relative position
+ // flag on the RenderObject has been cleared, so use the one on the style().
+ topLeft += m_layer->relativePositionOffset();
+ }
+
+ // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
+ // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
+ if (o->hasOverflowClip()) {
+ // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
+ // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
+ // anyway if its size does change.
+ topLeft -= o->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
+
+ IntRect repaintRect(topLeft, rect.size());
+ IntRect boxRect(0, 0, o->layer()->width(), o->layer()->height());
+ rect = intersection(repaintRect, boxRect);
+ if (rect.isEmpty())
+ return;
+ } else
+ rect.setLocation(topLeft);
+
+ o->computeAbsoluteRepaintRect(rect, fixed);
+}
+
+void RenderBox::repaintDuringLayoutIfMoved(const IntRect& rect)
+{
+ int newX = m_x;
+ int newY = m_y;
+ int newWidth = m_width;
+ int newHeight = m_height;
+ if (rect.x() != newX || rect.y() != newY) {
+ // The child moved. Invalidate the object's old and new positions. We have to do this
+ // since the object may not have gotten a layout.
+ m_x = rect.x();
+ m_y = rect.y();
+ m_width = rect.width();
+ m_height = rect.height();
+ repaint();
+ repaintOverhangingFloats(true);
+
+ m_x = newX;
+ m_y = newY;
+ m_width = newWidth;
+ m_height = newHeight;
+ repaint();
+ repaintOverhangingFloats(true);
+ }
+}
+
+int RenderBox::relativePositionOffsetX() const
+{
+ if (!style()->left().isAuto()) {
+ if (!style()->right().isAuto() && containingBlock()->style()->direction() == RTL)
+ return -style()->right().calcValue(containingBlockWidth());
+ return style()->left().calcValue(containingBlockWidth());
+ }
+ if (!style()->right().isAuto())
+ return -style()->right().calcValue(containingBlockWidth());
+ return 0;
+}
+
+int RenderBox::relativePositionOffsetY() const
+{
+ if (!style()->top().isAuto()) {
+ if (!style()->top().isPercent() || containingBlock()->style()->height().isFixed())
+ return style()->top().calcValue(containingBlockHeight());
+ } else if (!style()->bottom().isAuto()) {
+ if (!style()->bottom().isPercent() || containingBlock()->style()->height().isFixed())
+ return -style()->bottom().calcValue(containingBlockHeight());
+ }
+ return 0;
+}
+
+void RenderBox::calcWidth()
+{
+ if (isPositioned()) {
+ calcAbsoluteHorizontal();
+ return;
+ }
+
+ // If layout is limited to a subtree, the subtree root's width does not change.
+ if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
+ return;
+
+ // The parent box is flexing us, so it has increased or decreased our
+ // width. Use the width from the style context.
+ if (hasOverrideSize() && parent()->style()->boxOrient() == HORIZONTAL
+ && parent()->isFlexibleBox() && parent()->isFlexingChildren()) {
+ m_width = overrideSize();
+ return;
+ }
+
+ bool inVerticalBox = parent()->isFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
+ bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
+ bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inVerticalBox || !stretching);
+
+ Length width = (treatAsReplaced) ? Length(calcReplacedWidth(), Fixed) : style()->width();
+
+ RenderBlock* cb = containingBlock();
+ int containerWidth = max(0, containingBlockWidth());
+
+ Length marginLeft = style()->marginLeft();
+ Length marginRight = style()->marginRight();
+
+ if (isInline() && !isInlineBlockOrInlineTable()) {
+ // just calculate margins
+ m_marginLeft = marginLeft.calcMinValue(containerWidth);
+ m_marginRight = marginRight.calcMinValue(containerWidth);
+ if (treatAsReplaced)
+ m_width = max(width.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(), minPrefWidth());
+
+ return;
+ }
+
+ // Width calculations
+ if (treatAsReplaced)
+ m_width = width.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight();
+ else {
+ // Calculate Width
+ m_width = calcWidthUsing(Width, containerWidth);
+
+ // Calculate MaxWidth
+ if (!style()->maxWidth().isUndefined()) {
+ int maxW = calcWidthUsing(MaxWidth, containerWidth);
+ if (m_width > maxW) {
+ m_width = maxW;
+ width = style()->maxWidth();
+ }
+ }
+
+ // Calculate MinWidth
+ int minW = calcWidthUsing(MinWidth, containerWidth);
+ if (m_width < minW) {
+ m_width = minW;
+ width = style()->minWidth();
+ }
+ }
+
+ if (stretchesToMinIntrinsicWidth()) {
+ m_width = max(m_width, minPrefWidth());
+ width = Length(m_width, Fixed);
+ }
+
+ // Margin calculations
+ if (width.isAuto()) {
+ m_marginLeft = marginLeft.calcMinValue(containerWidth);
+ m_marginRight = marginRight.calcMinValue(containerWidth);
+ } else {
+ m_marginLeft = 0;
+ m_marginRight = 0;
+ calcHorizontalMargins(marginLeft, marginRight, containerWidth);
+ }
+
+ if (containerWidth && containerWidth != (m_width + m_marginLeft + m_marginRight)
+ && !isFloating() && !isInline() && !cb->isFlexibleBox()) {
+ if (cb->style()->direction() == LTR)
+ m_marginRight = containerWidth - m_width - m_marginLeft;
+ else
+ m_marginLeft = containerWidth - m_width - m_marginRight;
+ }
+}
+
+int RenderBox::calcWidthUsing(WidthType widthType, int cw)
+{
+ int width = m_width;
+ Length w;
+ if (widthType == Width)
+ w = style()->width();
+ else if (widthType == MinWidth)
+ w = style()->minWidth();
+ else
+ w = style()->maxWidth();
+
+ if (w.isIntrinsicOrAuto()) {
+ int marginLeft = style()->marginLeft().calcMinValue(cw);
+ int marginRight = style()->marginRight().calcMinValue(cw);
+ if (cw)
+ width = cw - marginLeft - marginRight;
+
+ if (sizesToIntrinsicWidth(widthType)) {
+ width = max(width, minPrefWidth());
+ width = min(width, maxPrefWidth());
+ }
+ } else
+ width = calcBorderBoxWidth(w.calcValue(cw));
+
+ return width;
+}
+
+bool RenderBox::sizesToIntrinsicWidth(WidthType widthType) const
+{
+ // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks,
+ // but they allow text to sit on the same line as the marquee.
+ if (isFloating() || (isCompact() && isInline())
+ || (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
+ return true;
+
+ // This code may look a bit strange. Basically width:intrinsic should clamp the size when testing both
+ // min-width and width. max-width is only clamped if it is also intrinsic.
+ Length width = (widthType == MaxWidth) ? style()->maxWidth() : style()->width();
+ if (width.type() == Intrinsic)
+ return true;
+
+ // Children of a horizontal marquee do not fill the container by default.
+ // FIXME: Need to deal with MAUTO value properly. It could be vertical.
+ if (parent()->style()->overflowX() == OMARQUEE) {
+ EMarqueeDirection dir = parent()->style()->marqueeDirection();
+ if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
+ return true;
+ }
+
+ // Flexible horizontal boxes lay out children at their intrinsic widths. Also vertical boxes
+ // that don't stretch their kids lay out their children at their intrinsic widths.
+ if (parent()->isFlexibleBox()
+ && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
+ return true;
+
+ return false;
+}
+
+void RenderBox::calcHorizontalMargins(const Length& marginLeft, const Length& marginRight, int containerWidth)
+{
+ if (isFloating() || isInline()) {
+ // Inline blocks/tables and floats don't have their margins increased.
+ m_marginLeft = marginLeft.calcMinValue(containerWidth);
+ m_marginRight = marginRight.calcMinValue(containerWidth);
+ return;
+ }
+
+ if ((marginLeft.isAuto() && marginRight.isAuto() && m_width < containerWidth)
+ || (!marginLeft.isAuto() && !marginRight.isAuto() && containingBlock()->style()->textAlign() == WEBKIT_CENTER)) {
+ m_marginLeft = max(0, (containerWidth - m_width) / 2);
+ m_marginRight = containerWidth - m_width - m_marginLeft;
+ } else if ((marginRight.isAuto() && m_width < containerWidth)
+ || (!marginLeft.isAuto() && containingBlock()->style()->direction() == RTL && containingBlock()->style()->textAlign() == WEBKIT_LEFT)) {
+ m_marginLeft = marginLeft.calcValue(containerWidth);
+ m_marginRight = containerWidth - m_width - m_marginLeft;
+ } else if ((marginLeft.isAuto() && m_width < containerWidth)
+ || (!marginRight.isAuto() && containingBlock()->style()->direction() == LTR && containingBlock()->style()->textAlign() == WEBKIT_RIGHT)) {
+ m_marginRight = marginRight.calcValue(containerWidth);
+ m_marginLeft = containerWidth - m_width - m_marginRight;
+ } else {
+ // This makes auto margins 0 if we failed a m_width < containerWidth test above (css2.1, 10.3.3).
+ m_marginLeft = marginLeft.calcMinValue(containerWidth);
+ m_marginRight = marginRight.calcMinValue(containerWidth);
+ }
+}
+
+void RenderBox::calcHeight()
+{
+ // Cell height is managed by the table and inline non-replaced elements do not support a height property.
+ if (isTableCell() || (isInline() && !isReplaced()))
+ return;
+
+ if (isPositioned())
+ calcAbsoluteVertical();
+ else {
+ calcVerticalMargins();
+
+ // For tables, calculate margins only.
+ if (isTable())
+ return;
+
+ Length h;
+ bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
+ bool stretching = parent()->style()->boxAlign() == BSTRETCH;
+ bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inHorizontalBox || !stretching);
+ bool checkMinMaxHeight = false;
+
+ // The parent box is flexing us, so it has increased or decreased our height. We have to
+ // grab our cached flexible height.
+ if (hasOverrideSize() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
+ && parent()->isFlexingChildren())
+ h = Length(overrideSize() - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed);
+ else if (treatAsReplaced)
+ h = Length(calcReplacedHeight(), Fixed);
+ else {
+ h = style()->height();
+ checkMinMaxHeight = true;
+ }
+
+ // Block children of horizontal flexible boxes fill the height of the box.
+ if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
+ && parent()->isStretchingChildren()) {
+ h = Length(parent()->contentHeight() - marginTop() - marginBottom() -
+ borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed);
+ checkMinMaxHeight = false;
+ }
+
+ int height;
+ if (checkMinMaxHeight) {
+ height = calcHeightUsing(style()->height());
+ if (height == -1)
+ height = m_height;
+ int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset.
+ int maxH = style()->maxHeight().isUndefined() ? height : calcHeightUsing(style()->maxHeight());
+ if (maxH == -1)
+ maxH = height;
+ height = min(maxH, height);
+ height = max(minH, height);
+ } else
+ // The only times we don't check min/max height are when a fixed length has
+ // been given as an override. Just use that. The value has already been adjusted
+ // for box-sizing.
+ height = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
+
+ m_height = height;
+ }
+
+ // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the
+ // <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height
+ // is specified.
+ if (stretchesToViewHeight() && !document()->printing()) {
+ int margins = collapsedMarginTop() + collapsedMarginBottom();
+ int visHeight = view()->viewHeight();
+ if (isRoot())
+ m_height = max(m_height, visHeight - margins);
+ else {
+ int marginsBordersPadding = margins + parent()->marginTop() + parent()->marginBottom()
+ + parent()->borderTop() + parent()->borderBottom()
+ + parent()->paddingTop() + parent()->paddingBottom();
+ m_height = max(m_height, visHeight - marginsBordersPadding);
+ }
+ }
+}
+
+int RenderBox::calcHeightUsing(const Length& h)
+{
+ int height = -1;
+ if (!h.isAuto()) {
+ if (h.isFixed())
+ height = h.value();
+ else if (h.isPercent())
+ height = calcPercentageHeight(h);
+ if (height != -1) {
+ height = calcBorderBoxHeight(height);
+ return height;
+ }
+ }
+ return height;
+}
+
+int RenderBox::calcPercentageHeight(const Length& height)
+{
+ int result = -1;
+ bool includeBorderPadding = isTable();
+ RenderBlock* cb = containingBlock();
+ if (style()->htmlHacks()) {
+ // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
+ // block that may have a specified height and then use it. In strict mode, this violates the
+ // 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()) {
+ cb = cb->containingBlock();
+ cb->addPercentHeightDescendant(this);
+ }
+ }
+
+ // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a 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()));
+
+ // 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 = static_cast<RenderTableCell*>(cb);
+ if (scrollsOverflowY() && (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto()))
+ return 0;
+ return -1;
+ }
+ includeBorderPadding = true;
+ }
+ // Otherwise we only use our percentage height if our containing block had a specified
+ // height.
+ else if (cb->style()->height().isFixed())
+ result = cb->calcContentBoxHeight(cb->style()->height().value());
+ else if (cb->style()->height().isPercent() && !isPositionedWithSpecifiedHeight) {
+ // We need to recur and compute the percentage height for our containing block.
+ result = cb->calcPercentageHeight(cb->style()->height());
+ if (result != -1)
+ result = cb->calcContentBoxHeight(result);
+ } else if (cb->isRenderView() || (cb->isBody() && style()->htmlHacks()) || isPositionedWithSpecifiedHeight) {
+ // Don't allow this to affect the block' m_height member variable, since this
+ // can get called while the block is still laying out its kids.
+ int oldHeight = cb->height();
+ cb->calcHeight();
+ result = cb->contentHeight();
+ cb->setHeight(oldHeight);
+ } else if (cb->isRoot() && isPositioned())
+ // Match the positioned objects behavior, which is that positioned objects will fill their viewport
+ // always. Note we could only hit this case by recurring into calcPercentageHeight on a positioned containing block.
+ result = cb->calcContentBoxHeight(cb->availableHeight());
+
+ if (result != -1) {
+ result = height.calcValue(result);
+ if (includeBorderPadding) {
+ // It is necessary to use the border-box to match WinIE's broken
+ // box model. This is essential for sizing inside
+ // table cells using percentage heights.
+ result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
+ result = max(0, result);
+ }
+ }
+ return result;
+}
+
+int RenderBox::calcReplacedWidth(bool includeMaxWidth) const
+{
+ int width = calcReplacedWidthUsing(style()->width());
+ int minW = calcReplacedWidthUsing(style()->minWidth());
+ int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth());
+
+ return max(minW, min(width, maxW));
+}
+
+int RenderBox::calcReplacedWidthUsing(Length width) const
+{
+ switch (width.type()) {
+ case Fixed:
+ return calcContentBoxWidth(width.value());
+ case Percent: {
+ const int cw = isPositioned() ? containingBlockWidthForPositioned(container()) : containingBlockWidth();
+ if (cw > 0)
+ return calcContentBoxWidth(width.calcMinValue(cw));
+ }
+ // fall through
+ default:
+ return intrinsicSize().width();
+ }
+ }
+
+int RenderBox::calcReplacedHeight() const
+{
+ int height = calcReplacedHeightUsing(style()->height());
+ int minH = calcReplacedHeightUsing(style()->minHeight());
+ int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight());
+
+ return max(minH, min(height, maxH));
+}
+
+int RenderBox::calcReplacedHeightUsing(Length height) const
+{
+ switch (height.type()) {
+ case Fixed:
+ return calcContentBoxHeight(height.value());
+ case Percent:
+ {
+ RenderObject* cb = isPositioned() ? container() : containingBlock();
+ while (cb->isAnonymous()) {
+ cb = cb->containingBlock();
+ static_cast<RenderBlock*>(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
+ }
+
+ if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
+ ASSERT(cb->isRenderBlock());
+ RenderBlock* block = static_cast<RenderBlock*>(cb);
+ int oldHeight = block->height();
+ block->calcHeight();
+ int newHeight = block->calcContentBoxHeight(block->contentHeight());
+ block->setHeight(oldHeight);
+ return calcContentBoxHeight(height.calcValue(newHeight));
+ }
+
+ int availableHeight = isPositioned() ? containingBlockHeightForPositioned(cb) : cb->availableHeight();
+
+ // It is necessary to use the border-box to match WinIE's broken
+ // box model. This is essential for sizing inside
+ // table cells using percentage heights.
+ if (cb->isTableCell() && (cb->style()->height().isAuto() || cb->style()->height().isPercent())) {
+ // Don't let table cells squeeze percent-height replaced elements
+ // <http://bugs.webkit.org/show_bug.cgi?id=15359>
+ availableHeight = max(availableHeight, intrinsicSize().height());
+ return height.calcValue(availableHeight - (borderTop() + borderBottom()
+ + paddingTop() + paddingBottom()));
+ }
+
+ return calcContentBoxHeight(height.calcValue(availableHeight));
+ }
+ default:
+ return intrinsicSize().height();
+ }
+}
+
+int RenderBox::availableHeight() const
+{
+ return availableHeightUsing(style()->height());
+}
+
+int RenderBox::availableHeightUsing(const Length& h) const
+{
+ if (h.isFixed())
+ return calcContentBoxHeight(h.value());
+
+ if (isRenderView())
+ return static_cast<const RenderView*>(this)->frameView()->visibleHeight();
+
+ // We need to stop here, since we don't want to increase the height of the table
+ // artificially. We're going to rely on this cell getting expanded to some new
+ // height, and then when we lay out again we'll use the calculation below.
+ if (isTableCell() && (h.isAuto() || h.isPercent()))
+ return overrideSize() - (borderLeft() + borderRight() + paddingLeft() + paddingRight());
+
+ if (h.isPercent())
+ return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight()));
+
+ if (isRenderBlock() && isPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
+ RenderBlock* block = const_cast<RenderBlock*>(static_cast<const RenderBlock*>(this));
+ int oldHeight = block->height();
+ block->calcHeight();
+ int newHeight = block->calcContentBoxHeight(block->contentHeight());
+ block->setHeight(oldHeight);
+ return calcContentBoxHeight(newHeight);
+ }
+
+ return containingBlock()->availableHeight();
+}
+
+void RenderBox::calcVerticalMargins()
+{
+ if (isTableCell()) {
+ m_marginTop = 0;
+ m_marginBottom = 0;
+ return;
+ }
+
+ // margins are calculated with respect to the _width_ of
+ // the containing block (8.3)
+ int cw = containingBlock()->contentWidth();
+
+ m_marginTop = style()->marginTop().calcMinValue(cw);
+ m_marginBottom = style()->marginBottom().calcMinValue(cw);
+}
+
+int RenderBox::staticX() const
+{
+ return m_layer ? m_layer->staticX() : 0;
+}
+
+int RenderBox::staticY() const
+{
+ return m_layer ? m_layer->staticY() : 0;
+}
+
+void RenderBox::setStaticX(int staticX)
+{
+ ASSERT(isPositioned() || isRelPositioned());
+ m_layer->setStaticX(staticX);
+}
+
+void RenderBox::setStaticY(int staticY)
+{
+ ASSERT(isPositioned() || isRelPositioned());
+
+ if (staticY == m_layer->staticY())
+ return;
+
+ m_layer->setStaticY(staticY);
+ setChildNeedsLayout(true, false);
+}
+
+int RenderBox::containingBlockWidthForPositioned(const RenderObject* containingBlock) const
+{
+ if (containingBlock->isInlineFlow()) {
+ ASSERT(containingBlock->isRelPositioned());
+
+ const RenderFlow* flow = static_cast<const RenderFlow*>(containingBlock);
+ InlineFlowBox* first = flow->firstLineBox();
+ InlineFlowBox* last = flow->lastLineBox();
+
+ // If the containing block is empty, return a width of 0.
+ if (!first || !last)
+ return 0;
+
+ int fromLeft;
+ int fromRight;
+ if (containingBlock->style()->direction() == LTR) {
+ fromLeft = first->xPos() + first->borderLeft();
+ fromRight = last->xPos() + last->width() - last->borderRight();
+ } else {
+ fromRight = first->xPos() + first->width() - first->borderRight();
+ fromLeft = last->xPos() + last->borderLeft();
+ }
+
+ return max(0, (fromRight - fromLeft));
+ }
+
+ return containingBlock->width() - containingBlock->borderLeft() - containingBlock->borderRight() - containingBlock->verticalScrollbarWidth();
+}
+
+int RenderBox::containingBlockHeightForPositioned(const RenderObject* containingBlock) const
+{
+ return containingBlock->height() - containingBlock->borderTop() - containingBlock->borderBottom();
+}
+
+void RenderBox::calcAbsoluteHorizontal()
+{
+ if (isReplaced()) {
+ calcAbsoluteHorizontalReplaced();
+ return;
+ }
+
+ // QUESTIONS
+ // FIXME 1: Which RenderObject's 'direction' property should used: the
+ // containing block (cb) as the spec seems to imply, the parent (parent()) as
+ // was previously done in calculating the static distances, or ourself, which
+ // was also previously done for deciding what to override when you had
+ // over-constrained margins? Also note that the container block is used
+ // in similar situations in other parts of the RenderBox class (see calcWidth()
+ // and calcHorizontalMargins()). For now we are using the parent for quirks
+ // mode and the containing block for strict mode.
+
+ // FIXME 2: Should we still deal with these the cases of 'left' or 'right' having
+ // the type 'static' in determining whether to calculate the static distance?
+ // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
+
+ // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater
+ // than or less than the computed m_width. Be careful of box-sizing and
+ // percentage issues.
+
+ // The following is based off of the W3C Working Draft from April 11, 2006 of
+ // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
+ // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
+ // (block-style-comments in this function and in calcAbsoluteHorizontalValues()
+ // correspond to text from the spec)
+
+
+ // We don't use containingBlock(), since we may be positioned by an enclosing
+ // relative positioned inline.
+ const RenderObject* containerBlock = container();
+
+ const int containerWidth = containingBlockWidthForPositioned(containerBlock);
+
+ // To match WinIE, in quirks mode use the parent's 'direction' property
+ // instead of the the container block's.
+ TextDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction();
+
+ const int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
+ const Length marginLeft = style()->marginLeft();
+ const Length marginRight = style()->marginRight();
+ Length left = style()->left();
+ Length right = style()->right();
+
+ /*---------------------------------------------------------------------------*\
+ * For the purposes of this section and the next, the term "static position"
+ * (of an element) refers, roughly, to the position an element would have had
+ * in the normal flow. More precisely:
+ *
+ * * The static position for 'left' is the distance from the left edge of the
+ * containing block to the left margin edge of a hypothetical box that would
+ * have been the first box of the element if its 'position' property had
+ * been 'static' and 'float' had been 'none'. The value is negative if the
+ * hypothetical box is to the left of the containing block.
+ * * The static position for 'right' is the distance from the right edge of the
+ * containing block to the right margin edge of the same hypothetical box as
+ * above. The value is positive if the hypothetical box is to the left of the
+ * containing block's edge.
+ *
+ * But rather than actually calculating the dimensions of that hypothetical box,
+ * user agents are free to make a guess at its probable position.
+ *
+ * For the purposes of calculating the static position, the containing block of
+ * fixed positioned elements is the initial containing block instead of the
+ * viewport, and all scrollable boxes should be assumed to be scrolled to their
+ * origin.
+ \*---------------------------------------------------------------------------*/
+
+ // see FIXME 2
+ // Calculate the static distance if needed.
+ if (left.isAuto() && right.isAuto()) {
+ if (containerDirection == LTR) {
+ // 'staticX' should already have been set through layout of the parent.
+ int staticPosition = staticX() - containerBlock->borderLeft();
+ for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent())
+ staticPosition += po->xPos();
+ left.setValue(Fixed, staticPosition);
+ } else {
+ RenderObject* po = parent();
+ // 'staticX' should already have been set through layout of the parent.
+ int staticPosition = staticX() + containerWidth + containerBlock->borderRight() - po->width();
+ for (; po && po != containerBlock; po = po->parent())
+ staticPosition -= po->xPos();
+ right.setValue(Fixed, staticPosition);
+ }
+ }
+
+ // Calculate constraint equation values for 'width' case.
+ calcAbsoluteHorizontalValues(style()->width(), containerBlock, containerDirection,
+ containerWidth, bordersPlusPadding,
+ left, right, marginLeft, marginRight,
+ m_width, m_marginLeft, m_marginRight, m_x);
+
+ // Calculate constraint equation values for 'max-width' case.
+ if (!style()->maxWidth().isUndefined()) {
+ int maxWidth;
+ int maxMarginLeft;
+ int maxMarginRight;
+ int maxXPos;
+
+ calcAbsoluteHorizontalValues(style()->maxWidth(), containerBlock, containerDirection,
+ containerWidth, bordersPlusPadding,
+ left, right, marginLeft, marginRight,
+ maxWidth, maxMarginLeft, maxMarginRight, maxXPos);
+
+ if (m_width > maxWidth) {
+ m_width = maxWidth;
+ m_marginLeft = maxMarginLeft;
+ m_marginRight = maxMarginRight;
+ m_x = maxXPos;
+ }
+ }
+
+ // Calculate constraint equation values for 'min-width' case.
+ if (!style()->minWidth().isZero()) {
+ int minWidth;
+ int minMarginLeft;
+ int minMarginRight;
+ int minXPos;
+
+ calcAbsoluteHorizontalValues(style()->minWidth(), containerBlock, containerDirection,
+ containerWidth, bordersPlusPadding,
+ left, right, marginLeft, marginRight,
+ minWidth, minMarginLeft, minMarginRight, minXPos);
+
+ if (m_width < minWidth) {
+ m_width = minWidth;
+ m_marginLeft = minMarginLeft;
+ m_marginRight = minMarginRight;
+ m_x = minXPos;
+ }
+ }
+
+ if (stretchesToMinIntrinsicWidth() && m_width < minPrefWidth() - bordersPlusPadding)
+ calcAbsoluteHorizontalValues(Length(minPrefWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection,
+ containerWidth, bordersPlusPadding,
+ left, right, marginLeft, marginRight,
+ m_width, m_marginLeft, m_marginRight, m_x);
+
+ // Put m_width into correct form.
+ m_width += bordersPlusPadding;
+}
+
+void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderObject* containerBlock, TextDirection containerDirection,
+ const int containerWidth, const int bordersPlusPadding,
+ const Length left, const Length right, const Length marginLeft, const Length marginRight,
+ 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
+ ASSERT(!(left.isAuto() && right.isAuto()));
+
+ int leftValue = 0;
+
+ bool widthIsAuto = width.isIntrinsicOrAuto();
+ bool leftIsAuto = left.isAuto();
+ bool rightIsAuto = right.isAuto();
+
+ if (!leftIsAuto && !widthIsAuto && !rightIsAuto) {
+ /*-----------------------------------------------------------------------*\
+ * If none of the three is 'auto': If both 'margin-left' and 'margin-
+ * right' are 'auto', solve the equation under the extra constraint that
+ * the two margins get equal values, unless this would make them negative,
+ * in which case when direction of the containing block is 'ltr' ('rtl'),
+ * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
+ * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
+ * solve the equation for that value. If the values are over-constrained,
+ * ignore the value for 'left' (in case the 'direction' property of the
+ * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
+ * and solve for that value.
+ \*-----------------------------------------------------------------------*/
+ // NOTE: It is not necessary to solve for 'right' in the over constrained
+ // case because the value is not used for any further calculations.
+
+ leftValue = left.calcValue(containerWidth);
+ widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
+
+ const int availableSpace = containerWidth - (leftValue + widthValue + right.calcValue(containerWidth) + bordersPlusPadding);
+
+ // Margins are now the only unknown
+ if (marginLeft.isAuto() && marginRight.isAuto()) {
+ // Both margins auto, solve for equality
+ if (availableSpace >= 0) {
+ marginLeftValue = availableSpace / 2; // split the diference
+ marginRightValue = availableSpace - marginLeftValue; // account for odd valued differences
+ } else {
+ // see FIXME 1
+ if (containerDirection == LTR) {
+ marginLeftValue = 0;
+ marginRightValue = availableSpace; // will be negative
+ } else {
+ marginLeftValue = availableSpace; // will be negative
+ marginRightValue = 0;
+ }
+ }
+ } else if (marginLeft.isAuto()) {
+ // Solve for left margin
+ marginRightValue = marginRight.calcValue(containerWidth);
+ marginLeftValue = availableSpace - marginRightValue;
+ } else if (marginRight.isAuto()) {
+ // Solve for right margin
+ marginLeftValue = marginLeft.calcValue(containerWidth);
+ marginRightValue = availableSpace - marginLeftValue;
+ } else {
+ // Over-constrained, solve for left if direction is RTL
+ marginLeftValue = marginLeft.calcValue(containerWidth);
+ marginRightValue = marginRight.calcValue(containerWidth);
+
+ // see FIXME 1 -- used to be "this->style()->direction()"
+ if (containerDirection == RTL)
+ leftValue = (availableSpace + leftValue) - marginLeftValue - marginRightValue;
+ }
+ } else {
+ /*--------------------------------------------------------------------*\
+ * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
+ * to 0, and pick the one of the following six rules that applies.
+ *
+ * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
+ * width is shrink-to-fit. Then solve for 'left'
+ *
+ * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
+ * ------------------------------------------------------------------
+ * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
+ * the 'direction' property of the containing block is 'ltr' set
+ * 'left' to the static position, otherwise set 'right' to the
+ * static position. Then solve for 'left' (if 'direction is 'rtl')
+ * or 'right' (if 'direction' is 'ltr').
+ * ------------------------------------------------------------------
+ *
+ * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
+ * width is shrink-to-fit . Then solve for 'right'
+ * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
+ * for 'left'
+ * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
+ * for 'width'
+ * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
+ * for 'right'
+ *
+ * Calculation of the shrink-to-fit width is similar to calculating the
+ * width of a table cell using the automatic table layout algorithm.
+ * Roughly: calculate the preferred width by formatting the content
+ * without breaking lines other than where explicit line breaks occur,
+ * and also calculate the preferred minimum width, e.g., by trying all
+ * possible line breaks. CSS 2.1 does not define the exact algorithm.
+ * Thirdly, calculate the available width: this is found by solving
+ * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
+ * to 0.
+ *
+ * Then the shrink-to-fit width is:
+ * min(max(preferred minimum width, available width), preferred width).
+ \*--------------------------------------------------------------------*/
+ // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
+ // because the value is not used for any further calculations.
+
+ // Calculate margins, 'auto' margins are ignored.
+ marginLeftValue = marginLeft.calcMinValue(containerWidth);
+ marginRightValue = marginRight.calcMinValue(containerWidth);
+
+ const int availableSpace = containerWidth - (marginLeftValue + marginRightValue + bordersPlusPadding);
+
+ // FIXME: Is there a faster way to find the correct case?
+ // Use rule/case that applies.
+ if (leftIsAuto && widthIsAuto && !rightIsAuto) {
+ // RULE 1: (use shrink-to-fit for width, and solve of left)
+ int rightValue = right.calcValue(containerWidth);
+
+ // FIXME: would it be better to have shrink-to-fit in one step?
+ int preferredWidth = maxPrefWidth() - bordersPlusPadding;
+ int preferredMinWidth = minPrefWidth() - bordersPlusPadding;
+ int availableWidth = availableSpace - rightValue;
+ widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
+ leftValue = availableSpace - (widthValue + rightValue);
+ } else if (!leftIsAuto && widthIsAuto && rightIsAuto) {
+ // RULE 3: (use shrink-to-fit for width, and no need solve of right)
+ leftValue = left.calcValue(containerWidth);
+
+ // FIXME: would it be better to have shrink-to-fit in one step?
+ int preferredWidth = maxPrefWidth() - bordersPlusPadding;
+ int preferredMinWidth = minPrefWidth() - bordersPlusPadding;
+ int availableWidth = availableSpace - leftValue;
+ widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
+ } else if (leftIsAuto && !width.isAuto() && !rightIsAuto) {
+ // RULE 4: (solve for left)
+ widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
+ leftValue = availableSpace - (widthValue + right.calcValue(containerWidth));
+ } else if (!leftIsAuto && widthIsAuto && !rightIsAuto) {
+ // RULE 5: (solve for width)
+ leftValue = left.calcValue(containerWidth);
+ widthValue = availableSpace - (leftValue + right.calcValue(containerWidth));
+ } else if (!leftIsAuto&& !widthIsAuto && rightIsAuto) {
+ // RULE 6: (no need solve for right)
+ leftValue = left.calcValue(containerWidth);
+ widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
+ }
+ }
+
+ // Use computed values to calculate the horizontal position.
+
+ // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively
+ // 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) {
+ const RenderFlow* flow = static_cast<const RenderFlow*>(containerBlock);
+ InlineFlowBox* firstLine = flow->firstLineBox();
+ InlineFlowBox* lastLine = flow->lastLineBox();
+ if (firstLine && lastLine && firstLine != lastLine) {
+ xPos = leftValue + marginLeftValue + lastLine->borderLeft() + (lastLine->xPos() - firstLine->xPos());
+ return;
+ }
+ }
+
+ xPos = leftValue + marginLeftValue + containerBlock->borderLeft();
+}
+
+void RenderBox::calcAbsoluteVertical()
+{
+ if (isReplaced()) {
+ calcAbsoluteVerticalReplaced();
+ return;
+ }
+
+ // The following is based off of the W3C Working Draft from April 11, 2006 of
+ // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
+ // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
+ // (block-style-comments in this function and in calcAbsoluteVerticalValues()
+ // correspond to text from the spec)
+
+
+ // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
+ const RenderObject* containerBlock = container();
+
+ const int containerHeight = containingBlockHeightForPositioned(containerBlock);
+
+ const int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
+ const Length marginTop = style()->marginTop();
+ const Length marginBottom = style()->marginBottom();
+ Length top = style()->top();
+ Length bottom = style()->bottom();
+
+ /*---------------------------------------------------------------------------*\
+ * For the purposes of this section and the next, the term "static position"
+ * (of an element) refers, roughly, to the position an element would have had
+ * in the normal flow. More precisely, the static position for 'top' is the
+ * distance from the top edge of the containing block to the top margin edge
+ * of a hypothetical box that would have been the first box of the element if
+ * its 'position' property had been 'static' and 'float' had been 'none'. The
+ * value is negative if the hypothetical box is above the containing block.
+ *
+ * But rather than actually calculating the dimensions of that hypothetical
+ * box, user agents are free to make a guess at its probable position.
+ *
+ * For the purposes of calculating the static position, the containing block
+ * of fixed positioned elements is the initial containing block instead of
+ * the viewport.
+ \*---------------------------------------------------------------------------*/
+
+ // see FIXME 2
+ // Calculate the static distance if needed.
+ if (top.isAuto() && bottom.isAuto()) {
+ // staticY should already have been set through layout of the parent()
+ int staticTop = staticY() - containerBlock->borderTop();
+ for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
+ if (!po->isTableRow())
+ staticTop += po->yPos();
+ }
+ top.setValue(Fixed, staticTop);
+ }
+
+
+ int height; // Needed to compute overflow.
+
+ // Calculate constraint equation values for 'height' case.
+ calcAbsoluteVerticalValues(style()->height(), containerBlock, containerHeight, bordersPlusPadding,
+ top, bottom, marginTop, marginBottom,
+ height, m_marginTop, m_marginBottom, m_y);
+
+ // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
+ // see FIXME 3
+
+ // Calculate constraint equation values for 'max-height' case.
+ if (!style()->maxHeight().isUndefined()) {
+ int maxHeight;
+ int maxMarginTop;
+ int maxMarginBottom;
+ int maxYPos;
+
+ calcAbsoluteVerticalValues(style()->maxHeight(), containerBlock, containerHeight, bordersPlusPadding,
+ top, bottom, marginTop, marginBottom,
+ maxHeight, maxMarginTop, maxMarginBottom, maxYPos);
+
+ if (height > maxHeight) {
+ height = maxHeight;
+ m_marginTop = maxMarginTop;
+ m_marginBottom = maxMarginBottom;
+ m_y = maxYPos;
+ }
+ }
+
+ // Calculate constraint equation values for 'min-height' case.
+ if (!style()->minHeight().isZero()) {
+ int minHeight;
+ int minMarginTop;
+ int minMarginBottom;
+ int minYPos;
+
+ calcAbsoluteVerticalValues(style()->minHeight(), containerBlock, containerHeight, bordersPlusPadding,
+ top, bottom, marginTop, marginBottom,
+ minHeight, minMarginTop, minMarginBottom, minYPos);
+
+ if (height < minHeight) {
+ height = minHeight;
+ m_marginTop = minMarginTop;
+ m_marginBottom = minMarginBottom;
+ m_y = minYPos;
+ }
+ }
+
+ // Set final height value.
+ m_height = height + bordersPlusPadding;
+}
+
+void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* containerBlock,
+ const int containerHeight, const int bordersPlusPadding,
+ const Length top, const Length bottom, const Length marginTop, const Length marginBottom,
+ int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos)
+{
+ // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
+ // converted to the static position in calcAbsoluteVertical()
+ ASSERT(!(top.isAuto() && bottom.isAuto()));
+
+ int contentHeight = m_height - bordersPlusPadding;
+
+ int topValue = 0;
+
+ bool heightIsAuto = height.isAuto();
+ bool topIsAuto = top.isAuto();
+ bool bottomIsAuto = bottom.isAuto();
+
+ // Height is never unsolved for tables.
+ if (isTable()) {
+ height.setValue(Fixed, contentHeight);
+ heightIsAuto = false;
+ }
+
+ if (!topIsAuto && !heightIsAuto && !bottomIsAuto) {
+ /*-----------------------------------------------------------------------*\
+ * If none of the three are 'auto': If both 'margin-top' and 'margin-
+ * bottom' are 'auto', solve the equation under the extra constraint that
+ * the two margins get equal values. If one of 'margin-top' or 'margin-
+ * bottom' is 'auto', solve the equation for that value. If the values
+ * are over-constrained, ignore the value for 'bottom' and solve for that
+ * value.
+ \*-----------------------------------------------------------------------*/
+ // NOTE: It is not necessary to solve for 'bottom' in the over constrained
+ // case because the value is not used for any further calculations.
+
+ heightValue = calcContentBoxHeight(height.calcValue(containerHeight));
+ topValue = top.calcValue(containerHeight);
+
+ const int availableSpace = containerHeight - (topValue + heightValue + bottom.calcValue(containerHeight) + bordersPlusPadding);
+
+ // Margins are now the only unknown
+ if (marginTop.isAuto() && marginBottom.isAuto()) {
+ // Both margins auto, solve for equality
+ // NOTE: This may result in negative values.
+ marginTopValue = availableSpace / 2; // split the diference
+ marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences
+ } else if (marginTop.isAuto()) {
+ // Solve for top margin
+ marginBottomValue = marginBottom.calcValue(containerHeight);
+ marginTopValue = availableSpace - marginBottomValue;
+ } else if (marginBottom.isAuto()) {
+ // Solve for bottom margin
+ marginTopValue = marginTop.calcValue(containerHeight);
+ marginBottomValue = availableSpace - marginTopValue;
+ } else {
+ // Over-constrained, (no need solve for bottom)
+ marginTopValue = marginTop.calcValue(containerHeight);
+ marginBottomValue = marginBottom.calcValue(containerHeight);
+ }
+ } else {
+ /*--------------------------------------------------------------------*\
+ * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
+ * to 0, and pick the one of the following six rules that applies.
+ *
+ * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
+ * the height is based on the content, and solve for 'top'.
+ *
+ * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
+ * ------------------------------------------------------------------
+ * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
+ * set 'top' to the static position, and solve for 'bottom'.
+ * ------------------------------------------------------------------
+ *
+ * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
+ * the height is based on the content, and solve for 'bottom'.
+ * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
+ * solve for 'top'.
+ * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
+ * solve for 'height'.
+ * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
+ * solve for 'bottom'.
+ \*--------------------------------------------------------------------*/
+ // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
+ // because the value is not used for any further calculations.
+
+ // Calculate margins, 'auto' margins are ignored.
+ marginTopValue = marginTop.calcMinValue(containerHeight);
+ marginBottomValue = marginBottom.calcMinValue(containerHeight);
+
+ const int availableSpace = containerHeight - (marginTopValue + marginBottomValue + bordersPlusPadding);
+
+ // Use rule/case that applies.
+ if (topIsAuto && heightIsAuto && !bottomIsAuto) {
+ // RULE 1: (height is content based, solve of top)
+ heightValue = contentHeight;
+ topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
+ } else if (!topIsAuto && heightIsAuto && bottomIsAuto) {
+ // RULE 3: (height is content based, no need solve of bottom)
+ topValue = top.calcValue(containerHeight);
+ heightValue = contentHeight;
+ } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) {
+ // RULE 4: (solve of top)
+ heightValue = calcContentBoxHeight(height.calcValue(containerHeight));
+ topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
+ } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) {
+ // RULE 5: (solve of height)
+ topValue = top.calcValue(containerHeight);
+ heightValue = max(0, availableSpace - (topValue + bottom.calcValue(containerHeight)));
+ } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) {
+ // RULE 6: (no need solve of bottom)
+ heightValue = calcContentBoxHeight(height.calcValue(containerHeight));
+ topValue = top.calcValue(containerHeight);
+ }
+ }
+
+ // Use computed values to calculate the vertical position.
+ yPos = topValue + marginTopValue + containerBlock->borderTop();
+}
+
+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"
+ // <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)
+
+ // We don't use containingBlock(), since we may be positioned by an enclosing
+ // relative positioned inline.
+ const RenderObject* containerBlock = container();
+
+ const int containerWidth = containingBlockWidthForPositioned(containerBlock);
+
+ // To match WinIE, in quirks mode use the parent's 'direction' property
+ // instead of the the container block's.
+ TextDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction();
+
+ // Variables to solve.
+ Length left = style()->left();
+ Length right = style()->right();
+ Length marginLeft = style()->marginLeft();
+ Length marginRight = style()->marginRight();
+
+
+ /*-----------------------------------------------------------------------*\
+ * 1. The used value of 'width' is determined as for inline replaced
+ * elements.
+ \*-----------------------------------------------------------------------*/
+ // NOTE: This value of width is FINAL in that the min/max width calculations
+ // are dealt with in calcReplacedWidth(). This means that the steps to produce
+ // correct max/min in the non-replaced version, are not necessary.
+ m_width = calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight();
+ const int availableSpace = containerWidth - m_width;
+
+ /*-----------------------------------------------------------------------*\
+ * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
+ * of the containing block is 'ltr', set 'left' to the static position;
+ * else if 'direction' is 'rtl', set 'right' to the static position.
+ \*-----------------------------------------------------------------------*/
+ // see FIXME 2
+ if (left.isAuto() && right.isAuto()) {
+ // see FIXME 1
+ if (containerDirection == LTR) {
+ // 'staticX' should already have been set through layout of the parent.
+ int staticPosition = staticX() - containerBlock->borderLeft();
+ for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent())
+ staticPosition += po->xPos();
+ left.setValue(Fixed, staticPosition);
+ } else {
+ RenderObject* po = parent();
+ // 'staticX' should already have been set through layout of the parent.
+ int staticPosition = staticX() + containerWidth + containerBlock->borderRight() - po->width();
+ for (; po && po != containerBlock; po = po->parent())
+ staticPosition -= po->xPos();
+ right.setValue(Fixed, staticPosition);
+ }
+ }
+
+ /*-----------------------------------------------------------------------*\
+ * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
+ * or 'margin-right' with '0'.
+ \*-----------------------------------------------------------------------*/
+ if (left.isAuto() || right.isAuto()) {
+ if (marginLeft.isAuto())
+ marginLeft.setValue(Fixed, 0);
+ if (marginRight.isAuto())
+ marginRight.setValue(Fixed, 0);
+ }
+
+ /*-----------------------------------------------------------------------*\
+ * 4. If at this point both 'margin-left' and 'margin-right' are still
+ * 'auto', solve the equation under the extra constraint that the two
+ * margins must get equal values, unless this would make them negative,
+ * in which case when the direction of the containing block is 'ltr'
+ * ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
+ * 'margin-right' ('margin-left').
+ \*-----------------------------------------------------------------------*/
+ int leftValue = 0;
+ int rightValue = 0;
+
+ if (marginLeft.isAuto() && marginRight.isAuto()) {
+ // 'left' and 'right' cannot be 'auto' due to step 3
+ ASSERT(!(left.isAuto() && right.isAuto()));
+
+ leftValue = left.calcValue(containerWidth);
+ rightValue = right.calcValue(containerWidth);
+
+ int difference = availableSpace - (leftValue + rightValue);
+ if (difference > 0) {
+ m_marginLeft = difference / 2; // split the diference
+ m_marginRight = difference - m_marginLeft; // account for odd valued differences
+ } else {
+ // see FIXME 1
+ if (containerDirection == LTR) {
+ m_marginLeft = 0;
+ m_marginRight = difference; // will be negative
+ } else {
+ m_marginLeft = difference; // will be negative
+ m_marginRight = 0;
+ }
+ }
+
+ /*-----------------------------------------------------------------------*\
+ * 5. If at this point there is an 'auto' left, solve the equation for
+ * that value.
+ \*-----------------------------------------------------------------------*/
+ } else if (left.isAuto()) {
+ m_marginLeft = marginLeft.calcValue(containerWidth);
+ m_marginRight = marginRight.calcValue(containerWidth);
+ rightValue = right.calcValue(containerWidth);
+
+ // Solve for 'left'
+ leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight);
+ } else if (right.isAuto()) {
+ m_marginLeft = marginLeft.calcValue(containerWidth);
+ m_marginRight = marginRight.calcValue(containerWidth);
+ leftValue = left.calcValue(containerWidth);
+
+ // Solve for 'right'
+ rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight);
+ } else if (marginLeft.isAuto()) {
+ m_marginRight = marginRight.calcValue(containerWidth);
+ leftValue = left.calcValue(containerWidth);
+ rightValue = right.calcValue(containerWidth);
+
+ // Solve for 'margin-left'
+ m_marginLeft = availableSpace - (leftValue + rightValue + m_marginRight);
+ } else if (marginRight.isAuto()) {
+ m_marginLeft = marginLeft.calcValue(containerWidth);
+ leftValue = left.calcValue(containerWidth);
+ rightValue = right.calcValue(containerWidth);
+
+ // Solve for 'margin-right'
+ m_marginRight = availableSpace - (leftValue + rightValue + m_marginLeft);
+ } else {
+ // Nothing is 'auto', just calculate the values.
+ m_marginLeft = marginLeft.calcValue(containerWidth);
+ m_marginRight = marginRight.calcValue(containerWidth);
+ rightValue = right.calcValue(containerWidth);
+ leftValue = left.calcValue(containerWidth);
+ }
+
+ /*-----------------------------------------------------------------------*\
+ * 6. If at this point the values are over-constrained, ignore the value
+ * for either 'left' (in case the 'direction' property of the
+ * containing block is 'rtl') or 'right' (in case 'direction' is
+ * 'ltr') and solve for that value.
+ \*-----------------------------------------------------------------------*/
+ // NOTE: It is not necessary to solve for 'right' when the direction is
+ // LTR because the value is not used.
+ int totalWidth = m_width + leftValue + rightValue + m_marginLeft + m_marginRight;
+ if (totalWidth > containerWidth && (containerDirection == RTL))
+ leftValue = containerWidth - (totalWidth - leftValue);
+
+ // Use computed values to calculate the horizontal position.
+
+ // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively
+ // 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) {
+ const RenderFlow* flow = static_cast<const RenderFlow*>(containerBlock);
+ InlineFlowBox* firstLine = flow->firstLineBox();
+ InlineFlowBox* lastLine = flow->lastLineBox();
+ if (firstLine && lastLine && firstLine != lastLine) {
+ m_x = leftValue + m_marginLeft + lastLine->borderLeft() + (lastLine->xPos() - firstLine->xPos());
+ return;
+ }
+ }
+
+ m_x = leftValue + m_marginLeft + containerBlock->borderLeft();
+}
+
+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"
+ // <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)
+
+ // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
+ const RenderObject* containerBlock = container();
+
+ const int containerHeight = containingBlockHeightForPositioned(containerBlock);
+
+ // Variables to solve.
+ Length top = style()->top();
+ Length bottom = style()->bottom();
+ Length marginTop = style()->marginTop();
+ Length marginBottom = style()->marginBottom();
+
+
+ /*-----------------------------------------------------------------------*\
+ * 1. The used value of 'height' is determined as for inline replaced
+ * elements.
+ \*-----------------------------------------------------------------------*/
+ // NOTE: This value of height is FINAL in that the min/max height calculations
+ // are dealt with in calcReplacedHeight(). This means that the steps to produce
+ // correct max/min in the non-replaced version, are not necessary.
+ m_height = calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
+ const int availableSpace = containerHeight - m_height;
+
+ /*-----------------------------------------------------------------------*\
+ * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
+ * with the element's static position.
+ \*-----------------------------------------------------------------------*/
+ // see FIXME 2
+ if (top.isAuto() && bottom.isAuto()) {
+ // staticY should already have been set through layout of the parent().
+ int staticTop = staticY() - containerBlock->borderTop();
+ for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
+ if (!po->isTableRow())
+ staticTop += po->yPos();
+ }
+ top.setValue(Fixed, staticTop);
+ }
+
+ /*-----------------------------------------------------------------------*\
+ * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
+ * 'margin-bottom' with '0'.
+ \*-----------------------------------------------------------------------*/
+ // FIXME: The spec. says that this step should only be taken when bottom is
+ // auto, but if only top is auto, this makes step 4 impossible.
+ if (top.isAuto() || bottom.isAuto()) {
+ if (marginTop.isAuto())
+ marginTop.setValue(Fixed, 0);
+ if (marginBottom.isAuto())
+ marginBottom.setValue(Fixed, 0);
+ }
+
+ /*-----------------------------------------------------------------------*\
+ * 4. If at this point both 'margin-top' and 'margin-bottom' are still
+ * 'auto', solve the equation under the extra constraint that the two
+ * margins must get equal values.
+ \*-----------------------------------------------------------------------*/
+ int topValue = 0;
+ int bottomValue = 0;
+
+ if (marginTop.isAuto() && marginBottom.isAuto()) {
+ // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combinded.
+ ASSERT(!(top.isAuto() || bottom.isAuto()));
+
+ topValue = top.calcValue(containerHeight);
+ bottomValue = bottom.calcValue(containerHeight);
+
+ int difference = availableSpace - (topValue + bottomValue);
+ // NOTE: This may result in negative values.
+ m_marginTop = difference / 2; // split the difference
+ m_marginBottom = difference - m_marginTop; // account for odd valued differences
+
+ /*-----------------------------------------------------------------------*\
+ * 5. If at this point there is only one 'auto' left, solve the equation
+ * for that value.
+ \*-----------------------------------------------------------------------*/
+ } else if (top.isAuto()) {
+ m_marginTop = marginTop.calcValue(containerHeight);
+ m_marginBottom = marginBottom.calcValue(containerHeight);
+ bottomValue = bottom.calcValue(containerHeight);
+
+ // Solve for 'top'
+ topValue = availableSpace - (bottomValue + m_marginTop + m_marginBottom);
+ } else if (bottom.isAuto()) {
+ m_marginTop = marginTop.calcValue(containerHeight);
+ m_marginBottom = marginBottom.calcValue(containerHeight);
+ topValue = top.calcValue(containerHeight);
+
+ // Solve for 'bottom'
+ // NOTE: It is not necessary to solve for 'bottom' because we don't ever
+ // use the value.
+ } else if (marginTop.isAuto()) {
+ m_marginBottom = marginBottom.calcValue(containerHeight);
+ topValue = top.calcValue(containerHeight);
+ bottomValue = bottom.calcValue(containerHeight);
+
+ // Solve for 'margin-top'
+ m_marginTop = availableSpace - (topValue + bottomValue + m_marginBottom);
+ } else if (marginBottom.isAuto()) {
+ m_marginTop = marginTop.calcValue(containerHeight);
+ topValue = top.calcValue(containerHeight);
+ bottomValue = bottom.calcValue(containerHeight);
+
+ // Solve for 'margin-bottom'
+ m_marginBottom = availableSpace - (topValue + bottomValue + m_marginTop);
+ } else {
+ // Nothing is 'auto', just calculate the values.
+ m_marginTop = marginTop.calcValue(containerHeight);
+ m_marginBottom = marginBottom.calcValue(containerHeight);
+ topValue = top.calcValue(containerHeight);
+ // NOTE: It is not necessary to solve for 'bottom' because we don't ever
+ // use the value.
+ }
+
+ /*-----------------------------------------------------------------------*\
+ * 6. If at this point the values are over-constrained, ignore the value
+ * for 'bottom' and solve for that value.
+ \*-----------------------------------------------------------------------*/
+ // NOTE: It is not necessary to do this step because we don't end up using
+ // the value of 'bottom' regardless of whether the values are over-constrained
+ // or not.
+
+ // Use computed values to calculate the vertical position.
+ m_y = topValue + m_marginTop + containerBlock->borderTop();
+}
+
+IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine)
+{
+ // VisiblePositions at offsets inside containers either a) refer to the positions before/after
+ // those containers (tables and select elements) or b) refer to the position inside an empty block.
+ // They never refer to children.
+ // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
+
+ // FIXME: What about border and padding?
+ const int caretWidth = 1;
+ IntRect rect(xPos(), yPos(), caretWidth, m_height);
+ TextDirection direction = box ? box->direction() : style()->direction();
+
+ if ((!caretOffset) ^ (direction == LTR))
+ rect.move(IntSize(m_width - caretWidth, 0));
+
+ if (box) {
+ RootInlineBox* rootBox = box->root();
+ int top = rootBox->topOverflow();
+ rect.setY(top);
+ rect.setHeight(rootBox->bottomOverflow() - top);
+ }
+
+ // If height of box is smaller than font height, use the latter one,
+ // otherwise the caret might become invisible.
+ //
+ // Also, if the box is not a replaced element, always use the font height.
+ // This prevents the "big caret" bug described in:
+ // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
+ //
+ // FIXME: ignoring :first-line, missing good reason to take care of
+ int fontHeight = style()->font().height();
+ if (fontHeight > rect.height() || !isReplaced() && !isTable())
+ rect.setHeight(fontHeight);
+
+ if (extraWidthToEndOfLine)
+ *extraWidthToEndOfLine = xPos() + m_width - rect.right();
+
+ // Move to local coords
+ rect.move(-xPos(), -yPos());
+ return rect;
+}
+
+int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
+{
+ if (!includeSelf || !m_width)
+ return 0;
+ int bottom = m_height;
+ if (isRelPositioned())
+ bottom += relativePositionOffsetY();
+ return bottom;
+}
+
+int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
+{
+ if (!includeSelf || !m_height)
+ return 0;
+ int right = m_width;
+ if (isRelPositioned())
+ right += relativePositionOffsetX();
+ return right;
+}
+
+int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
+{
+ if (!includeSelf || !m_height)
+ return m_width;
+ int left = 0;
+ if (isRelPositioned())
+ left += relativePositionOffsetX();
+ return left;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBox.h b/src/3rdparty/webkit/WebCore/rendering/RenderBox.h
new file mode 100644
index 0000000..54349fa
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderBox.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2006, 2007 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 RenderBox_h
+#define RenderBox_h
+
+#include "RenderObject.h"
+
+namespace WebCore {
+
+ enum WidthType { Width, MinWidth, MaxWidth };
+
+class RenderBox : public RenderObject {
+public:
+ RenderBox(Node*);
+ virtual ~RenderBox();
+
+ virtual const char* renderName() const { return "RenderBox"; }
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ virtual void destroy();
+
+ virtual int minPrefWidth() const;
+ virtual int maxPrefWidth() const;
+
+ virtual int overrideSize() const;
+ virtual int overrideWidth() const;
+ virtual int overrideHeight() const;
+ virtual void setOverrideSize(int);
+
+ virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const;
+ virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const;
+ virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const;
+
+ virtual IntSize offsetFromContainer(RenderObject*) const;
+
+ virtual int xPos() const { return m_x; }
+ virtual int yPos() const { return m_y; }
+ virtual void setPos(int x, int y);
+
+ virtual int width() const { return m_width; }
+ virtual int height() const { return m_height; }
+ virtual void setWidth(int width) { m_width = width; }
+ virtual void setHeight(int height) { m_height = height; }
+
+ virtual int marginTop() const { return m_marginTop; }
+ virtual int marginBottom() const { return m_marginBottom; }
+ virtual int marginLeft() const { return m_marginLeft; }
+ virtual int marginRight() const { return m_marginRight; }
+
+ virtual IntRect borderBox() const { return IntRect(0, -borderTopExtra(), width(), height() + borderTopExtra() + borderBottomExtra()); }
+
+ int calcBorderBoxWidth(int width) const;
+ int calcBorderBoxHeight(int height) const;
+ int calcContentBoxWidth(int width) const;
+ int calcContentBoxHeight(int height) const;
+
+ virtual void borderFitAdjust(int& /*x*/, int& /*w*/) const { } // Shrink the box in which the border paints if border-fit is set.
+
+ // This method is now public so that centered objects like tables that are
+ // shifted right by left-aligned floats can recompute their left and
+ // right margins (so that they can remain centered after being
+ // shifted. -dwh
+ void calcHorizontalMargins(const Length& marginLeft, const Length& marginRight, int containerWidth);
+
+ virtual void position(InlineBox*);
+
+ virtual void dirtyLineBoxes(bool fullLayout, bool isRootLineBox = false);
+
+ // For inline replaced elements, this function returns the inline box that owns us. Enables
+ // the replaced RenderObject to quickly determine what line it is contained on and to easily
+ // iterate over structures on the line.
+ virtual InlineBox* inlineBoxWrapper() const { return m_inlineBoxWrapper; }
+ virtual void setInlineBoxWrapper(InlineBox* boxWrapper) { m_inlineBoxWrapper = boxWrapper; }
+ virtual void deleteLineBoxWrapper();
+
+ 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;
+
+ virtual IntRect absoluteClippedOverflowRect();
+ virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false);
+ IntSize offsetForPositionedInContainer(RenderObject*) const;
+
+ virtual void repaintDuringLayoutIfMoved(const IntRect&);
+
+ virtual int containingBlockWidth() const;
+
+ virtual void calcWidth();
+ virtual void calcHeight();
+
+ bool stretchesToViewHeight() const
+ {
+ return style()->htmlHacks() && style()->height().isAuto() && !isFloatingOrPositioned() && (isRoot() || isBody());
+ }
+
+ virtual IntSize intrinsicSize() const { return IntSize(); }
+
+ // Whether or not the element shrinks to its intrinsic width (rather than filling the width
+ // of a containing block). HTML4 buttons, <select>s, <input>s, legends, and floating/compact elements do this.
+ bool sizesToIntrinsicWidth(WidthType) const;
+ virtual bool stretchesToMinIntrinsicWidth() const { return false; }
+
+ int calcWidthUsing(WidthType, int containerWidth);
+ int calcHeightUsing(const Length& height);
+ int calcReplacedWidthUsing(Length width) const;
+ int calcReplacedHeightUsing(Length height) const;
+
+ virtual int calcReplacedWidth(bool includeMaxWidth = true) const;
+ virtual int calcReplacedHeight() const;
+
+ int calcPercentageHeight(const Length& height);
+
+ virtual int availableHeight() const;
+ int availableHeightUsing(const Length&) const;
+
+ void calcVerticalMargins();
+
+ int relativePositionOffsetX() const;
+ int relativePositionOffsetY() const;
+ IntSize relativePositionOffset() const { return IntSize(relativePositionOffsetX(), relativePositionOffsetY()); }
+
+ virtual RenderLayer* layer() const { return m_layer; }
+
+ virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
+
+ virtual void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int clipY, int clipHeight,
+ int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver);
+ IntSize calculateBackgroundSize(const FillLayer*, int scaledWidth, int scaledHeight) const;
+
+ virtual int staticX() const;
+ virtual int staticY() const;
+ virtual void setStaticX(int staticX);
+ virtual void setStaticY(int staticY);
+
+ virtual IntRect getOverflowClipRect(int tx, int ty);
+ virtual IntRect getClipRect(int tx, int ty);
+
+ virtual void paintBoxDecorations(PaintInfo&, int tx, int ty);
+ virtual void paintMask(PaintInfo& paintInfo, int tx, int ty);
+ virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+
+ // Called when a positioned object moves but doesn't change size. A simplified layout is done
+ // that just updates the object's position.
+ virtual void tryLayoutDoingPositionedMovementOnly()
+ {
+ int oldWidth = m_width;
+ calcWidth();
+ // If we shrink to fit our width may have changed, so we still need full layout.
+ if (oldWidth != m_width)
+ return;
+ calcHeight();
+ setNeedsLayout(false);
+ }
+
+ virtual IntRect maskClipRect();
+
+protected:
+ virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle);
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int clipY, int clipHeight, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver);
+ void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int clipY, int clipHeight, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver);
+
+ void paintMaskImages(const PaintInfo&, int clipY, int clipHeight, int tx, int ty, int width, int height);
+
+#if PLATFORM(MAC)
+ void paintCustomHighlight(int tx, int ty, const AtomicString& type, bool behindText);
+#endif
+
+ void calcAbsoluteHorizontal();
+
+ virtual bool shouldCalculateSizeAsReplaced() const { return isReplaced() && !isInlineBlockOrInlineTable(); }
+
+private:
+ void paintRootBoxDecorations(PaintInfo&, int tx, int ty);
+ // Returns true if we did a full repaint
+ bool repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground);
+
+ void calculateBackgroundImageGeometry(const FillLayer*, int tx, int ty, int w, int h, IntRect& destRect, IntPoint& phase, IntSize& tileSize);
+
+ int containingBlockWidthForPositioned(const RenderObject* containingBlock) const;
+ int containingBlockHeightForPositioned(const RenderObject* containingBlock) const;
+
+ void calcAbsoluteVertical();
+ void calcAbsoluteHorizontalValues(Length width, const RenderObject* cb, TextDirection containerDirection,
+ int containerWidth, int bordersPlusPadding,
+ Length left, Length right, Length marginLeft, Length marginRight,
+ int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos);
+ void calcAbsoluteVerticalValues(Length height, const RenderObject* cb,
+ int containerHeight, int bordersPlusPadding,
+ Length top, Length bottom, Length marginTop, Length marginBottom,
+ int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos);
+
+ void calcAbsoluteVerticalReplaced();
+ void calcAbsoluteHorizontalReplaced();
+
+ // This function calculates the minimum and maximum preferred widths for an object.
+ // These values are used in shrink-to-fit layout systems.
+ // These include tables, positioned objects, floats and flexible boxes.
+ virtual void calcPrefWidths() = 0;
+
+protected:
+ // The width/height of the contents + borders + padding.
+ int m_width;
+ int m_height;
+
+ int m_x;
+ int m_y;
+
+ int m_marginLeft;
+ int m_marginRight;
+ int m_marginTop;
+ int m_marginBottom;
+
+ // The preferred width of the element if it were to break its lines at every possible opportunity.
+ int m_minPrefWidth;
+
+ // The preferred width of the element if it never breaks any lines at all.
+ int m_maxPrefWidth;
+
+ // A pointer to our layer if we have one.
+ RenderLayer* m_layer;
+
+ // For inline replaced elements, the inline box that owns us.
+ InlineBox* m_inlineBoxWrapper;
+
+private:
+ // Used to store state between styleWillChange and styleDidChange
+ static bool s_wasFloating;
+ static bool s_hadOverflowClip;
+};
+
+} // namespace WebCore
+
+#endif // RenderBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp
new file mode 100644
index 0000000..10e21c3
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderButton.cpp
@@ -0,0 +1,183 @@
+/**
+ * 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
+ * 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 "RenderButton.h"
+
+#include "Document.h"
+#include "GraphicsContext.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "RenderTextFragment.h"
+#include "RenderTheme.h"
+
+#if ENABLE(WML)
+#include "WMLDoElement.h"
+#include "WMLNames.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderButton::RenderButton(Node* node)
+ : RenderFlexibleBox(node)
+ , m_buttonText(0)
+ , m_inner(0)
+ , m_default(false)
+{
+}
+
+void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild)
+{
+ if (!m_inner) {
+ // Create an anonymous block.
+ ASSERT(!firstChild());
+ m_inner = createAnonymousBlock();
+ setupInnerStyle(m_inner->style());
+ RenderFlexibleBox::addChild(m_inner);
+ }
+
+ m_inner->addChild(newChild, beforeChild);
+}
+
+void RenderButton::removeChild(RenderObject* oldChild)
+{
+ if (oldChild == m_inner || !m_inner) {
+ RenderFlexibleBox::removeChild(oldChild);
+ m_inner = 0;
+ } else
+ m_inner->removeChild(oldChild);
+}
+
+void RenderButton::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
+{
+ if (m_inner) {
+ // RenderBlock::setStyle is going to apply a new style to the inner block, which
+ // will have the initial box flex value, 0. The current value is 1, because we set
+ // it right below. Here we change it back to 0 to avoid getting a spurious layout hint
+ // because of the difference.
+ m_inner->style()->setBoxFlex(0);
+ }
+ RenderBlock::styleWillChange(diff, newStyle);
+}
+
+void RenderButton::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+
+ if (m_buttonText)
+ m_buttonText->setStyle(style());
+ if (m_inner) // RenderBlock handled updating the anonymous block's style.
+ setupInnerStyle(m_inner->style());
+ setReplaced(isInline());
+
+ if (!m_default && theme()->isDefault(this)) {
+ if (!m_timer)
+ m_timer.set(new Timer<RenderButton>(this, &RenderButton::timerFired));
+ m_timer->startRepeating(0.03);
+ m_default = true;
+ } else if (m_default && !theme()->isDefault(this)) {
+ m_default = false;
+ m_timer.clear();
+ }
+}
+
+void RenderButton::setupInnerStyle(RenderStyle* innerStyle)
+{
+ ASSERT(innerStyle->refCount() == 1);
+ // RenderBlock::createAnonymousBlock creates a new RenderStyle, so this is
+ // safe to modify.
+ innerStyle->setBoxFlex(1.0f);
+ if (style()->hasAppearance())
+ theme()->adjustButtonInnerStyle(innerStyle);
+}
+
+void RenderButton::updateFromElement()
+{
+ // If we're an input element, we may need to change our button text.
+ if (element()->hasTagName(inputTag)) {
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(element());
+ String value = input->valueWithDefault();
+ setText(value);
+ }
+
+
+#if ENABLE(WML)
+ else if (element()->hasTagName(WMLNames::doTag)) {
+ WMLDoElement* doElement = static_cast<WMLDoElement*>(element());
+
+ String value = doElement->label();
+ if (value.isEmpty())
+ value = doElement->name();
+
+ setText(value);
+ }
+#endif
+}
+
+bool RenderButton::canHaveChildren() const
+{
+ // Input elements can't have children, but button elements can. We'll
+ // write the code assuming any other button types that might emerge in the future
+ // can also have children.
+ return !element()->hasTagName(inputTag);
+}
+
+void RenderButton::setText(const String& str)
+{
+ if (str.isEmpty()) {
+ if (m_buttonText) {
+ m_buttonText->destroy();
+ m_buttonText = 0;
+ }
+ } else {
+ if (m_buttonText)
+ m_buttonText->setText(str.impl());
+ else {
+ m_buttonText = new (renderArena()) RenderTextFragment(document(), str.impl());
+ m_buttonText->setStyle(style());
+ addChild(m_buttonText);
+ }
+ }
+}
+
+void RenderButton::updateBeforeAfterContent(RenderStyle::PseudoId type)
+{
+ if (m_inner)
+ m_inner->updateBeforeAfterContentForContainer(type, this);
+ else
+ updateBeforeAfterContentForContainer(type, this);
+}
+
+IntRect RenderButton::controlClipRect(int tx, int ty) const
+{
+ // Clip to the padding box to at least give content the extra padding space.
+ return IntRect(tx + borderLeft(), ty + borderTop(), m_width - borderLeft() - borderRight(), m_height - borderTop() - borderBottom());
+}
+
+void RenderButton::timerFired(Timer<RenderButton>*)
+{
+ repaint();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderButton.h b/src/3rdparty/webkit/WebCore/rendering/RenderButton.h
new file mode 100644
index 0000000..24e4767
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderButton.h
@@ -0,0 +1,77 @@
+/*
+ * 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
+ * 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 RenderButton_h
+#define RenderButton_h
+
+#include "RenderFlexibleBox.h"
+#include "Timer.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class RenderTextFragment;
+
+// RenderButtons are just like normal flexboxes except that they will generate an anonymous block child.
+// For inputs, they will also generate an anonymous RenderText and keep its style and content up
+// to date as the button changes.
+class RenderButton : public RenderFlexibleBox {
+public:
+ RenderButton(Node*);
+
+ virtual const char* renderName() const { return "RenderButton"; }
+
+ virtual void addChild(RenderObject* newChild, RenderObject *beforeChild = 0);
+ virtual void removeChild(RenderObject*);
+ virtual void removeLeftoverAnonymousBlock(RenderBlock*) { }
+ virtual bool createsAnonymousWrapper() const { return true; }
+
+ void setupInnerStyle(RenderStyle*);
+ virtual void updateFromElement();
+
+ virtual void updateBeforeAfterContent(RenderStyle::PseudoId);
+
+ virtual bool hasControlClip() const { return true; }
+ virtual IntRect controlClipRect(int /*tx*/, int /*ty*/) const;
+
+ void setText(const String&);
+
+ virtual bool canHaveChildren() const;
+
+protected:
+ virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle);
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ virtual bool hasLineIfEmpty() const { return true; }
+
+ void timerFired(Timer<RenderButton>*);
+
+ RenderTextFragment* m_buttonText;
+ RenderBlock* m_inner;
+
+ OwnPtr<Timer<RenderButton> > m_timer;
+ bool m_default;
+};
+
+} // namespace WebCore
+
+#endif // RenderButton_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderContainer.cpp
new file mode 100644
index 0000000..9f6d737
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderContainer.cpp
@@ -0,0 +1,701 @@
+/**
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "RenderContainer.h"
+
+#include "AXObjectCache.h"
+#include "Document.h"
+#include "RenderCounter.h"
+#include "RenderImageGeneratedContent.h"
+#include "RenderLayer.h"
+#include "RenderListItem.h"
+#include "RenderTable.h"
+#include "RenderTextFragment.h"
+#include "RenderView.h"
+#include "htmlediting.h"
+
+namespace WebCore {
+
+RenderContainer::RenderContainer(Node* node)
+ : RenderBox(node)
+ , m_firstChild(0)
+ , m_lastChild(0)
+{
+}
+
+RenderContainer::~RenderContainer()
+{
+}
+
+void RenderContainer::destroy()
+{
+ destroyLeftoverChildren();
+ RenderBox::destroy();
+}
+
+void RenderContainer::destroyLeftoverChildren()
+{
+ while (m_firstChild) {
+ if (m_firstChild->isListMarker() || (m_firstChild->style()->styleType() == RenderStyle::FIRST_LETTER && !m_firstChild->isText()))
+ m_firstChild->remove(); // List markers are owned by their enclosing list and so don't get destroyed by this container. Similarly, first letters are destroyed by their remaining text fragment.
+ else {
+ // Destroy any anonymous children remaining in the render tree, as well as implicit (shadow) DOM elements like those used in the engine-based text fields.
+ if (m_firstChild->element())
+ m_firstChild->element()->setRenderer(0);
+ m_firstChild->destroy();
+ }
+ }
+}
+
+bool RenderContainer::canHaveChildren() const
+{
+ return true;
+}
+
+static void updateListMarkerNumbers(RenderObject* child)
+{
+ for (RenderObject* r = child; r; r = r->nextSibling())
+ if (r->isListItem())
+ static_cast<RenderListItem*>(r)->updateValue();
+}
+
+void RenderContainer::addChild(RenderObject* newChild, RenderObject* beforeChild)
+{
+ bool needsTable = false;
+
+ if (newChild->isListItem())
+ updateListMarkerNumbers(beforeChild ? beforeChild : m_lastChild);
+ else if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP)
+ needsTable = !isTable();
+ else if (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION)
+ needsTable = !isTable();
+ else if (newChild->isTableSection())
+ needsTable = !isTable();
+ else if (newChild->isTableRow())
+ needsTable = !isTableSection();
+ else if (newChild->isTableCell()) {
+ needsTable = !isTableRow();
+ // I'm not 100% sure this is the best way to fix this, but without this
+ // change we recurse infinitely when trying to render the CSS2 test page:
+ // http://www.bath.ac.uk/%7Epy8ieh/internet/eviltests/htmlbodyheadrendering2.html.
+ // See Radar 2925291.
+ if (needsTable && isTableCell() && !m_firstChild && !newChild->isTableCell())
+ needsTable = false;
+ }
+
+ if (needsTable) {
+ RenderTable* table;
+ RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : m_lastChild;
+ if (afterChild && afterChild->isAnonymous() && afterChild->isTable())
+ table = static_cast<RenderTable*>(afterChild);
+ else {
+ table = new (renderArena()) RenderTable(document() /* is anonymous */);
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(style());
+ newStyle->setDisplay(TABLE);
+ table->setStyle(newStyle.release());
+ addChild(table, beforeChild);
+ }
+ table->addChild(newChild);
+ } else {
+ // just add it...
+ insertChildNode(newChild, beforeChild);
+ }
+
+ if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) {
+ RefPtr<StringImpl> textToTransform = static_cast<RenderText*>(newChild)->originalText();
+ if (textToTransform)
+ static_cast<RenderText*>(newChild)->setText(textToTransform.release(), true);
+ }
+}
+
+RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild, bool fullRemove)
+{
+ ASSERT(oldChild->parent() == this);
+
+ // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
+ // that a positioned child got yanked). We also repaint, so that the area exposed when the child
+ // disappears gets repainted properly.
+ if (!documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) {
+ oldChild->setNeedsLayoutAndPrefWidthsRecalc();
+ oldChild->repaint();
+ }
+
+ // If we have a line box wrapper, delete it.
+ oldChild->deleteLineBoxWrapper();
+
+ if (!documentBeingDestroyed() && fullRemove) {
+ // if we remove visible child from an invisible parent, we don't know the layer visibility any more
+ RenderLayer* layer = 0;
+ if (m_style->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
+ layer = enclosingLayer();
+ layer->dirtyVisibleContentStatus();
+ }
+
+ // Keep our layer hierarchy updated.
+ if (oldChild->firstChild() || oldChild->hasLayer()) {
+ if (!layer) layer = enclosingLayer();
+ oldChild->removeLayers(layer);
+ }
+
+ // renumber ordered lists
+ if (oldChild->isListItem())
+ updateListMarkerNumbers(oldChild->nextSibling());
+
+ if (oldChild->isPositioned() && childrenInline())
+ dirtyLinesFromChangedChild(oldChild);
+ }
+
+ // If oldChild is the start or end of the selection, then clear the selection to
+ // avoid problems of invalid pointers.
+ // FIXME: The SelectionController should be responsible for this when it
+ // is notified of DOM mutations.
+ if (!documentBeingDestroyed() && oldChild->isSelectionBorder())
+ view()->clearSelection();
+
+ // remove the child
+ if (oldChild->previousSibling())
+ oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
+ if (oldChild->nextSibling())
+ oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
+
+ if (m_firstChild == oldChild)
+ m_firstChild = oldChild->nextSibling();
+ if (m_lastChild == oldChild)
+ m_lastChild = oldChild->previousSibling();
+
+ oldChild->setPreviousSibling(0);
+ oldChild->setNextSibling(0);
+ oldChild->setParent(0);
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->childrenChanged(this);
+
+ return oldChild;
+}
+
+void RenderContainer::removeChild(RenderObject* oldChild)
+{
+ // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode
+ // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on
+ // layout anyway).
+ oldChild->removeFromObjectLists();
+
+ removeChildNode(oldChild);
+}
+
+RenderObject* RenderContainer::beforeAfterContainer(RenderStyle::PseudoId type)
+{
+ if (type == RenderStyle::BEFORE) {
+ RenderObject* first = this;
+ do {
+ // Skip list markers.
+ first = first->firstChild();
+ while (first && first->isListMarker())
+ first = first->nextSibling();
+ } while (first && first->isAnonymous() && first->style()->styleType() == RenderStyle::NOPSEUDO);
+ if (first && first->style()->styleType() != type)
+ return 0;
+ return first;
+ }
+ if (type == RenderStyle::AFTER) {
+ RenderObject* last = this;
+ do {
+ last = last->lastChild();
+ } while (last && last->isAnonymous() && last->style()->styleType() == RenderStyle::NOPSEUDO && !last->isListMarker());
+ if (last && last->style()->styleType() != type)
+ return 0;
+ return last;
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void RenderContainer::updateBeforeAfterContent(RenderStyle::PseudoId type)
+{
+ // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
+ if (parent() && parent()->createsAnonymousWrapper())
+ return;
+ updateBeforeAfterContentForContainer(type, this);
+}
+
+static RenderObject* findBeforeAfterParent(RenderObject* object)
+{
+ // Only table parts need to search for the :before or :after parent
+ if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
+ return object;
+
+ RenderObject* beforeAfterParent = object;
+ while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
+ beforeAfterParent = beforeAfterParent->firstChild();
+ return beforeAfterParent;
+}
+
+void RenderContainer::updateBeforeAfterContentForContainer(RenderStyle::PseudoId type, RenderContainer* styledObject)
+{
+ // In CSS2, before/after pseudo-content cannot nest. Check this first.
+ if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == RenderStyle::AFTER)
+ return;
+
+ RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
+ RenderObject* child = beforeAfterContainer(type);
+
+ // Whether or not we currently have generated content attached.
+ bool oldContentPresent = child;
+
+ // Whether or not we now want generated content.
+ bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
+
+ // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
+ // :after content and not :before content.
+ if (newContentWanted && type == RenderStyle::BEFORE && isInlineContinuation())
+ newContentWanted = false;
+
+ // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
+ // then we don't generate the :after content.
+ if (newContentWanted && type == RenderStyle::AFTER && isRenderInline() && continuation())
+ newContentWanted = false;
+
+ // If we don't want generated content any longer, or if we have generated content, but it's no longer
+ // identical to the new content data we want to build render objects for, then we nuke all
+ // of the old generated content.
+ if (!newContentWanted || (oldContentPresent && Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
+ // Nuke the child.
+ if (child && child->style()->styleType() == type) {
+ oldContentPresent = false;
+ child->destroy();
+ child = (type == RenderStyle::BEFORE) ? m_firstChild : m_lastChild;
+ }
+ }
+
+ // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
+ // have no generated content and can now return.
+ if (!newContentWanted)
+ return;
+
+ if (isInlineFlow() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE &&
+ !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
+ // According to the CSS2 spec (the end of section 12.1), the only allowed
+ // display values for the pseudo style are NONE and INLINE for inline flows.
+ // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
+ // For now we at least relax the restriction to allow all inline types like inline-block
+ // and inline-table.
+ pseudoElementStyle->setDisplay(INLINE);
+
+ if (oldContentPresent) {
+ if (child && child->style()->styleType() == type) {
+ // We have generated content present still. We want to walk this content and update our
+ // style information with the new pseudo-element style.
+ child->setStyle(pseudoElementStyle);
+
+ RenderObject* beforeAfterParent = findBeforeAfterParent(child);
+ if (!beforeAfterParent)
+ return;
+
+ // Note that if we ever support additional types of generated content (which should be way off
+ // in the future), this code will need to be patched.
+ for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
+ if (genChild->isText())
+ // Generated text content is a child whose style also needs to be set to the pseudo-element style.
+ genChild->setStyle(pseudoElementStyle);
+ else if (genChild->isImage()) {
+ // Images get an empty style that inherits from the 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() == RenderStyle::FIRST_LETTER);
+ }
+ }
+ return; // We've updated the generated content. That's all we needed to do.
+ }
+
+ RenderObject* insertBefore = (type == RenderStyle::BEFORE) ? firstChild() : 0;
+
+ // Generated content consists of a single container that houses multiple children (specified
+ // by the content property). This generated content container gets the pseudo-element style set on it.
+ RenderObject* generatedContentContainer = 0;
+
+ // Walk our list of generated content and create render objects for each.
+ for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->m_next) {
+ RenderObject* renderer = 0;
+ switch (content->m_type) {
+ case CONTENT_NONE:
+ break;
+ case CONTENT_TEXT:
+ renderer = new (renderArena()) RenderTextFragment(document() /* anonymous object */, content->m_content.m_text);
+ renderer->setStyle(pseudoElementStyle);
+ break;
+ case CONTENT_OBJECT: {
+ RenderImageGeneratedContent* image = new (renderArena()) RenderImageGeneratedContent(document()); // anonymous object
+ RefPtr<RenderStyle> style = RenderStyle::create();
+ style->inheritFrom(pseudoElementStyle);
+ image->setStyle(style.release());
+ if (StyleImage* styleImage = content->m_content.m_image)
+ image->setStyleImage(styleImage);
+ renderer = image;
+ break;
+ }
+ case CONTENT_COUNTER:
+ renderer = new (renderArena()) RenderCounter(document(), *content->m_content.m_counter);
+ renderer->setStyle(pseudoElementStyle);
+ break;
+ }
+
+ if (renderer) {
+ if (!generatedContentContainer) {
+ // Make a generated box that might be any display type now that we are able to drill down into children
+ // to find the original content properly.
+ generatedContentContainer = RenderObject::createObject(document(), pseudoElementStyle);
+ generatedContentContainer->setStyle(pseudoElementStyle);
+ addChild(generatedContentContainer, insertBefore);
+ }
+ generatedContentContainer->addChild(renderer);
+ }
+ }
+}
+
+bool RenderContainer::isAfterContent(RenderObject* child) const
+{
+ if (!child)
+ return false;
+ if (child->style()->styleType() != RenderStyle::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;
+}
+
+static void invalidateCountersInContainer(RenderObject* container)
+{
+ if (!container)
+ return;
+ container = findBeforeAfterParent(container);
+ if (!container)
+ return;
+ for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
+ if (content->isCounter())
+ static_cast<RenderCounter*>(content)->invalidate();
+ }
+}
+
+void RenderContainer::invalidateCounters()
+{
+ if (documentBeingDestroyed())
+ return;
+
+ invalidateCountersInContainer(beforeAfterContainer(RenderStyle::BEFORE));
+ invalidateCountersInContainer(beforeAfterContainer(RenderStyle::AFTER));
+}
+
+void RenderContainer::appendChildNode(RenderObject* newChild, bool fullAppend)
+{
+ ASSERT(newChild->parent() == 0);
+ ASSERT(!isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
+
+ newChild->setParent(this);
+ RenderObject* lChild = m_lastChild;
+
+ if (lChild) {
+ newChild->setPreviousSibling(lChild);
+ lChild->setNextSibling(newChild);
+ } else
+ m_firstChild = newChild;
+
+ m_lastChild = newChild;
+
+ if (fullAppend) {
+ // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
+ // and don't have a layer attached to ourselves.
+ RenderLayer* layer = 0;
+ if (newChild->firstChild() || newChild->hasLayer()) {
+ layer = enclosingLayer();
+ newChild->addLayers(layer, newChild);
+ }
+
+ // if the new child is visible but this object was not, tell the layer it has some visible content
+ // that needs to be drawn and layer visibility optimization can't be used
+ if (style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
+ if (!layer)
+ layer = enclosingLayer();
+ if (layer)
+ layer->setHasVisibleContent(true);
+ }
+
+ if (!newChild->isFloatingOrPositioned() && childrenInline())
+ dirtyLinesFromChangedChild(newChild);
+ }
+
+ newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
+ if (!normalChildNeedsLayout())
+ setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->childrenChanged(this);
+}
+
+void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild, bool fullInsert)
+{
+ if (!beforeChild) {
+ appendChildNode(child);
+ return;
+ }
+
+ ASSERT(!child->parent());
+ while (beforeChild->parent() != this && beforeChild->parent()->isAnonymousBlock())
+ beforeChild = beforeChild->parent();
+ ASSERT(beforeChild->parent() == this);
+
+ ASSERT(!isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
+
+ if (beforeChild == m_firstChild)
+ m_firstChild = child;
+
+ RenderObject* prev = beforeChild->previousSibling();
+ child->setNextSibling(beforeChild);
+ beforeChild->setPreviousSibling(child);
+ if(prev) prev->setNextSibling(child);
+ child->setPreviousSibling(prev);
+
+ child->setParent(this);
+
+ if (fullInsert) {
+ // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
+ // and don't have a layer attached to ourselves.
+ RenderLayer* layer = 0;
+ if (child->firstChild() || child->hasLayer()) {
+ layer = enclosingLayer();
+ child->addLayers(layer, child);
+ }
+
+ // if the new child is visible but this object was not, tell the layer it has some visible content
+ // that needs to be drawn and layer visibility optimization can't be used
+ if (style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
+ if (!layer)
+ layer = enclosingLayer();
+ if (layer)
+ layer->setHasVisibleContent(true);
+ }
+
+
+ if (!child->isFloating() && childrenInline())
+ dirtyLinesFromChangedChild(child);
+ }
+
+ child->setNeedsLayoutAndPrefWidthsRecalc();
+ if (!normalChildNeedsLayout())
+ setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->childrenChanged(this);
+}
+
+void RenderContainer::layout()
+{
+ ASSERT(needsLayout());
+
+ LayoutStateMaintainer statePusher(view(), this, IntSize(m_x, m_y));
+
+ RenderObject* child = m_firstChild;
+ while (child) {
+ child->layoutIfNeeded();
+ ASSERT(child->isRenderInline() || !child->needsLayout());
+ child = child->nextSibling();
+ }
+
+ statePusher.pop();
+ setNeedsLayout(false);
+}
+
+void RenderContainer::removeLeftoverAnonymousBlock(RenderBlock* child)
+{
+ ASSERT(child->isAnonymousBlock());
+ ASSERT(!child->childrenInline());
+
+ if (child->continuation())
+ return;
+
+ RenderObject* firstAnChild = child->firstChild();
+ RenderObject* lastAnChild = child->lastChild();
+ if (firstAnChild) {
+ RenderObject* o = firstAnChild;
+ while(o) {
+ o->setParent(this);
+ o = o->nextSibling();
+ }
+ firstAnChild->setPreviousSibling(child->previousSibling());
+ lastAnChild->setNextSibling(child->nextSibling());
+ if (child->previousSibling())
+ child->previousSibling()->setNextSibling(firstAnChild);
+ if (child->nextSibling())
+ child->nextSibling()->setPreviousSibling(lastAnChild);
+ } else {
+ if (child->previousSibling())
+ child->previousSibling()->setNextSibling(child->nextSibling());
+ if (child->nextSibling())
+ child->nextSibling()->setPreviousSibling(child->previousSibling());
+ }
+ if (child == m_firstChild)
+ m_firstChild = firstAnChild;
+ if (child == m_lastChild)
+ m_lastChild = lastAnChild;
+ child->setParent(0);
+ child->setPreviousSibling(0);
+ child->setNextSibling(0);
+ if (!child->isText()) {
+ RenderContainer *c = static_cast<RenderContainer*>(child);
+ c->m_firstChild = 0;
+ c->m_next = 0;
+ }
+ child->destroy();
+}
+
+VisiblePosition RenderContainer::positionForCoordinates(int x, int y)
+{
+ // no children...return this render object's element, if there is one, and offset 0
+ if (!m_firstChild)
+ return VisiblePosition(element(), 0, DOWNSTREAM);
+
+ if (isTable() && element()) {
+ int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
+ int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
+
+ if (x < 0 || x > right || y < 0 || y > bottom) {
+ if (x <= right / 2)
+ return VisiblePosition(Position(element(), 0));
+ else
+ return VisiblePosition(Position(element(), maxDeepOffset(element())));
+ }
+ }
+
+ // Pass off to the closest child.
+ int minDist = INT_MAX;
+ RenderObject* closestRenderer = 0;
+ int newX = x;
+ int newY = y;
+ if (isTableRow()) {
+ newX += xPos();
+ newY += yPos();
+ }
+ for (RenderObject* renderer = m_firstChild; renderer; renderer = renderer->nextSibling()) {
+ if (!renderer->firstChild() && !renderer->isInline() && !renderer->isBlockFlow()
+ || renderer->style()->visibility() != VISIBLE)
+ continue;
+
+ int top = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->yPos());
+ int bottom = top + renderer->contentHeight();
+ int left = borderLeft() + paddingLeft() + (isTableRow() ? 0 : renderer->xPos());
+ int right = left + renderer->contentWidth();
+
+ if (x <= right && x >= left && y <= top && y >= bottom) {
+ if (renderer->isTableRow())
+ return renderer->positionForCoordinates(x + newX - renderer->xPos(), y + newY - renderer->yPos());
+ return renderer->positionForCoordinates(x - renderer->xPos(), y - renderer->yPos());
+ }
+
+ // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces
+ // and use a different compare depending on which piece (x, y) is in.
+ IntPoint cmp;
+ if (x > right) {
+ if (y < top)
+ cmp = IntPoint(right, top);
+ else if (y > bottom)
+ cmp = IntPoint(right, bottom);
+ else
+ cmp = IntPoint(right, y);
+ } else if (x < left) {
+ if (y < top)
+ cmp = IntPoint(left, top);
+ else if (y > bottom)
+ cmp = IntPoint(left, bottom);
+ else
+ cmp = IntPoint(left, y);
+ } else {
+ if (y < top)
+ cmp = IntPoint(x, top);
+ else
+ cmp = IntPoint(x, bottom);
+ }
+
+ int x1minusx2 = cmp.x() - x;
+ int y1minusy2 = cmp.y() - y;
+
+ int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
+ if (dist < minDist) {
+ closestRenderer = renderer;
+ minDist = dist;
+ }
+ }
+
+ if (closestRenderer)
+ return closestRenderer->positionForCoordinates(newX - closestRenderer->xPos(), newY - closestRenderer->yPos());
+
+ return VisiblePosition(element(), 0, DOWNSTREAM);
+}
+
+void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigned end, bool)
+{
+ if (!m_firstChild && (isInline() || isAnonymousBlock())) {
+ FloatPoint absPos = localToAbsoluteForContent(FloatPoint());
+ absoluteRects(rects, absPos.x(), absPos.y());
+ return;
+ }
+
+ if (!m_firstChild)
+ return;
+
+ unsigned offset = start;
+ for (RenderObject* child = childAt(start); child && offset < end; child = child->nextSibling(), ++offset) {
+ if (child->isText() || child->isInline() || child->isAnonymousBlock()) {
+ FloatPoint absPos = child->localToAbsoluteForContent(FloatPoint());
+ child->absoluteRects(rects, absPos.x(), absPos.y());
+ }
+ }
+}
+
+void RenderContainer::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool /*useSelectionHeight*/)
+{
+ if (!m_firstChild && (isInline() || isAnonymousBlock())) {
+ absoluteQuads(quads);
+ return;
+ }
+
+ if (!m_firstChild)
+ return;
+
+ unsigned offset = start;
+ for (RenderObject* child = childAt(start); child && offset < end; child = child->nextSibling(), ++offset) {
+ if (child->isText() || child->isInline() || child->isAnonymousBlock())
+ child->absoluteQuads(quads);
+ }
+}
+
+#undef DEBUG_LAYOUT
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderContainer.h
new file mode 100644
index 0000000..68aba84
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderContainer.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2001 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 RenderContainer_h
+#define RenderContainer_h
+
+#include "RenderBox.h"
+
+namespace WebCore {
+
+// Base class for rendering objects that can have children.
+class RenderContainer : public RenderBox {
+public:
+ RenderContainer(Node*);
+ virtual ~RenderContainer();
+
+ virtual RenderObject* firstChild() const { return m_firstChild; }
+ virtual RenderObject* lastChild() const { return m_lastChild; }
+
+ virtual bool canHaveChildren() const;
+ virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0);
+ virtual void removeChild(RenderObject*);
+
+ virtual void destroy();
+ void destroyLeftoverChildren();
+
+ virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true);
+ virtual void appendChildNode(RenderObject*, bool fullAppend = true);
+ virtual void insertChildNode(RenderObject* child, RenderObject* before, bool fullInsert = true);
+
+ // Designed for speed. Don't waste time doing a bunch of work like layer updating and repainting when we know that our
+ // change in parentage is not going to affect anything.
+ virtual void moveChildNode(RenderObject* child) { appendChildNode(child->parent()->removeChildNode(child, false), false); }
+
+ virtual void layout();
+ virtual void calcPrefWidths() { setPrefWidthsDirty(false); }
+
+ virtual void removeLeftoverAnonymousBlock(RenderBlock* child);
+
+ RenderObject* beforeAfterContainer(RenderStyle::PseudoId);
+ virtual void updateBeforeAfterContent(RenderStyle::PseudoId);
+ void updateBeforeAfterContentForContainer(RenderStyle::PseudoId, RenderContainer*);
+ bool isAfterContent(RenderObject* child) const;
+ virtual void invalidateCounters();
+
+ virtual VisiblePosition positionForCoordinates(int x, int y);
+
+ virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+ virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+
+private:
+ RenderObject* m_firstChild;
+ RenderObject* m_lastChild;
+};
+
+} // namespace WebCore
+
+#endif // RenderContainer_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp
new file mode 100644
index 0000000..598f40d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.cpp
@@ -0,0 +1,306 @@
+/**
+ * Copyright (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2006, 2007 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 "RenderCounter.h"
+
+#include "CounterNode.h"
+#include "Document.h"
+#include "HTMLNames.h"
+#include "HTMLOListElement.h"
+#include "RenderListItem.h"
+#include "RenderListMarker.h"
+#include "RenderStyle.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+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 CounterMaps& counterMaps()
+{
+ DEFINE_STATIC_LOCAL(CounterMaps, staticCounterMaps, ());
+ return staticCounterMaps;
+}
+
+static inline RenderObject* previousSiblingOrParent(RenderObject* object)
+{
+ if (RenderObject* sibling = object->previousSibling())
+ return sibling;
+ 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)
+{
+ ASSERT(object);
+
+ // Real text nodes don't have their own style so they can't have counters.
+ // We can't even look at their styles or we'll see extra resets and increments!
+ if (object->isText() && !object->isBR())
+ return false;
+
+ RenderStyle* style = object->style();
+ ASSERT(style);
+
+ if (const CounterDirectiveMap* directivesMap = style->counterDirectives()) {
+ CounterDirectives directives = directivesMap->get(counterName.impl());
+ if (directives.m_reset) {
+ value = directives.m_resetValue;
+ if (directives.m_increment)
+ value += directives.m_incrementValue;
+ isReset = true;
+ return true;
+ }
+ if (directives.m_increment) {
+ value = directives.m_incrementValue;
+ isReset = false;
+ return true;
+ }
+ }
+
+ if (counterName == "list-item") {
+ if (object->isListItem()) {
+ if (static_cast<RenderListItem*>(object)->hasExplicitValue()) {
+ value = static_cast<RenderListItem*>(object)->explicitValue();
+ isReset = true;
+ return true;
+ }
+ value = 1;
+ isReset = false;
+ return true;
+ }
+ if (Node* e = object->element()) {
+ if (e->hasTagName(olTag)) {
+ value = static_cast<HTMLOListElement*>(e)->start();
+ isReset = true;
+ return true;
+ }
+ if (e->hasTagName(ulTag) || e->hasTagName(menuTag) || e->hasTagName(dirTag)) {
+ value = 0;
+ isReset = true;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool findPlaceForCounter(RenderObject* object, const AtomicString& counterName,
+ 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;
+ 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;
+ }
+ return true;
+ }
+ resetCandidate = previousSiblingOrParent(resetCandidate);
+ } else if (c) {
+ if (c->isReset())
+ candidateCounter = 0;
+ else if (!candidateCounter)
+ candidateCounter = c;
+ }
+ }
+
+ return false;
+}
+
+static CounterNode* counter(RenderObject* object, const AtomicString& counterName, bool alwaysCreateCounter)
+{
+ ASSERT(object);
+
+ if (object->m_hasCounterNodeMap)
+ if (CounterMap* nodeMap = counterMaps().get(object))
+ if (CounterNode* node = nodeMap->get(counterName.impl()))
+ return node;
+
+ bool isReset = false;
+ int value = 0;
+ if (!planCounter(object, counterName, 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);
+ }
+
+ CounterMap* nodeMap;
+ if (object->m_hasCounterNodeMap)
+ nodeMap = counterMaps().get(object);
+ else {
+ nodeMap = new CounterMap;
+ counterMaps().set(object, nodeMap);
+ object->m_hasCounterNodeMap = true;
+ }
+ nodeMap->set(counterName.impl(), newNode);
+
+ return newNode;
+}
+
+RenderCounter::RenderCounter(Document* node, const CounterContent& counter)
+ : RenderText(node, StringImpl::empty())
+ , m_counter(counter)
+ , m_counterNode(0)
+{
+}
+
+const char* RenderCounter::renderName() const
+{
+ return "RenderCounter";
+}
+
+bool RenderCounter::isCounter() const
+{
+ return true;
+}
+
+PassRefPtr<StringImpl> RenderCounter::originalText() const
+{
+ if (!parent())
+ return 0;
+
+ if (!m_counterNode)
+ m_counterNode = counter(parent(), m_counter.identifier(), true);
+
+ CounterNode* child = m_counterNode;
+ int value = child->isReset() ? child->value() : child->countInParent();
+
+ String text = listMarkerText(m_counter.listStyle(), value);
+
+ if (!m_counter.separator().isNull()) {
+ if (!child->isReset())
+ child = child->parent();
+ while (CounterNode* parent = child->parent()) {
+ text = listMarkerText(m_counter.listStyle(), child->countInParent())
+ + m_counter.separator() + text;
+ child = parent;
+ }
+ }
+
+ return text.impl();
+}
+
+void RenderCounter::dirtyLineBoxes(bool fullLayout, bool dummy)
+{
+ if (prefWidthsDirty())
+ calcPrefWidths(0);
+ RenderText::dirtyLineBoxes(fullLayout, dummy);
+}
+
+void RenderCounter::calcPrefWidths(int lead)
+{
+ setTextInternal(originalText());
+ RenderText::calcPrefWidths(lead);
+}
+
+void RenderCounter::invalidate()
+{
+ m_counterNode = 0;
+ setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+static void destroyCounterNodeChildren(AtomicStringImpl* 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);
+ child->renderer()->invalidateCounters();
+ delete child;
+ }
+}
+
+void RenderCounter::destroyCounterNodes(RenderObject* object)
+{
+ CounterMaps& maps = counterMaps();
+ CounterMap* map = maps.get(object);
+ if (!map)
+ return;
+ maps.remove(object);
+
+ 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;
+ }
+
+ delete map;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h
new file mode 100644
index 0000000..10be066
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderCounter.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2006, 2007, 2008 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 RenderCounter_h
+#define RenderCounter_h
+
+#include "CounterContent.h"
+#include "RenderText.h"
+
+namespace WebCore {
+
+class CounterNode;
+
+class RenderCounter : public RenderText {
+public:
+ RenderCounter(Document*, const CounterContent&);
+
+ virtual const char* renderName() const;
+ virtual bool isCounter() const;
+ virtual PassRefPtr<StringImpl> originalText() const;
+
+ virtual void dirtyLineBoxes(bool, bool);
+ virtual void calcPrefWidths(int leadWidth);
+
+ void invalidate();
+
+ static void destroyCounterNodes(RenderObject*);
+
+private:
+ CounterContent m_counter;
+ mutable CounterNode* m_counterNode;
+};
+
+} // namespace WebCore
+
+#endif // RenderCounter_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp
new file mode 100644
index 0000000..0e944f4
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.cpp
@@ -0,0 +1,282 @@
+/*
+ * 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)
+ * Copyright (C) 2004, 2005, 2006 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
+ * 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 "RenderFieldset.h"
+
+#include "HTMLNames.h"
+#include "GraphicsContext.h"
+
+#if ENABLE(WML)
+#include "WMLNames.h"
+#endif
+
+using std::min;
+using std::max;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderFieldset::RenderFieldset(Node* element)
+ : RenderBlock(element)
+{
+}
+
+void RenderFieldset::calcPrefWidths()
+{
+ RenderBlock::calcPrefWidths();
+ if (RenderObject* legend = findLegend()) {
+ int legendMinWidth = legend->minPrefWidth();
+
+ Length legendMarginLeft = legend->style()->marginLeft();
+ Length legendMarginRight = legend->style()->marginLeft();
+
+ if (legendMarginLeft.isFixed())
+ legendMinWidth += legendMarginLeft.value();
+
+ if (legendMarginRight.isFixed())
+ legendMinWidth += legendMarginRight.value();
+
+ m_minPrefWidth = max(m_minPrefWidth, legendMinWidth + paddingLeft() + paddingRight() + borderLeft() + borderRight());
+ }
+}
+
+RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren)
+{
+ RenderObject* legend = findLegend();
+ if (legend) {
+ if (relayoutChildren)
+ legend->setNeedsLayout(true);
+ legend->layoutIfNeeded();
+
+ int xPos;
+ if (style()->direction() == RTL) {
+ switch (legend->style()->textAlign()) {
+ case LEFT:
+ xPos = borderLeft() + paddingLeft();
+ break;
+ case CENTER:
+ xPos = (m_width - legend->width()) / 2;
+ break;
+ default:
+ xPos = m_width - paddingRight() - borderRight() - legend->width() - legend->marginRight();
+ }
+ } else {
+ switch (legend->style()->textAlign()) {
+ case RIGHT:
+ xPos = m_width - paddingRight() - borderRight() - legend->width();
+ break;
+ case CENTER:
+ xPos = (m_width - legend->width()) / 2;
+ break;
+ default:
+ xPos = borderLeft() + paddingLeft() + legend->marginLeft();
+ }
+ }
+ int b = borderTop();
+ int h = legend->height();
+ legend->setPos(xPos, max((b-h)/2, 0));
+ m_height = max(b,h) + paddingTop();
+ }
+ return legend;
+}
+
+RenderObject* RenderFieldset::findLegend() const
+{
+ for (RenderObject* legend = firstChild(); legend; legend = legend->nextSibling()) {
+ if (!legend->isFloatingOrPositioned() && legend->element() &&
+ legend->element()->hasTagName(legendTag)
+#if ENABLE(WML)
+ || legend->element()->hasTagName(WMLNames::insertedLegendTag)
+#endif
+ )
+ return legend;
+ }
+ return 0;
+}
+
+void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
+{
+ int w = width();
+ int h = height() + borderTopExtra() + borderBottomExtra();
+ RenderObject* legend = findLegend();
+ if (!legend)
+ return RenderBlock::paintBoxDecorations(paintInfo, tx, ty);
+
+ int yOff = (legend->yPos() > 0) ? 0 : (legend->height() - borderTop()) / 2;
+ int legendBottom = ty + legend->yPos() + legend->height();
+ h -= yOff;
+ ty += yOff - borderTopExtra();
+
+ int my = max(ty, paintInfo.rect.y());
+ int end = min(paintInfo.rect.bottom(), ty + h);
+ int mh = end - my;
+
+ paintBoxShadow(paintInfo.context, tx, ty, w, h, style());
+
+ paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h);
+
+ if (!style()->hasBorder())
+ return;
+
+ // Save time by not saving and restoring the GraphicsContext in the straight border case
+ if (!style()->hasBorderRadius())
+ return paintBorderMinusLegend(paintInfo.context, tx, ty, w, h, style(), legend->xPos(), legend->width(), legendBottom);
+
+ // We have rounded borders, create a clipping region
+ // around the legend and paint the border as normal
+ GraphicsContext* graphicsContext = paintInfo.context;
+ graphicsContext->save();
+
+ int clipTop = ty;
+ int clipHeight = max(static_cast<int>(style()->borderTopWidth()), legend->height());
+
+ graphicsContext->clipOut(IntRect(tx + legend->xPos(), clipTop,
+ legend->width(), clipHeight));
+ paintBorder(paintInfo.context, tx, ty, w, h, style(), true, true);
+
+ graphicsContext->restore();
+}
+
+void RenderFieldset::paintMask(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
+ return;
+
+ int w = width();
+ int h = height() + borderTopExtra() + borderBottomExtra();
+ RenderObject* legend = findLegend();
+ if (!legend)
+ return RenderBlock::paintMask(paintInfo, tx, ty);
+
+ int yOff = (legend->yPos() > 0) ? 0 : (legend->height() - borderTop()) / 2;
+ h -= yOff;
+ ty += yOff - borderTopExtra();
+
+ int my = max(ty, paintInfo.rect.y());
+ int end = min(paintInfo.rect.bottom(), ty + h);
+ int mh = end - my;
+
+ paintMaskImages(paintInfo, my, mh, tx, ty, w, h);
+}
+
+void RenderFieldset::paintBorderMinusLegend(GraphicsContext* graphicsContext, int tx, int ty, int w, int h,
+ const RenderStyle* style, int lx, int lw, int lb)
+{
+ const Color& tc = style->borderTopColor();
+ const Color& bc = style->borderBottomColor();
+
+ EBorderStyle ts = style->borderTopStyle();
+ EBorderStyle bs = style->borderBottomStyle();
+ EBorderStyle ls = style->borderLeftStyle();
+ EBorderStyle rs = style->borderRightStyle();
+
+ bool render_t = ts > BHIDDEN;
+ bool render_l = ls > BHIDDEN;
+ bool render_r = rs > BHIDDEN;
+ bool render_b = bs > BHIDDEN;
+
+ int borderLeftWidth = style->borderLeftWidth();
+ int borderRightWidth = style->borderRightWidth();
+
+ if (render_t) {
+ if (lx >= borderLeftWidth)
+ drawBorder(graphicsContext, tx, ty, tx + min(lx, w), ty + style->borderTopWidth(), BSTop, tc, style->color(), ts,
+ (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? borderLeftWidth : 0),
+ (lx >= w && render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? borderRightWidth : 0));
+ if (lx + lw <= w - borderRightWidth)
+ drawBorder(graphicsContext, tx + max(0, lx + lw), ty, tx + w, ty + style->borderTopWidth(), BSTop, tc, style->color(), ts,
+ (lx + lw <= 0 && render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? borderLeftWidth : 0),
+ (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? borderRightWidth : 0));
+ }
+
+ if (render_b)
+ drawBorder(graphicsContext, tx, ty + h - style->borderBottomWidth(), tx + w, ty + h, BSBottom, bc, style->color(), bs,
+ (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? style->borderLeftWidth() : 0),
+ (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? style->borderRightWidth() : 0));
+
+ if (render_l) {
+ const Color& lc = style->borderLeftColor();
+ int startY = ty;
+
+ bool ignore_top =
+ (tc == lc) &&
+ (ls >= OUTSET) &&
+ (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET);
+
+ bool ignore_bottom =
+ (bc == lc) &&
+ (ls >= OUTSET) &&
+ (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET);
+
+ if (lx < borderLeftWidth && lx + lw > 0) {
+ // The legend intersects the border.
+ ignore_top = true;
+ startY = lb;
+ }
+
+ drawBorder(graphicsContext, tx, startY, tx + borderLeftWidth, ty + h, BSLeft, lc, style->color(), ls,
+ ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth());
+ }
+
+ if (render_r) {
+ const Color& rc = style->borderRightColor();
+ int startY = ty;
+
+ bool ignore_top =
+ (tc == rc) &&
+ (rs >= DOTTED || rs == INSET) &&
+ (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET);
+
+ bool ignore_bottom =
+ (bc == rc) &&
+ (rs >= DOTTED || rs == INSET) &&
+ (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET);
+
+ if (lx < w && lx + lw > w - borderRightWidth) {
+ // The legend intersects the border.
+ ignore_top = true;
+ startY = lb;
+ }
+
+ drawBorder(graphicsContext, tx + w - borderRightWidth, startY, tx + w, ty + h, BSRight, rc, style->color(), rs,
+ ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth());
+ }
+}
+
+void RenderFieldset::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+
+ // WinIE renders fieldsets with display:inline like they're inline-blocks. For us,
+ // an inline-block is just a block element with replaced set to true and inline set
+ // to true. Ensure that if we ended up being inline that we set our replaced flag
+ // so that we're treated like an inline-block.
+ if (isInline())
+ setReplaced(true);
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.h b/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.h
new file mode 100644
index 0000000..47d1a91
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFieldset.h
@@ -0,0 +1,60 @@
+/*
+ * 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)
+ * Copyright (C) 2004, 2006 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
+ * 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 RenderFieldset_h
+#define RenderFieldset_h
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class RenderFieldset : public RenderBlock {
+public:
+ RenderFieldset(Node*);
+
+ virtual const char* renderName() const { return "RenderFieldSet"; }
+ virtual bool isFieldset() const { return true; }
+
+ virtual RenderObject* layoutLegend(bool relayoutChildren);
+
+ virtual void calcPrefWidths();
+ virtual bool avoidsFloats() const { return true; }
+ virtual bool expandsToEncloseOverhangingFloats() const { return style()->height().isAuto(); }
+ virtual bool stretchesToMinIntrinsicWidth() const { return true; }
+
+ RenderObject* findLegend() const;
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+private:
+ virtual void paintBoxDecorations(PaintInfo&, int tx, int ty);
+ virtual void paintMask(PaintInfo& paintInfo, int tx, int ty);
+ void paintBorderMinusLegend(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, int lx, int lw, int lb);
+};
+
+} // namespace WebCore
+
+#endif // RenderFieldset_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp
new file mode 100644
index 0000000..6a4bb54
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2006, 2007 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 "RenderFileUploadControl.h"
+
+#include "FileList.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "Icon.h"
+#include "LocalizedStrings.h"
+#include "Page.h"
+#include "RenderButton.h"
+#include "RenderText.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include <math.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+const int afterButtonSpacing = 4;
+const int iconHeight = 16;
+const int iconWidth = 16;
+const int iconFilenameSpacing = 2;
+const int defaultWidthNumChars = 34;
+const int buttonShadowHeight = 2;
+
+class HTMLFileUploadInnerButtonElement : public HTMLInputElement {
+public:
+ HTMLFileUploadInnerButtonElement(Document*, Node* shadowParent);
+
+ virtual bool isShadowNode() const { return true; }
+ virtual Node* shadowParentNode() { return m_shadowParent; }
+
+private:
+ Node* m_shadowParent;
+};
+
+RenderFileUploadControl::RenderFileUploadControl(HTMLInputElement* input)
+ : RenderBlock(input)
+ , m_button(0)
+ , m_fileChooser(FileChooser::create(this, input->value()))
+{
+}
+
+RenderFileUploadControl::~RenderFileUploadControl()
+{
+ if (m_button)
+ m_button->detach();
+ m_fileChooser->disconnectClient();
+}
+
+void RenderFileUploadControl::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+ if (m_button)
+ m_button->renderer()->setStyle(createButtonStyle(style()));
+
+ setReplaced(isInline());
+}
+
+void RenderFileUploadControl::valueChanged()
+{
+ // onChange may destroy this renderer
+ RefPtr<FileChooser> fileChooser = m_fileChooser;
+
+ HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node());
+ inputElement->setFileListFromRenderer(fileChooser->filenames());
+ inputElement->onChange();
+
+ // only repaint if it doesn't seem we have been destroyed
+ if (!fileChooser->disconnected())
+ repaint();
+}
+
+bool RenderFileUploadControl::allowsMultipleFiles()
+{
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ return !input->getAttribute(multipleAttr).isNull();
+}
+
+void RenderFileUploadControl::click()
+{
+ Frame* frame = node()->document()->frame();
+ if (!frame)
+ return;
+ Page* page = frame->page();
+ if (!page)
+ return;
+ page->chrome()->runOpenPanel(frame, m_fileChooser);
+}
+
+void RenderFileUploadControl::updateFromElement()
+{
+ HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node());
+ ASSERT(inputElement->inputType() == HTMLInputElement::FILE);
+
+ if (!m_button) {
+ m_button = new HTMLFileUploadInnerButtonElement(document(), inputElement);
+ m_button->setInputType("button");
+ m_button->setValue(fileButtonChooseFileLabel());
+ RefPtr<RenderStyle> buttonStyle = createButtonStyle(style());
+ RenderObject* renderer = m_button->createRenderer(renderArena(), buttonStyle.get());
+ m_button->setRenderer(renderer);
+ renderer->setStyle(buttonStyle.release());
+ renderer->updateFromElement();
+ m_button->setAttached();
+ m_button->setInDocument(true);
+
+ addChild(renderer);
+ }
+
+ m_button->setDisabled(!theme()->isEnabled(this));
+
+ // 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.
+ FileList* files = inputElement->files();
+ ASSERT(files);
+ if (files && files->isEmpty() && !m_fileChooser->filenames().isEmpty()) {
+ m_fileChooser->clear();
+ repaint();
+ }
+}
+
+int RenderFileUploadControl::maxFilenameWidth() const
+{
+ return max(0, contentWidth() - m_button->renderer()->width() - afterButtonSpacing
+ - (m_fileChooser->icon() ? iconWidth + iconFilenameSpacing : 0));
+}
+
+PassRefPtr<RenderStyle> RenderFileUploadControl::createButtonStyle(const RenderStyle* parentStyle) const
+{
+ RefPtr<RenderStyle> style = getCachedPseudoStyle(RenderStyle::FILE_UPLOAD_BUTTON);
+ if (!style) {
+ style = RenderStyle::create();
+ if (parentStyle)
+ style->inheritFrom(parentStyle);
+ }
+
+ // Button text will wrap on file upload controls with widths smaller than the intrinsic button width
+ // without this setWhiteSpace.
+ style->setWhiteSpace(NOWRAP);
+
+ return style.release();
+}
+
+void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (style()->visibility() != VISIBLE)
+ return;
+
+ // Push a clip.
+ if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) {
+ IntRect clipRect(tx + borderLeft(), ty + borderTop(),
+ width() - borderLeft() - borderRight(), height() - borderBottom() - borderTop() + buttonShadowHeight);
+ if (clipRect.isEmpty())
+ return;
+ paintInfo.context->save();
+ paintInfo.context->clip(clipRect);
+ }
+
+ if (paintInfo.phase == PaintPhaseForeground) {
+ const String& displayedFilename = m_fileChooser->basenameForWidth(style()->font(), maxFilenameWidth());
+ unsigned length = displayedFilename.length();
+ const UChar* string = displayedFilename.characters();
+ TextRun textRun(string, length, false, 0, 0, style()->direction() == RTL, style()->unicodeBidi() == Override);
+
+ // Determine where the filename should be placed
+ int contentLeft = tx + borderLeft() + paddingLeft();
+ int buttonAndIconWidth = m_button->renderer()->width() + afterButtonSpacing
+ + (m_fileChooser->icon() ? iconWidth + iconFilenameSpacing : 0);
+ int textX;
+ if (style()->direction() == LTR)
+ textX = contentLeft + buttonAndIconWidth;
+ else
+ textX = contentLeft + contentWidth() - buttonAndIconWidth - style()->font().width(textRun);
+ // We want to match the button's baseline
+ RenderButton* buttonRenderer = static_cast<RenderButton*>(m_button->renderer());
+ int textY = buttonRenderer->absoluteBoundingBoxRect().y()
+ + buttonRenderer->marginTop() + buttonRenderer->borderTop() + buttonRenderer->paddingTop()
+ + buttonRenderer->baselinePosition(true, false);
+
+ paintInfo.context->setFont(style()->font());
+ paintInfo.context->setFillColor(style()->color());
+
+ // Draw the filename
+ paintInfo.context->drawBidiText(textRun, IntPoint(textX, textY));
+
+ if (m_fileChooser->icon()) {
+ // Determine where the icon should be placed
+ int iconY = ty + borderTop() + paddingTop() + (contentHeight() - iconHeight) / 2;
+ int iconX;
+ if (style()->direction() == LTR)
+ iconX = contentLeft + m_button->renderer()->width() + afterButtonSpacing;
+ else
+ iconX = contentLeft + contentWidth() - m_button->renderer()->width() - afterButtonSpacing - iconWidth;
+
+ // Draw the file icon
+ m_fileChooser->icon()->paint(paintInfo.context, IntRect(iconX, iconY, iconWidth, iconHeight));
+ }
+ }
+
+ // Paint the children.
+ RenderBlock::paintObject(paintInfo, tx, ty);
+
+ // Pop the clip.
+ if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseChildBlockBackgrounds)
+ paintInfo.context->restore();
+}
+
+void RenderFileUploadControl::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = 0;
+
+ if (style()->width().isFixed() && style()->width().value() > 0)
+ m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
+ else {
+ // Figure out how big the filename space needs to be for a given number of characters
+ // (using "0" as the nominal character).
+ const UChar ch = '0';
+ float charWidth = style()->font().floatWidth(TextRun(&ch, 1, false, 0, 0, false, false, false));
+ m_maxPrefWidth = (int)ceilf(charWidth * defaultWidthNumChars);
+ }
+
+ if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
+ m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
+ m_minPrefWidth = 0;
+ else
+ m_minPrefWidth = m_maxPrefWidth;
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
+ m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ }
+
+ int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+ m_minPrefWidth += toAdd;
+ m_maxPrefWidth += toAdd;
+
+ setPrefWidthsDirty(false);
+}
+
+void RenderFileUploadControl::receiveDroppedFiles(const Vector<String>& paths)
+{
+ if (allowsMultipleFiles())
+ m_fileChooser->chooseFiles(paths);
+ else
+ m_fileChooser->chooseFile(paths[0]);
+}
+
+String RenderFileUploadControl::buttonValue()
+{
+ if (!m_button)
+ return String();
+
+ return m_button->value();
+}
+
+String RenderFileUploadControl::fileTextValue()
+{
+ return m_fileChooser->basenameForWidth(style()->font(), maxFilenameWidth());
+}
+
+HTMLFileUploadInnerButtonElement::HTMLFileUploadInnerButtonElement(Document* doc, Node* shadowParent)
+ : HTMLInputElement(inputTag, doc)
+ , m_shadowParent(shadowParent)
+{
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h
new file mode 100644
index 0000000..60e7a7b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFileUploadControl.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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
+ * 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 RenderFileUploadControl_h
+#define RenderFileUploadControl_h
+
+#include "FileChooser.h"
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class HTMLInputElement;
+
+// Each RenderFileUploadControl contains a RenderButton (for opening the file chooser), and
+// sufficient space to draw a file icon and filename. The RenderButton has a shadow node
+// associated with it to receive click/hover events.
+
+class RenderFileUploadControl : public RenderBlock, private FileChooserClient {
+public:
+ RenderFileUploadControl(HTMLInputElement*);
+ ~RenderFileUploadControl();
+
+ virtual const char* renderName() const { return "RenderFileUploadControl"; }
+
+ virtual void updateFromElement();
+ virtual void calcPrefWidths();
+ virtual void paintObject(PaintInfo&, int tx, int ty);
+
+ void click();
+
+ void valueChanged();
+
+ void receiveDroppedFiles(const Vector<String>&);
+
+ String buttonValue();
+ String fileTextValue();
+
+ bool allowsMultipleFiles();
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+private:
+ int maxFilenameWidth() const;
+ PassRefPtr<RenderStyle> createButtonStyle(const RenderStyle* parentStyle) const;
+
+ RefPtr<HTMLInputElement> m_button;
+ RefPtr<FileChooser> m_fileChooser;
+};
+
+} // namespace WebCore
+
+#endif // RenderFileUploadControl_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp
new file mode 100644
index 0000000..08bc567
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.cpp
@@ -0,0 +1,1157 @@
+/*
+ * This file is part of the render object implementation for KHTML.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003 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
+ * 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 "RenderFlexibleBox.h"
+
+#include "CharacterNames.h"
+#include "RenderLayer.h"
+#include "RenderView.h"
+#include <wtf/StdLibExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+class FlexBoxIterator {
+public:
+ FlexBoxIterator(RenderFlexibleBox* parent) {
+ box = parent;
+ if (box->style()->boxOrient() == HORIZONTAL && box->style()->direction() == RTL)
+ forward = box->style()->boxDirection() != BNORMAL;
+ else
+ forward = box->style()->boxDirection() == BNORMAL;
+ lastOrdinal = 1;
+ if (!forward) {
+ // No choice, since we're going backwards, we have to find out the highest ordinal up front.
+ RenderObject* child = box->firstChild();
+ while (child) {
+ if (child->style()->boxOrdinalGroup() > lastOrdinal)
+ lastOrdinal = child->style()->boxOrdinalGroup();
+ child = child->nextSibling();
+ }
+ }
+
+ reset();
+ }
+
+ void reset() {
+ current = 0;
+ currentOrdinal = forward ? 0 : lastOrdinal+1;
+ }
+
+ RenderObject* first() {
+ reset();
+ return next();
+ }
+
+ RenderObject* next() {
+
+ do {
+ if (!current) {
+ if (forward) {
+ currentOrdinal++;
+ if (currentOrdinal > lastOrdinal)
+ return 0;
+ current = box->firstChild();
+ } else {
+ currentOrdinal--;
+ if (currentOrdinal == 0)
+ return 0;
+ current = box->lastChild();
+ }
+ }
+ else
+ current = forward ? current->nextSibling() : current->previousSibling();
+ if (current && current->style()->boxOrdinalGroup() > lastOrdinal)
+ lastOrdinal = current->style()->boxOrdinalGroup();
+ } while (!current || current->style()->boxOrdinalGroup() != currentOrdinal ||
+ current->style()->visibility() == COLLAPSE);
+ return current;
+ }
+
+private:
+ RenderFlexibleBox* box;
+ RenderObject* current;
+ bool forward;
+ unsigned int currentOrdinal;
+ unsigned int lastOrdinal;
+};
+
+RenderFlexibleBox::RenderFlexibleBox(Node* node)
+:RenderBlock(node)
+{
+ setChildrenInline(false); // All of our children must be block-level
+ m_flexingChildren = m_stretchingChildren = false;
+}
+
+RenderFlexibleBox::~RenderFlexibleBox()
+{
+}
+
+void RenderFlexibleBox::calcHorizontalPrefWidths()
+{
+ RenderObject *child = firstChild();
+ while (child) {
+ // positioned children don't affect the minmaxwidth
+ if (child->isPositioned() || child->style()->visibility() == COLLAPSE) {
+ child = child->nextSibling();
+ continue;
+ }
+
+ // A margin basically has three types: fixed, percentage, and auto (variable).
+ // Auto and percentage margins simply become 0 when computing min/max width.
+ // Fixed margins can be added in as is.
+ Length ml = child->style()->marginLeft();
+ Length mr = child->style()->marginRight();
+ int margin = 0, marginLeft = 0, marginRight = 0;
+ if (ml.isFixed())
+ marginLeft += ml.value();
+ if (mr.isFixed())
+ marginRight += mr.value();
+ margin = marginLeft + marginRight;
+
+ m_minPrefWidth += child->minPrefWidth() + margin;
+ m_maxPrefWidth += child->maxPrefWidth() + margin;
+
+ child = child->nextSibling();
+ }
+}
+
+void RenderFlexibleBox::calcVerticalPrefWidths()
+{
+ RenderObject *child = firstChild();
+ while(child != 0)
+ {
+ // Positioned children and collapsed children don't affect the min/max width
+ if (child->isPositioned() || child->style()->visibility() == COLLAPSE) {
+ child = child->nextSibling();
+ continue;
+ }
+
+ // A margin basically has three types: fixed, percentage, and auto (variable).
+ // Auto/percentage margins simply become 0 when computing min/max width.
+ // Fixed margins can be added in as is.
+ Length ml = child->style()->marginLeft();
+ Length mr = child->style()->marginRight();
+ int margin = 0;
+ if (ml.isFixed())
+ margin += ml.value();
+ if (mr.isFixed())
+ margin += mr.value();
+
+ int w = child->minPrefWidth() + margin;
+ m_minPrefWidth = max(w, m_minPrefWidth);
+
+ w = child->maxPrefWidth() + margin;
+ m_maxPrefWidth = max(w, m_maxPrefWidth);
+
+ child = child->nextSibling();
+ }
+}
+
+void RenderFlexibleBox::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ if (style()->width().isFixed() && style()->width().value() > 0)
+ m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
+ else {
+ m_minPrefWidth = m_maxPrefWidth = 0;
+
+ if (hasMultipleLines() || isVertical())
+ calcVerticalPrefWidths();
+ else
+ calcHorizontalPrefWidths();
+
+ m_maxPrefWidth = max(m_minPrefWidth, m_maxPrefWidth);
+ }
+
+ if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
+ m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ }
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
+ m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ }
+
+ int toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight();
+ m_minPrefWidth += toAdd;
+ m_maxPrefWidth += toAdd;
+
+ setPrefWidthsDirty(false);
+}
+
+void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
+{
+ ASSERT(needsLayout());
+
+ if (!relayoutChildren && layoutOnlyPositionedObjects())
+ return;
+
+ IntRect oldBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout();
+ if (checkForRepaint) {
+ oldBounds = absoluteClippedOverflowRect();
+ oldOutlineBox = absoluteOutlineBounds();
+ }
+
+ LayoutStateMaintainer statePusher(view(), this, IntSize(m_x, m_y), !hasReflection());
+
+ int previousWidth = m_width;
+ int previousHeight = m_height;
+
+ calcWidth();
+ calcHeight();
+ m_overflowWidth = m_width;
+
+ if (previousWidth != m_width || previousHeight != m_height ||
+ (parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL &&
+ parent()->style()->boxAlign() == BSTRETCH))
+ relayoutChildren = true;
+
+ m_height = 0;
+ m_overflowHeight = 0;
+ m_flexingChildren = m_stretchingChildren = false;
+
+ initMaxMarginValues();
+
+ // For overflow:scroll blocks, ensure we have both scrollbars in place always.
+ if (scrollsOverflow()) {
+ if (style()->overflowX() == OSCROLL)
+ m_layer->setHasHorizontalScrollbar(true);
+ if (style()->overflowY() == OSCROLL)
+ m_layer->setHasVerticalScrollbar(true);
+ }
+
+ if (isHorizontal())
+ layoutHorizontalBox(relayoutChildren);
+ else
+ layoutVerticalBox(relayoutChildren);
+
+ int oldHeight = m_height;
+ calcHeight();
+ if (oldHeight != m_height) {
+ // If the block got expanded in size, then increase our overflowheight to match.
+ if (m_overflowHeight > m_height)
+ m_overflowHeight -= (borderBottom() + paddingBottom() + horizontalScrollbarHeight());
+ if (m_overflowHeight < m_height)
+ m_overflowHeight = m_height;
+ }
+ if (previousHeight != m_height)
+ relayoutChildren = true;
+
+ layoutPositionedObjects(relayoutChildren || isRoot());
+
+ if (!isFloatingOrPositioned() && m_height == 0) {
+ // We are a block with no border and padding and a computed height
+ // of 0. The CSS spec states that zero-height blocks collapse their margins
+ // together.
+ // When blocks are self-collapsing, we just use the top margin values and set the
+ // bottom margin max values to 0. This way we don't factor in the values
+ // twice when we collapse with our previous vertically adjacent and
+ // following vertically adjacent blocks.
+ int pos = maxTopPosMargin();
+ int neg = maxTopNegMargin();
+ if (maxBottomPosMargin() > pos)
+ pos = maxBottomPosMargin();
+ if (maxBottomNegMargin() > neg)
+ neg = maxBottomNegMargin();
+ setMaxTopMargins(pos, neg);
+ setMaxBottomMargins(0, 0);
+ }
+
+ // Always ensure our overflow width is at least as large as our width.
+ if (m_overflowWidth < m_width)
+ m_overflowWidth = m_width;
+
+ if (!hasOverflowClip()) {
+ for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+ m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur);
+ m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur);
+ m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur);
+ m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur);
+ }
+
+ 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());
+ }
+ }
+
+ statePusher.pop();
+
+ // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if
+ // we overflow or not.
+ if (hasOverflowClip())
+ m_layer->updateScrollInfoAfterLayout();
+
+ // Repaint with our new bounds if they are different from our old bounds.
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+
+ setNeedsLayout(false);
+}
+
+void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
+{
+ int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
+ int yPos = borderTop() + paddingTop();
+ int xPos = borderLeft() + paddingLeft();
+ bool heightSpecified = false;
+ int oldHeight = 0;
+
+ unsigned int highestFlexGroup = 0;
+ unsigned int lowestFlexGroup = 0;
+ bool haveFlex = false;
+ int remainingSpace = 0;
+ m_overflowHeight = m_height;
+
+ // The first walk over our kids is to find out if we have any flexible children.
+ FlexBoxIterator iterator(this);
+ RenderObject* child = iterator.next();
+ while (child) {
+ // Check to see if this child flexes.
+ if (!child->isPositioned() && child->style()->boxFlex() > 0.0f) {
+ // We always have to lay out flexible objects again, since the flex distribution
+ // may have changed, and we need to reallocate space.
+ child->setOverrideSize(-1);
+ if (!relayoutChildren)
+ child->setChildNeedsLayout(true, false);
+ haveFlex = true;
+ unsigned int flexGroup = child->style()->boxFlexGroup();
+ if (lowestFlexGroup == 0)
+ lowestFlexGroup = flexGroup;
+ if (flexGroup < lowestFlexGroup)
+ lowestFlexGroup = flexGroup;
+ if (flexGroup > highestFlexGroup)
+ highestFlexGroup = flexGroup;
+ }
+ child = iterator.next();
+ }
+
+ // We do 2 passes. The first pass is simply to lay everyone out at
+ // their preferred widths. The second pass handles flexing the children.
+ do {
+ // Reset our height.
+ m_height = yPos;
+ m_overflowHeight = m_height;
+ xPos = borderLeft() + paddingLeft();
+
+ // Our first pass is done without flexing. We simply lay the children
+ // out within the box. We have to do a layout first in order to determine
+ // our box's intrinsic height.
+ int maxAscent = 0, maxDescent = 0;
+ child = iterator.first();
+ while (child) {
+ // make sure we relayout children if we need it.
+ if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))
+ child->setChildNeedsLayout(true, false);
+
+ if (child->isPositioned()) {
+ child = iterator.next();
+ continue;
+ }
+
+ // Compute the child's vertical margins.
+ child->calcVerticalMargins();
+
+ // Now do the layout.
+ child->layoutIfNeeded();
+
+ // Update our height and overflow height.
+ if (style()->boxAlign() == BBASELINE) {
+ int ascent = child->marginTop() + child->getBaselineOfFirstLineBox();
+ if (ascent == -1)
+ ascent = child->marginTop() + child->height() + child->marginBottom();
+ int descent = (child->marginTop() + child->height() + child->marginBottom()) - ascent;
+
+ // Update our maximum ascent.
+ maxAscent = max(maxAscent, ascent);
+
+ // Update our maximum descent.
+ maxDescent = max(maxDescent, descent);
+
+ // Now update our height.
+ m_height = max(yPos + maxAscent + maxDescent, m_height);
+ }
+ else
+ m_height = max(m_height, yPos + child->marginTop() + child->height() + child->marginBottom());
+
+ child = iterator.next();
+ }
+
+ if (!iterator.first() && hasLineIfEmpty())
+ m_height += lineHeight(true, true);
+
+ m_height += toAdd;
+
+ // Always make sure our overflowheight is at least our height.
+ if (m_overflowHeight < m_height)
+ m_overflowHeight = m_height;
+
+ oldHeight = m_height;
+ calcHeight();
+
+ relayoutChildren = false;
+ if (oldHeight != m_height)
+ heightSpecified = true;
+
+ // Now that our height is actually known, we can place our boxes.
+ m_stretchingChildren = (style()->boxAlign() == BSTRETCH);
+ child = iterator.first();
+ while (child) {
+ if (child->isPositioned()) {
+ child->containingBlock()->insertPositionedObject(child);
+ if (child->hasStaticX()) {
+ if (style()->direction() == LTR)
+ child->setStaticX(xPos);
+ else child->setStaticX(width() - xPos);
+ }
+ if (child->hasStaticY())
+ child->setStaticY(yPos);
+ child = iterator.next();
+ continue;
+ }
+
+ // We need to see if this child's height has changed, since we make block elements
+ // fill the height of a containing box by default.
+ // Now do a layout.
+ int oldChildHeight = child->height();
+ static_cast<RenderBox*>(child)->calcHeight();
+ if (oldChildHeight != child->height())
+ child->setChildNeedsLayout(true, false);
+ child->layoutIfNeeded();
+
+ // We can place the child now, using our value of box-align.
+ xPos += child->marginLeft();
+ int childY = yPos;
+ switch (style()->boxAlign()) {
+ case BCENTER:
+ childY += child->marginTop() + max(0, (contentHeight() - (child->height() + child->marginTop() + child->marginBottom()))/2);
+ break;
+ case BBASELINE: {
+ int ascent = child->marginTop() + child->getBaselineOfFirstLineBox();
+ if (ascent == -1)
+ ascent = child->marginTop() + child->height() + child->marginBottom();
+ childY += child->marginTop() + (maxAscent - ascent);
+ break;
+ }
+ case BEND:
+ childY += contentHeight() - child->marginBottom() - child->height();
+ break;
+ default: // BSTART
+ childY += child->marginTop();
+ break;
+ }
+
+ placeChild(child, xPos, childY);
+
+ if (child->isRenderBlock())
+ static_cast<RenderBlock*>(child)->addVisualOverflow(static_cast<RenderBlock*>(child)->floatRect());
+
+ m_overflowHeight = max(m_overflowHeight, childY + child->overflowHeight(false));
+ m_overflowTop = min(m_overflowTop, child->yPos() + child->overflowTop(false));
+
+ xPos += child->width() + child->marginRight();
+
+ child = iterator.next();
+ }
+
+ remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
+
+ m_stretchingChildren = false;
+ if (m_flexingChildren)
+ haveFlex = false; // We're done.
+ else if (haveFlex) {
+ // We have some flexible objects. See if we need to grow/shrink them at all.
+ if (!remainingSpace)
+ break;
+
+ // Allocate the remaining space among the flexible objects. If we are trying to
+ // grow, then we go from the lowest flex group to the highest flex group. For shrinking,
+ // we go from the highest flex group to the lowest group.
+ bool expanding = remainingSpace > 0;
+ unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
+ unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
+ for (unsigned int i = start; i <= end && remainingSpace; i++) {
+ // Always start off by assuming the group can get all the remaining space.
+ int groupRemainingSpace = remainingSpace;
+ do {
+ // Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
+ // For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
+ // computing the allowed growth before an object hits its min/max width (and thus
+ // forces a totalFlex recomputation).
+ int groupRemainingSpaceAtBeginning = groupRemainingSpace;
+ float totalFlex = 0.0f;
+ child = iterator.first();
+ while (child) {
+ if (allowedChildFlex(child, expanding, i))
+ totalFlex += child->style()->boxFlex();
+ child = iterator.next();
+ }
+ child = iterator.first();
+ int spaceAvailableThisPass = groupRemainingSpace;
+ while (child) {
+ int allowedFlex = allowedChildFlex(child, expanding, i);
+ if (allowedFlex) {
+ int projectedFlex = (allowedFlex == INT_MAX) ? allowedFlex : (int)(allowedFlex * (totalFlex / child->style()->boxFlex()));
+ spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
+ }
+ child = iterator.next();
+ }
+
+ // The flex groups may not have any flexible objects this time around.
+ if (!spaceAvailableThisPass || totalFlex == 0.0f) {
+ // If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
+ groupRemainingSpace = 0;
+ continue;
+ }
+
+ // Now distribute the space to objects.
+ child = iterator.first();
+ while (child && spaceAvailableThisPass && totalFlex) {
+ if (allowedChildFlex(child, expanding, i)) {
+ int spaceAdd = (int)(spaceAvailableThisPass * (child->style()->boxFlex()/totalFlex));
+ if (spaceAdd) {
+ child->setOverrideSize(child->overrideWidth() + spaceAdd);
+ m_flexingChildren = true;
+ relayoutChildren = true;
+ }
+
+ spaceAvailableThisPass -= spaceAdd;
+ remainingSpace -= spaceAdd;
+ groupRemainingSpace -= spaceAdd;
+
+ totalFlex -= child->style()->boxFlex();
+ }
+ child = iterator.next();
+ }
+ if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
+ // this is not advancing, avoid getting stuck by distributing the remaining pixels
+ child = iterator.first();
+ int spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
+ while (child && groupRemainingSpace) {
+ if (allowedChildFlex(child, expanding, i)) {
+ child->setOverrideSize(child->overrideWidth() + spaceAdd);
+ m_flexingChildren = true;
+ relayoutChildren = true;
+ remainingSpace -= spaceAdd;
+ groupRemainingSpace -= spaceAdd;
+ }
+ child = iterator.next();
+ }
+ }
+ } while (groupRemainingSpace);
+ }
+
+ // We didn't find any children that could grow.
+ if (haveFlex && !m_flexingChildren)
+ haveFlex = false;
+ }
+ } while (haveFlex);
+
+ m_flexingChildren = false;
+
+ if (remainingSpace > 0 && ((style()->direction() == LTR && style()->boxPack() != BSTART) ||
+ (style()->direction() == RTL && style()->boxPack() != BEND))) {
+ // Children must be repositioned.
+ int offset = 0;
+ if (style()->boxPack() == BJUSTIFY) {
+ // Determine the total number of children.
+ int totalChildren = 0;
+ child = iterator.first();
+ while (child) {
+ if (child->isPositioned()) {
+ child = iterator.next();
+ continue;
+ }
+ totalChildren++;
+ child = iterator.next();
+ }
+
+ // Iterate over the children and space them out according to the
+ // justification level.
+ if (totalChildren > 1) {
+ totalChildren--;
+ bool firstChild = true;
+ child = iterator.first();
+ while (child) {
+ if (child->isPositioned()) {
+ child = iterator.next();
+ continue;
+ }
+
+ if (firstChild) {
+ firstChild = false;
+ child = iterator.next();
+ continue;
+ }
+
+ offset += remainingSpace/totalChildren;
+ remainingSpace -= (remainingSpace/totalChildren);
+ totalChildren--;
+
+ placeChild(child, child->xPos()+offset, child->yPos());
+ child = iterator.next();
+ }
+ }
+ } else {
+ if (style()->boxPack() == BCENTER)
+ offset += remainingSpace/2;
+ else // END for LTR, START for RTL
+ offset += remainingSpace;
+ child = iterator.first();
+ while (child) {
+ if (child->isPositioned()) {
+ child = iterator.next();
+ continue;
+ }
+ placeChild(child, child->xPos()+offset, child->yPos());
+ child = iterator.next();
+ }
+ }
+ }
+
+ child = iterator.first();
+ while (child && child->isPositioned()) {
+ child = iterator.next();
+ }
+
+ if (child) {
+ m_overflowLeft = min(child->xPos() + child->overflowLeft(false), m_overflowLeft);
+
+ RenderObject* lastChild = child;
+ while ((child = iterator.next())) {
+ if (!child->isPositioned())
+ lastChild = child;
+ }
+ m_overflowWidth = max(lastChild->xPos() + 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)
+ m_height = oldHeight;
+}
+
+void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
+{
+ int xPos = borderLeft() + paddingLeft();
+ int yPos = borderTop() + paddingTop();
+ if( style()->direction() == RTL )
+ xPos = m_width - paddingRight() - borderRight();
+ int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
+ bool heightSpecified = false;
+ int oldHeight = 0;
+
+ unsigned int highestFlexGroup = 0;
+ unsigned int lowestFlexGroup = 0;
+ bool haveFlex = false;
+ int remainingSpace = 0;
+
+ // The first walk over our kids is to find out if we have any flexible children.
+ FlexBoxIterator iterator(this);
+ RenderObject *child = iterator.next();
+ while (child) {
+ // Check to see if this child flexes.
+ if (!child->isPositioned() && child->style()->boxFlex() > 0.0f) {
+ // We always have to lay out flexible objects again, since the flex distribution
+ // may have changed, and we need to reallocate space.
+ child->setOverrideSize(-1);
+ if (!relayoutChildren)
+ child->setChildNeedsLayout(true, false);
+ haveFlex = true;
+ unsigned int flexGroup = child->style()->boxFlexGroup();
+ if (lowestFlexGroup == 0)
+ lowestFlexGroup = flexGroup;
+ if (flexGroup < lowestFlexGroup)
+ lowestFlexGroup = flexGroup;
+ if (flexGroup > highestFlexGroup)
+ highestFlexGroup = flexGroup;
+ }
+ child = iterator.next();
+ }
+
+ // 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;
+ if (haveLineClamp) {
+ int maxLineCount = 0;
+ child = iterator.first();
+ while (child) {
+ if (!child->isPositioned()) {
+ if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) ||
+ (child->style()->height().isAuto() && child->isBlockFlow() && !child->needsLayout())) {
+ child->setChildNeedsLayout(true, false);
+
+ // Dirty all the positioned objects.
+ if (child->isRenderBlock()) {
+ static_cast<RenderBlock*>(child)->markPositionedObjectsForLayout();
+ static_cast<RenderBlock*>(child)->clearTruncation();
+ }
+ }
+ child->layoutIfNeeded();
+ if (child->style()->height().isAuto() && child->isBlockFlow())
+ maxLineCount = max(maxLineCount, static_cast<RenderBlock*>(child)->lineCount());
+ }
+ child = iterator.next();
+ }
+
+ // 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));
+ if (numVisibleLines < maxLineCount) {
+ for (child = iterator.first(); child; child = iterator.next()) {
+ if (child->isPositioned() || !child->style()->height().isAuto() || !child->isBlockFlow())
+ continue;
+
+ RenderBlock* blockChild = static_cast<RenderBlock*>(child);
+ int lineCount = blockChild->lineCount();
+ if (lineCount <= numVisibleLines)
+ continue;
+
+ int newHeight = blockChild->heightForLineCount(numVisibleLines);
+ if (newHeight == child->height())
+ continue;
+
+ child->setChildNeedsLayout(true, false);
+ child->setOverrideSize(newHeight);
+ m_flexingChildren = true;
+ child->layoutIfNeeded();
+ m_flexingChildren = false;
+ child->setOverrideSize(-1);
+
+ // FIXME: For now don't support RTL.
+ if (style()->direction() != LTR)
+ continue;
+
+ // Get the last line
+ RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount-1);
+ if (!lastLine)
+ continue;
+
+ // See if the last item is an anchor
+ InlineBox* anchorBox = lastLine->lastChild();
+ if (!anchorBox)
+ continue;
+ if (!anchorBox->object()->element())
+ continue;
+ if (!anchorBox->object()->element()->isLink())
+ continue;
+
+ RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines-1);
+ if (!lastVisibleLine)
+ continue;
+
+ const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
+ DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
+
+ const Font& font = style(numVisibleLines == 1)->font();
+ int ellipsisAndSpaceWidth = font.width(TextRun(ellipsisAndSpace, 2));
+
+ // Get ellipsis width + " " + anchor width
+ int totalWidth = ellipsisAndSpaceWidth + anchorBox->width();
+
+ // See if this width can be accommodated on the last visible line
+ RenderBlock* destBlock = static_cast<RenderBlock*>(lastVisibleLine->object());
+ RenderBlock* srcBlock = static_cast<RenderBlock*>(lastLine->object());
+
+ // FIXME: Directions of src/destBlock could be different from our direction and from one another.
+ if (srcBlock->style()->direction() != LTR)
+ continue;
+ if (destBlock->style()->direction() != LTR)
+ continue;
+
+ int blockEdge = destBlock->rightOffset(lastVisibleLine->yPos());
+ if (!lastVisibleLine->canAccommodateEllipsis(true, blockEdge,
+ lastVisibleLine->xPos() + lastVisibleLine->width(),
+ totalWidth))
+ continue;
+
+ // Let the truncation code kick in.
+ lastVisibleLine->placeEllipsis(ellipsisAndSpaceStr, true, blockEdge, totalWidth, anchorBox);
+ destBlock->setHasMarkupTruncation(true);
+ }
+ }
+ }
+
+ // We do 2 passes. The first pass is simply to lay everyone out at
+ // their preferred widths. The second pass handles flexing the children.
+ // Our first pass is done without flexing. We simply lay the children
+ // out within the box.
+ do {
+ m_height = borderTop() + paddingTop();
+ int minHeight = m_height + toAdd;
+ m_overflowHeight = m_height;
+
+ child = iterator.first();
+ while (child) {
+ // make sure we relayout children if we need it.
+ if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))))
+ child->setChildNeedsLayout(true, false);
+
+ if (child->isPositioned())
+ {
+ child->containingBlock()->insertPositionedObject(child);
+ if (child->hasStaticX()) {
+ if (style()->direction() == LTR)
+ child->setStaticX(borderLeft()+paddingLeft());
+ else
+ child->setStaticX(borderRight()+paddingRight());
+ }
+ if (child->hasStaticY())
+ child->setStaticY(m_height);
+ child = iterator.next();
+ continue;
+ }
+
+ // Compute the child's vertical margins.
+ child->calcVerticalMargins();
+
+ // Add in the child's marginTop to our height.
+ m_height += child->marginTop();
+
+ // Now do a layout.
+ child->layoutIfNeeded();
+
+ // We can place the child now, using our value of box-align.
+ int childX = borderLeft() + paddingLeft();
+ switch (style()->boxAlign()) {
+ case BCENTER:
+ case BBASELINE: // Baseline just maps to center for vertical boxes
+ childX += child->marginLeft() + max(0, (contentWidth() - (child->width() + child->marginLeft() + child->marginRight()))/2);
+ break;
+ case BEND:
+ if (style()->direction() == RTL)
+ childX += child->marginLeft();
+ else
+ childX += contentWidth() - child->marginRight() - child->width();
+ break;
+ default: // BSTART/BSTRETCH
+ if (style()->direction() == LTR)
+ childX += child->marginLeft();
+ else
+ childX += contentWidth() - child->marginRight() - child->width();
+ break;
+ }
+
+ // Place the child.
+ placeChild(child, childX, m_height);
+ m_height += child->height() + child->marginBottom();
+
+ if (child->isRenderBlock())
+ static_cast<RenderBlock*>(child)->addVisualOverflow(static_cast<RenderBlock*>(child)->floatRect());
+
+ // See if this child has made our overflow need to grow.
+ m_overflowWidth = max(child->xPos() + child->overflowWidth(false), m_overflowWidth);
+ m_overflowLeft = min(child->xPos() + child->overflowLeft(false), m_overflowLeft);
+
+ child = iterator.next();
+ }
+
+ yPos = m_height;
+
+ if (!iterator.first() && hasLineIfEmpty())
+ m_height += lineHeight(true, true);
+
+ m_height += toAdd;
+
+ // Negative margins can cause our height to shrink below our minimal height (border/padding).
+ // If this happens, ensure that the computed height is increased to the minimal height.
+ if (m_height < minHeight)
+ m_height = minHeight;
+
+ // Always make sure our overflowheight is at least our height.
+ if (m_overflowHeight < m_height)
+ m_overflowHeight = m_height;
+
+ // Now we have to calc our height, so we know how much space we have remaining.
+ oldHeight = m_height;
+ calcHeight();
+ if (oldHeight != m_height)
+ heightSpecified = true;
+
+ remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos;
+
+ if (m_flexingChildren)
+ haveFlex = false; // We're done.
+ else if (haveFlex) {
+ // We have some flexible objects. See if we need to grow/shrink them at all.
+ if (!remainingSpace)
+ break;
+
+ // Allocate the remaining space among the flexible objects. If we are trying to
+ // grow, then we go from the lowest flex group to the highest flex group. For shrinking,
+ // we go from the highest flex group to the lowest group.
+ bool expanding = remainingSpace > 0;
+ unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
+ unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
+ for (unsigned int i = start; i <= end && remainingSpace; i++) {
+ // Always start off by assuming the group can get all the remaining space.
+ int groupRemainingSpace = remainingSpace;
+ do {
+ // Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
+ // For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
+ // computing the allowed growth before an object hits its min/max width (and thus
+ // forces a totalFlex recomputation).
+ int groupRemainingSpaceAtBeginning = groupRemainingSpace;
+ float totalFlex = 0.0f;
+ child = iterator.first();
+ while (child) {
+ if (allowedChildFlex(child, expanding, i))
+ totalFlex += child->style()->boxFlex();
+ child = iterator.next();
+ }
+ child = iterator.first();
+ int spaceAvailableThisPass = groupRemainingSpace;
+ while (child) {
+ int allowedFlex = allowedChildFlex(child, expanding, i);
+ if (allowedFlex) {
+ int projectedFlex = (allowedFlex == INT_MAX) ? allowedFlex : (int)(allowedFlex * (totalFlex / child->style()->boxFlex()));
+ spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
+ }
+ child = iterator.next();
+ }
+
+ // The flex groups may not have any flexible objects this time around.
+ if (!spaceAvailableThisPass || totalFlex == 0.0f) {
+ // If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
+ groupRemainingSpace = 0;
+ continue;
+ }
+
+ // Now distribute the space to objects.
+ child = iterator.first();
+ while (child && spaceAvailableThisPass && totalFlex) {
+ if (allowedChildFlex(child, expanding, i)) {
+ int spaceAdd = (int)(spaceAvailableThisPass * (child->style()->boxFlex()/totalFlex));
+ if (spaceAdd) {
+ child->setOverrideSize(child->overrideHeight() + spaceAdd);
+ m_flexingChildren = true;
+ relayoutChildren = true;
+ }
+
+ spaceAvailableThisPass -= spaceAdd;
+ remainingSpace -= spaceAdd;
+ groupRemainingSpace -= spaceAdd;
+
+ totalFlex -= child->style()->boxFlex();
+ }
+ child = iterator.next();
+ }
+ if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
+ // this is not advancing, avoid getting stuck by distributing the remaining pixels
+ child = iterator.first();
+ int spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
+ while (child && groupRemainingSpace) {
+ if (allowedChildFlex(child, expanding, i)) {
+ child->setOverrideSize(child->overrideHeight() + spaceAdd);
+ m_flexingChildren = true;
+ relayoutChildren = true;
+ remainingSpace -= spaceAdd;
+ groupRemainingSpace -= spaceAdd;
+ }
+ child = iterator.next();
+ }
+ }
+ } while (groupRemainingSpace);
+ }
+
+ // We didn't find any children that could grow.
+ if (haveFlex && !m_flexingChildren)
+ haveFlex = false;
+ }
+ } while (haveFlex);
+
+ if (style()->boxPack() != BSTART && remainingSpace > 0) {
+ // Children must be repositioned.
+ int offset = 0;
+ if (style()->boxPack() == BJUSTIFY) {
+ // Determine the total number of children.
+ int totalChildren = 0;
+ child = iterator.first();
+ while (child) {
+ if (child->isPositioned()) {
+ child = iterator.next();
+ continue;
+ }
+ totalChildren++;
+ child = iterator.next();
+ }
+
+ // Iterate over the children and space them out according to the
+ // justification level.
+ if (totalChildren > 1) {
+ totalChildren--;
+ bool firstChild = true;
+ child = iterator.first();
+ while (child) {
+ if (child->isPositioned()) {
+ child = iterator.next();
+ continue;
+ }
+
+ if (firstChild) {
+ firstChild = false;
+ child = iterator.next();
+ continue;
+ }
+
+ offset += remainingSpace/totalChildren;
+ remainingSpace -= (remainingSpace/totalChildren);
+ totalChildren--;
+ placeChild(child, child->xPos(), child->yPos()+offset);
+ child = iterator.next();
+ }
+ }
+ } else {
+ if (style()->boxPack() == BCENTER)
+ offset += remainingSpace/2;
+ else // END
+ offset += remainingSpace;
+ child = iterator.first();
+ while (child) {
+ if (child->isPositioned()) {
+ child = iterator.next();
+ continue;
+ }
+ placeChild(child, child->xPos(), child->yPos()+offset);
+ child = iterator.next();
+ }
+ }
+ }
+
+ child = iterator.first();
+ while (child && child->isPositioned()) {
+ child = iterator.next();
+ }
+
+ if (child) {
+ m_overflowTop = min(child->yPos() + child->overflowTop(false), m_overflowTop);
+
+ RenderObject* lastChild = child;
+ while ((child = iterator.next())) {
+ if (!child->isPositioned())
+ lastChild = child;
+ }
+ m_overflowHeight = max(lastChild->yPos() + 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.
+ if (heightSpecified)
+ m_height = oldHeight;
+}
+
+void RenderFlexibleBox::placeChild(RenderObject* child, int x, int y)
+{
+ IntRect oldRect(child->xPos(), child->yPos() , child->width(), child->height());
+
+ // Place the child.
+ child->setPos(x, y);
+
+ // 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 (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
+ child->repaintDuringLayoutIfMoved(oldRect);
+}
+
+int RenderFlexibleBox::allowedChildFlex(RenderObject* child, bool expanding, unsigned int group)
+{
+ if (child->isPositioned() || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group)
+ return 0;
+
+ if (expanding) {
+ if (isHorizontal()) {
+ // FIXME: For now just handle fixed values.
+ int maxW = INT_MAX;
+ int w = child->overrideWidth() - (child->borderLeft() + child->borderRight() + child->paddingLeft() + child->paddingRight());
+ if (!child->style()->maxWidth().isUndefined() &&
+ child->style()->maxWidth().isFixed())
+ maxW = child->style()->maxWidth().value();
+ else if (child->style()->maxWidth().type() == Intrinsic)
+ maxW = child->maxPrefWidth();
+ else if (child->style()->maxWidth().type() == MinIntrinsic)
+ maxW = child->minPrefWidth();
+ if (maxW == INT_MAX)
+ return maxW;
+ return max(0, maxW - w);
+ } else {
+ // FIXME: For now just handle fixed values.
+ int maxH = INT_MAX;
+ int h = child->overrideHeight() - (child->borderTop() + child->borderBottom() + child->paddingTop() + child->paddingBottom());
+ if (!child->style()->maxHeight().isUndefined() &&
+ child->style()->maxHeight().isFixed())
+ maxH = child->style()->maxHeight().value();
+ if (maxH == INT_MAX)
+ return maxH;
+ return max(0, maxH - h);
+ }
+ }
+
+ // FIXME: For now just handle fixed values.
+ if (isHorizontal()) {
+ int minW = child->minPrefWidth();
+ int w = child->overrideWidth() - (child->borderLeft() + child->borderRight() + child->paddingLeft() + child->paddingRight());
+ if (child->style()->minWidth().isFixed())
+ minW = child->style()->minWidth().value();
+ else if (child->style()->minWidth().type() == Intrinsic)
+ minW = child->maxPrefWidth();
+ else if (child->style()->minWidth().type() == MinIntrinsic)
+ minW = child->minPrefWidth();
+
+ int allowedShrinkage = min(0, minW - w);
+ return allowedShrinkage;
+ } else {
+ if (child->style()->minHeight().isFixed()) {
+ int minH = child->style()->minHeight().value();
+ int h = child->overrideHeight() - (child->borderLeft() + child->borderRight() + child->paddingLeft() + child->paddingRight());
+ int allowedShrinkage = min(0, minH - h);
+ return allowedShrinkage;
+ }
+ }
+
+ return 0;
+}
+
+const char *RenderFlexibleBox::renderName() const
+{
+ if (isFloating())
+ return "RenderFlexibleBox (floating)";
+ if (isPositioned())
+ return "RenderFlexibleBox (positioned)";
+ if (isRelPositioned())
+ return "RenderFlexibleBox (relative positioned)";
+ return "RenderFlexibleBox";
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.h b/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.h
new file mode 100644
index 0000000..f48caf5
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFlexibleBox.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the render object implementation for KHTML.
+ *
+ * Copyright (C) 2003 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
+ * 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 RenderFlexibleBox_h
+#define RenderFlexibleBox_h
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class RenderFlexibleBox : public RenderBlock {
+public:
+ RenderFlexibleBox(Node*);
+ virtual ~RenderFlexibleBox();
+
+ virtual const char* renderName() const;
+
+ virtual void calcPrefWidths();
+ void calcHorizontalPrefWidths();
+ void calcVerticalPrefWidths();
+
+ virtual void layoutBlock(bool relayoutChildren);
+ void layoutHorizontalBox(bool relayoutChildren);
+ void layoutVerticalBox(bool relayoutChildren);
+
+ virtual bool avoidsFloats() const { return true; }
+
+ virtual bool isFlexibleBox() const { return true; }
+ virtual bool isFlexingChildren() const { return m_flexingChildren; }
+ virtual bool isStretchingChildren() const { return m_stretchingChildren; }
+
+ void placeChild(RenderObject* child, int x, int y);
+
+protected:
+ int allowedChildFlex(RenderObject* child, bool expanding, unsigned group);
+
+ bool hasMultipleLines() const { return style()->boxLines() == MULTIPLE; }
+ bool isVertical() const { return style()->boxOrient() == VERTICAL; }
+ bool isHorizontal() const { return style()->boxOrient() == HORIZONTAL; }
+
+ bool m_flexingChildren : 1;
+ bool m_stretchingChildren : 1;
+};
+
+} // namespace WebCore
+
+#endif // RenderFlexibleBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp
new file mode 100644
index 0000000..86a92f3
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp
@@ -0,0 +1,883 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "RenderFlow.h"
+
+#include "Document.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "InlineTextBox.h"
+#include "RenderArena.h"
+#include "RenderInline.h"
+#include "RenderLayer.h"
+#include "RenderView.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#ifndef NDEBUG
+
+RenderFlow::~RenderFlow()
+{
+ ASSERT(!m_firstLineBox);
+ ASSERT(!m_lastLineBox);
+}
+
+#endif
+
+RenderFlow* RenderFlow::createAnonymousFlow(Document* doc, PassRefPtr<RenderStyle> style)
+{
+ RenderFlow* result;
+ if (style->display() == INLINE)
+ result = new (doc->renderArena()) RenderInline(doc);
+ else
+ result = new (doc->renderArena()) RenderBlock(doc);
+ result->setStyle(style);
+ return result;
+}
+
+RenderFlow* RenderFlow::continuationBefore(RenderObject* beforeChild)
+{
+ if (beforeChild && beforeChild->parent() == this)
+ return this;
+
+ RenderFlow* curr = continuation();
+ RenderFlow* nextToLast = this;
+ RenderFlow* last = this;
+ while (curr) {
+ if (beforeChild && beforeChild->parent() == curr) {
+ if (curr->firstChild() == beforeChild)
+ return last;
+ return curr;
+ }
+
+ nextToLast = last;
+ last = curr;
+ curr = curr->continuation();
+ }
+
+ if (!beforeChild && !last->firstChild())
+ return nextToLast;
+ return last;
+}
+
+void RenderFlow::addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild)
+{
+ if (beforeChild && (beforeChild->parent()->isTableRow() || beforeChild->parent()->isTableSection() || beforeChild->parent()->isTable())) {
+ RenderObject* anonymousTablePart = beforeChild->parent();
+ ASSERT(anonymousTablePart->isAnonymous());
+ while (!anonymousTablePart->isTable()) {
+ anonymousTablePart = anonymousTablePart->parent();
+ ASSERT(anonymousTablePart->isAnonymous());
+ }
+ return anonymousTablePart->addChild(newChild, beforeChild);
+ }
+
+ RenderFlow* flow = continuationBefore(beforeChild);
+ ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() ||
+ beforeChild->parent()->isRenderInline());
+ RenderFlow* beforeChildParent = beforeChild ? static_cast<RenderFlow*>(beforeChild->parent()) :
+ (flow->continuation() ? flow->continuation() : flow);
+
+ if (newChild->isFloatingOrPositioned())
+ return beforeChildParent->addChildToFlow(newChild, beforeChild);
+
+ // A continuation always consists of two potential candidates: an inline or an anonymous
+ // block box holding block children.
+ bool childInline = newChild->isInline();
+ bool bcpInline = beforeChildParent->isInline();
+ bool flowInline = flow->isInline();
+
+ if (flow == beforeChildParent)
+ return flow->addChildToFlow(newChild, beforeChild);
+ else {
+ // The goal here is to match up if we can, so that we can coalesce and create the
+ // minimal # of continuations needed for the inline.
+ if (childInline == bcpInline)
+ return beforeChildParent->addChildToFlow(newChild, beforeChild);
+ else if (flowInline == childInline)
+ return flow->addChildToFlow(newChild, 0); // Just treat like an append.
+ else
+ return beforeChildParent->addChildToFlow(newChild, beforeChild);
+ }
+}
+
+void RenderFlow::addChild(RenderObject* newChild, RenderObject* beforeChild)
+{
+ if (continuation())
+ return addChildWithContinuation(newChild, beforeChild);
+ return addChildToFlow(newChild, beforeChild);
+}
+
+void RenderFlow::extractLineBox(InlineFlowBox* box)
+{
+ checkConsistency();
+
+ m_lastLineBox = box->prevFlowBox();
+ if (box == m_firstLineBox)
+ m_firstLineBox = 0;
+ if (box->prevLineBox())
+ box->prevLineBox()->setNextLineBox(0);
+ box->setPreviousLineBox(0);
+ for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox())
+ curr->setExtracted();
+
+ checkConsistency();
+}
+
+void RenderFlow::attachLineBox(InlineFlowBox* box)
+{
+ checkConsistency();
+
+ if (m_lastLineBox) {
+ m_lastLineBox->setNextLineBox(box);
+ box->setPreviousLineBox(m_lastLineBox);
+ } else
+ m_firstLineBox = box;
+ InlineFlowBox* last = box;
+ for (InlineFlowBox* curr = box; curr; curr = curr->nextFlowBox()) {
+ curr->setExtracted(false);
+ last = curr;
+ }
+ m_lastLineBox = last;
+
+ checkConsistency();
+}
+
+void RenderFlow::removeLineBox(InlineFlowBox* box)
+{
+ checkConsistency();
+
+ if (box == m_firstLineBox)
+ m_firstLineBox = box->nextFlowBox();
+ if (box == m_lastLineBox)
+ m_lastLineBox = box->prevFlowBox();
+ if (box->nextLineBox())
+ box->nextLineBox()->setPreviousLineBox(box->prevLineBox());
+ if (box->prevLineBox())
+ box->prevLineBox()->setNextLineBox(box->nextLineBox());
+
+ checkConsistency();
+}
+
+void RenderFlow::deleteLineBoxes()
+{
+ if (m_firstLineBox) {
+ RenderArena* arena = renderArena();
+ InlineRunBox* next;
+ for (InlineRunBox* curr = m_firstLineBox; curr; curr = next) {
+ next = curr->nextLineBox();
+ curr->destroy(arena);
+ }
+ m_firstLineBox = 0;
+ m_lastLineBox = 0;
+ }
+}
+
+void RenderFlow::destroy()
+{
+ // Detach our continuation first.
+ if (m_continuation)
+ m_continuation->destroy();
+ m_continuation = 0;
+
+ // 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.
+ RenderContainer::destroyLeftoverChildren();
+
+ if (!documentBeingDestroyed()) {
+ if (m_firstLineBox) {
+ // We can't wait for RenderContainer::destroy to clear the selection,
+ // because by then we will have nuked the line boxes.
+ // FIXME: The SelectionController should be responsible for this when it
+ // is notified of DOM mutations.
+ if (isSelectionBorder())
+ view()->clearSelection();
+
+ // If line boxes are contained inside a root, that means we're an inline.
+ // In that case, we need to remove all the line boxes so that the parent
+ // lines aren't pointing to deleted children. If the first line box does
+ // not have a parent that means they are either already disconnected or
+ // root lines that can just be destroyed without disconnecting.
+ if (m_firstLineBox->parent()) {
+ for (InlineRunBox* box = m_firstLineBox; box; box = box->nextLineBox())
+ box->remove();
+ }
+
+ // If we are an anonymous block, then our line boxes might have children
+ // that will outlast this block. In the non-anonymous block case those
+ // children will be destroyed by the time we return from this function.
+ if (isAnonymousBlock()) {
+ for (InlineFlowBox* box = m_firstLineBox; box; box = box->nextFlowBox()) {
+ while (InlineBox* childBox = box->firstChild())
+ childBox->remove();
+ }
+ }
+ } else if (isInline() && parent())
+ parent()->dirtyLinesFromChangedChild(this);
+ }
+
+ deleteLineBoxes();
+
+ RenderContainer::destroy();
+}
+
+void RenderFlow::dirtyLinesFromChangedChild(RenderObject* child)
+{
+ if (!parent() || (selfNeedsLayout() && !isInlineFlow()) || isTable())
+ return;
+
+ // If we have no first line box, then just bail early.
+ if (!firstLineBox()) {
+ // For an empty inline, go ahead and propagate the check up to our parent, unless the parent
+ // is already dirty.
+ if (isInline() && !parent()->selfNeedsLayout())
+ parent()->dirtyLinesFromChangedChild(this);
+ return;
+ }
+
+ // Try to figure out which line box we belong in. First try to find a previous
+ // line box by examining our siblings. If we didn't find a line box, then use our
+ // parent's first line box.
+ RootInlineBox* box = 0;
+ RenderObject* curr = 0;
+ for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) {
+ if (curr->isFloatingOrPositioned())
+ continue;
+
+ if (curr->isReplaced()) {
+ InlineBox* wrapper = curr->inlineBoxWrapper();
+ if (wrapper)
+ box = wrapper->root();
+ } else if (curr->isText()) {
+ InlineTextBox* textBox = static_cast<RenderText*>(curr)->lastTextBox();
+ if (textBox)
+ box = textBox->root();
+ } else if (curr->isInlineFlow()) {
+ InlineRunBox* runBox = static_cast<RenderFlow*>(curr)->lastLineBox();
+ if (runBox)
+ box = runBox->root();
+ }
+
+ if (box)
+ break;
+ }
+ if (!box)
+ box = firstLineBox()->root();
+
+ // If we found a line box, then dirty it.
+ if (box) {
+ RootInlineBox* adjacentBox;
+ box->markDirty();
+
+ // dirty the adjacent lines that might be affected
+ // NOTE: we dirty the previous line because RootInlineBox objects cache
+ // the address of the first object on the next line after a BR, which we may be
+ // invalidating here. For more info, see how RenderBlock::layoutInlineChildren
+ // calls setLineBreakInfo with the result of findNextLineBreak. findNextLineBreak,
+ // despite the name, actually returns the first RenderObject after the BR.
+ // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize."
+ adjacentBox = box->prevRootBox();
+ if (adjacentBox)
+ adjacentBox->markDirty();
+ if (child->isBR() || (curr && curr->isBR())) {
+ adjacentBox = box->nextRootBox();
+ if (adjacentBox)
+ adjacentBox->markDirty();
+ }
+ }
+}
+
+int RenderFlow::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
+{
+ if (firstLine) {
+ RenderStyle* s = style(firstLine);
+ Length lh = s->lineHeight();
+ if (lh.isNegative()) {
+ if (s == style()) {
+ if (m_lineHeight == -1)
+ m_lineHeight = RenderObject::lineHeight(false);
+ return m_lineHeight;
+ }
+ return s->font().lineSpacing();
+ }
+ if (lh.isPercent())
+ return lh.calcMinValue(s->fontSize());
+ return lh.value();
+ }
+
+ if (m_lineHeight == -1)
+ m_lineHeight = RenderObject::lineHeight(false);
+ return m_lineHeight;
+}
+
+void RenderFlow::dirtyLineBoxes(bool fullLayout, bool isRootLineBox)
+{
+ if (!isRootLineBox && isReplaced())
+ return RenderContainer::dirtyLineBoxes(fullLayout, isRootLineBox);
+
+ if (fullLayout)
+ deleteLineBoxes();
+ else {
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
+ curr->dirtyLineBoxes();
+ }
+}
+
+InlineBox* RenderFlow::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool /*isOnlyRun*/)
+{
+ checkConsistency();
+
+ if (!isRootLineBox &&
+ (isReplaced() || makePlaceHolderBox)) // Inline tables and inline blocks
+ return RenderContainer::createInlineBox(false, isRootLineBox); // (or positioned element placeholders).
+
+ InlineFlowBox* flowBox = 0;
+ if (isInlineFlow())
+ flowBox = new (renderArena()) InlineFlowBox(this);
+ else
+ flowBox = new (renderArena()) RootInlineBox(this);
+
+ if (!m_firstLineBox)
+ m_firstLineBox = m_lastLineBox = flowBox;
+ else {
+ m_lastLineBox->setNextLineBox(flowBox);
+ flowBox->setPreviousLineBox(m_lastLineBox);
+ m_lastLineBox = flowBox;
+ }
+
+ checkConsistency();
+
+ return flowBox;
+}
+
+void RenderFlow::paintLines(PaintInfo& paintInfo, int tx, int ty)
+{
+ // Only paint during the foreground/selection phases.
+ if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseOutline
+ && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines && paintInfo.phase != PaintPhaseTextClip
+ && paintInfo.phase != PaintPhaseMask)
+ return;
+
+ bool inlineFlow = isInlineFlow();
+ if (inlineFlow)
+ ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer.
+
+ // If we have no lines then we have no work to do.
+ if (!firstLineBox())
+ return;
+
+ // We can check the first box and last box and avoid painting if we don't
+ // 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() - maximalOutlineSize(paintInfo.phase);
+ int h = maximalOutlineSize(paintInfo.phase) + lastLineBox()->root()->bottomOverflow() - yPos;
+ yPos += ty;
+ if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y())
+ return;
+
+ PaintInfo info(paintInfo);
+ RenderFlowSequencedSet outlineObjects;
+ info.outlineObjects = &outlineObjects;
+
+ // See if our root lines intersect with the dirty rect. If so, then we paint
+ // them. 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.
+ RenderView* v = view();
+ bool usePrintRect = !v->printRect().isEmpty();
+ for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) {
+ if (usePrintRect) {
+ // FIXME: This is a feeble effort to avoid splitting a line across two pages.
+ // It is utterly inadequate, and this should not be done at paint time at all.
+ // 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(), this);
+ // If we were able to truncate, don't paint.
+ if (ty + curr->root()->topOverflow() >= v->truncatedAt())
+ break;
+ }
+ }
+ }
+
+ int top = min(curr->root()->topOverflow(), curr->root()->selectionTop()) - maximalOutlineSize(info.phase);
+ int bottom = curr->root()->bottomOverflow() + maximalOutlineSize(info.phase);
+ h = bottom - top;
+ yPos = ty + top;
+ if (yPos < info.rect.bottom() && yPos + h > info.rect.y())
+ curr->paint(info, tx, ty);
+ }
+
+ if (info.phase == PaintPhaseOutline || info.phase == PaintPhaseSelfOutline || info.phase == PaintPhaseChildOutlines) {
+ RenderFlowSequencedSet::iterator end = info.outlineObjects->end();
+ for (RenderFlowSequencedSet::iterator it = info.outlineObjects->begin(); it != end; ++it) {
+ RenderFlow* flow = *it;
+ flow->paintOutline(info.context, tx, ty);
+ }
+ info.outlineObjects->clear();
+ }
+}
+
+bool RenderFlow::hitTestLines(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
+{
+ if (hitTestAction != HitTestForeground)
+ return false;
+
+ bool inlineFlow = isInlineFlow();
+ if (inlineFlow)
+ ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer.
+
+ // If we have no lines then we have no work to do.
+ if (!firstLineBox())
+ return false;
+
+ // We can check the first box and last box and avoid hit testing if we don't
+ // 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()))
+ 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()) {
+ bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty);
+ if (inside) {
+ updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+IntRect RenderFlow::absoluteClippedOverflowRect()
+{
+ if (isInlineFlow()) {
+ // Only compacts and run-ins are allowed in here during layout.
+ ASSERT(!view() || !view()->layoutState() || isCompact() || isRunIn());
+
+ if (!firstLineBox() && !continuation())
+ return IntRect();
+
+ // Find our leftmost position.
+ int left = 0;
+ int top = firstLineBox() ? firstLineBox()->yPos() : 0;
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
+ if (curr == firstLineBox() || curr->xPos() < left)
+ left = curr->xPos();
+ }
+
+ // Now invalidate a rectangle.
+ int ow = style() ? style()->outlineSize() : 0;
+ if (isCompact())
+ left -= m_x;
+
+ // We need to add in the relative position offsets of any inlines (including us) up to our
+ // containing block.
+ RenderBlock* cb = containingBlock();
+ for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isInlineFlow() && inlineFlow != cb;
+ inlineFlow = inlineFlow->parent()) {
+ if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
+ inlineFlow->layer()->relativePositionOffset(left, top);
+ }
+
+ IntRect r(-ow + left, -ow + top, width() + ow * 2, height() + ow * 2);
+ if (cb->hasColumns())
+ cb->adjustRectForColumns(r);
+
+ if (cb->hasOverflowClip()) {
+ // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
+ // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
+ // anyway if its size does change.
+ int x = r.x();
+ int y = r.y();
+ IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height());
+ cb->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden.
+ IntRect repaintRect(x, y, r.width(), r.height());
+ r = intersection(repaintRect, boxRect);
+ }
+ cb->computeAbsoluteRepaintRect(r);
+
+ if (ow) {
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+ if (!curr->isText()) {
+ IntRect childRect = curr->getAbsoluteRepaintRectWithOutline(ow);
+ r.unite(childRect);
+ }
+ }
+
+ if (continuation() && !continuation()->isInline()) {
+ IntRect contRect = continuation()->getAbsoluteRepaintRectWithOutline(ow);
+ r.unite(contRect);
+ }
+ }
+
+ return r;
+ }
+
+ return RenderContainer::absoluteClippedOverflowRect();
+}
+
+int RenderFlow::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ ASSERT(!isInlineFlow());
+ if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
+ return includeSelf && m_width > 0 ? overflowHeight(false) : 0;
+
+ int bottom = includeSelf && m_width > 0 ? m_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
+ // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to
+ // the abs div.
+ for (RenderObject* c = firstChild(); c; c = c->nextSibling()) {
+ if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow())
+ bottom = max(bottom, c->yPos() + c->lowestPosition(false));
+ }
+ }
+
+ if (includeSelf && isRelPositioned())
+ bottom += relativePositionOffsetY();
+
+ return bottom;
+}
+
+int RenderFlow::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ ASSERT(!isInlineFlow());
+ if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
+ return includeSelf && m_height > 0 ? overflowWidth(false) : 0;
+
+ int right = includeSelf && m_height > 0 ? m_width : 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
+ // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to
+ // the abs div.
+ for (RenderObject* c = firstChild(); c; c = c->nextSibling()) {
+ if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow())
+ right = max(right, c->xPos() + c->rightmostPosition(false));
+ }
+ }
+
+ if (includeSelf && isRelPositioned())
+ right += relativePositionOffsetX();
+
+ return right;
+}
+
+int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ ASSERT(!isInlineFlow());
+ if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
+ return includeSelf && m_height > 0 ? overflowLeft(false) : m_width;
+
+ int left = includeSelf && m_height > 0 ? 0 : m_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
+ // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to
+ // the abs div.
+ for (RenderObject* c = firstChild(); c; c = c->nextSibling()) {
+ if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow())
+ left = min(left, c->xPos() + c->leftmostPosition(false));
+ }
+ }
+
+ if (includeSelf && isRelPositioned())
+ left += relativePositionOffsetX();
+
+ return left;
+}
+
+IntRect RenderFlow::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
+{
+ // Do the normal calculation in most cases.
+ if (firstChild() || style()->display() == INLINE)
+ return RenderContainer::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
+
+ // This is a special case:
+ // The element is not an inline element, and it's empty. So we have to
+ // calculate a fake position to indicate where objects are to be inserted.
+
+ // FIXME: This does not take into account either :first-line or :first-letter
+ // However, as soon as some content is entered, the line boxes will be
+ // constructed and this kludge is not called any more. So only the caret size
+ // of an empty :first-line'd block is wrong. I think we can live with that.
+ RenderStyle* currentStyle = firstLineStyle();
+ int height = lineHeight(true);
+ const int caretWidth = 1;
+
+ enum CaretAlignment { alignLeft, alignRight, alignCenter };
+
+ CaretAlignment alignment = alignLeft;
+
+ switch (currentStyle->textAlign()) {
+ case TAAUTO:
+ case JUSTIFY:
+ if (currentStyle->direction() == RTL)
+ alignment = alignRight;
+ break;
+ case LEFT:
+ case WEBKIT_LEFT:
+ break;
+ case CENTER:
+ case WEBKIT_CENTER:
+ alignment = alignCenter;
+ break;
+ case RIGHT:
+ case WEBKIT_RIGHT:
+ alignment = alignRight;
+ break;
+ }
+
+ int x = borderLeft() + paddingLeft();
+ int w = width();
+
+ switch (alignment) {
+ case alignLeft:
+ break;
+ case alignCenter:
+ x = (x + w - (borderRight() + paddingRight())) / 2;
+ break;
+ case alignRight:
+ x = w - (borderRight() + paddingRight());
+ break;
+ }
+
+ if (extraWidthToEndOfLine) {
+ if (isRenderBlock()) {
+ *extraWidthToEndOfLine = w - (x + caretWidth);
+ } else {
+ // FIXME: This code looks wrong.
+ // myRight and containerRight are set up, but then clobbered.
+ // So *extraWidthToEndOfLine will always be 0 here.
+
+ int myRight = x + caretWidth;
+ // FIXME: why call localToAbsoluteForContent() twice here, too?
+ FloatPoint absRightPoint = localToAbsoluteForContent(FloatPoint(myRight, 0));
+
+ int containerRight = containingBlock()->xPos() + containingBlockWidth();
+ FloatPoint absContainerPoint = localToAbsoluteForContent(FloatPoint(containerRight, 0));
+
+ *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
+ }
+ }
+
+ int y = paddingTop() + borderTop();
+
+ return IntRect(x, y, caretWidth, height);
+}
+
+void RenderFlow::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+{
+ if (isRenderBlock()) {
+ // Continuations should include their margins in the outline rect.
+ if (continuation()) {
+ bool nextInlineHasLineBox = continuation()->firstLineBox();
+ bool prevInlineHasLineBox = static_cast<RenderFlow*>(continuation()->element()->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()));
+ }
+
+ if (!hasOverflowClip() && !hasControlClip()) {
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
+ graphicsContext->addFocusRingRect(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height()));
+
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
+ if (!curr->isText() && !curr->isListMarker()) {
+ FloatPoint pos;
+ // FIXME: This doesn't work correctly with transforms.
+ if (curr->layer())
+ pos = curr->localToAbsolute();
+ else
+ pos = FloatPoint(tx + curr->xPos(), ty + curr->yPos());
+ curr->addFocusRingRects(graphicsContext, pos.x(), pos.y());
+ }
+ }
+
+ if (continuation()) {
+ if (isInline())
+ continuation()->addFocusRingRects(graphicsContext,
+ tx - containingBlock()->xPos() + continuation()->xPos(),
+ ty - containingBlock()->yPos() + continuation()->yPos());
+ else
+ continuation()->addFocusRingRects(graphicsContext,
+ tx - xPos() + continuation()->containingBlock()->xPos(),
+ ty - yPos() + continuation()->containingBlock()->yPos());
+ }
+}
+
+void RenderFlow::paintOutline(GraphicsContext* graphicsContext, int tx, int ty)
+{
+ if (!hasOutline())
+ return;
+
+ if (style()->outlineStyleIsAuto() || hasOutlineAnnotation()) {
+ int ow = style()->outlineWidth();
+ Color oc = style()->outlineColor();
+ if (!oc.isValid())
+ oc = style()->color();
+
+ graphicsContext->initFocusRing(ow, style()->outlineOffset());
+ addFocusRingRects(graphicsContext, tx, ty);
+ if (style()->outlineStyleIsAuto())
+ graphicsContext->drawFocusRing(oc);
+ else
+ addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect());
+ graphicsContext->clearFocusRing();
+ }
+
+ if (style()->outlineStyleIsAuto() || style()->outlineStyle() == BNONE)
+ return;
+
+ Vector<IntRect> rects;
+
+ rects.append(IntRect());
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
+ rects.append(IntRect(curr->xPos(), curr->yPos(), curr->width(), curr->height()));
+
+ rects.append(IntRect());
+
+ for (unsigned i = 1; i < rects.size() - 1; i++)
+ paintOutlineForLine(graphicsContext, tx, ty, rects.at(i - 1), rects.at(i), rects.at(i + 1));
+}
+
+void RenderFlow::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, int ty,
+ const IntRect& lastline, const IntRect& thisline, const IntRect& nextline)
+{
+ int ow = style()->outlineWidth();
+ EBorderStyle os = style()->outlineStyle();
+ Color oc = style()->outlineColor();
+ if (!oc.isValid())
+ oc = style()->color();
+
+ int offset = style()->outlineOffset();
+
+ int t = ty + thisline.y() - offset;
+ int l = tx + thisline.x() - offset;
+ int b = ty + thisline.bottom() + offset;
+ int r = tx + thisline.right() + offset;
+
+ // left edge
+ drawBorder(graphicsContext,
+ l - ow,
+ t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0),
+ l,
+ b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0),
+ BSLeft,
+ oc, style()->color(), os,
+ (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow),
+ (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow));
+
+ // right edge
+ drawBorder(graphicsContext,
+ r,
+ t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0),
+ r + ow,
+ b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0),
+ BSRight,
+ oc, style()->color(), os,
+ (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow),
+ (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow));
+ // upper edge
+ if (thisline.x() < lastline.x())
+ drawBorder(graphicsContext,
+ l - ow,
+ t - ow,
+ min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())),
+ t ,
+ BSTop, oc, style()->color(), os,
+ ow,
+ (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow);
+
+ if (lastline.right() < thisline.right())
+ drawBorder(graphicsContext,
+ max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow),
+ t - ow,
+ r + ow,
+ t ,
+ BSTop, oc, style()->color(), os,
+ (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow,
+ ow);
+
+ // lower edge
+ if (thisline.x() < nextline.x())
+ drawBorder(graphicsContext,
+ l - ow,
+ b,
+ min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000),
+ b + ow,
+ BSBottom, oc, style()->color(), os,
+ ow,
+ (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow);
+
+ if (nextline.right() < thisline.right())
+ drawBorder(graphicsContext,
+ max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow),
+ b,
+ r + ow,
+ b + ow,
+ BSBottom, oc, style()->color(), os,
+ (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow,
+ ow);
+}
+
+void RenderFlow::calcMargins(int containerWidth)
+{
+ m_marginLeft = style()->marginLeft().calcMinValue(containerWidth);
+ m_marginRight = style()->marginRight().calcMinValue(containerWidth);
+}
+
+#ifndef NDEBUG
+
+void RenderFlow::checkConsistency() const
+{
+#ifdef CHECK_CONSISTENCY
+ const InlineFlowBox* prev = 0;
+ for (const InlineFlowBox* child = m_firstLineBox; child != 0; child = child->nextFlowBox()) {
+ ASSERT(child->object() == this);
+ ASSERT(child->prevFlowBox() == prev);
+ prev = child;
+ }
+ ASSERT(prev == m_lastLineBox);
+#endif
+}
+
+#endif
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFlow.h b/src/3rdparty/webkit/WebCore/rendering/RenderFlow.h
new file mode 100644
index 0000000..7e3a345
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFlow.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 RenderFlow_h
+#define RenderFlow_h
+
+#include "RenderContainer.h"
+
+namespace WebCore {
+
+/**
+ * all geometry managing stuff is only in the block elements.
+ *
+ * Inline elements don't layout themselves, but the whole paragraph
+ * gets flowed by the surrounding block element. This is, because
+ * one needs to know the whole paragraph to calculate bidirectional
+ * behaviour of text, so putting the layouting routines in the inline
+ * elements is impossible.
+ */
+class RenderFlow : public RenderContainer {
+public:
+ RenderFlow(Node* node)
+ : RenderContainer(node)
+ , m_continuation(0)
+ , m_firstLineBox(0)
+ , m_lastLineBox(0)
+ , m_lineHeight(-1)
+ , m_childrenInline(true)
+ , m_firstLine(false)
+ , m_topMarginQuirk(false)
+ , m_bottomMarginQuirk(false)
+ , m_hasMarkupTruncation(false)
+ , m_selectionState(SelectionNone)
+ , m_hasColumns(false)
+ , m_isContinuation(false)
+ {
+ }
+#ifndef NDEBUG
+ virtual ~RenderFlow();
+#endif
+
+ virtual RenderFlow* continuation() const { return m_continuation; }
+ void setContinuation(RenderFlow* c) { m_continuation = c; }
+ RenderFlow* continuationBefore(RenderObject* beforeChild);
+
+ void addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild);
+ virtual void addChildToFlow(RenderObject* newChild, RenderObject* beforeChild) = 0;
+ virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0);
+
+ static RenderFlow* createAnonymousFlow(Document*, PassRefPtr<RenderStyle>);
+
+ void extractLineBox(InlineFlowBox*);
+ void attachLineBox(InlineFlowBox*);
+ void removeLineBox(InlineFlowBox*);
+ void deleteLineBoxes();
+ virtual void destroy();
+
+ virtual void dirtyLinesFromChangedChild(RenderObject* child);
+
+ virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
+
+ InlineFlowBox* firstLineBox() const { return m_firstLineBox; }
+ InlineFlowBox* lastLineBox() const { return m_lastLineBox; }
+
+ virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun=false);
+ virtual void dirtyLineBoxes(bool fullLayout, bool isRootLineBox = false);
+
+ void paintLines(PaintInfo&, int tx, int ty);
+ bool hitTestLines(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ virtual IntRect absoluteClippedOverflowRect();
+
+ 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;
+
+ virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
+
+ virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+ void paintOutlineForLine(GraphicsContext*, int tx, int ty, const IntRect& prevLine, const IntRect& thisLine, const IntRect& nextLine);
+ void paintOutline(GraphicsContext*, int tx, int ty);
+
+ virtual bool hasColumns() const { return m_hasColumns; }
+
+ void calcMargins(int containerWidth);
+
+ void checkConsistency() const;
+
+private:
+ // An inline can be split with blocks occurring in between the inline content.
+ // When this occurs we need a pointer to our next object. We can basically be
+ // split into a sequence of inlines and blocks. The continuation will either be
+ // an anonymous block (that houses other blocks) or it will be an inline flow.
+ RenderFlow* m_continuation;
+
+protected:
+ // For block flows, each box represents the root inline box for a line in the
+ // paragraph.
+ // For inline flows, each box represents a portion of that inline.
+ InlineFlowBox* m_firstLineBox;
+ InlineFlowBox* m_lastLineBox;
+
+ mutable int m_lineHeight;
+
+ // These bitfields are moved here from subclasses to pack them together
+ // from RenderBlock
+ bool m_childrenInline : 1;
+ bool m_firstLine : 1;
+ bool m_topMarginQuirk : 1;
+ bool m_bottomMarginQuirk : 1;
+ bool m_hasMarkupTruncation : 1;
+ unsigned m_selectionState : 3; // SelectionState
+ bool m_hasColumns : 1;
+
+ // from RenderInline
+ bool m_isContinuation : 1; // Whether or not we're a continuation of an inline.
+};
+
+#ifdef NDEBUG
+inline void RenderFlow::checkConsistency() const
+{
+}
+#endif
+
+} // namespace WebCore
+
+#endif // RenderFlow_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp
new file mode 100644
index 0000000..83401fc
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.cpp
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 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
+ * 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"
+
+#if ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT)
+#include "RenderForeignObject.h"
+
+#include "GraphicsContext.h"
+#include "RenderView.h"
+#include "SVGForeignObjectElement.h"
+#include "SVGLength.h"
+#include "SVGTransformList.h"
+
+namespace WebCore {
+
+RenderForeignObject::RenderForeignObject(SVGForeignObjectElement* node)
+ : RenderSVGBlock(node)
+{
+}
+
+TransformationMatrix RenderForeignObject::translationForAttributes()
+{
+ SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(element());
+ return TransformationMatrix().translate(foreign->x().value(foreign), foreign->y().value(foreign));
+}
+
+void RenderForeignObject::paint(PaintInfo& paintInfo, int parentX, int parentY)
+{
+ if (paintInfo.context->paintingDisabled())
+ return;
+
+ paintInfo.context->save();
+ paintInfo.context->concatCTM(TransformationMatrix().translate(parentX, parentY));
+ paintInfo.context->concatCTM(localTransform());
+ paintInfo.context->concatCTM(translationForAttributes());
+ paintInfo.context->clip(getClipRect(parentX, parentY));
+
+ float opacity = style()->opacity();
+ if (opacity < 1.0f)
+ // FIXME: Possible optimization by clipping to bbox here, once relativeBBox is implemented & clip, mask and filter support added.
+ paintInfo.context->beginTransparencyLayer(opacity);
+
+ PaintInfo pi(paintInfo);
+ pi.rect = absoluteTransform().inverse().mapRect(paintInfo.rect);
+ RenderBlock::paint(pi, 0, 0);
+
+ if (opacity < 1.0f)
+ paintInfo.context->endTransparencyLayer();
+
+ paintInfo.context->restore();
+}
+
+void RenderForeignObject::computeAbsoluteRepaintRect(IntRect& r, bool f)
+{
+ TransformationMatrix transform = translationForAttributes() * localTransform();
+ r = transform.mapRect(r);
+
+ RenderBlock::computeAbsoluteRepaintRect(r, f);
+}
+
+bool RenderForeignObject::requiresLayer()
+{
+ return false;
+}
+
+bool RenderForeignObject::calculateLocalTransform()
+{
+ TransformationMatrix oldTransform = m_localTransform;
+ m_localTransform = static_cast<SVGForeignObjectElement*>(element())->animatedLocalTransform();
+ return (oldTransform != m_localTransform);
+}
+
+void RenderForeignObject::layout()
+{
+ ASSERT(needsLayout());
+
+ // Arbitrary affine transforms are incompatible with LayoutState.
+ view()->disableLayoutState();
+
+ IntRect oldBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout();
+ if (checkForRepaint) {
+ oldBounds = m_absoluteBounds;
+ oldOutlineBox = absoluteOutlineBounds();
+ }
+
+ calculateLocalTransform();
+
+ RenderBlock::layout();
+
+ m_absoluteBounds = absoluteClippedOverflowRect();
+
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+
+ view()->enableLayoutState();
+ setNeedsLayout(false);
+}
+
+bool RenderForeignObject::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
+{
+ TransformationMatrix totalTransform = absoluteTransform();
+ totalTransform *= translationForAttributes();
+ double localX, localY;
+ totalTransform.inverse().map(x, y, &localX, &localY);
+ return RenderBlock::nodeAtPoint(request, result, static_cast<int>(localX), static_cast<int>(localY), tx, ty, hitTestAction);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h
new file mode 100644
index 0000000..c7f30e9
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderForeignObject.h
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 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
+ * 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 RenderForeignObject_h
+#define RenderForeignObject_h
+#if ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT)
+
+#include "TransformationMatrix.h"
+#include "RenderSVGBlock.h"
+
+namespace WebCore {
+
+class SVGForeignObjectElement;
+
+class RenderForeignObject : public RenderSVGBlock {
+public:
+ RenderForeignObject(SVGForeignObjectElement*);
+
+ virtual const char* renderName() const { return "RenderForeignObject"; }
+
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+
+ virtual TransformationMatrix localTransform() const { return m_localTransform; }
+ virtual bool calculateLocalTransform();
+
+ virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed);
+ virtual bool requiresLayer();
+ virtual void layout();
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ private:
+ TransformationMatrix translationForAttributes();
+
+ TransformationMatrix m_localTransform;
+ IntRect m_absoluteBounds;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT)
+#endif // RenderForeignObject_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp
new file mode 100644
index 0000000..15bd24e
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrame.cpp
@@ -0,0 +1,62 @@
+/**
+ * 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)
+ * Copyright (C) 2004, 2005, 2006 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
+ * 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 "RenderFrame.h"
+#include "RenderFrameSet.h"
+#include "FrameView.h"
+#include "HTMLFrameSetElement.h"
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderFrame::RenderFrame(HTMLFrameElement* frame)
+ : RenderPart(frame)
+{
+ setInline(false);
+}
+
+FrameEdgeInfo RenderFrame::edgeInfo() const
+{
+ return FrameEdgeInfo(element()->noResize(), element()->hasFrameBorder());
+}
+
+void RenderFrame::viewCleared()
+{
+ if (element() && m_widget && m_widget->isFrameView()) {
+ FrameView* view = static_cast<FrameView*>(m_widget);
+ int marginw = element()->getMarginWidth();
+ int marginh = element()->getMarginHeight();
+
+ if (marginw != -1)
+ view->setMarginWidth(marginw);
+ if (marginh != -1)
+ view->setMarginHeight(marginh);
+ }
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrame.h b/src/3rdparty/webkit/WebCore/rendering/RenderFrame.h
new file mode 100644
index 0000000..49aedd3
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrame.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the KDE project.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2006 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
+ * 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 RenderFrame_h
+#define RenderFrame_h
+
+#include "HTMLFrameElement.h"
+#include "RenderPart.h"
+#include "RenderFrameSet.h"
+
+namespace WebCore {
+
+class RenderFrame : public RenderPart {
+public:
+ RenderFrame(HTMLFrameElement*);
+
+ virtual const char* renderName() const { return "RenderFrame"; }
+ virtual bool isFrame() const { return true; }
+
+ HTMLFrameElement* element() const { return static_cast<HTMLFrameElement*>(RenderPart::element()); }
+
+ FrameEdgeInfo edgeInfo() const;
+
+ virtual void viewCleared();
+};
+
+} // namespace WebCore
+
+#endif // RenderFrame_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp
new file mode 100644
index 0000000..d93fa86
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.cpp
@@ -0,0 +1,669 @@
+/**
+ * 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)
+ * Copyright (C) 2004, 2005, 2006 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
+ * 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 "RenderFrameSet.h"
+
+#include "Document.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLFrameSetElement.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "MouseEvent.h"
+#include "RenderFrame.h"
+#include "RenderView.h"
+
+namespace WebCore {
+
+RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet)
+ : RenderContainer(frameSet)
+ , m_isResizing(false)
+ , m_isChildResizing(false)
+{
+ setInline(false);
+}
+
+RenderFrameSet::~RenderFrameSet()
+{
+}
+
+RenderFrameSet::GridAxis::GridAxis()
+ : m_splitBeingResized(noSplit)
+{
+}
+
+inline HTMLFrameSetElement* RenderFrameSet::frameSet() const
+{
+ return static_cast<HTMLFrameSetElement*>(node());
+}
+
+static Color borderStartEdgeColor()
+{
+ return Color(170,170,170);
+}
+
+static Color borderEndEdgeColor()
+{
+ return Color::black;
+}
+
+static Color borderFillColor()
+{
+ return Color(208, 208, 208);
+}
+
+void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
+{
+ if (!paintInfo.rect.intersects(borderRect))
+ return;
+
+ // FIXME: We should do something clever when borders from distinct framesets meet at a join.
+
+ // Fill first.
+ GraphicsContext* context = paintInfo.context;
+ context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->borderLeftColor() : borderFillColor());
+
+ // 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());
+ }
+}
+
+void RenderFrameSet::paintRowBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
+{
+ if (!paintInfo.rect.intersects(borderRect))
+ return;
+
+ // FIXME: We should do something clever when borders from distinct framesets meet at a join.
+
+ // Fill first.
+ GraphicsContext* context = paintInfo.context;
+ context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->borderLeftColor() : borderFillColor());
+
+ // 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());
+ }
+}
+
+void RenderFrameSet::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (paintInfo.phase != PaintPhaseForeground)
+ return;
+
+ RenderObject* child = firstChild();
+ if (!child)
+ return;
+
+ // Add in our offsets.
+ tx += m_x;
+ ty += m_y;
+
+ int rows = frameSet()->totalRows();
+ int cols = frameSet()->totalCols();
+ int borderThickness = frameSet()->border();
+
+ int yPos = 0;
+ for (int r = 0; r < rows; r++) {
+ int xPos = 0;
+ for (int c = 0; c < cols; c++) {
+ child->paint(paintInfo, tx, ty);
+ xPos += m_cols.m_sizes[c];
+ if (borderThickness && m_cols.m_allowBorder[c + 1]) {
+ paintColumnBorder(paintInfo, IntRect(tx + xPos, ty + yPos, borderThickness, height()));
+ xPos += borderThickness;
+ }
+ child = child->nextSibling();
+ if (!child)
+ return;
+ }
+ yPos += m_rows.m_sizes[r];
+ if (borderThickness && m_rows.m_allowBorder[r + 1]) {
+ paintRowBorder(paintInfo, IntRect(tx, ty + yPos, width(), borderThickness));
+ yPos += borderThickness;
+ }
+ }
+}
+
+bool RenderFrameSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
+ int x, int y, int tx, int ty, HitTestAction action)
+{
+ if (action != HitTestForeground)
+ return false;
+
+ bool inside = RenderContainer::nodeAtPoint(request, result, x, y, tx, ty, action)
+ || m_isResizing || canResize(IntPoint(x, y));
+
+ if (inside && frameSet()->noResize()
+ && !request.readonly && !result.innerNode()) {
+ result.setInnerNode(node());
+ result.setInnerNonSharedNode(node());
+ }
+
+ return inside || m_isChildResizing;
+}
+
+void RenderFrameSet::GridAxis::resize(int size)
+{
+ m_sizes.resize(size);
+ m_deltas.resize(size);
+ m_deltas.fill(0);
+
+ // To track edges for resizability and borders, we need to be (size + 1). This is because a parent frameset
+ // may ask us for information about our left/top/right/bottom edges in order to make its own decisions about
+ // what to do. We are capable of tainting that parent frameset's borders, so we have to cache this info.
+ m_preventResize.resize(size + 1);
+ m_allowBorder.resize(size + 1);
+}
+
+void RenderFrameSet::layOutAxis(GridAxis& axis, const Length* grid, int availableLen)
+{
+ availableLen = max(availableLen, 0);
+
+ int* gridLayout = axis.m_sizes.data();
+
+ if (!grid) {
+ gridLayout[0] = availableLen;
+ return;
+ }
+
+ int gridLen = axis.m_sizes.size();
+ ASSERT(gridLen);
+
+ int totalRelative = 0;
+ int totalFixed = 0;
+ int totalPercent = 0;
+ int countRelative = 0;
+ int countFixed = 0;
+ int countPercent = 0;
+
+ // First we need to investigate how many columns of each type we have and
+ // how much space these columns are going to require.
+ for (int i = 0; i < gridLen; ++i) {
+ // Count the total length of all of the fixed columns/rows -> totalFixed
+ // Count the number of columns/rows which are fixed -> countFixed
+ if (grid[i].isFixed()) {
+ gridLayout[i] = max(grid[i].value(), 0);
+ totalFixed += gridLayout[i];
+ countFixed++;
+ }
+
+ // Count the total percentage of all of the percentage columns/rows -> totalPercent
+ // Count the number of columns/rows which are percentages -> countPercent
+ if (grid[i].isPercent()) {
+ gridLayout[i] = max(grid[i].calcValue(availableLen), 0);
+ totalPercent += gridLayout[i];
+ countPercent++;
+ }
+
+ // Count the total relative of all the relative columns/rows -> totalRelative
+ // Count the number of columns/rows which are relative -> countRelative
+ if (grid[i].isRelative()) {
+ totalRelative += max(grid[i].value(), 1);
+ countRelative++;
+ }
+ }
+
+ int remainingLen = availableLen;
+
+ // Fixed columns/rows are our first priority. If there is not enough space to fit all fixed
+ // columns/rows we need to proportionally adjust their size.
+ if (totalFixed > remainingLen) {
+ int remainingFixed = remainingLen;
+
+ for (int i = 0; i < gridLen; ++i) {
+ if (grid[i].isFixed()) {
+ gridLayout[i] = (gridLayout[i] * remainingFixed) / totalFixed;
+ remainingLen -= gridLayout[i];
+ }
+ }
+ } else
+ remainingLen -= totalFixed;
+
+ // Percentage columns/rows are our second priority. Divide the remaining space proportionally
+ // over all percentage columns/rows. IMPORTANT: the size of each column/row is not relative
+ // to 100%, but to the total percentage. For example, if there are three columns, each of 75%,
+ // and the available space is 300px, each column will become 100px in width.
+ if (totalPercent > remainingLen) {
+ int remainingPercent = remainingLen;
+
+ for (int i = 0; i < gridLen; ++i) {
+ if (grid[i].isPercent()) {
+ gridLayout[i] = (gridLayout[i] * remainingPercent) / totalPercent;
+ remainingLen -= gridLayout[i];
+ }
+ }
+ } else
+ remainingLen -= totalPercent;
+
+ // Relative columns/rows are our last priority. Divide the remaining space proportionally
+ // over all relative columns/rows. IMPORTANT: the relative value of 0* is treated as 1*.
+ if (countRelative) {
+ int lastRelative = 0;
+ int remainingRelative = remainingLen;
+
+ for (int i = 0; i < gridLen; ++i) {
+ if (grid[i].isRelative()) {
+ gridLayout[i] = (max(grid[i].value(), 1) * remainingRelative) / totalRelative;
+ remainingLen -= gridLayout[i];
+ lastRelative = i;
+ }
+ }
+
+ // If we could not evenly distribute the available space of all of the relative
+ // columns/rows, the remainder will be added to the last column/row.
+ // For example: if we have a space of 100px and three columns (*,*,*), the remainder will
+ // be 1px and will be added to the last column: 33px, 33px, 34px.
+ if (remainingLen) {
+ gridLayout[lastRelative] += remainingLen;
+ remainingLen = 0;
+ }
+ }
+
+ // If we still have some left over space we need to divide it over the already existing
+ // columns/rows
+ if (remainingLen) {
+ // Our first priority is to spread if over the percentage columns. The remaining
+ // space is spread evenly, for example: if we have a space of 100px, the columns
+ // definition of 25%,25% used to result in two columns of 25px. After this the
+ // columns will each be 50px in width.
+ if (countPercent && totalPercent) {
+ int remainingPercent = remainingLen;
+ int changePercent = 0;
+
+ for (int i = 0; i < gridLen; ++i) {
+ if (grid[i].isPercent()) {
+ changePercent = (remainingPercent * gridLayout[i]) / totalPercent;
+ gridLayout[i] += changePercent;
+ remainingLen -= changePercent;
+ }
+ }
+ } else if (totalFixed) {
+ // Our last priority is to spread the remaining space over the fixed columns.
+ // For example if we have 100px of space and two column of each 40px, both
+ // columns will become exactly 50px.
+ int remainingFixed = remainingLen;
+ int changeFixed = 0;
+
+ for (int i = 0; i < gridLen; ++i) {
+ if (grid[i].isFixed()) {
+ changeFixed = (remainingFixed * gridLayout[i]) / totalFixed;
+ gridLayout[i] += changeFixed;
+ remainingLen -= changeFixed;
+ }
+ }
+ }
+ }
+
+ // If we still have some left over space we probably ended up with a remainder of
+ // a division. We cannot spread it evenly anymore. If we have any percentage
+ // columns/rows simply spread the remainder equally over all available percentage columns,
+ // regardless of their size.
+ if (remainingLen && countPercent) {
+ int remainingPercent = remainingLen;
+ int changePercent = 0;
+
+ for (int i = 0; i < gridLen; ++i) {
+ if (grid[i].isPercent()) {
+ changePercent = remainingPercent / countPercent;
+ gridLayout[i] += changePercent;
+ remainingLen -= changePercent;
+ }
+ }
+ }
+
+ // If we don't have any percentage columns/rows we only have fixed columns. Spread
+ // the remainder equally over all fixed columns/rows.
+ else if (remainingLen && countFixed) {
+ int remainingFixed = remainingLen;
+ int changeFixed = 0;
+
+ for (int i = 0; i < gridLen; ++i) {
+ if (grid[i].isFixed()) {
+ changeFixed = remainingFixed / countFixed;
+ gridLayout[i] += changeFixed;
+ remainingLen -= changeFixed;
+ }
+ }
+ }
+
+ // Still some left over. Add it to the last column, because it is impossible
+ // spread it evenly or equally.
+ if (remainingLen)
+ gridLayout[gridLen - 1] += remainingLen;
+
+ // now we have the final layout, distribute the delta over it
+ bool worked = true;
+ int* gridDelta = axis.m_deltas.data();
+ for (int i = 0; i < gridLen; ++i) {
+ if (gridLayout[i] && gridLayout[i] + gridDelta[i] <= 0)
+ worked = false;
+ gridLayout[i] += gridDelta[i];
+ }
+ // if the deltas broke something, undo them
+ if (!worked) {
+ for (int i = 0; i < gridLen; ++i)
+ gridLayout[i] -= gridDelta[i];
+ axis.m_deltas.fill(0);
+ }
+}
+
+void RenderFrameSet::fillFromEdgeInfo(const FrameEdgeInfo& edgeInfo, int r, int c)
+{
+ if (edgeInfo.allowBorder(LeftFrameEdge))
+ m_cols.m_allowBorder[c] = true;
+ if (edgeInfo.allowBorder(RightFrameEdge))
+ m_cols.m_allowBorder[c + 1] = true;
+ if (edgeInfo.preventResize(LeftFrameEdge))
+ m_cols.m_preventResize[c] = true;
+ if (edgeInfo.preventResize(RightFrameEdge))
+ m_cols.m_preventResize[c + 1] = true;
+
+ if (edgeInfo.allowBorder(TopFrameEdge))
+ m_rows.m_allowBorder[r] = true;
+ if (edgeInfo.allowBorder(BottomFrameEdge))
+ m_rows.m_allowBorder[r + 1] = true;
+ if (edgeInfo.preventResize(TopFrameEdge))
+ m_rows.m_preventResize[r] = true;
+ if (edgeInfo.preventResize(BottomFrameEdge))
+ m_rows.m_preventResize[r + 1] = true;
+}
+
+void RenderFrameSet::computeEdgeInfo()
+{
+ m_rows.m_preventResize.fill(frameSet()->noResize());
+ m_rows.m_allowBorder.fill(false);
+ m_cols.m_preventResize.fill(frameSet()->noResize());
+ m_cols.m_allowBorder.fill(false);
+
+ RenderObject* child = firstChild();
+ if (!child)
+ return;
+
+ int rows = frameSet()->totalRows();
+ int cols = frameSet()->totalCols();
+ for (int r = 0; r < rows; ++r) {
+ for (int c = 0; c < cols; ++c) {
+ FrameEdgeInfo edgeInfo;
+ if (child->isFrameSet())
+ edgeInfo = static_cast<RenderFrameSet*>(child)->edgeInfo();
+ else
+ edgeInfo = static_cast<RenderFrame*>(child)->edgeInfo();
+ fillFromEdgeInfo(edgeInfo, r, c);
+ child = child->nextSibling();
+ if (!child)
+ return;
+ }
+ }
+}
+
+FrameEdgeInfo RenderFrameSet::edgeInfo() const
+{
+ FrameEdgeInfo result(frameSet()->noResize(), true);
+
+ int rows = frameSet()->totalRows();
+ int cols = frameSet()->totalCols();
+ if (rows && cols) {
+ result.setPreventResize(LeftFrameEdge, m_cols.m_preventResize[0]);
+ result.setAllowBorder(LeftFrameEdge, m_cols.m_allowBorder[0]);
+ result.setPreventResize(RightFrameEdge, m_cols.m_preventResize[cols]);
+ result.setAllowBorder(RightFrameEdge, m_cols.m_allowBorder[cols]);
+ result.setPreventResize(TopFrameEdge, m_rows.m_preventResize[0]);
+ result.setAllowBorder(TopFrameEdge, m_rows.m_allowBorder[0]);
+ result.setPreventResize(BottomFrameEdge, m_rows.m_preventResize[rows]);
+ result.setAllowBorder(BottomFrameEdge, m_rows.m_allowBorder[rows]);
+ }
+
+ return result;
+}
+
+void RenderFrameSet::layout()
+{
+ ASSERT(needsLayout());
+
+ bool doFullRepaint = selfNeedsLayout() && checkForRepaintDuringLayout();
+ IntRect oldBounds;
+ if (doFullRepaint)
+ oldBounds = absoluteClippedOverflowRect();
+
+ if (!parent()->isFrameSet() && !document()->printing()) {
+ m_width = view()->viewWidth();
+ m_height = view()->viewHeight();
+ }
+
+ size_t cols = frameSet()->totalCols();
+ size_t rows = frameSet()->totalRows();
+
+ if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) {
+ m_rows.resize(rows);
+ m_cols.resize(cols);
+ }
+
+ int borderThickness = frameSet()->border();
+ layOutAxis(m_rows, frameSet()->rowLengths(), m_height - (rows - 1) * borderThickness);
+ layOutAxis(m_cols, frameSet()->colLengths(), m_width - (cols - 1) * borderThickness);
+
+ positionFrames();
+
+ RenderContainer::layout();
+
+ computeEdgeInfo();
+
+ if (doFullRepaint) {
+ view()->repaintViewRectangle(oldBounds);
+ IntRect newBounds = absoluteClippedOverflowRect();
+ if (newBounds != oldBounds)
+ view()->repaintViewRectangle(newBounds);
+ }
+
+ setNeedsLayout(false);
+}
+
+void RenderFrameSet::positionFrames()
+{
+ RenderObject* child = firstChild();
+ if (!child)
+ return;
+
+ int rows = frameSet()->totalRows();
+ int cols = frameSet()->totalCols();
+
+ int yPos = 0;
+ int borderThickness = frameSet()->border();
+ for (int r = 0; r < rows; r++) {
+ int xPos = 0;
+ int height = m_rows.m_sizes[r];
+ for (int c = 0; c < cols; c++) {
+ child->setPos(xPos, yPos);
+ int width = m_cols.m_sizes[c];
+
+ // has to be resized and itself resize its contents
+ if (width != child->width() || height != child->height()) {
+ child->setWidth(width);
+ child->setHeight(height);
+ child->setNeedsLayout(true);
+ child->layout();
+ }
+
+ xPos += width + borderThickness;
+
+ child = child->nextSibling();
+ if (!child)
+ return;
+ }
+ yPos += height + borderThickness;
+ }
+
+ // all the remaining frames are hidden to avoid ugly spurious unflowed frames
+ for (; child; child = child->nextSibling()) {
+ child->setWidth(0);
+ child->setHeight(0);
+ child->setNeedsLayout(false);
+ }
+}
+
+void RenderFrameSet::startResizing(GridAxis& axis, int position)
+{
+ int split = hitTestSplit(axis, position);
+ if (split == noSplit || !axis.m_allowBorder[split] || axis.m_preventResize[split]) {
+ axis.m_splitBeingResized = noSplit;
+ return;
+ }
+ axis.m_splitBeingResized = split;
+ axis.m_splitResizeOffset = position - splitPosition(axis, split);
+}
+
+void RenderFrameSet::continueResizing(GridAxis& axis, int position)
+{
+ if (needsLayout())
+ return;
+ if (axis.m_splitBeingResized == noSplit)
+ return;
+ int currentSplitPosition = splitPosition(axis, axis.m_splitBeingResized);
+ int delta = (position - currentSplitPosition) - axis.m_splitResizeOffset;
+ if (delta == 0)
+ return;
+ axis.m_deltas[axis.m_splitBeingResized - 1] += delta;
+ axis.m_deltas[axis.m_splitBeingResized] -= delta;
+ setNeedsLayout(true);
+}
+
+bool RenderFrameSet::userResize(MouseEvent* evt)
+{
+ if (!m_isResizing) {
+ if (needsLayout())
+ return false;
+ if (evt->type() == eventNames().mousedownEvent && evt->button() == LeftButton) {
+ startResizing(m_cols, evt->pageX() - xPos());
+ startResizing(m_rows, evt->pageY() - yPos());
+ if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) {
+ setIsResizing(true);
+ return true;
+ }
+ }
+ } else {
+ if (evt->type() == eventNames().mousemoveEvent || (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton)) {
+ continueResizing(m_cols, evt->pageX() - xPos());
+ continueResizing(m_rows, evt->pageY() - yPos());
+ if (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton) {
+ setIsResizing(false);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void RenderFrameSet::setIsResizing(bool isResizing)
+{
+ m_isResizing = isResizing;
+ for (RenderObject* p = parent(); p; p = p->parent())
+ if (p->isFrameSet())
+ static_cast<RenderFrameSet*>(p)->m_isChildResizing = isResizing;
+ if (Frame* frame = document()->frame())
+ frame->eventHandler()->setResizingFrameSet(isResizing ? frameSet() : 0);
+}
+
+bool RenderFrameSet::isResizingRow() const
+{
+ return m_isResizing && m_rows.m_splitBeingResized != noSplit;
+}
+
+bool RenderFrameSet::isResizingColumn() const
+{
+ return m_isResizing && m_cols.m_splitBeingResized != noSplit;
+}
+
+bool RenderFrameSet::canResize(const IntPoint& p) const
+{
+ return hitTestSplit(m_cols, p.x()) != noSplit || hitTestSplit(m_rows, p.y()) != noSplit;
+}
+
+bool RenderFrameSet::canResizeRow(const IntPoint& p) const
+{
+ int r = hitTestSplit(m_rows, p.y());
+ return r != noSplit && m_rows.m_allowBorder[r] && !m_rows.m_preventResize[r];
+}
+
+bool RenderFrameSet::canResizeColumn(const IntPoint& p) const
+{
+ int c = hitTestSplit(m_cols, p.x());
+ return c != noSplit && m_cols.m_allowBorder[c] && !m_cols.m_preventResize[c];
+}
+
+int RenderFrameSet::splitPosition(const GridAxis& axis, int split) const
+{
+ if (needsLayout())
+ return 0;
+
+ int borderThickness = frameSet()->border();
+
+ int size = axis.m_sizes.size();
+ if (!size)
+ return 0;
+
+ int position = 0;
+ for (int i = 0; i < split && i < size; ++i)
+ position += axis.m_sizes[i] + borderThickness;
+ return position - borderThickness;
+}
+
+int RenderFrameSet::hitTestSplit(const GridAxis& axis, int position) const
+{
+ if (needsLayout())
+ return noSplit;
+
+ int borderThickness = frameSet()->border();
+ if (borderThickness <= 0)
+ return noSplit;
+
+ size_t size = axis.m_sizes.size();
+ if (!size)
+ return noSplit;
+
+ int splitPosition = axis.m_sizes[0];
+ for (size_t i = 1; i < size; ++i) {
+ if (position >= splitPosition && position < splitPosition + borderThickness)
+ return i;
+ splitPosition += borderThickness + axis.m_sizes[i];
+ }
+ return noSplit;
+}
+
+bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle*) const
+{
+ return child->isFrame() || child->isFrameSet();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h
new file mode 100644
index 0000000..5401c1b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderFrameSet.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2006, 2008 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 RenderFrameSet_h
+#define RenderFrameSet_h
+
+#include "RenderContainer.h"
+
+namespace WebCore {
+
+class HTMLFrameSetElement;
+class MouseEvent;
+
+enum FrameEdge { LeftFrameEdge, RightFrameEdge, TopFrameEdge, BottomFrameEdge };
+
+struct FrameEdgeInfo
+{
+ FrameEdgeInfo(bool preventResize = false, bool allowBorder = true)
+ : m_preventResize(4)
+ , m_allowBorder(4)
+ {
+ m_preventResize.fill(preventResize);
+ m_allowBorder.fill(allowBorder);
+ }
+
+ bool preventResize(FrameEdge edge) const { return m_preventResize[edge]; }
+ bool allowBorder(FrameEdge edge) const { return m_allowBorder[edge]; }
+
+ void setPreventResize(FrameEdge edge, bool preventResize) { m_preventResize[edge] = preventResize; }
+ void setAllowBorder(FrameEdge edge, bool allowBorder) { m_allowBorder[edge] = allowBorder; }
+
+private:
+ Vector<bool> m_preventResize;
+ Vector<bool> m_allowBorder;
+};
+
+class RenderFrameSet : public RenderContainer {
+public:
+ RenderFrameSet(HTMLFrameSetElement*);
+ virtual ~RenderFrameSet();
+
+ virtual const char* renderName() const { return "RenderFrameSet"; }
+ virtual bool isFrameSet() const { return true; }
+
+ virtual void layout();
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+ virtual void paint(PaintInfo& paintInfo, int tx, int ty);
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
+
+ FrameEdgeInfo edgeInfo() const;
+
+ bool userResize(MouseEvent*);
+
+ bool isResizingRow() const;
+ bool isResizingColumn() const;
+
+ bool canResizeRow(const IntPoint&) const;
+ bool canResizeColumn(const IntPoint&) const;
+
+private:
+ static const int noSplit = -1;
+
+ class GridAxis : Noncopyable {
+ public:
+ GridAxis();
+ void resize(int);
+ Vector<int> m_sizes;
+ Vector<int> m_deltas;
+ Vector<bool> m_preventResize;
+ Vector<bool> m_allowBorder;
+ int m_splitBeingResized;
+ int m_splitResizeOffset;
+ };
+
+ inline HTMLFrameSetElement* frameSet() const;
+
+ bool canResize(const IntPoint&) const;
+ void setIsResizing(bool);
+
+ void layOutAxis(GridAxis&, const Length*, int availableSpace);
+ void computeEdgeInfo();
+ void fillFromEdgeInfo(const FrameEdgeInfo& edgeInfo, int r, int c);
+ void positionFrames();
+
+ int splitPosition(const GridAxis&, int split) const;
+ int hitTestSplit(const GridAxis&, int position) const;
+
+ void startResizing(GridAxis&, int position);
+ void continueResizing(GridAxis&, int position);
+
+ void paintRowBorder(const PaintInfo& paintInfo, const IntRect& rect);
+ void paintColumnBorder(const PaintInfo& paintInfo, const IntRect& rect);
+
+ GridAxis m_rows;
+ GridAxis m_cols;
+
+ bool m_isResizing;
+ bool m_isChildResizing;
+};
+
+} // namespace WebCore
+
+#endif // RenderFrameSet_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.cpp
new file mode 100644
index 0000000..cc8c2c1
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RenderHTMLCanvas.h"
+
+#include "Document.h"
+#include "GraphicsContext.h"
+#include "HTMLCanvasElement.h"
+#include "HTMLNames.h"
+#include "RenderView.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderHTMLCanvas::RenderHTMLCanvas(HTMLCanvasElement* element)
+ : RenderReplaced(element, element->size())
+{
+}
+
+void RenderHTMLCanvas::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
+{
+ IntRect rect = contentBox();
+ rect.move(tx, ty);
+ static_cast<HTMLCanvasElement*>(node())->paint(paintInfo.context, rect);
+}
+
+void RenderHTMLCanvas::canvasSizeChanged()
+{
+ IntSize size = static_cast<HTMLCanvasElement*>(node())->size();
+ IntSize zoomedSize(size.width() * style()->effectiveZoom(), size.height() * style()->effectiveZoom());
+
+ if (size == intrinsicSize())
+ return;
+
+ setIntrinsicSize(size);
+
+ if (!prefWidthsDirty())
+ setPrefWidthsDirty(true);
+
+ IntSize oldSize = IntSize(m_width, m_height);
+ calcWidth();
+ calcHeight();
+ if (oldSize == IntSize(m_width, m_height))
+ return;
+
+ if (!selfNeedsLayout())
+ setNeedsLayout(true);
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.h b/src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.h
new file mode 100644
index 0000000..ad6c505
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderHTMLCanvas.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderHTMLCanvas_h
+#define RenderHTMLCanvas_h
+
+#include "RenderReplaced.h"
+
+namespace WebCore {
+
+class HTMLCanvasElement;
+
+class RenderHTMLCanvas : public RenderReplaced {
+public:
+ RenderHTMLCanvas(HTMLCanvasElement*);
+
+ virtual const char* renderName() const { return "RenderHTMLCanvas"; }
+
+ virtual void paintReplaced(PaintInfo& paintInfo, int tx, int ty);
+
+ void canvasSizeChanged();
+
+protected:
+ virtual void intrinsicSizeChanged() { canvasSizeChanged(); }
+
+};
+
+} // namespace WebCore
+
+#endif // RenderHTMLCanvas_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp
new file mode 100644
index 0000000..fc6f19b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderImage.cpp
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (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.
+ *
+ * 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 "RenderImage.h"
+
+#include "BitmapImage.h"
+#include "Document.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLImageElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLMapElement.h"
+#include "HTMLNames.h"
+#include "HitTestResult.h"
+#include "Page.h"
+#include "RenderView.h"
+#include "SystemTime.h"
+
+#if ENABLE(WML)
+#include "WMLImageElement.h"
+#include "WMLNames.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+static const double cInterpolationCutoff = 800. * 800.;
+static const double cLowQualityTimeThreshold = 0.050; // 50 ms
+
+class RenderImageScaleData {
+public:
+ RenderImageScaleData(RenderImage* image, const IntSize& size, double time, bool lowQualityScale)
+ : m_size(size)
+ , m_time(time)
+ , m_lowQualityScale(lowQualityScale)
+ , m_highQualityRepaintTimer(image, &RenderImage::highQualityRepaintTimerFired)
+ {
+ }
+
+ ~RenderImageScaleData()
+ {
+ m_highQualityRepaintTimer.stop();
+ }
+
+ const IntSize& size() const { return m_size; }
+ double time() const { return m_time; }
+ bool useLowQualityScale() const { return m_lowQualityScale; }
+ Timer<RenderImage>& hiqhQualityRepaintTimer() { return m_highQualityRepaintTimer; }
+
+ void setSize(const IntSize& s) { m_size = s; }
+ void setTime(double t) { m_time = t; }
+ void setUseLowQualityScale(bool b)
+ {
+ m_highQualityRepaintTimer.stop();
+ m_lowQualityScale = b;
+ if (b)
+ m_highQualityRepaintTimer.startOneShot(cLowQualityTimeThreshold);
+ }
+
+private:
+ IntSize m_size;
+ double m_time;
+ bool m_lowQualityScale;
+ Timer<RenderImage> m_highQualityRepaintTimer;
+};
+
+class RenderImageScaleObserver
+{
+public:
+ static bool shouldImagePaintAtLowQuality(RenderImage*, const IntSize&);
+
+ static void imageDestroyed(RenderImage* image)
+ {
+ if (gImages) {
+ RenderImageScaleData* data = gImages->take(image);
+ delete data;
+ if (gImages->size() == 0) {
+ delete gImages;
+ gImages = 0;
+ }
+ }
+ }
+
+ static void highQualityRepaintTimerFired(RenderImage* image)
+ {
+ RenderImageScaleObserver::imageDestroyed(image);
+ image->repaint();
+ }
+
+ static HashMap<RenderImage*, RenderImageScaleData*>* gImages;
+};
+
+bool RenderImageScaleObserver::shouldImagePaintAtLowQuality(RenderImage* 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() || !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->image()->width(), image->image()->height());
+
+ // Look ourselves up in the hashtable.
+ RenderImageScaleData* data = 0;
+ if (gImages)
+ data = gImages->get(image);
+
+ if (imageSize == size) {
+ // There is no scale in effect. If we had a scale in effect before, we can just delete this data.
+ if (data) {
+ gImages->remove(image);
+ 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 (image->document()->page()->inLowQualityImageInterpolationMode()) {
+ double totalPixels = static_cast<double>(image->image()->width()) * static_cast<double>(image->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 RenderImageScaleData(image, size, currentTime(), false);
+ if (!gImages)
+ gImages = new HashMap<RenderImage*, RenderImageScaleData*>;
+ gImages->set(image, data);
+ return false;
+ }
+
+ // We are scaled, but we painted already at this size, so just keep using whatever mode we last painted with.
+ if (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->time() < cLowQualityTimeThreshold);
+ data->setTime(newTime);
+ data->setSize(size);
+ return data->useLowQualityScale();
+}
+
+HashMap<RenderImage*, RenderImageScaleData*>* RenderImageScaleObserver::gImages = 0;
+
+void RenderImage::highQualityRepaintTimerFired(Timer<RenderImage>*)
+{
+ RenderImageScaleObserver::highQualityRepaintTimerFired(this);
+}
+
+using namespace HTMLNames;
+
+RenderImage::RenderImage(Node* node)
+ : RenderReplaced(node, IntSize(0, 0))
+ , m_cachedImage(0)
+{
+ updateAltText();
+
+ view()->frameView()->setIsVisuallyNonEmpty();
+}
+
+RenderImage::~RenderImage()
+{
+ if (m_cachedImage)
+ m_cachedImage->removeClient(this);
+ RenderImageScaleObserver::imageDestroyed(this);
+}
+
+void RenderImage::setCachedImage(CachedImage* newImage)
+{
+ if (m_cachedImage == newImage)
+ return;
+ if (m_cachedImage)
+ m_cachedImage->removeClient(this);
+ m_cachedImage = newImage;
+ if (m_cachedImage) {
+ m_cachedImage->addClient(this);
+ if (m_cachedImage->errorOccurred())
+ imageChanged(m_cachedImage.get());
+ }
+}
+
+// If we'll be displaying either alt text or an image, add some padding.
+static const unsigned short paddingWidth = 4;
+static const unsigned short paddingHeight = 4;
+
+// Alt text is restricted to this maximum size, in pixels. These are
+// signed integers because they are compared with other signed values.
+static const int maxAltTextWidth = 1024;
+static const int maxAltTextHeight = 256;
+
+// Sets the image height and width to fit the alt text. Returns true if the
+// image size changed.
+bool RenderImage::setImageSizeForAltText(CachedImage* newImage /* = 0 */)
+{
+ int imageWidth = 0;
+ int imageHeight = 0;
+
+ // If we'll be displaying either text or an image, add a little padding.
+ if (!m_altText.isEmpty() || newImage) {
+ imageWidth = paddingWidth;
+ imageHeight = paddingHeight;
+ }
+
+ if (newImage) {
+ // 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();
+ imageHeight += newImage->image()->height() * style()->effectiveZoom();
+ }
+
+ // we have an alt and the user meant it (its not a text we invented)
+ if (!m_altText.isEmpty()) {
+ const Font& font = style()->font();
+ imageWidth = max(imageWidth, min(font.width(TextRun(m_altText.characters(), m_altText.length())), maxAltTextWidth));
+ imageHeight = max(imageHeight, min(font.height(), maxAltTextHeight));
+ }
+
+ IntSize imageSize = IntSize(imageWidth, imageHeight);
+ if (imageSize == intrinsicSize())
+ return false;
+
+ setIntrinsicSize(imageSize);
+ return true;
+}
+
+void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
+{
+ if (documentBeingDestroyed())
+ return;
+
+ if (hasBoxDecorations() || hasMask())
+ RenderReplaced::imageChanged(newImage, rect);
+
+ if (newImage != imagePtr() || !newImage)
+ return;
+
+ bool imageSizeChanged = false;
+
+ // Set image dimensions, taking into account the size of the alt text.
+ if (errorOccurred())
+ imageSizeChanged = setImageSizeForAltText(m_cachedImage.get());
+
+ bool shouldRepaint = true;
+
+ // Image dimensions have been changed, see what needs to be done
+ if (imageSize(style()->effectiveZoom()) != intrinsicSize() || imageSizeChanged) {
+ if (!errorOccurred())
+ setIntrinsicSize(imageSize(style()->effectiveZoom()));
+
+ // In the case of generated image content using :before/:after, we might not be in the
+ // render tree yet. In that case, we don't need to worry about check for layout, since we'll get a
+ // layout when we get added in to the render tree hierarchy later.
+ if (containingBlock()) {
+ // lets see if we need to relayout at all..
+ int oldwidth = m_width;
+ int oldheight = m_height;
+ if (!prefWidthsDirty())
+ setPrefWidthsDirty(true);
+ calcWidth();
+ calcHeight();
+
+ if (imageSizeChanged || m_width != oldwidth || m_height != oldheight) {
+ shouldRepaint = false;
+ if (!selfNeedsLayout())
+ setNeedsLayout(true);
+ }
+
+ m_width = oldwidth;
+ m_height = oldheight;
+ }
+ }
+
+ if (shouldRepaint) {
+ IntRect repaintRect;
+ if (rect) {
+ // The image changed rect is in source image coordinates (pre-zooming),
+ // so map from the bounds of the image to the contentsBox.
+ repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageSize(1.0f)), contentBox()));
+ // Guard against too-large changed rects.
+ repaintRect.intersect(contentBox());
+ } else
+ repaintRect = contentBox();
+
+ repaintRectangle(repaintRect);
+ }
+}
+
+void RenderImage::resetAnimation()
+{
+ if (m_cachedImage) {
+ image()->resetAnimation();
+ if (!needsLayout())
+ repaint();
+ }
+}
+
+void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
+{
+ int cWidth = contentWidth();
+ int cHeight = contentHeight();
+ int leftBorder = borderLeft();
+ int topBorder = borderTop();
+ int leftPad = paddingLeft();
+ int topPad = paddingTop();
+
+ if (document()->printing() && !view()->printImages())
+ return;
+
+ GraphicsContext* context = paintInfo.context;
+
+ if (!hasImage() || errorOccurred()) {
+ if (paintInfo.phase == PaintPhaseSelection)
+ return;
+
+ if (cWidth > 2 && cHeight > 2) {
+ // Draw an outline rect where the image should be.
+ context->setStrokeStyle(SolidStroke);
+ context->setStrokeColor(Color::lightGray);
+ context->setFillColor(Color::transparent);
+ context->drawRect(IntRect(tx + leftBorder + leftPad, ty + topBorder + topPad, cWidth, cHeight));
+
+ bool errorPictureDrawn = false;
+ int imageX = 0;
+ int imageY = 0;
+ // When calculating the usable dimensions, exclude the pixels of
+ // the ouline rect so the error image/alt text doesn't draw on it.
+ int usableWidth = cWidth - 2;
+ int usableHeight = cHeight - 2;
+
+ if (errorOccurred() && !image()->isNull() && (usableWidth >= image()->width()) && (usableHeight >= image()->height())) {
+ // Center the error image, accounting for border and padding.
+ int centerX = (usableWidth - image()->width()) / 2;
+ if (centerX < 0)
+ centerX = 0;
+ int centerY = (usableHeight - image()->height()) / 2;
+ if (centerY < 0)
+ centerY = 0;
+ imageX = leftBorder + leftPad + centerX + 1;
+ imageY = topBorder + topPad + centerY + 1;
+ context->drawImage(image(), IntPoint(tx + imageX, ty + imageY));
+ errorPictureDrawn = true;
+ }
+
+ if (!m_altText.isEmpty()) {
+ String text = m_altText;
+ text.replace('\\', backslashAsCurrencySymbol());
+ context->setFont(style()->font());
+ context->setFillColor(style()->color());
+ int ax = tx + leftBorder + leftPad;
+ int ay = ty + topBorder + topPad;
+ const Font& font = style()->font();
+ int ascent = font.ascent();
+
+ // Only draw the alt text if it'll fit within the content box,
+ // and only if it fits above the error image.
+ TextRun textRun(text.characters(), text.length());
+ int textWidth = font.width(textRun);
+ if (errorPictureDrawn) {
+ if (usableWidth >= textWidth && font.height() <= imageY)
+ context->drawText(textRun, IntPoint(ax, ay + ascent));
+ } else if (usableWidth >= textWidth && cHeight >= font.height())
+ context->drawText(textRun, IntPoint(ax, ay + ascent));
+ }
+ }
+ } else if (hasImage() && cWidth > 0 && cHeight > 0) {
+ Image* img = image(cWidth, cHeight);
+ if (!img || img->isNull())
+ return;
+
+#if PLATFORM(MAC)
+ if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
+ paintCustomHighlight(tx - m_x, ty - m_y, style()->highlight(), true);
+#endif
+
+ IntSize contentSize(cWidth, cHeight);
+ bool useLowQualityScaling = RenderImageScaleObserver::shouldImagePaintAtLowQuality(this, contentSize);
+ IntRect rect(IntPoint(tx + leftBorder + leftPad, ty + topBorder + topPad), contentSize);
+ HTMLImageElement* imageElt = (element() && element()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(element()) : 0;
+ CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver;
+ context->drawImage(image(cWidth, cHeight), rect, compositeOperator, useLowQualityScaling);
+ }
+}
+
+int RenderImage::minimumReplacedHeight() const
+{
+ return errorOccurred() ? intrinsicSize().height() : 0;
+}
+
+HTMLMapElement* RenderImage::imageMap()
+{
+ HTMLImageElement* i = element() && element()->hasTagName(imgTag) ? static_cast<HTMLImageElement*>(element()) : 0;
+ return i ? i->document()->getImageMap(i->useMap()) : 0;
+}
+
+bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
+{
+ bool inside = RenderReplaced::nodeAtPoint(request, result, _x, _y, _tx, _ty, hitTestAction);
+
+ if (inside && element()) {
+ int tx = _tx + m_x;
+ int ty = _ty + m_y;
+
+ HTMLMapElement* map = imageMap();
+ if (map) {
+ // we're a client side image map
+ inside = map->mapMouseEvent(_x - tx, _y - ty, IntSize(contentWidth(), contentHeight()), result);
+ result.setInnerNonSharedNode(element());
+ }
+ }
+
+ return inside;
+}
+
+void RenderImage::updateAltText()
+{
+ if (!element())
+ return;
+
+ if (element()->hasTagName(inputTag))
+ m_altText = static_cast<HTMLInputElement*>(element())->altText();
+ else if (element()->hasTagName(imgTag))
+ m_altText = static_cast<HTMLImageElement*>(element())->altText();
+#if ENABLE(WML)
+ else if (element()->hasTagName(WMLNames::imgTag))
+ m_altText = static_cast<WMLImageElement*>(element())->altText();
+#endif
+}
+
+bool RenderImage::isWidthSpecified() const
+{
+ switch (style()->width().type()) {
+ case Fixed:
+ case Percent:
+ return true;
+ case Auto:
+ case Relative: // FIXME: Shouldn't this case return true?
+ case Static:
+ case Intrinsic:
+ case MinIntrinsic:
+ return false;
+ }
+ ASSERT(false);
+ return false;
+}
+
+bool RenderImage::isHeightSpecified() const
+{
+ switch (style()->height().type()) {
+ case Fixed:
+ case Percent:
+ return true;
+ case Auto:
+ case Relative: // FIXME: Shouldn't this case return true?
+ case Static:
+ case Intrinsic:
+ case MinIntrinsic:
+ return false;
+ }
+ ASSERT(false);
+ return false;
+}
+
+int RenderImage::calcReplacedWidth(bool includeMaxWidth) const
+{
+ if (imageHasRelativeWidth())
+ if (RenderObject* cb = isPositioned() ? container() : containingBlock())
+ setImageContainerSize(IntSize(cb->availableWidth(), cb->availableHeight()));
+
+ int width;
+ if (isWidthSpecified())
+ width = calcReplacedWidthUsing(style()->width());
+ else if (usesImageContainerSize())
+ width = imageSize(style()->effectiveZoom()).width();
+ else if (imageHasRelativeWidth())
+ width = 0; // If the image is relatively-sized, set the width to 0 until there is a set container size.
+ else
+ width = calcAspectRatioWidth();
+
+ int minW = calcReplacedWidthUsing(style()->minWidth());
+ int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth());
+
+ return max(minW, min(width, maxW));
+}
+
+int RenderImage::calcReplacedHeight() const
+{
+ int height;
+ if (isHeightSpecified())
+ height = calcReplacedHeightUsing(style()->height());
+ else if (usesImageContainerSize())
+ height = imageSize(style()->effectiveZoom()).height();
+ else if (imageHasRelativeHeight())
+ height = 0; // If the image is relatively-sized, set the height to 0 until there is a set container size.
+ else
+ height = calcAspectRatioHeight();
+
+ int minH = calcReplacedHeightUsing(style()->minHeight());
+ int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight());
+
+ return max(minH, min(height, maxH));
+}
+
+int RenderImage::calcAspectRatioWidth() const
+{
+ IntSize size = intrinsicSize();
+ if (!size.height())
+ return 0;
+ if (!hasImage() || errorOccurred())
+ return size.width(); // Don't bother scaling.
+ return RenderReplaced::calcReplacedHeight() * size.width() / size.height();
+}
+
+int RenderImage::calcAspectRatioHeight() const
+{
+ IntSize size = intrinsicSize();
+ if (!size.width())
+ return 0;
+ if (!hasImage() || errorOccurred())
+ return size.height(); // Don't bother scaling.
+ return RenderReplaced::calcReplacedWidth() * size.height() / size.width();
+}
+
+void RenderImage::calcPrefWidths()
+{
+ 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);
+}
+
+Image* RenderImage::nullImage()
+{
+ return Image::nullImage();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderImage.h b/src/3rdparty/webkit/WebCore/rendering/RenderImage.h
new file mode 100644
index 0000000..71896d6
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderImage.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (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 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 RenderImage_h
+#define RenderImage_h
+
+#include "CachedImage.h"
+#include "CachedResourceHandle.h"
+#include "RenderReplaced.h"
+
+namespace WebCore {
+
+class HTMLMapElement;
+
+class RenderImage : public RenderReplaced {
+public:
+ RenderImage(Node*);
+ virtual ~RenderImage();
+
+ virtual const char* renderName() const { return "RenderImage"; }
+
+ virtual bool isImage() const { return true; }
+ virtual bool isRenderImage() const { return true; }
+
+ virtual void paintReplaced(PaintInfo& paintInfo, int tx, int ty);
+
+ virtual int minimumReplacedHeight() const;
+
+ virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+
+ bool setImageSizeForAltText(CachedImage* newImage = 0);
+
+ void updateAltText();
+
+ void setCachedImage(CachedImage*);
+ CachedImage* cachedImage() const { return m_cachedImage.get(); }
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ virtual int calcReplacedWidth(bool includeMaxWidth = true) const;
+ virtual int calcReplacedHeight() const;
+
+ virtual void calcPrefWidths();
+
+ HTMLMapElement* imageMap();
+
+ void resetAnimation();
+
+ virtual bool hasImage() const { return m_cachedImage; }
+
+ void highQualityRepaintTimerFired(Timer<RenderImage>*);
+
+protected:
+ virtual Image* image(int /*w*/ = 0, int /*h*/ = 0) { return m_cachedImage ? m_cachedImage->image() : nullImage(); }
+ virtual bool errorOccurred() const { return m_cachedImage && m_cachedImage->errorOccurred(); }
+ virtual bool usesImageContainerSize() const { return m_cachedImage ? m_cachedImage->usesImageContainerSize() : false; }
+ virtual void setImageContainerSize(const IntSize& size) const { if (m_cachedImage) m_cachedImage->setImageContainerSize(size); }
+ virtual bool imageHasRelativeWidth() const { return m_cachedImage ? m_cachedImage->imageHasRelativeWidth() : false; }
+ virtual bool imageHasRelativeHeight() const { return m_cachedImage ? m_cachedImage->imageHasRelativeHeight() : false; }
+ 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()); }
+
+private:
+ int calcAspectRatioWidth() const;
+ int calcAspectRatioHeight() const;
+
+ bool isWidthSpecified() const;
+ bool isHeightSpecified() const;
+
+protected:
+ // The image we are rendering.
+ CachedResourceHandle<CachedImage> m_cachedImage;
+
+ // Text to display as long as the image isn't available.
+ String m_altText;
+
+ static Image* nullImage();
+
+ friend class RenderImageScaleObserver;
+};
+
+} // namespace WebCore
+
+#endif // RenderImage_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.cpp
new file mode 100644
index 0000000..29d0508
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RenderImageGeneratedContent.h"
+
+#include "RenderBlock.h"
+#include "RenderStyle.h"
+#include "StyleCachedImage.h"
+
+namespace WebCore {
+
+RenderImageGeneratedContent::RenderImageGeneratedContent(Node* n)
+: RenderImage(n)
+{}
+
+RenderImageGeneratedContent::~RenderImageGeneratedContent()
+{
+ m_cachedImage = 0;
+ m_styleImage->removeClient(this);
+}
+
+void RenderImageGeneratedContent::setStyleImage(StyleImage* image)
+{
+ if (image->isCachedImage())
+ m_cachedImage = static_cast<StyleCachedImage*>(image)->cachedImage();
+ m_styleImage = image;
+ m_styleImage->addClient(this);
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.h b/src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.h
new file mode 100644
index 0000000..cab0192
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderImageGeneratedContent.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderImageGeneratedContent_h
+#define RenderImageGeneratedContent_h
+
+#include "RenderImage.h"
+#include <wtf/RefPtr.h>
+
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+class StyleImage;
+
+class RenderImageGeneratedContent : public RenderImage
+{
+public:
+ RenderImageGeneratedContent(Node*);
+ virtual ~RenderImageGeneratedContent();
+
+ void setStyleImage(StyleImage*);
+
+ virtual bool hasImage() const { return true; }
+
+protected:
+ virtual Image* image(int w = 0, int h = 0) { return m_styleImage->image(this, IntSize(w, h)); }
+ virtual bool errorOccurred() const { return m_styleImage->errorOccurred(); }
+ virtual bool usesImageContainerSize() const { return m_styleImage->usesImageContainerSize(); }
+ virtual void setImageContainerSize(const IntSize& size) const { m_styleImage->setImageContainerSize(size); }
+ virtual bool imageHasRelativeWidth() const { return m_styleImage->imageHasRelativeWidth(); }
+ virtual bool imageHasRelativeHeight() const { return m_styleImage->imageHasRelativeHeight(); }
+ virtual IntSize imageSize(float multiplier) const { return m_styleImage->imageSize(this, multiplier); }
+ virtual WrappedImagePtr imagePtr() const { return m_styleImage->data(); }
+
+private:
+ RefPtr<StyleImage> m_styleImage;
+};
+
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp
new file mode 100644
index 0000000..40e5029
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderInline.cpp
@@ -0,0 +1,399 @@
+/*
+ * This file is part of the render object implementation for KHTML.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 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
+ * 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 "RenderInline.h"
+
+#include "Document.h"
+#include "RenderArena.h"
+#include "RenderBlock.h"
+#include "VisiblePosition.h"
+
+namespace WebCore {
+
+RenderInline::RenderInline(Node* node)
+ : RenderFlow(node)
+{
+}
+
+RenderInline::~RenderInline()
+{
+}
+
+void RenderInline::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderFlow::styleDidChange(diff, oldStyle);
+
+ setInline(true);
+ setHasReflection(false);
+
+ // Ensure that all of the split inlines pick up the new style. We
+ // only do this if we're an inline, since we don't want to propagate
+ // a block's style to the other inlines.
+ // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before
+ // and after the block share the same style, but the block doesn't
+ // need to pass its style on to anyone else.
+ RenderFlow* currCont = continuation();
+ while (currCont) {
+ if (currCont->isInline()) {
+ RenderFlow* nextCont = currCont->continuation();
+ currCont->setContinuation(0);
+ currCont->setStyle(style());
+ currCont->setContinuation(nextCont);
+ }
+ currCont = currCont->continuation();
+ }
+
+ m_lineHeight = -1;
+
+ // Update pseudos for :before and :after now.
+ if (!isAnonymous()) {
+ updateBeforeAfterContent(RenderStyle::BEFORE);
+ updateBeforeAfterContent(RenderStyle::AFTER);
+ }
+}
+
+bool RenderInline::isInlineContinuation() const
+{
+ return m_isContinuation;
+}
+
+static inline bool isAfterContent(RenderObject* child)
+{
+ if (!child)
+ return false;
+ if (child->style()->styleType() != RenderStyle::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::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild)
+{
+ // Make sure we don't append things after :after-generated content if we have it.
+ if (!beforeChild && isAfterContent(lastChild()))
+ beforeChild = lastChild();
+
+ if (!newChild->isInline() && !newChild->isFloatingOrPositioned()) {
+ // We are placing a block inside an inline. We have to perform a split of this
+ // inline into continuations. This involves creating an anonymous block box to hold
+ // |newChild|. We then make that block box a continuation of this inline. We take all of
+ // the children after |beforeChild| and put them in a clone of this object.
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(style());
+ newStyle->setDisplay(BLOCK);
+
+ RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
+ newBox->setStyle(newStyle.release());
+ RenderFlow* oldContinuation = continuation();
+ setContinuation(newBox);
+
+ // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
+ // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
+ // content gets properly destroyed.
+ bool isLastChild = (beforeChild == lastChild());
+ updateBeforeAfterContent(RenderStyle::AFTER);
+ if (isLastChild && beforeChild != lastChild())
+ beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
+ // point to be 0. It's just a straight append now.
+
+ splitFlow(beforeChild, newBox, newChild, oldContinuation);
+ return;
+ }
+
+ RenderContainer::addChild(newChild, beforeChild);
+
+ newChild->setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+RenderInline* RenderInline::cloneInline(RenderFlow* src)
+{
+ RenderInline* o = new (src->renderArena()) RenderInline(src->element());
+ o->m_isContinuation = true;
+ o->setStyle(src->style());
+ return o;
+}
+
+void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
+ RenderBlock* middleBlock,
+ RenderObject* beforeChild, RenderFlow* oldCont)
+{
+ // Create a clone of this inline.
+ RenderInline* clone = cloneInline(this);
+ clone->setContinuation(oldCont);
+
+ // Now take all of the children from beforeChild to the end and remove
+ // them from |this| and place them in the clone.
+ RenderObject* o = beforeChild;
+ while (o) {
+ RenderObject* tmp = o;
+ o = tmp->nextSibling();
+ clone->addChildToFlow(removeChildNode(tmp), 0);
+ tmp->setNeedsLayoutAndPrefWidthsRecalc();
+ }
+
+ // Hook |clone| up as the continuation of the middle block.
+ middleBlock->setContinuation(clone);
+
+ // We have been reparented and are now under the fromBlock. We need
+ // to walk up our inline parent chain until we hit the containing block.
+ // Once we hit the containing block we're done.
+ RenderFlow* curr = static_cast<RenderFlow*>(parent());
+ RenderFlow* currChild = this;
+
+ // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
+ // There will eventually be a better approach to this problem that will let us nest to a much
+ // greater depth (see bugzilla bug 13430) but for now we have a limit. This *will* result in
+ // incorrect rendering, but the alternative is to hang forever.
+ unsigned splitDepth = 1;
+ const unsigned cMaxSplitDepth = 200;
+ while (curr && curr != fromBlock) {
+ if (splitDepth < cMaxSplitDepth) {
+ // Create a new clone.
+ RenderInline* cloneChild = clone;
+ clone = cloneInline(curr);
+
+ // Insert our child clone as the first child.
+ clone->addChildToFlow(cloneChild, 0);
+
+ // Hook the clone up as a continuation of |curr|.
+ RenderFlow* oldCont = curr->continuation();
+ curr->setContinuation(clone);
+ clone->setContinuation(oldCont);
+
+ // Someone may have indirectly caused a <q> to split. When this happens, the :after content
+ // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
+ // content gets properly destroyed.
+ curr->updateBeforeAfterContent(RenderStyle::AFTER);
+
+ // Now we need to take all of the children starting from the first child
+ // *after* currChild and append them all to the clone.
+ o = currChild->nextSibling();
+ while (o) {
+ RenderObject* tmp = o;
+ o = tmp->nextSibling();
+ clone->addChildToFlow(curr->removeChildNode(tmp), 0);
+ tmp->setNeedsLayoutAndPrefWidthsRecalc();
+ }
+ }
+
+ // Keep walking up the chain.
+ currChild = curr;
+ curr = static_cast<RenderFlow*>(curr->parent());
+ splitDepth++;
+ }
+
+ // Now we are at the block level. We need to put the clone into the toBlock.
+ toBlock->appendChildNode(clone);
+
+ // Now take all the children after currChild and remove them from the fromBlock
+ // and put them in the toBlock.
+ o = currChild->nextSibling();
+ while (o) {
+ RenderObject* tmp = o;
+ o = tmp->nextSibling();
+ toBlock->appendChildNode(fromBlock->removeChildNode(tmp));
+ }
+}
+
+void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
+ RenderObject* newChild, RenderFlow* oldCont)
+{
+ RenderBlock* pre = 0;
+ RenderBlock* block = containingBlock();
+
+ // Delete our line boxes before we do the inline split into continuations.
+ block->deleteLineBoxTree();
+
+ bool madeNewBeforeBlock = false;
+ if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
+ // We can reuse this block and make it the preBlock of the next continuation.
+ pre = block;
+ block = block->containingBlock();
+ } else {
+ // No anonymous block available for use. Make one.
+ pre = block->createAnonymousBlock();
+ madeNewBeforeBlock = true;
+ }
+
+ RenderBlock* post = block->createAnonymousBlock();
+
+ RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
+ if (madeNewBeforeBlock)
+ block->insertChildNode(pre, boxFirst);
+ block->insertChildNode(newBlockBox, boxFirst);
+ block->insertChildNode(post, boxFirst);
+ block->setChildrenInline(false);
+
+ if (madeNewBeforeBlock) {
+ RenderObject* o = boxFirst;
+ while (o) {
+ RenderObject* no = o;
+ o = no->nextSibling();
+ pre->appendChildNode(block->removeChildNode(no));
+ no->setNeedsLayoutAndPrefWidthsRecalc();
+ }
+ }
+
+ splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
+
+ // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
+ // time in makeChildrenNonInline by just setting this explicitly up front.
+ newBlockBox->setChildrenInline(false);
+
+ // We don't just call addChild, since it would pass things off to the
+ // continuation, so we call addChildToFlow explicitly instead. We delayed
+ // adding the newChild until now so that the |newBlockBox| would be fully
+ // connected, thus allowing newChild access to a renderArena should it need
+ // to wrap itself in additional boxes (e.g., table construction).
+ newBlockBox->addChildToFlow(newChild, 0);
+
+ // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
+ // get deleted properly. Because objects moves from the pre block into the post block, we want to
+ // make new line boxes instead of leaving the old line boxes around.
+ pre->setNeedsLayoutAndPrefWidthsRecalc();
+ block->setNeedsLayoutAndPrefWidthsRecalc();
+ post->setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ paintLines(paintInfo, tx, ty);
+}
+
+void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel)
+{
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
+ rects.append(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height()));
+
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+ if (!curr->isText())
+ curr->absoluteRects(rects, tx + curr->xPos(), ty + curr->yPos(), false);
+ }
+
+ if (continuation() && topLevel)
+ continuation()->absoluteRects(rects,
+ tx - containingBlock()->xPos() + continuation()->xPos(),
+ ty - containingBlock()->yPos() + continuation()->yPos(),
+ topLevel);
+}
+
+void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
+ FloatRect localRect(curr->xPos(), curr->yPos(), curr->width(), curr->height());
+ quads.append(localToAbsoluteQuad(localRect));
+ }
+
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+ if (!curr->isText())
+ curr->absoluteQuads(quads, false);
+ }
+
+ if (continuation() && topLevel)
+ continuation()->absoluteQuads(quads, topLevel);
+}
+
+bool RenderInline::requiresLayer()
+{
+ return isRelPositioned() || isTransparent() || hasMask();
+}
+
+int RenderInline::width() const
+{
+ // Return the width of the minimal left side and the maximal right side.
+ int leftSide = 0;
+ int rightSide = 0;
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
+ if (curr == firstLineBox() || curr->xPos() < leftSide)
+ leftSide = curr->xPos();
+ if (curr == firstLineBox() || curr->xPos() + curr->width() > rightSide)
+ rightSide = curr->xPos() + curr->width();
+ }
+
+ return rightSide - leftSide;
+}
+
+int RenderInline::height() const
+{
+ // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero. We have been
+ // unable to reproduce this at all (and consequently unable to figure ot why this is happening). The assert will hopefully catch the problem in debug
+ // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now.
+ ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist.
+ if (firstLineBox() && lastLineBox())
+ return lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos();
+ return 0;
+}
+
+int RenderInline::offsetLeft() const
+{
+ int x = RenderFlow::offsetLeft();
+ if (firstLineBox())
+ x += firstLineBox()->xPos();
+ return x;
+}
+
+int RenderInline::offsetTop() const
+{
+ int y = RenderFlow::offsetTop();
+ if (firstLineBox())
+ y += firstLineBox()->yPos();
+ return y;
+}
+
+const char* RenderInline::renderName() const
+{
+ if (isRelPositioned())
+ return "RenderInline (relative positioned)";
+ if (isAnonymous())
+ return "RenderInline (generated)";
+ return "RenderInline";
+}
+
+bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
+ int x, int y, int tx, int ty, HitTestAction hitTestAction)
+{
+ return hitTestLines(request, result, x, y, tx, ty, hitTestAction);
+}
+
+VisiblePosition RenderInline::positionForCoordinates(int x, int y)
+{
+ // Translate the coords from the pre-anonymous block to the post-anonymous block.
+ RenderBlock* cb = containingBlock();
+ int parentBlockX = cb->xPos() + x;
+ int parentBlockY = cb->yPos() + y;
+ for (RenderObject* c = continuation(); c; c = c->continuation()) {
+ RenderObject* contBlock = c;
+ if (c->isInline())
+ contBlock = c->containingBlock();
+ if (c->isInline() || c->firstChild())
+ return c->positionForCoordinates(parentBlockX - contBlock->xPos(), parentBlockY - contBlock->yPos());
+ }
+
+ return RenderFlow::positionForCoordinates(x, y);
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderInline.h b/src/3rdparty/webkit/WebCore/rendering/RenderInline.h
new file mode 100644
index 0000000..1c42a6f
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderInline.h
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the render object implementation for KHTML.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003 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
+ * 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 RenderInline_h
+#define RenderInline_h
+
+#include "RenderFlow.h"
+
+namespace WebCore {
+
+class Position;
+
+class RenderInline : public RenderFlow {
+public:
+ RenderInline(Node*);
+ virtual ~RenderInline();
+
+ virtual const char* renderName() const;
+
+ virtual bool isRenderInline() const { return true; }
+ virtual bool isInlineFlow() const { return true; }
+ virtual bool childrenInline() const { return true; }
+
+ virtual bool isInlineContinuation() const;
+
+ virtual void addChildToFlow(RenderObject* newChild, RenderObject* beforeChild);
+ void splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, RenderBlock* middleBlock,
+ RenderObject* beforeChild, RenderFlow* oldCont);
+ void splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
+ RenderObject* newChild, RenderFlow* oldCont);
+
+ virtual void layout() { } // Do nothing for layout()
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ // overrides RenderObject
+ virtual bool requiresLayer();
+
+ virtual int width() const;
+ virtual int height() const;
+
+ // used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) to return
+ // the remaining width on a given line (and the height of a single line).
+ virtual int offsetLeft() const;
+ virtual int offsetTop() const;
+
+ void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+
+ virtual VisiblePosition positionForCoordinates(int x, int y);
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ static RenderInline* cloneInline(RenderFlow* src);
+
+};
+
+} // namespace WebCore
+
+#endif // RenderInline_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp
new file mode 100644
index 0000000..9c9eff0
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.cpp
@@ -0,0 +1,2609 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Portions are Copyright (C) 1998 Netscape Communications Corporation.
+ *
+ * Other contributors:
+ * Robert O'Callahan <roc+@cs.cmu.edu>
+ * David Baron <dbaron@fas.harvard.edu>
+ * Christian Biesinger <cbiesinger@web.de>
+ * Randall Jesup <rjesup@wgate.com>
+ * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
+ * Josh Soref <timeless@mac.com>
+ * Boris Zbarsky <bzbarsky@mit.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+ */
+
+#include "config.h"
+#include "RenderLayer.h"
+
+#include "CSSPropertyNames.h"
+#include "Document.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "FloatRect.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "OverflowEvent.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "RenderArena.h"
+#include "RenderInline.h"
+#include "RenderMarquee.h"
+#include "RenderReplica.h"
+#include "RenderScrollbar.h"
+#include "RenderScrollbarPart.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "ScaleTransformOperation.h"
+#include "Scrollbar.h"
+#include "ScrollbarTheme.h"
+#include "SelectionController.h"
+#include "TranslateTransformOperation.h"
+#include <wtf/StdLibExtras.h>
+
+#if ENABLE(SVG)
+#include "SVGNames.h"
+#endif
+
+#define MIN_INTERSECT_FOR_REVEAL 32
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+const RenderLayer::ScrollAlignment RenderLayer::gAlignCenterIfNeeded = { RenderLayer::noScroll, RenderLayer::alignCenter, RenderLayer::alignToClosestEdge };
+const RenderLayer::ScrollAlignment RenderLayer::gAlignToEdgeIfNeeded = { RenderLayer::noScroll, RenderLayer::alignToClosestEdge, RenderLayer::alignToClosestEdge };
+const RenderLayer::ScrollAlignment RenderLayer::gAlignCenterAlways = { RenderLayer::alignCenter, RenderLayer::alignCenter, RenderLayer::alignCenter };
+const RenderLayer::ScrollAlignment RenderLayer::gAlignTopAlways = { RenderLayer::alignTop, RenderLayer::alignTop, RenderLayer::alignTop };
+const RenderLayer::ScrollAlignment RenderLayer::gAlignBottomAlways = { RenderLayer::alignBottom, RenderLayer::alignBottom, RenderLayer::alignBottom };
+
+const int MinimumWidthWhileResizing = 100;
+const int MinimumHeightWhileResizing = 40;
+
+void* ClipRects::operator new(size_t sz, RenderArena* renderArena) throw()
+{
+ return renderArena->allocate(sz);
+}
+
+void ClipRects::operator delete(void* ptr, size_t sz)
+{
+ // Stash size where destroy can find it.
+ *(size_t *)ptr = sz;
+}
+
+void ClipRects::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);
+}
+
+RenderLayer::RenderLayer(RenderObject* object)
+ : m_object(object)
+ , m_parent(0)
+ , m_previous(0)
+ , m_next(0)
+ , m_first(0)
+ , m_last(0)
+ , m_relX(0)
+ , m_relY(0)
+ , m_x(0)
+ , m_y(0)
+ , m_width(0)
+ , m_height(0)
+ , m_scrollX(0)
+ , m_scrollY(0)
+ , m_scrollOriginX(0)
+ , m_scrollLeftOverflow(0)
+ , m_scrollWidth(0)
+ , m_scrollHeight(0)
+ , m_inResizeMode(false)
+ , m_posZOrderList(0)
+ , m_negZOrderList(0)
+ , m_overflowList(0)
+ , m_clipRects(0)
+#ifndef NDEBUG
+ , m_clipRectsRoot(0)
+#endif
+ , m_scrollDimensionsDirty(true)
+ , m_zOrderListsDirty(true)
+ , m_overflowListDirty(true)
+ , m_isOverflowOnly(shouldBeOverflowOnly())
+ , m_usedTransparency(false)
+ , m_paintingInsideReflection(false)
+ , m_inOverflowRelayout(false)
+ , m_needsFullRepaint(false)
+ , m_overflowStatusDirty(true)
+ , m_visibleContentStatusDirty(true)
+ , m_hasVisibleContent(false)
+ , m_visibleDescendantStatusDirty(false)
+ , m_hasVisibleDescendant(false)
+ , m_marquee(0)
+ , m_staticX(0)
+ , m_staticY(0)
+ , m_transform(0)
+ , m_reflection(0)
+ , m_scrollCorner(0)
+ , m_resizer(0)
+{
+ if (!object->firstChild() && object->style()) {
+ m_visibleContentStatusDirty = false;
+ m_hasVisibleContent = object->style()->visibility() == VISIBLE;
+ }
+}
+
+RenderLayer::~RenderLayer()
+{
+ if (inResizeMode() && !renderer()->documentBeingDestroyed()) {
+ if (Frame* frame = renderer()->document()->frame())
+ frame->eventHandler()->resizeLayerDestroyed();
+ }
+
+ destroyScrollbar(HorizontalScrollbar);
+ destroyScrollbar(VerticalScrollbar);
+
+ // Child layers will be deleted by their corresponding render objects, so
+ // we don't need to delete them ourselves.
+
+ delete m_posZOrderList;
+ delete m_negZOrderList;
+ delete m_overflowList;
+ delete m_marquee;
+
+ // 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_scrollCorner)
+ m_scrollCorner->destroy();
+ if (m_resizer)
+ m_resizer->destroy();
+}
+
+void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
+{
+ if (doFullRepaint) {
+ m_object->repaint();
+ checkForRepaint = doFullRepaint = false;
+ }
+
+ updateLayerPosition(); // For relpositioned layers or non-positioned layers,
+ // we need to keep in sync, since we may have shifted relative
+ // to our parent layer.
+
+ int x = 0;
+ int y = 0;
+ convertToLayerCoords(root(), x, y);
+ positionOverflowControls(x, y);
+
+ updateVisibilityStatus();
+
+ updateTransform();
+
+ if (m_hasVisibleContent) {
+ RenderView* view = m_object->view();
+ ASSERT(view);
+ // FIXME: Optimize using LayoutState and remove the disableLayoutState() call
+ // from updateScrollInfoAfterLayout().
+ ASSERT(!view->layoutState());
+
+ IntRect newRect = m_object->absoluteClippedOverflowRect();
+ IntRect newOutlineBox = m_object->absoluteOutlineBounds();
+ if (checkForRepaint) {
+ if (view && !view->printing()) {
+ if (m_needsFullRepaint) {
+ view->repaintViewRectangle(m_repaintRect);
+ if (newRect != m_repaintRect)
+ view->repaintViewRectangle(newRect);
+ } else
+ m_object->repaintAfterLayoutIfNeeded(m_repaintRect, m_outlineBox);
+ }
+ }
+ m_repaintRect = newRect;
+ m_outlineBox = newOutlineBox;
+ } else {
+ m_repaintRect = IntRect();
+ m_outlineBox = IntRect();
+ }
+
+ m_needsFullRepaint = false;
+
+ // Go ahead and update the reflection's position and size.
+ if (m_reflection)
+ m_reflection->layout();
+
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+ child->updateLayerPositions(doFullRepaint, checkForRepaint);
+
+ // With all our children positioned, now update our marquee if we need to.
+ if (m_marquee)
+ m_marquee->updateMarqueePosition();
+}
+
+void RenderLayer::updateTransform()
+{
+ bool hasTransform = renderer()->hasTransform();
+ bool hadTransform = m_transform;
+ if (hasTransform != hadTransform) {
+ if (hasTransform)
+ m_transform.set(new TransformationMatrix);
+ else
+ m_transform.clear();
+ }
+
+ if (hasTransform) {
+ m_transform->reset();
+ renderer()->style()->applyTransform(*m_transform, renderer()->borderBox().size());
+ }
+}
+
+void RenderLayer::setHasVisibleContent(bool b)
+{
+ if (m_hasVisibleContent == b && !m_visibleContentStatusDirty)
+ return;
+ m_visibleContentStatusDirty = false;
+ m_hasVisibleContent = b;
+ if (m_hasVisibleContent) {
+ m_repaintRect = renderer()->absoluteClippedOverflowRect();
+ m_outlineBox = renderer()->absoluteOutlineBounds();
+ if (!isOverflowOnly())
+ dirtyStackingContextZOrderLists();
+ }
+ if (parent())
+ parent()->childVisibilityChanged(m_hasVisibleContent);
+}
+
+void RenderLayer::dirtyVisibleContentStatus()
+{
+ m_visibleContentStatusDirty = true;
+ if (parent())
+ parent()->dirtyVisibleDescendantStatus();
+}
+
+void RenderLayer::childVisibilityChanged(bool newVisibility)
+{
+ if (m_hasVisibleDescendant == newVisibility || m_visibleDescendantStatusDirty)
+ return;
+ if (newVisibility) {
+ RenderLayer* l = this;
+ while (l && !l->m_visibleDescendantStatusDirty && !l->m_hasVisibleDescendant) {
+ l->m_hasVisibleDescendant = true;
+ l = l->parent();
+ }
+ } else
+ dirtyVisibleDescendantStatus();
+}
+
+void RenderLayer::dirtyVisibleDescendantStatus()
+{
+ RenderLayer* l = this;
+ while (l && !l->m_visibleDescendantStatusDirty) {
+ l->m_visibleDescendantStatusDirty = true;
+ l = l->parent();
+ }
+}
+
+void RenderLayer::updateVisibilityStatus()
+{
+ if (m_visibleDescendantStatusDirty) {
+ m_hasVisibleDescendant = false;
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
+ child->updateVisibilityStatus();
+ if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
+ m_hasVisibleDescendant = true;
+ break;
+ }
+ }
+ m_visibleDescendantStatusDirty = false;
+ }
+
+ if (m_visibleContentStatusDirty) {
+ if (m_object->style()->visibility() == VISIBLE)
+ m_hasVisibleContent = true;
+ else {
+ // layer may be hidden but still have some visible content, check for this
+ m_hasVisibleContent = false;
+ RenderObject* r = m_object->firstChild();
+ while (r) {
+ if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
+ m_hasVisibleContent = true;
+ break;
+ }
+ if (r->firstChild() && !r->hasLayer())
+ r = r->firstChild();
+ else if (r->nextSibling())
+ r = r->nextSibling();
+ else {
+ do {
+ r = r->parent();
+ if (r==m_object)
+ r = 0;
+ } while (r && !r->nextSibling());
+ if (r)
+ r = r->nextSibling();
+ }
+ }
+ }
+ m_visibleContentStatusDirty = false;
+ }
+}
+
+void RenderLayer::updateLayerPosition()
+{
+ // Clear our cached clip rect information.
+ clearClipRects();
+
+ int x = m_object->xPos();
+ int y = m_object->yPos() - m_object->borderTopExtra();
+
+ if (!m_object->isPositioned() && m_object->parent()) {
+ // We must adjust our position by walking up the render tree looking for the
+ // nearest enclosing object with a layer.
+ RenderObject* curr = m_object->parent();
+ while (curr && !curr->hasLayer()) {
+ if (!curr->isTableRow()) {
+ // Rows and cells share the same coordinate space (that of the section).
+ // Omit them when computing our xpos/ypos.
+ x += curr->xPos();
+ y += curr->yPos();
+ }
+ curr = curr->parent();
+ }
+ y += curr->borderTopExtra();
+ if (curr->isTableRow()) {
+ // Put ourselves into the row coordinate space.
+ x -= curr->xPos();
+ y -= curr->yPos();
+ }
+ }
+
+ m_relX = m_relY = 0;
+ if (m_object->isRelPositioned()) {
+ m_relX = static_cast<RenderBox*>(m_object)->relativePositionOffsetX();
+ m_relY = static_cast<RenderBox*>(m_object)->relativePositionOffsetY();
+ x += m_relX; y += m_relY;
+ }
+
+ // Subtract our parent's scroll offset.
+ if (m_object->isPositioned() && enclosingPositionedAncestor()) {
+ RenderLayer* positionedParent = enclosingPositionedAncestor();
+
+ // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
+ positionedParent->subtractScrolledContentOffset(x, y);
+
+ if (m_object->isPositioned()) {
+ IntSize offset = static_cast<RenderBox*>(m_object)->offsetForPositionedInContainer(positionedParent->renderer());
+ x += offset.width();
+ y += offset.height();
+ }
+ } else if (parent())
+ parent()->subtractScrolledContentOffset(x, y);
+
+ setPos(x,y);
+
+ setWidth(m_object->width());
+ setHeight(m_object->height() + m_object->borderTopExtra() + m_object->borderBottomExtra());
+
+ if (!m_object->hasOverflowClip()) {
+ if (m_object->overflowWidth() > m_object->width())
+ setWidth(m_object->overflowWidth());
+ if (m_object->overflowHeight() > m_object->height())
+ setHeight(m_object->overflowHeight());
+ }
+}
+
+RenderLayer *RenderLayer::stackingContext() const
+{
+ RenderLayer* curr = parent();
+ for ( ; curr && !curr->m_object->isRenderView() && !curr->m_object->isRoot() &&
+ curr->m_object->style()->hasAutoZIndex();
+ curr = curr->parent()) { }
+ return curr;
+}
+
+RenderLayer* RenderLayer::enclosingPositionedAncestor() const
+{
+ RenderLayer* curr = parent();
+ for ( ; curr && !curr->m_object->isRenderView() && !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned() && !curr->hasTransform();
+ curr = curr->parent()) { }
+ return curr;
+}
+
+RenderLayer* RenderLayer::enclosingTransformedAncestor() const
+{
+ RenderLayer* curr = parent();
+ for ( ; curr && !curr->m_object->isRenderView() && !curr->transform(); curr = curr->parent())
+ { }
+ return curr;
+}
+
+IntPoint RenderLayer::absoluteToContents(const IntPoint& absolutePoint) const
+{
+ // We don't use convertToLayerCoords because it doesn't know about transforms
+ return roundedIntPoint(renderer()->absoluteToLocal(absolutePoint, false, true));
+}
+
+bool RenderLayer::requiresSlowRepaints() const
+{
+ if (isTransparent() || hasReflection() || hasTransform())
+ return true;
+ if (!parent())
+ return false;
+ return parent()->requiresSlowRepaints();
+}
+
+bool RenderLayer::isTransparent() const
+{
+#if ENABLE(SVG)
+ if (m_object->node()->namespaceURI() == SVGNames::svgNamespaceURI)
+ return false;
+#endif
+ return m_object->isTransparent() || m_object->hasMask();
+}
+
+RenderLayer*
+RenderLayer::transparentAncestor()
+{
+ RenderLayer* curr = parent();
+ for ( ; curr && !curr->isTransparent(); curr = curr->parent()) { }
+ return curr;
+}
+
+static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransform, const RenderLayer* l, const RenderLayer* rootLayer)
+{
+ // 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.
+
+ TransformationMatrix* t = l->transform();
+ if (t && rootLayer != l) {
+ // 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;
+ int y = 0;
+ l->convertToLayerCoords(rootLayer, x, y);
+ TransformationMatrix transform;
+ transform.translate(x, y);
+ transform = *t * 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;
+ }
+
+ // 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);
+}
+
+void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer)
+{
+ if (p->paintingDisabled() || (isTransparent() && m_usedTransparency))
+ return;
+
+ RenderLayer* ancestor = transparentAncestor();
+ if (ancestor)
+ ancestor->beginTransparencyLayers(p, rootLayer);
+
+ if (isTransparent()) {
+ m_usedTransparency = true;
+ p->save();
+ p->clip(transparencyClipBox(TransformationMatrix(), this, rootLayer));
+ p->beginTransparencyLayer(renderer()->opacity());
+ }
+}
+
+void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw()
+{
+ return renderArena->allocate(sz);
+}
+
+void RenderLayer::operator delete(void* ptr, size_t sz)
+{
+ // Stash size where destroy can find it.
+ *(size_t *)ptr = sz;
+}
+
+void RenderLayer::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 RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
+{
+ RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
+ if (prevSibling) {
+ child->setPreviousSibling(prevSibling);
+ prevSibling->setNextSibling(child);
+ } else
+ setFirstChild(child);
+
+ if (beforeChild) {
+ beforeChild->setPreviousSibling(child);
+ child->setNextSibling(beforeChild);
+ } else
+ setLastChild(child);
+
+ child->setParent(this);
+
+ if (child->isOverflowOnly())
+ dirtyOverflowList();
+
+ if (!child->isOverflowOnly() || child->firstChild()) {
+ // Dirty the z-order list in which we are contained. The stackingContext() can be null in the
+ // case where we're building up generated content layers. This is ok, since the lists will start
+ // off dirty in that case anyway.
+ child->dirtyStackingContextZOrderLists();
+ }
+
+ child->updateVisibilityStatus();
+ if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
+ childVisibilityChanged(true);
+}
+
+RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
+{
+ // remove the child
+ if (oldChild->previousSibling())
+ oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
+ if (oldChild->nextSibling())
+ oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
+
+ if (m_first == oldChild)
+ m_first = oldChild->nextSibling();
+ if (m_last == oldChild)
+ m_last = oldChild->previousSibling();
+
+ if (oldChild->isOverflowOnly())
+ dirtyOverflowList();
+ if (!oldChild->isOverflowOnly() || oldChild->firstChild()) {
+ // Dirty the z-order list in which we are contained. When called via the
+ // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
+ // from the main layer tree, so we need to null-check the |stackingContext| value.
+ oldChild->dirtyStackingContextZOrderLists();
+ }
+
+ oldChild->setPreviousSibling(0);
+ oldChild->setNextSibling(0);
+ oldChild->setParent(0);
+
+ oldChild->updateVisibilityStatus();
+ if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
+ childVisibilityChanged(false);
+
+ return oldChild;
+}
+
+void RenderLayer::removeOnlyThisLayer()
+{
+ if (!m_parent)
+ return;
+
+ // Dirty the clip rects.
+ clearClipRectsIncludingDescendants();
+
+ // Remove us from the parent.
+ RenderLayer* parent = m_parent;
+ RenderLayer* nextSib = nextSibling();
+ parent->removeChild(this);
+
+ if (reflection())
+ removeChild(reflectionLayer());
+
+ // Now walk our kids and reattach them to our parent.
+ RenderLayer* current = m_first;
+ while (current) {
+ RenderLayer* next = current->nextSibling();
+ removeChild(current);
+ parent->addChild(current, nextSib);
+ current->updateLayerPositions();
+ current = next;
+ }
+
+ destroy(renderer()->renderArena());
+}
+
+void RenderLayer::insertOnlyThisLayer()
+{
+ if (!m_parent && renderer()->parent()) {
+ // We need to connect ourselves when our renderer() has a parent.
+ // Find our enclosingLayer and add ourselves.
+ RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
+ RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0;
+ if (parentLayer)
+ parentLayer->addChild(this, beforeChild);
+ }
+
+ // Remove all descendant layers from the hierarchy and add them to the new position.
+ for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
+ curr->moveLayers(m_parent, this);
+
+ // Clear out all the clip rects.
+ clearClipRectsIncludingDescendants();
+}
+
+void
+RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const
+{
+ if (ancestorLayer == this)
+ return;
+
+ if (m_object->style()->position() == FixedPosition) {
+ // Add in the offset of the view. We can obtain this by calling
+ // localToAbsolute() on the RenderView.
+ FloatPoint absPos = m_object->localToAbsolute(FloatPoint(), true);
+ x += absPos.x();
+ y += absPos.y();
+ return;
+ }
+
+ RenderLayer* parentLayer;
+ if (m_object->style()->position() == AbsolutePosition)
+ parentLayer = enclosingPositionedAncestor();
+ else
+ parentLayer = parent();
+
+ if (!parentLayer) return;
+
+ parentLayer->convertToLayerCoords(ancestorLayer, x, y);
+
+ x += xPos();
+ y += yPos();
+}
+
+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
+
+ const int iconRadius = 10;
+ Frame* frame = renderer()->document()->frame();
+ if (!frame)
+ return;
+
+ IntPoint currentMousePosition = frame->eventHandler()->currentMousePosition();
+
+ // We need to check if the current mouse position is out of the window. When the mouse is out of the window, the position is incoherent
+ static IntPoint previousMousePosition;
+ if (currentMousePosition.x() < 0 || currentMousePosition.y() < 0)
+ currentMousePosition = previousMousePosition;
+ else
+ previousMousePosition = currentMousePosition;
+
+ int xDelta = currentMousePosition.x() - sourcePoint.x();
+ int yDelta = currentMousePosition.y() - sourcePoint.y();
+
+ if (abs(xDelta) < iconRadius) // at the center we let the space for the icon
+ xDelta = 0;
+ if (abs(yDelta) < iconRadius)
+ 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);
+}
+
+void RenderLayer::scrollByRecursively(int xDelta, int yDelta)
+{
+ bool restrictedByLineClamp = false;
+ if (m_object->parent())
+ restrictedByLineClamp = m_object->parent()->style()->lineClamp() >= 0;
+
+ if (m_object->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
+ int leftToScrollX = newOffsetX - scrollXOffset();
+ int leftToScrollY = newOffsetY - scrollYOffset();
+ if ((leftToScrollX || leftToScrollY) && m_object->parent()) {
+ m_object->parent()->enclosingLayer()->scrollByRecursively(leftToScrollX, leftToScrollY);
+ Frame* frame = renderer()->document()->frame();
+ if (frame)
+ frame->eventHandler()->updateAutoscrollRenderer();
+ }
+ } else if (m_object->view()->frameView())
+ m_object->view()->frameView()->scrollBy(IntSize(xDelta, yDelta));
+}
+
+
+void
+RenderLayer::addScrolledContentOffset(int& x, int& y) const
+{
+ x += scrollXOffset() + m_scrollLeftOverflow;
+ y += scrollYOffset();
+}
+
+void
+RenderLayer::subtractScrolledContentOffset(int& x, int& y) const
+{
+ x -= scrollXOffset() + m_scrollLeftOverflow;
+ y -= scrollYOffset();
+}
+
+void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint)
+{
+ if (renderer()->style()->overflowX() != OMARQUEE) {
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+
+ // Call the scrollWidth/Height functions so that the dimensions will be computed if they need
+ // to be (for overflow:hidden blocks).
+ int maxX = scrollWidth() - m_object->clientWidth();
+ int maxY = scrollHeight() - m_object->clientHeight();
+
+ if (x > maxX) x = maxX;
+ if (y > maxY) y = maxY;
+ }
+
+ // FIXME: Eventually, we will want to perform a blit. For now never
+ // blit, since the check for blitting is going to be very
+ // complicated (since it will involve testing whether our layer
+ // is either occluded by another layer or clipped by an enclosing
+ // layer or contains fixed backgrounds, etc.).
+ int newScrollX = x - m_scrollOriginX;
+ if (m_scrollY == y && m_scrollX == newScrollX)
+ return;
+ m_scrollX = newScrollX;
+ m_scrollY = y;
+
+ // Update the positions of our child layers.
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+ child->updateLayerPositions(false, false);
+
+ RenderView* view = renderer()->view();
+
+ // We should have a RenderView if we're trying to scroll.
+ ASSERT(view);
+ if (view) {
+#if ENABLE(DASHBOARD_SUPPORT)
+ // Update dashboard regions, scrolling may change the clip of a
+ // particular region.
+ view->frameView()->updateDashboardRegions();
+#endif
+
+ view->updateWidgetPositions();
+ }
+
+ // The caret rect needs to be invalidated after scrolling
+ Frame* frame = renderer()->document()->frame();
+ if (frame)
+ frame->invalidateSelection();
+
+ // Just schedule a full repaint of our object.
+ if (repaint)
+ m_object->repaint();
+
+ if (updateScrollbars) {
+ if (m_hBar)
+ m_hBar->setValue(scrollXOffset());
+ if (m_vBar)
+ m_vBar->setValue(m_scrollY);
+ }
+
+ // Schedule the scroll DOM event.
+ if (view) {
+ if (FrameView* frameView = view->frameView())
+ frameView->scheduleEvent(Event::create(eventNames().scrollEvent, false, false), EventTargetNodeCast(renderer()->element()));
+ }
+}
+
+void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
+{
+ RenderLayer* parentLayer = 0;
+ IntRect newRect = rect;
+ int xOffset = 0, yOffset = 0;
+
+ // We may end up propagating a scroll event. It is important that we suspend events until
+ // the end of the function since they could delete the layer or the layer's m_object.
+ FrameView* frameView = m_object->document()->view();
+ if (frameView)
+ frameView->pauseScheduledEvents();
+
+ bool restrictedByLineClamp = false;
+ if (m_object->parent()) {
+ parentLayer = m_object->parent()->enclosingLayer();
+ restrictedByLineClamp = m_object->parent()->style()->lineClamp() >= 0;
+ }
+
+ if (m_object->hasOverflowClip() && !restrictedByLineClamp) {
+ // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
+ // This will prevent us from revealing text hidden by the slider in Safari RSS.
+ FloatPoint absPos = m_object->localToAbsolute();
+ absPos.move(m_object->borderLeft(), m_object->borderTop());
+
+ IntRect layerBounds = IntRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), m_object->clientWidth(), m_object->clientHeight());
+ IntRect exposeRect = IntRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height());
+ IntRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY);
+
+ xOffset = r.x() - absPos.x();
+ yOffset = r.y() - absPos.y();
+ // Adjust offsets if they're outside of the allowable range.
+ xOffset = max(0, min(scrollWidth() - layerBounds.width(), xOffset));
+ yOffset = max(0, min(scrollHeight() - layerBounds.height(), yOffset));
+
+ if (xOffset != scrollXOffset() || yOffset != scrollYOffset()) {
+ int diffX = scrollXOffset();
+ int diffY = scrollYOffset();
+ scrollToOffset(xOffset, yOffset);
+ diffX = scrollXOffset() - diffX;
+ diffY = scrollYOffset() - diffY;
+ newRect.setX(rect.x() - diffX);
+ newRect.setY(rect.y() - diffY);
+ }
+ } else if (!parentLayer && renderer()->canBeProgramaticallyScrolled(scrollToAnchor)) {
+ if (frameView) {
+ if (m_object->document() && m_object->document()->ownerElement() && m_object->document()->ownerElement()->renderer()) {
+ IntRect viewRect = frameView->visibleContentRect();
+ IntRect r = getRectToExpose(viewRect, rect, alignX, alignY);
+
+ xOffset = r.x();
+ yOffset = r.y();
+ // Adjust offsets if they're outside of the allowable range.
+ xOffset = max(0, min(frameView->contentsWidth(), xOffset));
+ yOffset = max(0, min(frameView->contentsHeight(), yOffset));
+
+ frameView->setScrollPosition(IntPoint(xOffset, yOffset));
+ parentLayer = m_object->document()->ownerElement()->renderer()->enclosingLayer();
+ newRect.setX(rect.x() - frameView->scrollX() + frameView->x());
+ newRect.setY(rect.y() - frameView->scrollY() + frameView->y());
+ } else {
+ IntRect viewRect = frameView->visibleContentRect(true);
+ IntRect r = getRectToExpose(viewRect, rect, alignX, alignY);
+
+ // If this is the outermost view that RenderLayer needs to scroll, then we should scroll the view recursively
+ // Other apps, like Mail, rely on this feature.
+ frameView->scrollRectIntoViewRecursively(r);
+ }
+ }
+ }
+
+ if (parentLayer)
+ parentLayer->scrollRectToVisible(newRect, scrollToAnchor, alignX, alignY);
+
+ if (frameView)
+ frameView->resumeScheduledEvents();
+}
+
+IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
+{
+ // Determine the appropriate X behavior.
+ ScrollBehavior scrollX;
+ IntRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
+ int intersectWidth = intersection(visibleRect, exposeRectX).width();
+ if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
+ // If the rectangle is fully visible, use the specified visible behavior.
+ // If the rectangle is partially visible, but over a certain threshold,
+ // then treat it as fully visible to avoid unnecessary horizontal scrolling
+ scrollX = getVisibleBehavior(alignX);
+ else if (intersectWidth == visibleRect.width()) {
+ // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
+ scrollX = getVisibleBehavior(alignX);
+ if (scrollX == alignCenter)
+ scrollX = noScroll;
+ } else if (intersectWidth > 0)
+ // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
+ scrollX = getPartialBehavior(alignX);
+ else
+ scrollX = getHiddenBehavior(alignX);
+ // If we're trying to align to the closest edge, and the exposeRect is further right
+ // than the visibleRect, and not bigger than the visible area, then align with the right.
+ if (scrollX == alignToClosestEdge && exposeRect.right() > visibleRect.right() && exposeRect.width() < visibleRect.width())
+ scrollX = alignRight;
+
+ // Given the X behavior, compute the X coordinate.
+ int x;
+ if (scrollX == noScroll)
+ x = visibleRect.x();
+ else if (scrollX == alignRight)
+ x = exposeRect.right() - visibleRect.width();
+ else if (scrollX == alignCenter)
+ x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
+ else
+ x = exposeRect.x();
+
+ // Determine the appropriate Y behavior.
+ ScrollBehavior scrollY;
+ IntRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
+ int intersectHeight = intersection(visibleRect, exposeRectY).height();
+ if (intersectHeight == exposeRect.height())
+ // If the rectangle is fully visible, use the specified visible behavior.
+ scrollY = getVisibleBehavior(alignY);
+ else if (intersectHeight == visibleRect.height()) {
+ // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
+ scrollY = getVisibleBehavior(alignY);
+ if (scrollY == alignCenter)
+ scrollY = noScroll;
+ } else if (intersectHeight > 0)
+ // If the rectangle is partially visible, use the specified partial behavior
+ scrollY = getPartialBehavior(alignY);
+ else
+ scrollY = getHiddenBehavior(alignY);
+ // If we're trying to align to the closest edge, and the exposeRect is further down
+ // than the visibleRect, and not bigger than the visible area, then align with the bottom.
+ if (scrollY == alignToClosestEdge && exposeRect.bottom() > visibleRect.bottom() && exposeRect.height() < visibleRect.height())
+ scrollY = alignBottom;
+
+ // Given the Y behavior, compute the Y coordinate.
+ int y;
+ if (scrollY == noScroll)
+ y = visibleRect.y();
+ else if (scrollY == alignBottom)
+ y = exposeRect.bottom() - visibleRect.height();
+ else if (scrollY == alignCenter)
+ y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
+ else
+ y = exposeRect.y();
+
+ return IntRect(IntPoint(x, y), visibleRect.size());
+}
+
+void RenderLayer::autoscroll()
+{
+ Frame* frame = renderer()->document()->frame();
+ if (!frame)
+ return;
+
+ FrameView* frameView = frame->view();
+ if (!frameView)
+ return;
+
+ frame->eventHandler()->updateSelectionForMouseDrag();
+
+ IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition());
+ scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), false, gAlignToEdgeIfNeeded, gAlignToEdgeIfNeeded);
+}
+
+void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset)
+{
+ if (!inResizeMode() || !m_object->hasOverflowClip())
+ return;
+
+ // Set the width and height of the shadow ancestor node if there is one.
+ // This is necessary for textarea elements since the resizable layer is in the shadow content.
+ Element* element = static_cast<Element*>(m_object->node()->shadowAncestorNode());
+ RenderBox* renderer = static_cast<RenderBox*>(element->renderer());
+
+ EResize resize = renderer->style()->resize();
+ if (resize == RESIZE_NONE)
+ return;
+
+ Document* document = element->document();
+ if (!document->frame()->eventHandler()->mousePressed())
+ return;
+
+ float zoomFactor = renderer->style()->effectiveZoom();
+
+ IntSize newOffset = offsetFromResizeCorner(document->view()->windowToContents(evt.pos()));
+ newOffset.setWidth(newOffset.width() / zoomFactor);
+ newOffset.setHeight(newOffset.height() / zoomFactor);
+
+ IntSize currentSize = IntSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
+ IntSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
+ element->setMinimumSizeForResizing(minimumSize);
+
+ IntSize adjustedOldOffset = IntSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
+
+ IntSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
+
+ CSSStyleDeclaration* style = element->style();
+ bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX;
+
+ ExceptionCode ec;
+
+ if (difference.width()) {
+ if (element && element->isControl()) {
+ // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
+ style->setProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false, ec);
+ style->setProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false, ec);
+ }
+ int baseWidth = renderer->width() - (isBoxSizingBorder ? 0
+ : renderer->borderLeft() + renderer->paddingLeft() + renderer->borderRight() + renderer->paddingRight());
+ baseWidth = baseWidth / zoomFactor;
+ style->setProperty(CSSPropertyWidth, String::number(baseWidth + difference.width()) + "px", false, ec);
+ }
+
+ if (difference.height()) {
+ if (element && element->isControl()) {
+ // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
+ style->setProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false, ec);
+ style->setProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false, ec);
+ }
+ int baseHeight = renderer->height() - (isBoxSizingBorder ? 0
+ : renderer->borderTop() + renderer->paddingTop() + renderer->borderBottom() + renderer->paddingBottom());
+ baseHeight = baseHeight / zoomFactor;
+ style->setProperty(CSSPropertyHeight, String::number(baseHeight + difference.height()) + "px", false, ec);
+ }
+
+ document->updateLayout();
+
+ // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
+}
+
+void RenderLayer::valueChanged(Scrollbar*)
+{
+ // Update scroll position from scrollbars.
+
+ bool needUpdate = false;
+ int newX = scrollXOffset();
+ int newY = m_scrollY;
+
+ if (m_hBar) {
+ newX = m_hBar->value();
+ if (newX != scrollXOffset())
+ needUpdate = true;
+ }
+
+ if (m_vBar) {
+ newY = m_vBar->value();
+ if (newY != m_scrollY)
+ needUpdate = true;
+ }
+
+ if (needUpdate)
+ scrollToOffset(newX, newY, false);
+}
+
+bool RenderLayer::isActive() const
+{
+ Page* page = renderer()->document()->frame()->page();
+ return page && page->focusController()->isActive();
+}
+
+
+static IntRect cornerRect(const RenderLayer* layer, const IntRect& bounds)
+{
+ int horizontalThickness;
+ int verticalThickness;
+ if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
+ // FIXME: This isn't right. We need to know the thickness of custom scrollbars
+ // even when they don't exist in order to set the resizer square size properly.
+ horizontalThickness = ScrollbarTheme::nativeTheme()->scrollbarThickness();
+ verticalThickness = horizontalThickness;
+ } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
+ horizontalThickness = layer->verticalScrollbar()->width();
+ verticalThickness = horizontalThickness;
+ } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) {
+ verticalThickness = layer->horizontalScrollbar()->height();
+ horizontalThickness = verticalThickness;
+ } else {
+ horizontalThickness = layer->verticalScrollbar()->width();
+ verticalThickness = layer->horizontalScrollbar()->height();
+ }
+ return IntRect(bounds.right() - horizontalThickness - layer->renderer()->style()->borderRightWidth(),
+ bounds.bottom() - verticalThickness - layer->renderer()->style()->borderBottomWidth(),
+ horizontalThickness, verticalThickness);
+}
+
+static IntRect scrollCornerRect(const RenderLayer* layer, const IntRect& bounds)
+{
+ // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
+ // This happens when:
+ // (a) A resizer is present and at least one scrollbar is present
+ // (b) Both scrollbars are present.
+ bool hasHorizontalBar = layer->horizontalScrollbar();
+ bool hasVerticalBar = layer->verticalScrollbar();
+ bool hasResizer = layer->renderer()->style()->resize() != RESIZE_NONE;
+ if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
+ return cornerRect(layer, bounds);
+ return IntRect();
+}
+
+static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds)
+{
+ if (layer->renderer()->style()->resize() == RESIZE_NONE)
+ return IntRect();
+ return cornerRect(layer, bounds);
+}
+
+bool RenderLayer::scrollbarCornerPresent() const
+{
+ return !scrollCornerRect(this, m_object->borderBox()).isEmpty();
+}
+
+void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
+{
+ IntRect scrollRect = rect;
+ if (scrollbar == m_vBar.get())
+ scrollRect.move(renderer()->width() - renderer()->borderRight() - scrollbar->width(), renderer()->borderTop());
+ else
+ scrollRect.move(renderer()->borderLeft(), renderer()->height() - renderer()->borderBottom() - scrollbar->height());
+ renderer()->repaintRectangle(scrollRect);
+}
+
+PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
+{
+ RefPtr<Scrollbar> widget;
+ bool hasCustomScrollbarStyle = m_object->node()->shadowAncestorNode()->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR);
+ if (hasCustomScrollbarStyle)
+ widget = RenderScrollbar::createCustomScrollbar(this, orientation, m_object->node()->shadowAncestorNode()->renderer());
+ else
+ widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
+ m_object->document()->view()->addChild(widget.get());
+ return widget.release();
+}
+
+void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
+{
+ RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
+ if (scrollbar) {
+ scrollbar->removeFromParent();
+ scrollbar->setClient(0);
+ scrollbar = 0;
+ }
+}
+
+void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
+{
+ if (hasScrollbar == (m_hBar != 0))
+ return;
+
+ if (hasScrollbar)
+ m_hBar = createScrollbar(HorizontalScrollbar);
+ else
+ destroyScrollbar(HorizontalScrollbar);
+
+ // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
+ if (m_hBar)
+ m_hBar->styleChanged();
+ if (m_vBar)
+ m_vBar->styleChanged();
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ // Force an update since we know the scrollbars have changed things.
+ if (m_object->document()->hasDashboardRegions())
+ m_object->document()->setDashboardRegionsDirty(true);
+#endif
+}
+
+void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
+{
+ if (hasScrollbar == (m_vBar != 0))
+ return;
+
+ if (hasScrollbar)
+ m_vBar = createScrollbar(VerticalScrollbar);
+ else
+ destroyScrollbar(VerticalScrollbar);
+
+ // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
+ if (m_hBar)
+ m_hBar->styleChanged();
+ if (m_vBar)
+ m_vBar->styleChanged();
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ // Force an update since we know the scrollbars have changed things.
+ if (m_object->document()->hasDashboardRegions())
+ m_object->document()->setDashboardRegionsDirty(true);
+#endif
+}
+
+int RenderLayer::verticalScrollbarWidth() const
+{
+ if (!m_vBar)
+ return 0;
+ return m_vBar->width();
+}
+
+int RenderLayer::horizontalScrollbarHeight() const
+{
+ if (!m_hBar)
+ return 0;
+ return m_hBar->height();
+}
+
+IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
+{
+ // Currently the resize corner is always the bottom right corner
+ IntPoint bottomRight(width(), height());
+ IntPoint localPoint = absoluteToContents(absolutePoint);
+ return localPoint - bottomRight;
+}
+
+void RenderLayer::positionOverflowControls(int tx, int ty)
+{
+ if (!m_hBar && !m_vBar && (!m_object->hasOverflowClip() || m_object->style()->resize() == RESIZE_NONE))
+ return;
+
+ IntRect borderBox = m_object->borderBox();
+ IntRect scrollCorner(scrollCornerRect(this, borderBox));
+ IntRect absBounds(borderBox.x() + tx, borderBox.y() + ty, borderBox.width(), borderBox.height());
+ if (m_vBar)
+ m_vBar->setFrameRect(IntRect(absBounds.right() - m_object->borderRight() - m_vBar->width(),
+ absBounds.y() + m_object->borderTop(),
+ m_vBar->width(),
+ absBounds.height() - (m_object->borderTop() + m_object->borderBottom()) - scrollCorner.height()));
+
+ if (m_hBar)
+ m_hBar->setFrameRect(IntRect(absBounds.x() + m_object->borderLeft(),
+ absBounds.bottom() - m_object->borderBottom() - m_hBar->height(),
+ absBounds.width() - (m_object->borderLeft() + m_object->borderRight()) - scrollCorner.width(),
+ m_hBar->height()));
+
+ if (m_scrollCorner)
+ m_scrollCorner->setRect(scrollCorner);
+ if (m_resizer)
+ m_resizer->setRect(resizerCornerRect(this, borderBox));
+}
+
+int RenderLayer::scrollWidth()
+{
+ if (m_scrollDimensionsDirty)
+ computeScrollDimensions();
+ return m_scrollWidth;
+}
+
+int RenderLayer::scrollHeight()
+{
+ if (m_scrollDimensionsDirty)
+ computeScrollDimensions();
+ return m_scrollHeight;
+}
+
+void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
+{
+ m_scrollDimensionsDirty = false;
+
+ bool ltr = m_object->style()->direction() == LTR;
+
+ int clientWidth = m_object->clientWidth();
+ int clientHeight = m_object->clientHeight();
+
+ m_scrollLeftOverflow = ltr ? 0 : min(0, m_object->leftmostPosition(true, false) - m_object->borderLeft());
+
+ int rightPos = ltr ?
+ m_object->rightmostPosition(true, false) - m_object->borderLeft() :
+ clientWidth - m_scrollLeftOverflow;
+ int bottomPos = m_object->lowestPosition(true, false) - m_object->borderTop();
+
+ m_scrollWidth = max(rightPos, clientWidth);
+ m_scrollHeight = max(bottomPos, clientHeight);
+
+ m_scrollOriginX = ltr ? 0 : m_scrollWidth - clientWidth;
+
+ if (needHBar)
+ *needHBar = rightPos > clientWidth;
+ if (needVBar)
+ *needVBar = bottomPos > clientHeight;
+}
+
+void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
+{
+ if (m_overflowStatusDirty) {
+ m_horizontalOverflow = horizontalOverflow;
+ m_verticalOverflow = verticalOverflow;
+ m_overflowStatusDirty = false;
+
+ return;
+ }
+
+ bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
+ bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
+
+ if (horizontalOverflowChanged || verticalOverflowChanged) {
+ m_horizontalOverflow = horizontalOverflow;
+ m_verticalOverflow = verticalOverflow;
+
+ if (FrameView* frameView = m_object->document()->view()) {
+ frameView->scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
+ EventTargetNodeCast(m_object->element()));
+ }
+ }
+}
+
+void
+RenderLayer::updateScrollInfoAfterLayout()
+{
+ m_scrollDimensionsDirty = true;
+
+ bool horizontalOverflow, verticalOverflow;
+ computeScrollDimensions(&horizontalOverflow, &verticalOverflow);
+
+ if (m_object->style()->overflowX() != OMARQUEE) {
+ // Layout may cause us to be in an invalid scroll position. In this case we need
+ // to pull our scroll offsets back to the max (or push them up to the min).
+ int newX = max(0, min(scrollXOffset(), scrollWidth() - m_object->clientWidth()));
+ int newY = max(0, min(m_scrollY, scrollHeight() - m_object->clientHeight()));
+ if (newX != scrollXOffset() || newY != m_scrollY) {
+ RenderView* view = m_object->view();
+ ASSERT(view);
+ // scrollToOffset() may call updateLayerPositions(), which doesn't work
+ // with LayoutState.
+ // FIXME: Remove the disableLayoutState/enableLayoutState if the above changes.
+ if (view)
+ view->disableLayoutState();
+ scrollToOffset(newX, newY);
+ if (view)
+ view->enableLayoutState();
+ }
+ }
+
+ bool haveHorizontalBar = m_hBar;
+ bool haveVerticalBar = m_vBar;
+
+ // overflow:scroll should just enable/disable.
+ if (m_object->style()->overflowX() == OSCROLL)
+ m_hBar->setEnabled(horizontalOverflow);
+ if (m_object->style()->overflowY() == OSCROLL)
+ m_vBar->setEnabled(verticalOverflow);
+
+ // A dynamic change from a scrolling overflow to overflow:hidden means we need to get rid of any
+ // scrollbars that may be present.
+ if (m_object->style()->overflowX() == OHIDDEN && haveHorizontalBar)
+ setHasHorizontalScrollbar(false);
+ if (m_object->style()->overflowY() == OHIDDEN && haveVerticalBar)
+ setHasVerticalScrollbar(false);
+
+ // overflow:auto may need to lay out again if scrollbars got added/removed.
+ bool scrollbarsChanged = (m_object->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) ||
+ (m_object->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
+ if (scrollbarsChanged) {
+ if (m_object->hasAutoHorizontalScrollbar())
+ setHasHorizontalScrollbar(horizontalOverflow);
+ if (m_object->hasAutoVerticalScrollbar())
+ setHasVerticalScrollbar(verticalOverflow);
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ // Force an update since we know the scrollbars have changed things.
+ if (m_object->document()->hasDashboardRegions())
+ m_object->document()->setDashboardRegionsDirty(true);
+#endif
+
+ m_object->repaint();
+
+ if (m_object->style()->overflowX() == OAUTO || m_object->style()->overflowY() == OAUTO) {
+ if (!m_inOverflowRelayout) {
+ // Our proprietary overflow: overlay value doesn't trigger a layout.
+ m_inOverflowRelayout = true;
+ m_object->setNeedsLayout(true);
+ if (m_object->isRenderBlock())
+ static_cast<RenderBlock*>(m_object)->layoutBlock(true);
+ else
+ m_object->layout();
+ m_inOverflowRelayout = false;
+ }
+ }
+ }
+
+ // If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985).
+ if (m_hBar && m_object->hasAutoHorizontalScrollbar())
+ m_hBar->setEnabled(true);
+ if (m_vBar && m_object->hasAutoVerticalScrollbar())
+ m_vBar->setEnabled(true);
+
+ // Set up the range (and page step/line step).
+ if (m_hBar) {
+ int clientWidth = m_object->clientWidth();
+ int pageStep = (clientWidth - cAmountToKeepWhenPaging);
+ if (pageStep < 0) pageStep = clientWidth;
+ m_hBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
+ m_hBar->setProportion(clientWidth, m_scrollWidth);
+ m_hBar->setValue(scrollXOffset());
+ }
+ if (m_vBar) {
+ int clientHeight = m_object->clientHeight();
+ int pageStep = (clientHeight - cAmountToKeepWhenPaging);
+ if (pageStep < 0) pageStep = clientHeight;
+ m_vBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
+ m_vBar->setProportion(clientHeight, m_scrollHeight);
+ }
+
+ if (m_object->element() && m_object->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
+ updateOverflowStatus(horizontalOverflow, verticalOverflow);
+}
+
+void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
+{
+ // Don't do anything if we have no overflow.
+ if (!m_object->hasOverflowClip())
+ return;
+
+ // Move the scrollbar widgets 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).
+ positionOverflowControls(tx, ty);
+
+ // Now that we're sure the scrollbars are in the right place, paint them.
+ if (m_hBar)
+ m_hBar->paint(context, damageRect);
+ if (m_vBar)
+ m_vBar->paint(context, damageRect);
+
+ // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
+ // edge of the box.
+ paintScrollCorner(context, tx, ty, damageRect);
+
+ // Paint our resizer last, since it sits on top of the scroll corner.
+ paintResizer(context, tx, ty, damageRect);
+}
+
+void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
+{
+ IntRect cornerRect = scrollCornerRect(this, m_object->borderBox());
+ IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height());
+ if (!absRect.intersects(damageRect))
+ return;
+
+ if (context->updatingControlTints()) {
+ updateScrollCornerStyle();
+ return;
+ }
+
+ if (m_scrollCorner) {
+ m_scrollCorner->paintIntoRect(context, tx, ty, absRect);
+ return;
+ }
+
+ context->fillRect(absRect, Color::white);
+}
+
+void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
+{
+ if (m_object->style()->resize() == RESIZE_NONE)
+ return;
+
+ IntRect cornerRect = resizerCornerRect(this, m_object->borderBox());
+ IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height());
+ if (!absRect.intersects(damageRect))
+ return;
+
+ if (context->updatingControlTints()) {
+ updateResizerStyle();
+ return;
+ }
+
+ if (m_resizer) {
+ m_resizer->paintIntoRect(context, tx, ty, absRect);
+ return;
+ }
+
+ // 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);
+
+ // 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.
+ if (m_hBar || m_vBar) {
+ context->save();
+ IntRect largerCorner = absRect;
+ largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
+ context->setStrokeColor(Color(makeRGB(217, 217, 217)));
+ context->setStrokeThickness(1.0f);
+ context->setFillColor(Color::transparent);
+ context->drawRect(largerCorner);
+ context->restore();
+ }
+}
+
+bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
+{
+ if (!m_object->hasOverflowClip() || m_object->style()->resize() == RESIZE_NONE)
+ return false;
+
+ IntPoint localPoint = absoluteToContents(absolutePoint);
+
+ IntRect localBounds(0, 0, m_object->width(), m_object->height());
+ return resizerCornerRect(this, localBounds).contains(localPoint);
+}
+
+bool RenderLayer::hitTestOverflowControls(HitTestResult& result)
+{
+ if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
+ return false;
+
+ int x = 0;
+ int y = 0;
+ convertToLayerCoords(root(), x, y);
+ IntRect absBounds(x, y, renderer()->width(), renderer()->height());
+
+ IntRect resizeControlRect;
+ if (renderer()->style()->resize() != RESIZE_NONE) {
+ resizeControlRect = resizerCornerRect(this, absBounds);
+ if (resizeControlRect.contains(result.point()))
+ return true;
+ }
+
+ int resizeControlSize = max(resizeControlRect.height(), 0);
+
+ if (m_vBar) {
+ IntRect vBarRect(absBounds.right() - renderer()->borderRight() - m_vBar->width(), absBounds.y() + renderer()->borderTop(), m_vBar->width(), absBounds.height() - (renderer()->borderTop() + renderer()->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
+ if (vBarRect.contains(result.point())) {
+ result.setScrollbar(m_vBar.get());
+ return true;
+ }
+ }
+
+ resizeControlSize = max(resizeControlRect.width(), 0);
+ if (m_hBar) {
+ IntRect hBarRect(absBounds.x() + renderer()->borderLeft(), absBounds.bottom() - renderer()->borderBottom() - m_hBar->height(), absBounds.width() - (renderer()->borderLeft() + renderer()->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), m_hBar->height());
+ if (hBarRect.contains(result.point())) {
+ result.setScrollbar(m_hBar.get());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
+{
+ bool didHorizontalScroll = false;
+ bool didVerticalScroll = false;
+
+ if (m_hBar) {
+ if (granularity == ScrollByDocument) {
+ // Special-case for the ScrollByDocument granularity. A document scroll can only be up
+ // or down and in both cases the horizontal bar goes all the way to the left.
+ didHorizontalScroll = m_hBar->scroll(ScrollLeft, ScrollByDocument, multiplier);
+ } else
+ didHorizontalScroll = m_hBar->scroll(direction, granularity, multiplier);
+ }
+
+ if (m_vBar)
+ didVerticalScroll = m_vBar->scroll(direction, granularity, multiplier);
+
+ return (didHorizontalScroll || didVerticalScroll);
+}
+
+void
+RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintRestriction paintRestriction, RenderObject *paintingRoot)
+{
+ paintLayer(this, p, damageRect, false, paintRestriction, paintingRoot);
+}
+
+static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
+{
+ if (paintDirtyRect == clipRect)
+ return;
+ p->save();
+ p->clip(clipRect);
+}
+
+static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
+{
+ if (paintDirtyRect == clipRect)
+ return;
+ p->restore();
+}
+
+void
+RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
+ const IntRect& paintDirtyRect, bool haveTransparency, PaintRestriction paintRestriction,
+ RenderObject* paintingRoot, bool appliedTransform, bool temporaryClipRects)
+{
+ // Avoid painting layers when stylesheets haven't loaded. This eliminates FOUC.
+ // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
+ // will do a full repaint().
+ if (renderer()->document()->didLayoutWithPendingStylesheets() && !renderer()->isRenderView() && !renderer()->isRoot())
+ return;
+
+ // If this layer is totally invisible then there is nothing to paint.
+ if (!m_object->opacity())
+ return;
+
+ if (isTransparent())
+ haveTransparency = true;
+
+ // Apply a transform if we have one. A reflection is considered to be a transform, since it is a flip and a translate.
+ if (m_transform && !appliedTransform) {
+ // If the transform can't be inverted, then don't paint anything.
+ if (!m_transform->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 (haveTransparency)
+ parent()->beginTransparencyLayers(p, rootLayer);
+
+ // Make sure the parent's clip rects have been calculated.
+ IntRect clipRect = paintDirtyRect;
+ if (parent()) {
+ if (temporaryClipRects) {
+ ClipRects parentClipRects;
+ parent()->calculateClipRects(rootLayer, parentClipRects);
+ clipRect = parentClipRects.overflowClipRect();
+ } else {
+ parent()->updateClipRects(rootLayer);
+ clipRect = parent()->clipRects()->overflowClipRect();
+ }
+ clipRect.intersect(paintDirtyRect);
+ }
+
+ // Push the parent coordinate space's clip.
+ setClip(p, paintDirtyRect, clipRect);
+
+ // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
+ // This involves subtracting out the position of the layer in our current coordinate space.
+ int x = 0;
+ int y = 0;
+ convertToLayerCoords(rootLayer, x, y);
+ TransformationMatrix transform;
+ transform.translate(x, y);
+ transform = *m_transform * transform;
+
+ // Apply the transform.
+ p->save();
+ p->concatCTM(transform);
+
+ // Now do a paint with the root layer shifted to be us.
+ paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), haveTransparency, paintRestriction, paintingRoot, true, temporaryClipRects);
+
+ p->restore();
+
+ // Restore the clip.
+ restoreClip(p, paintDirtyRect, clipRect);
+
+ return;
+ }
+
+ // Paint the reflection first if we have one.
+ if (m_reflection && !m_paintingInsideReflection && (!m_transform || appliedTransform)) {
+ // Mark that we are now inside replica painting.
+ m_paintingInsideReflection = true;
+ reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
+ m_paintingInsideReflection = false;
+ }
+
+ // Calculate the clip rects we should use.
+ IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
+ calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, temporaryClipRects);
+ int x = layerBounds.x();
+ int y = layerBounds.y();
+ int tx = x - renderer()->xPos();
+ int ty = y - renderer()->yPos() + renderer()->borderTopExtra();
+
+ // Ensure our lists are up-to-date.
+ updateZOrderLists();
+ updateOverflowList();
+
+ bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText;
+ bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText;
+
+ // 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.
+ RenderObject* paintingRootForRenderer = 0;
+ if (paintingRoot && !m_object->isDescendantOf(paintingRoot))
+ paintingRootForRenderer = paintingRoot;
+
+ // We want to paint our layer, but only if we intersect the damage rect.
+ bool shouldPaint = intersectsDamageRect(layerBounds, damageRect, rootLayer) && m_hasVisibleContent;
+ if (shouldPaint && !selectionOnly && !damageRect.isEmpty()) {
+ // Begin transparency layers lazily now that we know we have to paint something.
+ if (haveTransparency)
+ beginTransparencyLayers(p, rootLayer);
+
+ // Paint our background first, before painting any child layers.
+ // Establish the clip used to paint our background.
+ setClip(p, paintDirtyRect, damageRect);
+
+ // Paint the background.
+ RenderObject::PaintInfo paintInfo(p, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0);
+ renderer()->paint(paintInfo, tx, 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.
+ paintOverflowControls(p, x, y, damageRect);
+
+ // Restore the clip.
+ restoreClip(p, paintDirtyRect, damageRect);
+ }
+
+ // 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, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
+
+ // 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);
+
+ // Set up the clip used when painting our children.
+ setClip(p, paintDirtyRect, clipRectToApply);
+ RenderObject::PaintInfo paintInfo(p, clipRectToApply,
+ selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds,
+ forceBlackText, paintingRootForRenderer, 0);
+ renderer()->paint(paintInfo, tx, ty);
+ if (!selectionOnly) {
+ paintInfo.phase = PaintPhaseFloat;
+ renderer()->paint(paintInfo, tx, ty);
+ paintInfo.phase = PaintPhaseForeground;
+ renderer()->paint(paintInfo, tx, ty);
+ paintInfo.phase = PaintPhaseChildOutlines;
+ renderer()->paint(paintInfo, tx, ty);
+ }
+
+ // Now restore our clip.
+ restoreClip(p, paintDirtyRect, clipRectToApply);
+ }
+
+ if (!outlineRect.isEmpty()) {
+ // Paint our own outline
+ RenderObject::PaintInfo paintInfo(p, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0);
+ setClip(p, paintDirtyRect, outlineRect);
+ renderer()->paint(paintInfo, tx, ty);
+ restoreClip(p, paintDirtyRect, outlineRect);
+ }
+
+ // Paint any child layers that have overflow.
+ if (m_overflowList)
+ for (Vector<RenderLayer*>::iterator it = m_overflowList->begin(); it != m_overflowList->end(); ++it)
+ it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
+
+ // 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, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
+
+ if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty()) {
+ setClip(p, paintDirtyRect, damageRect);
+
+ // Paint the mask.
+ RenderObject::PaintInfo paintInfo(p, damageRect, PaintPhaseMask, false, paintingRootForRenderer, 0);
+ renderer()->paint(paintInfo, tx, ty);
+
+ // Restore the clip.
+ restoreClip(p, paintDirtyRect, damageRect);
+ }
+
+ // End our transparency layer
+ if (isTransparent() && m_usedTransparency) {
+ p->endTransparencyLayer();
+ p->restore();
+ m_usedTransparency = false;
+ }
+}
+
+static inline IntRect frameVisibleRect(RenderObject* renderer)
+{
+ FrameView* frameView = renderer->document()->view();
+ if (!frameView)
+ return IntRect();
+
+ return frameView->visibleContentRect();
+}
+
+bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
+{
+ renderer()->document()->updateLayout();
+
+ IntRect boundsRect(m_x, m_y, width(), height());
+ boundsRect.intersect(frameVisibleRect(renderer()));
+
+ RenderLayer* insideLayer = hitTestLayer(this, request, result, boundsRect, result.point());
+
+ // 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.
+ 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();
+ }
+
+ // Next set up the correct :hover/:active state along the new chain.
+ updateHoverActiveState(request, result);
+
+ // Now return whether we were inside this layer (this will always be true for the root
+ // layer).
+ return insideLayer;
+}
+
+Node* RenderLayer::enclosingElement() const
+{
+ for (RenderObject* r = renderer(); r; r = r->parent()) {
+ if (Node* e = r->element())
+ return e;
+ }
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
+ const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform)
+{
+ // Apply a transform if we have one.
+ if (m_transform && !appliedTransform) {
+ // If the transform can't be inverted, then don't hit test this layer at all.
+ if (!m_transform->isInvertible())
+ return 0;
+
+ // Make sure the parent's clip rects have been calculated.
+ if (parent()) {
+ parent()->updateClipRects(rootLayer);
+
+ // Go ahead and test the enclosing clip now.
+ IntRect clipRect = parent()->clipRects()->overflowClipRect();
+ if (!clipRect.contains(hitTestPoint))
+ return 0;
+ }
+
+ // Adjust the transform such that the renderer's upper left corner is at (0,0) in user space.
+ // This involves subtracting out the position of the layer in our current coordinate space.
+ int x = 0;
+ int y = 0;
+ convertToLayerCoords(rootLayer, x, y);
+ TransformationMatrix transform;
+ transform.translate(x, y);
+ transform = *m_transform * transform;
+
+ // Map the hit test point into the transformed space and then do a hit test with the root layer shifted to be us.
+ return hitTestLayer(this, request, result, transform.inverse().mapRect(hitTestRect), transform.inverse().mapPoint(hitTestPoint), true);
+ }
+
+ // Calculate the clip rects we should use.
+ IntRect layerBounds;
+ IntRect bgRect;
+ IntRect fgRect;
+ IntRect outlineRect;
+ calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect);
+
+ // Ensure our lists are up-to-date.
+ updateZOrderLists();
+ updateOverflowList();
+
+ // This variable tracks which layer the mouse ends up being inside. The minute we find an insideLayer,
+ // we are done and can return it.
+ RenderLayer* insideLayer = 0;
+
+ // Begin by walking our list of positive layers from highest z-index down to the lowest
+ // z-index.
+ if (m_posZOrderList) {
+ for (int i = m_posZOrderList->size() - 1; i >= 0; --i) {
+ insideLayer = m_posZOrderList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
+ if (insideLayer)
+ return insideLayer;
+ }
+ }
+
+ // Now check our overflow objects.
+ if (m_overflowList) {
+ for (int i = m_overflowList->size() - 1; i >= 0; --i) {
+ insideLayer = m_overflowList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
+ if (insideLayer)
+ return insideLayer;
+ }
+ }
+
+ // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
+ if (fgRect.contains(hitTestPoint) &&
+ renderer()->hitTest(request, result, hitTestPoint,
+ layerBounds.x() - renderer()->xPos(),
+ layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(),
+ HitTestDescendants)) {
+ // For positioned generated content, we might still not have a
+ // node by the time we get to the layer level, since none of
+ // the content in the layer has an element. So just walk up
+ // the tree.
+ if (!result.innerNode() || !result.innerNonSharedNode()) {
+ Node* e = enclosingElement();
+ if (!result.innerNode())
+ result.setInnerNode(e);
+ if (!result.innerNonSharedNode())
+ result.setInnerNonSharedNode(e);
+ }
+
+ return this;
+ }
+
+ // Now check our negative z-index children.
+ if (m_negZOrderList) {
+ for (int i = m_negZOrderList->size() - 1; i >= 0; --i) {
+ insideLayer = m_negZOrderList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
+ if (insideLayer)
+ return insideLayer;
+ }
+ }
+
+ // Next we want to see if the mouse is inside this layer but not any of its children.
+ if (bgRect.contains(hitTestPoint) &&
+ renderer()->hitTest(request, result, hitTestPoint,
+ layerBounds.x() - renderer()->xPos(),
+ layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(),
+ HitTestSelf)) {
+ if (!result.innerNode() || !result.innerNonSharedNode()) {
+ Node* e = enclosingElement();
+ if (!result.innerNode())
+ result.setInnerNode(e);
+ if (!result.innerNonSharedNode())
+ result.setInnerNonSharedNode(e);
+ }
+
+ return this;
+ }
+
+ // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
+ // return ourselves. We do this so mouse events continue getting delivered after a drag has
+ // exited the WebView, and so hit testing over a scrollbar hits the content document.
+ if ((request.active || request.mouseUp) && renderer()->isRenderView()) {
+ renderer()->updateHitTestResult(result, hitTestPoint);
+ return this;
+ }
+
+ return 0;
+}
+
+void RenderLayer::updateClipRects(const RenderLayer* rootLayer)
+{
+ if (m_clipRects) {
+ ASSERT(rootLayer == m_clipRectsRoot);
+ return; // We have the correct cached value.
+ }
+
+ // For transformed layers, the root layer was shifted to be us, so there is no need to
+ // examine the parent. We want to cache clip rects with us as the root.
+ RenderLayer* parentLayer = rootLayer != this ? parent() : 0;
+ if (parentLayer)
+ parentLayer->updateClipRects(rootLayer);
+
+ ClipRects clipRects;
+ calculateClipRects(rootLayer, clipRects, true);
+
+ if (parentLayer && parentLayer->clipRects() && clipRects == *parentLayer->clipRects())
+ m_clipRects = parentLayer->clipRects();
+ else
+ m_clipRects = new (m_object->renderArena()) ClipRects(clipRects);
+ m_clipRects->ref();
+#ifndef NDEBUG
+ m_clipRectsRoot = rootLayer;
+#endif
+}
+
+void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool useCached) const
+{
+ IntRect infiniteRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX);
+ if (!parent()) {
+ // The root layer's clip rect is always infinite.
+ clipRects.reset(infiniteRect);
+ return;
+ }
+
+ // For transformed layers, the root layer was shifted to be us, so there is no need to
+ // examine the parent. We want to cache clip rects with us as the root.
+ RenderLayer* parentLayer = rootLayer != this ? parent() : 0;
+
+ // Ensure that our parent's clip has been calculated so that we can examine the values.
+ if (parentLayer) {
+ if (useCached && parentLayer->clipRects())
+ clipRects = *parentLayer->clipRects();
+ else
+ parentLayer->calculateClipRects(rootLayer, clipRects);
+ }
+ else
+ clipRects.reset(infiniteRect);
+
+ // A fixed object is essentially the root of its containing block hierarchy, so when
+ // we encounter such an object, we reset our clip rects to the fixedClipRect.
+ if (m_object->style()->position() == FixedPosition) {
+ clipRects.setPosClipRect(clipRects.fixedClipRect());
+ clipRects.setOverflowClipRect(clipRects.fixedClipRect());
+ clipRects.setFixed(true);
+ }
+ else if (m_object->style()->position() == RelativePosition)
+ clipRects.setPosClipRect(clipRects.overflowClipRect());
+ else if (m_object->style()->position() == AbsolutePosition)
+ clipRects.setOverflowClipRect(clipRects.posClipRect());
+
+ // Update the clip rects that will be passed to child layers.
+ if (m_object->hasOverflowClip() || m_object->hasClip()) {
+ // This layer establishes a clip of some kind.
+ int x = 0;
+ int y = 0;
+ convertToLayerCoords(rootLayer, x, y);
+ RenderView* view = renderer()->view();
+ ASSERT(view);
+ if (view && clipRects.fixed() && rootLayer->renderer() == view) {
+ x -= view->frameView()->scrollX();
+ y -= view->frameView()->scrollY();
+ }
+
+ if (m_object->hasOverflowClip()) {
+ IntRect newOverflowClip = m_object->getOverflowClipRect(x,y);
+ clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
+ if (m_object->isPositioned() || m_object->isRelPositioned())
+ clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
+ }
+ if (m_object->hasClip()) {
+ IntRect newPosClip = m_object->getClipRect(x,y);
+ clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect()));
+ clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect()));
+ clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect()));
+ }
+ }
+}
+
+void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds,
+ IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects) const
+{
+ if (rootLayer != this && parent()) {
+ ClipRects parentClipRects;
+ if (temporaryClipRects)
+ parent()->calculateClipRects(rootLayer, parentClipRects);
+ else {
+ parent()->updateClipRects(rootLayer);
+ parentClipRects = *parent()->clipRects();
+ }
+
+ backgroundRect = m_object->style()->position() == FixedPosition ? parentClipRects.fixedClipRect() :
+ (m_object->isPositioned() ? parentClipRects.posClipRect() :
+ parentClipRects.overflowClipRect());
+ RenderView* view = renderer()->view();
+ ASSERT(view);
+ if (view && parentClipRects.fixed() && rootLayer->renderer() == view)
+ backgroundRect.move(view->frameView()->scrollX(), view->frameView()->scrollY());
+
+ backgroundRect.intersect(paintDirtyRect);
+ } else
+ backgroundRect = paintDirtyRect;
+
+ foregroundRect = backgroundRect;
+ outlineRect = backgroundRect;
+
+ int x = 0;
+ int y = 0;
+ convertToLayerCoords(rootLayer, x, y);
+ layerBounds = IntRect(x,y,width(),height());
+
+ // Update the clip rects that will be passed to child layers.
+ if (m_object->hasOverflowClip() || m_object->hasClip()) {
+ // This layer establishes a clip of some kind.
+ if (m_object->hasOverflowClip())
+ foregroundRect.intersect(m_object->getOverflowClipRect(x,y));
+ if (m_object->hasClip()) {
+ // Clip applies to *us* as well, so go ahead and update the damageRect.
+ IntRect newPosClip = m_object->getClipRect(x,y);
+ backgroundRect.intersect(newPosClip);
+ foregroundRect.intersect(newPosClip);
+ outlineRect.intersect(newPosClip);
+ }
+
+ // If we establish a clip at all, then go ahead and make sure our background
+ // rect is intersected with our layer's bounds.
+ if (ShadowData* boxShadow = renderer()->style()->boxShadow()) {
+ IntRect overflow = layerBounds;
+ do {
+ IntRect shadowRect = layerBounds;
+ shadowRect.move(boxShadow->x, boxShadow->y);
+ shadowRect.inflate(boxShadow->blur);
+ overflow.unite(shadowRect);
+ boxShadow = boxShadow->next;
+ } while (boxShadow);
+ backgroundRect.intersect(overflow);
+ } else
+ backgroundRect.intersect(layerBounds);
+ }
+}
+
+IntRect RenderLayer::childrenClipRect() const
+{
+ RenderLayer* rootLayer = renderer()->document()->renderer()->layer();
+ IntRect layerBounds, backgroundRect, foregroundRect, outlineRect;
+ calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect);
+ return foregroundRect;
+}
+
+IntRect RenderLayer::selfClipRect() const
+{
+ RenderLayer* rootLayer = renderer()->document()->renderer()->layer();
+ IntRect layerBounds, backgroundRect, foregroundRect, outlineRect;
+ calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect);
+ return backgroundRect;
+}
+
+bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect& damageRect, const RenderLayer* rootLayer) const
+{
+ // Always examine the canvas and the root.
+ // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
+ // paints the root's background.
+ if (renderer()->isRenderView() || renderer()->isRoot())
+ return true;
+
+ // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we
+ // can go ahead and return true.
+ RenderView* view = renderer()->view();
+ ASSERT(view);
+ if (view && !renderer()->isInlineFlow()) {
+ IntRect b = layerBounds;
+ b.inflate(view->maximalOutlineSize());
+ if (b.intersects(damageRect))
+ return true;
+ }
+
+ // Otherwise we need to compute the bounding box of this single layer and see if it intersects
+ // the damage rect.
+ return boundingBox(rootLayer).intersects(damageRect);
+}
+
+IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) 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
+ // 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.
+ // (3) Floats. When a layer has overhanging floats that it paints, we need to make sure to include these overhanging floats
+ // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those
+ // floats.
+ IntRect result;
+ if (renderer()->isInlineFlow()) {
+ // Go from our first line box to our last line box.
+ RenderInline* inlineFlow = static_cast<RenderInline*>(renderer());
+ InlineFlowBox* firstBox = inlineFlow->firstLineBox();
+ if (!firstBox)
+ return result;
+ int top = firstBox->root()->topOverflow();
+ int bottom = inlineFlow->lastLineBox()->root()->bottomOverflow();
+ int left = firstBox->xPos();
+ for (InlineRunBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox())
+ left = min(left, curr->xPos());
+ result = IntRect(m_x + left, m_y + (top - renderer()->yPos()), width(), bottom - top);
+ } else if (renderer()->isTableRow()) {
+ // Our bounding box is just the union of all of our cells' border/overflow rects.
+ for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
+ if (child->isTableCell()) {
+ IntRect bbox = child->borderBox();
+ bbox.move(0, child->borderTopExtra());
+ result.unite(bbox);
+ IntRect overflowRect = renderer()->overflowRect(false);
+ overflowRect.move(0, child->borderTopExtra());
+ if (bbox != overflowRect)
+ result.unite(overflowRect);
+ }
+ }
+ result.move(m_x, m_y);
+ } else {
+ if (renderer()->hasMask())
+ result = renderer()->maskClipRect();
+ else {
+ IntRect bbox = renderer()->borderBox();
+ result = bbox;
+ IntRect overflowRect = renderer()->overflowRect(false);
+ if (bbox != overflowRect)
+ result.unite(overflowRect);
+ }
+
+ // We have to adjust the x/y of this result so that it is in the coordinate space of the layer.
+ // We also have to add in borderTopExtra here, since borderBox(), in order to play well with methods like
+ // floatRect that deal with child content, uses an origin of (0,0) that is at the child content box (so
+ // border box returns a y coord of -borderTopExtra(). The layer, however, uses the outer box. This is all
+ // really confusing.
+ result.move(m_x, m_y + renderer()->borderTopExtra());
+ }
+
+ // Convert the bounding box to an absolute position. We can do this easily by looking at the delta
+ // between the bounding box's xpos and our layer's xpos and then applying that to the absolute layerBounds
+ // passed in.
+ int absX = 0, absY = 0;
+ convertToLayerCoords(rootLayer, absX, absY);
+ result.move(absX - m_x, absY - m_y);
+ RenderView* view = renderer()->view();
+ ASSERT(view);
+ if (view)
+ result.inflate(view->maximalOutlineSize());
+ return result;
+}
+
+void RenderLayer::clearClipRectsIncludingDescendants()
+{
+ if (!m_clipRects)
+ return;
+
+ clearClipRects();
+
+ for (RenderLayer* l = firstChild(); l; l = l->nextSibling())
+ l->clearClipRectsIncludingDescendants();
+}
+
+void RenderLayer::clearClipRects()
+{
+ if (m_clipRects) {
+ m_clipRects->deref(m_object->renderArena());
+ m_clipRects = 0;
+#ifndef NDEBUG
+ m_clipRectsRoot = 0;
+#endif
+ }
+}
+
+static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
+{
+ if (!obj1 || !obj2)
+ return 0;
+
+ for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor())
+ for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor())
+ if (currObj1 == currObj2)
+ return currObj1;
+
+ return 0;
+}
+
+void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result)
+{
+ // We don't update :hover/:active state when the result is marked as readonly.
+ if (request.readonly)
+ return;
+
+ Document* doc = renderer()->document();
+
+ Node* activeNode = doc->activeNode();
+ if (activeNode && !request.active) {
+ // We are clearing the :active chain because the mouse has been released.
+ for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) {
+ if (curr->element() && !curr->isText())
+ curr->element()->setInActiveChain(false);
+ }
+ doc->setActiveNode(0);
+ } else {
+ Node* newActiveNode = result.innerNode();
+ if (!activeNode && newActiveNode && request.active) {
+ // We are setting the :active chain and freezing it. If future moves happen, they
+ // will need to reference this chain.
+ for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) {
+ if (curr->element() && !curr->isText()) {
+ curr->element()->setInActiveChain(true);
+ }
+ }
+ doc->setActiveNode(newActiveNode);
+ }
+ }
+
+ // If the mouse is down and if this is a mouse move event, we want to restrict changes in
+ // :hover/:active to only apply to elements that are in the :active chain that we froze
+ // at the time the mouse went down.
+ bool mustBeInActiveChain = request.active && request.mouseMove;
+
+ // Check to see if the hovered node has changed. If not, then we don't need to
+ // do anything.
+ RefPtr<Node> oldHoverNode = doc->hoverNode();
+ Node* newHoverNode = result.innerNode();
+
+ // Update our current hover node.
+ doc->setHoverNode(newHoverNode);
+
+ // We have two different objects. Fetch their renderers.
+ RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
+ RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
+
+ // Locate the common ancestor render object for the two renderers.
+ RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
+
+ if (oldHoverObj != newHoverObj) {
+ // The old hover path only needs to be cleared up to (and not including) the common ancestor;
+ for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
+ if (curr->element() && !curr->isText() && (!mustBeInActiveChain || curr->element()->inActiveChain())) {
+ curr->element()->setActive(false);
+ curr->element()->setHovered(false);
+ }
+ }
+ }
+
+ // Now set the hover state for our new object up to the root.
+ for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
+ if (curr->element() && !curr->isText() && (!mustBeInActiveChain || curr->element()->inActiveChain())) {
+ curr->element()->setActive(request.active);
+ curr->element()->setHovered(true);
+ }
+ }
+}
+
+// Helper for the sorting of layers by z-index.
+static inline bool compareZIndex(RenderLayer* first, RenderLayer* second)
+{
+ return first->zIndex() < second->zIndex();
+}
+
+void RenderLayer::dirtyZOrderLists()
+{
+ if (m_posZOrderList)
+ m_posZOrderList->clear();
+ if (m_negZOrderList)
+ m_negZOrderList->clear();
+ m_zOrderListsDirty = true;
+}
+
+void RenderLayer::dirtyStackingContextZOrderLists()
+{
+ RenderLayer* sc = stackingContext();
+ if (sc)
+ sc->dirtyZOrderLists();
+}
+
+void RenderLayer::dirtyOverflowList()
+{
+ if (m_overflowList)
+ m_overflowList->clear();
+ m_overflowListDirty = true;
+}
+
+void RenderLayer::updateZOrderLists()
+{
+ if (!isStackingContext() || !m_zOrderListsDirty)
+ return;
+
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+ if (!m_reflection || reflectionLayer() != child)
+ child->collectLayers(m_posZOrderList, m_negZOrderList);
+
+ // Sort the two lists.
+ if (m_posZOrderList)
+ std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex);
+ if (m_negZOrderList)
+ std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex);
+
+ m_zOrderListsDirty = false;
+}
+
+void RenderLayer::updateOverflowList()
+{
+ if (!m_overflowListDirty)
+ return;
+
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
+ // Ignore non-overflow layers and reflections.
+ if (child->isOverflowOnly() && (!m_reflection || reflectionLayer() != child)) {
+ if (!m_overflowList)
+ m_overflowList = new Vector<RenderLayer*>;
+ m_overflowList->append(child);
+ }
+ }
+
+ m_overflowListDirty = false;
+}
+
+void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderLayer*>*& negBuffer)
+{
+ updateVisibilityStatus();
+
+ // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists.
+ if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isOverflowOnly()) {
+ // Determine which buffer the child should be in.
+ Vector<RenderLayer*>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
+
+ // Create the buffer if it doesn't exist yet.
+ if (!buffer)
+ buffer = new Vector<RenderLayer*>;
+
+ // Append ourselves at the end of the appropriate buffer.
+ buffer->append(this);
+ }
+
+ // Recur into our children to collect more layers, but only if we don't establish
+ // a stacking context.
+ if (m_hasVisibleDescendant && !isStackingContext()) {
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
+ // Ignore reflections.
+ if (!m_reflection || reflectionLayer() != child)
+ child->collectLayers(posBuffer, negBuffer);
+ }
+ }
+}
+
+void RenderLayer::repaintIncludingDescendants()
+{
+ m_object->repaint();
+ for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
+ curr->repaintIncludingDescendants();
+}
+
+bool RenderLayer::shouldBeOverflowOnly() const
+{
+ return (renderer()->hasOverflowClip() || renderer()->hasReflection()) &&
+ !renderer()->isPositioned() &&
+ !renderer()->isRelPositioned() &&
+ !renderer()->hasTransform() &&
+ !isTransparent();
+}
+
+void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle*)
+{
+ bool isOverflowOnly = shouldBeOverflowOnly();
+ if (isOverflowOnly != m_isOverflowOnly) {
+ m_isOverflowOnly = isOverflowOnly;
+ RenderLayer* p = parent();
+ if (p)
+ p->dirtyOverflowList();
+ dirtyStackingContextZOrderLists();
+ }
+
+ if (m_object->style()->overflowX() == OMARQUEE && m_object->style()->marqueeBehavior() != MNONE) {
+ if (!m_marquee)
+ m_marquee = new RenderMarquee(this);
+ m_marquee->updateMarqueeStyle();
+ }
+ else if (m_marquee) {
+ delete m_marquee;
+ m_marquee = 0;
+ }
+
+ if (!hasReflection() && m_reflection) {
+ m_reflection->destroy();
+ m_reflection = 0;
+ } else if (hasReflection()) {
+ if (!m_reflection)
+ createReflection();
+ updateReflectionStyle();
+ }
+
+ // FIXME: Need to detect a swap from custom to native scrollbars (and vice versa).
+ if (m_hBar)
+ m_hBar->styleChanged();
+ if (m_vBar)
+ m_vBar->styleChanged();
+
+ updateScrollCornerStyle();
+ updateResizerStyle();
+}
+
+void RenderLayer::updateScrollCornerStyle()
+{
+ RenderObject* actualRenderer = m_object->node()->isElementNode() ? m_object->node()->shadowAncestorNode()->renderer() : m_object;
+ RefPtr<RenderStyle> corner = m_object->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::SCROLLBAR_CORNER, actualRenderer->style()) : 0;
+ if (corner) {
+ if (!m_scrollCorner) {
+ m_scrollCorner = new (m_object->renderArena()) RenderScrollbarPart(m_object->document());
+ m_scrollCorner->setParent(m_object);
+ }
+ m_scrollCorner->setStyle(corner.release());
+ } else if (m_scrollCorner) {
+ m_scrollCorner->destroy();
+ m_scrollCorner = 0;
+ }
+}
+
+void RenderLayer::updateResizerStyle()
+{
+ RenderObject* actualRenderer = m_object->node()->isElementNode() ? m_object->node()->shadowAncestorNode()->renderer() : m_object;
+ RefPtr<RenderStyle> resizer = m_object->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::RESIZER, actualRenderer->style()) : 0;
+ if (resizer) {
+ if (!m_resizer) {
+ m_resizer = new (m_object->renderArena()) RenderScrollbarPart(m_object->document());
+ m_resizer->setParent(m_object);
+ }
+ m_resizer->setStyle(resizer.release());
+ } else if (m_resizer) {
+ m_resizer->destroy();
+ m_resizer = 0;
+ }
+}
+
+RenderLayer* RenderLayer::reflectionLayer() const
+{
+ return m_reflection ? m_reflection->layer() : 0;
+}
+
+void RenderLayer::createReflection()
+{
+ ASSERT(!m_reflection);
+ m_reflection = new (renderer()->renderArena()) RenderReplica(renderer()->document());
+ m_reflection->setParent(renderer()); // We create a 1-way connection.
+}
+
+void RenderLayer::updateReflectionStyle()
+{
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(renderer()->style());
+
+ // Map in our transform.
+ TransformOperations transform;
+ switch (renderer()->style()->boxReflect()->direction()) {
+ case ReflectionBelow:
+ transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::TRANSLATE));
+ transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::TRANSLATE));
+ transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE));
+ break;
+ case ReflectionAbove:
+ transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE));
+ transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::TRANSLATE));
+ transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::TRANSLATE));
+ break;
+ case ReflectionRight:
+ transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::TRANSLATE));
+ transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE));
+ transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE));
+ break;
+ case ReflectionLeft:
+ transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE));
+ transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::TRANSLATE));
+ transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE));
+ break;
+ }
+ newStyle->setTransform(transform);
+
+ // Map in our mask.
+ newStyle->setMaskBoxImage(renderer()->style()->boxReflect()->mask());
+
+ m_reflection->setStyle(newStyle.release());
+}
+
+void RenderLayer::suspendMarquees()
+{
+ if (m_marquee)
+ m_marquee->suspend();
+
+ for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
+ curr->suspendMarquees();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h
new file mode 100644
index 0000000..b2ba48c
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderLayer.h
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * Portions are Copyright (C) 1998 Netscape Communications Corporation.
+ *
+ * Other contributors:
+ * Robert O'Callahan <roc+@cs.cmu.edu>
+ * David Baron <dbaron@fas.harvard.edu>
+ * Christian Biesinger <cbiesinger@web.de>
+ * Randall Jesup <rjesup@wgate.com>
+ * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
+ * Josh Soref <timeless@mac.com>
+ * Boris Zbarsky <bzbarsky@mit.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+ */
+
+#ifndef RenderLayer_h
+#define RenderLayer_h
+
+#include "ScrollbarClient.h"
+#include "RenderObject.h"
+#include "Timer.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class TransformationMatrix;
+class CachedResource;
+class HitTestResult;
+class RenderFrameSet;
+class RenderMarquee;
+class RenderObject;
+class RenderReplica;
+class RenderScrollbarPart;
+class RenderStyle;
+class RenderTable;
+class RenderText;
+class RenderView;
+class Scrollbar;
+
+struct HitTestRequest;
+
+class ClipRects {
+public:
+ ClipRects()
+ : m_refCnt(0)
+ , m_fixed(false)
+ {
+ }
+
+ ClipRects(const IntRect& r)
+ : m_overflowClipRect(r)
+ , m_fixedClipRect(r)
+ , m_posClipRect(r)
+ , m_refCnt(0)
+ , m_fixed(false)
+ {
+ }
+
+ ClipRects(const ClipRects& other)
+ : m_overflowClipRect(other.overflowClipRect())
+ , m_fixedClipRect(other.fixedClipRect())
+ , m_posClipRect(other.posClipRect())
+ , m_refCnt(0)
+ , m_fixed(other.fixed())
+ {
+ }
+
+ void reset(const IntRect& r)
+ {
+ m_overflowClipRect = r;
+ m_fixedClipRect = r;
+ m_posClipRect = r;
+ m_fixed = false;
+ }
+
+ const IntRect& overflowClipRect() const { return m_overflowClipRect; }
+ void setOverflowClipRect(const IntRect& r) { m_overflowClipRect = r; }
+
+ const IntRect& fixedClipRect() const { return m_fixedClipRect; }
+ void setFixedClipRect(const IntRect&r) { m_fixedClipRect = r; }
+
+ const IntRect& posClipRect() const { return m_posClipRect; }
+ void setPosClipRect(const IntRect& r) { m_posClipRect = r; }
+
+ bool fixed() const { return m_fixed; }
+ void setFixed(bool fixed) { m_fixed = fixed; }
+
+ void ref() { m_refCnt++; }
+ void deref(RenderArena* renderArena) { if (--m_refCnt == 0) destroy(renderArena); }
+
+ void destroy(RenderArena*);
+
+ // 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);
+
+ bool operator==(const ClipRects& other) const
+ {
+ return m_overflowClipRect == other.overflowClipRect() &&
+ m_fixedClipRect == other.fixedClipRect() &&
+ m_posClipRect == other.posClipRect() &&
+ m_fixed == other.fixed();
+ }
+
+ ClipRects& operator=(const ClipRects& other)
+ {
+ m_overflowClipRect = other.overflowClipRect();
+ m_fixedClipRect = other.fixedClipRect();
+ m_posClipRect = other.posClipRect();
+ m_fixed = other.fixed();
+ return *this;
+ }
+
+private:
+ // The normal operator new is disallowed on all render objects.
+ void* operator new(size_t) throw();
+
+private:
+ IntRect m_overflowClipRect;
+ IntRect m_fixedClipRect;
+ IntRect m_posClipRect;
+ unsigned m_refCnt : 31;
+ bool m_fixed : 1;
+};
+
+class RenderLayer : public ScrollbarClient {
+public:
+ enum ScrollBehavior {
+ noScroll,
+ alignCenter,
+ alignTop,
+ alignBottom,
+ alignLeft,
+ alignRight,
+ alignToClosestEdge
+ };
+
+ struct ScrollAlignment {
+ ScrollBehavior m_rectVisible;
+ ScrollBehavior m_rectHidden;
+ ScrollBehavior m_rectPartial;
+ };
+
+ friend class RenderReplica;
+
+ static const ScrollAlignment gAlignCenterIfNeeded;
+ static const ScrollAlignment gAlignToEdgeIfNeeded;
+ static const ScrollAlignment gAlignCenterAlways;
+ static const ScrollAlignment gAlignTopAlways;
+ static const ScrollAlignment gAlignBottomAlways;
+
+ static ScrollBehavior getVisibleBehavior(const ScrollAlignment& s) { return s.m_rectVisible; }
+ static ScrollBehavior getPartialBehavior(const ScrollAlignment& s) { return s.m_rectPartial; }
+ static ScrollBehavior getHiddenBehavior(const ScrollAlignment& s) { return s.m_rectHidden; }
+
+ RenderLayer(RenderObject*);
+ ~RenderLayer();
+
+ RenderObject* renderer() const { return m_object; }
+ RenderLayer* parent() const { return m_parent; }
+ RenderLayer* previousSibling() const { return m_previous; }
+ RenderLayer* nextSibling() const { return m_next; }
+ RenderLayer* firstChild() const { return m_first; }
+ RenderLayer* lastChild() const { return m_last; }
+
+ void addChild(RenderLayer* newChild, RenderLayer* beforeChild = 0);
+ RenderLayer* removeChild(RenderLayer*);
+
+ void removeOnlyThisLayer();
+ void insertOnlyThisLayer();
+
+ void repaintIncludingDescendants();
+
+ void styleChanged(RenderStyle::Diff, const RenderStyle*);
+
+ RenderMarquee* marquee() const { return m_marquee; }
+ void suspendMarquees();
+
+ bool isOverflowOnly() const { return m_isOverflowOnly; }
+
+ bool requiresSlowRepaints() const;
+
+ bool isTransparent() const;
+ RenderLayer* transparentAncestor();
+ void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer);
+
+ bool hasReflection() const { return m_object->hasReflection(); }
+ RenderReplica* reflection() const { return m_reflection; }
+ RenderLayer* reflectionLayer() const;
+
+ const RenderLayer* root() const
+ {
+ const RenderLayer* curr = this;
+ while (curr->parent())
+ curr = curr->parent();
+ return curr;
+ }
+
+ int xPos() const { return m_x; }
+ int yPos() const { return m_y; }
+ void setPos(int xPos, int yPos)
+ {
+ m_x = xPos;
+ m_y = yPos;
+ }
+
+ int width() const { return m_width; }
+ int height() const { return m_height; }
+ void setWidth(int w) { m_width = w; }
+ void setHeight(int h) { m_height = h; }
+
+ int scrollWidth();
+ int scrollHeight();
+
+ void panScrollFromPoint(const IntPoint&);
+
+ // Scrolling methods for layers that can scroll their overflow.
+ void scrollByRecursively(int xDelta, int yDelta);
+ void addScrolledContentOffset(int& x, int& y) const;
+ void subtractScrolledContentOffset(int& x, int& y) const;
+ IntSize scrolledContentOffset() const { return IntSize(scrollXOffset() + m_scrollLeftOverflow, scrollYOffset()); }
+
+ int scrollXOffset() const { return m_scrollX + m_scrollOriginX; }
+ int scrollYOffset() const { return m_scrollY; }
+
+ void scrollToOffset(int x, int y, bool updateScrollbars = true, bool repaint = true);
+ void scrollToXOffset(int x) { scrollToOffset(x, m_scrollY); }
+ void scrollToYOffset(int y) { scrollToOffset(m_scrollX + m_scrollOriginX, y); }
+ void scrollRectToVisible(const IntRect&, bool scrollToAnchor = false, const ScrollAlignment& alignX = gAlignCenterIfNeeded, const ScrollAlignment& alignY = gAlignCenterIfNeeded);
+
+ IntRect getRectToExpose(const IntRect& visibleRect, const IntRect& exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY);
+
+ void setHasHorizontalScrollbar(bool);
+ void setHasVerticalScrollbar(bool);
+
+ PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation);
+ void destroyScrollbar(ScrollbarOrientation);
+
+ Scrollbar* horizontalScrollbar() const { return m_hBar.get(); }
+ Scrollbar* verticalScrollbar() const { return m_vBar.get(); }
+
+ int verticalScrollbarWidth() const;
+ int horizontalScrollbarHeight() const;
+
+ void positionOverflowControls(int tx, int ty);
+ bool isPointInResizeControl(const IntPoint& absolutePoint) const;
+ bool hitTestOverflowControls(HitTestResult&);
+ IntSize offsetFromResizeCorner(const IntPoint& absolutePoint) const;
+
+ void paintOverflowControls(GraphicsContext*, int tx, int ty, const IntRect& damageRect);
+ void paintScrollCorner(GraphicsContext*, int tx, int ty, const IntRect& damageRect);
+ void paintResizer(GraphicsContext*, int tx, int ty, const IntRect& damageRect);
+
+ void updateScrollInfoAfterLayout();
+
+ bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f);
+ void autoscroll();
+
+ void resize(const PlatformMouseEvent&, const IntSize&);
+ bool inResizeMode() const { return m_inResizeMode; }
+ void setInResizeMode(bool b) { m_inResizeMode = b; }
+
+ void updateLayerPosition();
+ void updateLayerPositions(bool doFullRepaint = false, bool checkForRepaint = true);
+
+ void updateTransform();
+
+ void relativePositionOffset(int& relX, int& relY) const { relX += m_relX; relY += m_relY; }
+ IntSize relativePositionOffset() const { return IntSize(m_relX, m_relY); }
+
+ void clearClipRectsIncludingDescendants();
+ void clearClipRects();
+
+ // 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(); }
+
+ void dirtyZOrderLists();
+ void dirtyStackingContextZOrderLists();
+ void updateZOrderLists();
+ Vector<RenderLayer*>* posZOrderList() const { return m_posZOrderList; }
+ Vector<RenderLayer*>* negZOrderList() const { return m_negZOrderList; }
+
+ void dirtyOverflowList();
+ void updateOverflowList();
+ Vector<RenderLayer*>* overflowList() const { return m_overflowList; }
+
+ bool hasVisibleContent() const { return m_hasVisibleContent; }
+ void setHasVisibleContent(bool);
+ void dirtyVisibleContentStatus();
+
+ // Gets the nearest enclosing positioned ancestor layer (also includes
+ // the <html> layer and the root layer).
+ RenderLayer* enclosingPositionedAncestor() const;
+
+ void convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const;
+
+ bool hasAutoZIndex() const { return renderer()->style()->hasAutoZIndex(); }
+ int zIndex() const { return renderer()->style()->zIndex(); }
+
+ // The two main functions that use the layer system. The paint method
+ // 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);
+ bool hitTest(const HitTestRequest&, HitTestResult&);
+
+ // This method figures out our layerBounds in coordinates relative to
+ // |rootLayer}. It also computes our background and foreground clip rects
+ // for painting/event handling.
+ void calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds,
+ IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects = false) const;
+
+ // Compute and cache clip rects computed with the given layer as the root
+ void updateClipRects(const RenderLayer* rootLayer);
+ // Compute and return the clip rects. If useCached is true, will used previously computed clip rects on ancestors
+ // (rather than computing them all from scratch up the parent chain).
+ void calculateClipRects(const RenderLayer* rootLayer, ClipRects&, bool useCached = false) const;
+ ClipRects* clipRects() const { return m_clipRects; }
+
+ IntRect childrenClipRect() const; // Returns the foreground clip rect of the layer in the document's coordinate space.
+ IntRect selfClipRect() const; // Returns the background clip rect of the layer in the document's coordinate space.
+
+ bool intersectsDamageRect(const IntRect& layerBounds, const IntRect& damageRect, const RenderLayer* rootLayer) const;
+
+ // Returns a bounding box for this layer only.
+ IntRect boundingBox(const RenderLayer* rootLayer) const;
+
+ void updateHoverActiveState(const HitTestRequest&, HitTestResult&);
+
+ IntRect repaintRect() const { return m_repaintRect; }
+ void setNeedsFullRepaint(bool f = true) { m_needsFullRepaint = f; }
+
+ int staticX() const { return m_staticX; }
+ int staticY() const { return m_staticY; }
+ void setStaticX(int staticX) { m_staticX = staticX; }
+ void setStaticY(int staticY) { m_staticY = staticY; }
+
+ bool hasTransform() const { return m_object->hasTransform(); }
+ TransformationMatrix* transform() const { return m_transform.get(); }
+
+ void destroy(RenderArena*);
+
+ // Overloaded new operator. Derived classes must override operator new
+ // in order to allocate out of the RenderArena.
+ void* operator new(size_t, RenderArena*) throw();
+
+ // Overridden to prevent the normal delete from being called.
+ void operator delete(void*, size_t);
+
+private:
+ // The normal operator new is disallowed on all render objects.
+ void* operator new(size_t) throw();
+
+private:
+ void setNextSibling(RenderLayer* next) { m_next = next; }
+ void setPreviousSibling(RenderLayer* prev) { m_previous = prev; }
+ void setParent(RenderLayer* parent) { m_parent = parent; }
+ void setFirstChild(RenderLayer* first) { m_first = first; }
+ void setLastChild(RenderLayer* last) { m_last = last; }
+
+ void collectLayers(Vector<RenderLayer*>*&, Vector<RenderLayer*>*&);
+
+ void paintLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect,
+ bool haveTransparency, PaintRestriction, RenderObject* paintingRoot,
+ bool appliedTransform = false, bool temporaryClipRects = false);
+ RenderLayer* hitTestLayer(RenderLayer* rootLayer, const HitTestRequest&, HitTestResult&, const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform = false);
+ void computeScrollDimensions(bool* needHBar = 0, bool* needVBar = 0);
+
+ bool shouldBeOverflowOnly() const;
+
+ virtual void valueChanged(Scrollbar*);
+ virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&);
+ virtual bool isActive() const;
+ virtual bool scrollbarCornerPresent() const;
+
+ void updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow);
+
+ void childVisibilityChanged(bool newVisibility);
+ void dirtyVisibleDescendantStatus();
+ void updateVisibilityStatus();
+
+ Node* enclosingElement() const;
+
+ void createReflection();
+ void updateReflectionStyle();
+ bool paintingInsideReflection() const { return m_paintingInsideReflection; }
+
+ RenderLayer* enclosingTransformedAncestor() const;
+
+ // Convert a point in absolute coords into layer coords, taking transforms into account
+ IntPoint absoluteToContents(const IntPoint&) const;
+
+ void updateScrollCornerStyle();
+ void updateResizerStyle();
+
+protected:
+ RenderObject* m_object;
+
+ RenderLayer* m_parent;
+ RenderLayer* m_previous;
+ RenderLayer* m_next;
+ RenderLayer* m_first;
+ RenderLayer* m_last;
+
+ IntRect m_repaintRect; // Cached repaint rects. Used by layout.
+ IntRect m_outlineBox;
+
+ // Our current relative position offset.
+ int m_relX;
+ int m_relY;
+
+ // Our (x,y) coordinates are in our parent layer's coordinate space.
+ int m_x;
+ int m_y;
+
+ // The layer's width/height
+ int m_width;
+ int m_height;
+
+ // Our scroll offsets if the view is scrolled.
+ int m_scrollX;
+ int m_scrollY;
+ int m_scrollOriginX; // only non-zero for rtl content
+ int m_scrollLeftOverflow; // only non-zero for rtl content
+
+ // The width/height of our scrolled area.
+ int m_scrollWidth;
+ int m_scrollHeight;
+
+ // For layers with overflow, we have a pair of scrollbars.
+ RefPtr<Scrollbar> m_hBar;
+ RefPtr<Scrollbar> m_vBar;
+
+ // Keeps track of whether the layer is currently resizing, so events can cause resizing to start and stop.
+ bool m_inResizeMode;
+
+ // For layers that establish stacking contexts, m_posZOrderList holds a sorted list of all the
+ // descendant layers within the stacking context that have z-indices of 0 or greater
+ // (auto will count as 0). m_negZOrderList holds descendants within our stacking context with negative
+ // z-indices.
+ Vector<RenderLayer*>* m_posZOrderList;
+ Vector<RenderLayer*>* m_negZOrderList;
+
+ // This list contains child layers that cannot create stacking contexts. For now it is just
+ // overflow layers, but that may change in the future.
+ Vector<RenderLayer*>* m_overflowList;
+
+ ClipRects* m_clipRects; // Cached clip rects used when painting and hit testing.
+#ifndef NDEBUG
+ const RenderLayer* m_clipRectsRoot; // Root layer used to compute clip rects.
+#endif
+
+ bool m_scrollDimensionsDirty : 1;
+ bool m_zOrderListsDirty : 1;
+ bool m_overflowListDirty: 1;
+ bool m_isOverflowOnly : 1;
+
+ bool m_usedTransparency : 1; // Tracks whether we need to close a transparent layer, i.e., whether
+ // we ended up painting this layer or any descendants (and therefore need to
+ // blend).
+ bool m_paintingInsideReflection : 1; // A state bit tracking if we are painting inside a replica.
+ bool m_inOverflowRelayout : 1;
+ bool m_needsFullRepaint : 1;
+
+ bool m_overflowStatusDirty : 1;
+ bool m_horizontalOverflow : 1;
+ bool m_verticalOverflow : 1;
+ bool m_visibleContentStatusDirty : 1;
+ bool m_hasVisibleContent : 1;
+ bool m_visibleDescendantStatusDirty : 1;
+ bool m_hasVisibleDescendant : 1;
+
+ RenderMarquee* m_marquee; // Used by layers with overflow:marquee
+
+ // Cached normal flow values for absolute positioned elements with static left/top values.
+ int m_staticX;
+ int m_staticY;
+
+ OwnPtr<TransformationMatrix> m_transform;
+
+ // May ultimately be extended to many replicas (with their own paint order).
+ RenderReplica* m_reflection;
+
+ // Renderers to hold our custom scroll corner and resizer.
+ RenderScrollbarPart* m_scrollCorner;
+ RenderScrollbarPart* m_resizer;
+};
+
+} // namespace WebCore
+
+#endif // RenderLayer_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLegend.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderLegend.cpp
new file mode 100644
index 0000000..1fac53f
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderLegend.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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)
+ * Copyright (C) 2004, 2005, 2006 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
+ * 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 "RenderLegend.h"
+
+namespace WebCore {
+
+RenderLegend::RenderLegend(Node* element)
+ : RenderBlock(element)
+{
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderLegend.h b/src/3rdparty/webkit/WebCore/rendering/RenderLegend.h
new file mode 100644
index 0000000..649f132
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderLegend.h
@@ -0,0 +1,42 @@
+/*
+ * 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)
+ * Copyright (C) 2004, 2006 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
+ * 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 RenderLegend_h
+#define RenderLegend_h
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+ class RenderLegend : public RenderBlock {
+ public:
+ RenderLegend(Node*);
+
+ virtual const char* renderName() const { return "RenderLegend"; }
+ };
+
+} // namespace WebCore
+
+#endif // RenderLegend_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp
new file mode 100644
index 0000000..35b9451
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderListBox.cpp
@@ -0,0 +1,649 @@
+/*
+ * This file is part of the select element renderer in WebCore.
+ *
+ * Copyright (C) 2006, 2007, 2008 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RenderListBox.h"
+
+#include "AXObjectCache.h"
+#include "CSSStyleSelector.h"
+#include "Document.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLOptGroupElement.h"
+#include "HTMLOptionElement.h"
+#include "HTMLSelectElement.h"
+#include "HitTestResult.h"
+#include "Page.h"
+#include "RenderScrollbar.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "Scrollbar.h"
+#include "SelectionController.h"
+#include "NodeRenderStyle.h"
+#include <math.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+const int rowSpacing = 1;
+
+const int optionsSpacingHorizontal = 2;
+
+const int minSize = 4;
+const int maxDefaultSize = 10;
+
+// FIXME: This hardcoded baselineAdjustment is what we used to do for the old
+// widget, but I'm not sure this is right for the new control.
+const int baselineAdjustment = 7;
+
+RenderListBox::RenderListBox(HTMLSelectElement* element)
+ : RenderBlock(element)
+ , m_optionsChanged(true)
+ , m_scrollToRevealSelectionAfterLayout(false)
+ , m_inAutoscroll(false)
+ , m_optionsWidth(0)
+ , m_indexOffset(0)
+{
+}
+
+RenderListBox::~RenderListBox()
+{
+ setHasVerticalScrollbar(false);
+}
+
+void RenderListBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+ setReplaced(isInline());
+}
+
+void RenderListBox::updateFromElement()
+{
+ if (m_optionsChanged) {
+ const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(node())->listItems();
+ int size = numItems();
+
+ float width = 0;
+ for (int i = 0; i < size; ++i) {
+ HTMLElement* element = listItems[i];
+ String text;
+ Font itemFont = style()->font();
+ if (element->hasTagName(optionTag))
+ text = static_cast<HTMLOptionElement*>(element)->optionText();
+ else if (element->hasTagName(optgroupTag)) {
+ text = static_cast<HTMLOptGroupElement*>(element)->groupLabelText();
+ FontDescription d = itemFont.fontDescription();
+ d.setWeight(d.bolderWeight());
+ itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
+ itemFont.update(document()->styleSelector()->fontSelector());
+ }
+
+ if (!text.isEmpty()) {
+ float textWidth = itemFont.floatWidth(TextRun(text.impl(), 0, 0, 0, false, false, false, false));
+ width = max(width, textWidth);
+ }
+ }
+ m_optionsWidth = static_cast<int>(ceilf(width));
+ m_optionsChanged = false;
+
+ setHasVerticalScrollbar(true);
+
+ setNeedsLayoutAndPrefWidthsRecalc();
+ }
+}
+
+void RenderListBox::selectionChanged()
+{
+ repaint();
+ if (!m_inAutoscroll) {
+ if (m_optionsChanged || needsLayout())
+ m_scrollToRevealSelectionAfterLayout = true;
+ else
+ scrollToRevealSelection();
+ }
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->selectedChildrenChanged(this);
+}
+
+void RenderListBox::layout()
+{
+ RenderBlock::layout();
+ if (m_scrollToRevealSelectionAfterLayout)
+ scrollToRevealSelection();
+}
+
+void RenderListBox::scrollToRevealSelection()
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+
+ m_scrollToRevealSelectionAfterLayout = false;
+
+ int firstIndex = select->activeSelectionStartListIndex();
+ if (firstIndex >= 0 && !listIndexIsVisible(select->activeSelectionEndListIndex()))
+ scrollToRevealElementAtListIndex(firstIndex);
+}
+
+void RenderListBox::calcPrefWidths()
+{
+ ASSERT(!m_optionsChanged);
+
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = 0;
+
+ if (style()->width().isFixed() && style()->width().value() > 0)
+ m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
+ else {
+ m_maxPrefWidth = m_optionsWidth + 2 * optionsSpacingHorizontal;
+ if (m_vBar)
+ m_maxPrefWidth += m_vBar->width();
+ }
+
+ if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
+ m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
+ m_minPrefWidth = 0;
+ else
+ m_minPrefWidth = m_maxPrefWidth;
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
+ m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ }
+
+ int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+ m_minPrefWidth += toAdd;
+ m_maxPrefWidth += toAdd;
+
+ setPrefWidthsDirty(false);
+}
+
+int RenderListBox::size() const
+{
+ int specifiedSize = static_cast<HTMLSelectElement*>(node())->size();
+ if (specifiedSize > 1)
+ return max(minSize, specifiedSize);
+ return min(max(minSize, numItems()), maxDefaultSize);
+}
+
+int RenderListBox::numVisibleItems() const
+{
+ // Only count fully visible rows. But don't return 0 even if only part of a row shows.
+ return max(1, (contentHeight() + rowSpacing) / itemHeight());
+}
+
+int RenderListBox::numItems() const
+{
+ return static_cast<HTMLSelectElement*>(node())->listItems().size();
+}
+
+int RenderListBox::listHeight() const
+{
+ return itemHeight() * numItems() - rowSpacing;
+}
+
+void RenderListBox::calcHeight()
+{
+ int toAdd = paddingTop() + paddingBottom() + borderTop() + borderBottom();
+
+ int itemHeight = RenderListBox::itemHeight();
+ m_height = itemHeight * size() - rowSpacing + toAdd;
+
+ RenderBlock::calcHeight();
+
+ if (m_vBar) {
+ bool enabled = numVisibleItems() < numItems();
+ m_vBar->setEnabled(enabled);
+ m_vBar->setSteps(1, min(1, numVisibleItems() - 1), itemHeight);
+ m_vBar->setProportion(numVisibleItems(), numItems());
+ if (!enabled)
+ m_indexOffset = 0;
+ }
+}
+
+int RenderListBox::baselinePosition(bool, bool) const
+{
+ return height() + marginTop() + marginBottom() - baselineAdjustment;
+}
+
+IntRect RenderListBox::itemBoundingBoxRect(int tx, int ty, int index)
+{
+ return IntRect(tx + borderLeft() + paddingLeft(),
+ ty + borderTop() + paddingTop() + itemHeight() * (index - m_indexOffset),
+ contentWidth(), itemHeight());
+}
+
+void RenderListBox::paintObject(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (style()->visibility() != VISIBLE)
+ return;
+
+ int listItemsSize = numItems();
+
+ if (paintInfo.phase == PaintPhaseForeground) {
+ int index = m_indexOffset;
+ while (index < listItemsSize && index <= m_indexOffset + numVisibleItems()) {
+ paintItemForeground(paintInfo, tx, ty, index);
+ index++;
+ }
+ }
+
+ // Paint the children.
+ RenderBlock::paintObject(paintInfo, tx, ty);
+
+ if (paintInfo.phase == PaintPhaseBlockBackground)
+ paintScrollbar(paintInfo, tx, ty);
+ else if (paintInfo.phase == PaintPhaseChildBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) {
+ int index = m_indexOffset;
+ while (index < listItemsSize && index <= m_indexOffset + numVisibleItems()) {
+ paintItemBackground(paintInfo, tx, ty, index);
+ index++;
+ }
+ }
+}
+
+void RenderListBox::paintScrollbar(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (m_vBar) {
+ IntRect scrollRect(tx + width() - borderRight() - m_vBar->width(),
+ ty + borderTop(),
+ m_vBar->width(),
+ height() - (borderTop() + borderBottom()));
+ m_vBar->setFrameRect(scrollRect);
+ m_vBar->paint(paintInfo.context, paintInfo.rect);
+ }
+}
+
+void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, int listIndex)
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ const Vector<HTMLElement*>& listItems = select->listItems();
+ HTMLElement* element = listItems[listIndex];
+
+ String itemText;
+ if (element->hasTagName(optionTag))
+ itemText = static_cast<HTMLOptionElement*>(element)->optionText();
+ else if (element->hasTagName(optgroupTag))
+ itemText = static_cast<HTMLOptGroupElement*>(element)->groupLabelText();
+
+ // Determine where the item text should be placed
+ IntRect r = itemBoundingBoxRect(tx, ty, listIndex);
+ r.move(optionsSpacingHorizontal, style()->font().ascent());
+
+ RenderStyle* itemStyle = element->renderStyle();
+ if (!itemStyle)
+ itemStyle = style();
+
+ Color textColor = element->renderStyle() ? element->renderStyle()->color() : style()->color();
+ if (element->hasTagName(optionTag) && static_cast<HTMLOptionElement*>(element)->selected()) {
+ if (document()->frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node())
+ textColor = theme()->activeListBoxSelectionForegroundColor();
+ // Honor the foreground color for disabled items
+ else if (!element->disabled())
+ textColor = theme()->inactiveListBoxSelectionForegroundColor();
+ }
+
+ paintInfo.context->setFillColor(textColor);
+
+ Font itemFont = style()->font();
+ if (element->hasTagName(optgroupTag)) {
+ FontDescription d = itemFont.fontDescription();
+ d.setWeight(d.bolderWeight());
+ itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
+ itemFont.update(document()->styleSelector()->fontSelector());
+ }
+ paintInfo.context->setFont(itemFont);
+
+ unsigned length = itemText.length();
+ const UChar* string = itemText.characters();
+ TextRun textRun(string, length, 0, 0, 0, itemStyle->direction() == RTL, itemStyle->unicodeBidi() == Override, false, false);
+
+ // Draw the item text
+ if (itemStyle->visibility() != HIDDEN)
+ paintInfo.context->drawBidiText(textRun, r.location());
+}
+
+void RenderListBox::paintItemBackground(PaintInfo& paintInfo, int tx, int ty, int listIndex)
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ const Vector<HTMLElement*>& listItems = select->listItems();
+ HTMLElement* element = listItems[listIndex];
+
+ Color backColor;
+ if (element->hasTagName(optionTag) && static_cast<HTMLOptionElement*>(element)->selected()) {
+ if (document()->frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node())
+ backColor = theme()->activeListBoxSelectionBackgroundColor();
+ else
+ backColor = theme()->inactiveListBoxSelectionBackgroundColor();
+ } else
+ backColor = element->renderStyle() ? element->renderStyle()->backgroundColor() : style()->backgroundColor();
+
+ // Draw the background for this list box item
+ if (!element->renderStyle() || element->renderStyle()->visibility() != HIDDEN) {
+ IntRect itemRect = itemBoundingBoxRect(tx, ty, listIndex);
+ itemRect.intersect(controlClipRect(tx, ty));
+ paintInfo.context->fillRect(itemRect, backColor);
+ }
+}
+
+bool RenderListBox::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty)
+{
+ if (!m_vBar)
+ return false;
+
+ IntRect vertRect(_tx + width() - borderRight() - m_vBar->width(),
+ _ty + borderTop() - borderTopExtra(),
+ m_vBar->width(),
+ height() + borderTopExtra() + borderBottomExtra() - borderTop() - borderBottom());
+
+ if (vertRect.contains(_x, _y)) {
+ result.setScrollbar(m_vBar.get());
+ return true;
+ }
+ return false;
+}
+
+int RenderListBox::listIndexAtOffset(int offsetX, int offsetY)
+{
+ if (!numItems())
+ return -1;
+
+ if (offsetY < borderTop() + paddingTop() || offsetY > height() - paddingBottom() - borderBottom())
+ return -1;
+
+ int scrollbarWidth = m_vBar ? m_vBar->width() : 0;
+ if (offsetX < borderLeft() + paddingLeft() || offsetX > width() - borderRight() - paddingRight() - scrollbarWidth)
+ return -1;
+
+ int newOffset = (offsetY - borderTop() - paddingTop()) / itemHeight() + m_indexOffset;
+ return newOffset < numItems() ? newOffset : -1;
+}
+
+void RenderListBox::panScroll(const IntPoint& panStartMousePosition)
+{
+ const int maxSpeed = 20;
+ const int iconRadius = 7;
+ const int speedReducer = 4;
+
+ // FIXME: This doesn't work correctly with transforms.
+ FloatPoint absOffset = localToAbsolute();
+
+ IntPoint currentMousePosition = document()->frame()->eventHandler()->currentMousePosition();
+ // We need to check if the current mouse position is out of the window. When the mouse is out of the window, the position is incoherent
+ static IntPoint previousMousePosition;
+ if (currentMousePosition.y() < 0)
+ currentMousePosition = previousMousePosition;
+ else
+ previousMousePosition = currentMousePosition;
+
+ int yDelta = currentMousePosition.y() - panStartMousePosition.y();
+
+ // If the point is too far from the center we limit the speed
+ yDelta = max(min(yDelta, maxSpeed), -maxSpeed);
+
+ if(abs(yDelta) < iconRadius) // at the center we let the space for the icon
+ return;
+
+ if (yDelta > 0)
+ //offsetY = view()->viewHeight();
+ absOffset.move(0, listHeight());
+ else if (yDelta < 0)
+ yDelta--;
+
+ // Let's attenuate the speed
+ yDelta /= speedReducer;
+
+ IntPoint scrollPoint(0,0);
+ scrollPoint.setY(absOffset.y() + yDelta);
+ int newOffset = scrollToward(scrollPoint);
+ if (newOffset < 0)
+ return;
+
+ m_inAutoscroll = true;
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ select->updateListBoxSelection(!select->multiple());
+ m_inAutoscroll = false;
+}
+
+int RenderListBox::scrollToward(const IntPoint& destination)
+{
+ // FIXME: This doesn't work correctly with transforms.
+ FloatPoint absPos = localToAbsolute();
+ int offsetX = destination.x() - absPos.x();
+ int offsetY = destination.y() - absPos.y();
+
+ int rows = numVisibleItems();
+ int offset = m_indexOffset;
+
+ if (offsetY < borderTop() + paddingTop() && scrollToRevealElementAtListIndex(offset - 1))
+ return offset - 1;
+
+ if (offsetY > height() - paddingBottom() - borderBottom() && scrollToRevealElementAtListIndex(offset + rows))
+ return offset + rows - 1;
+
+ return listIndexAtOffset(offsetX, offsetY);
+}
+
+void RenderListBox::autoscroll()
+{
+ IntPoint pos = document()->frame()->view()->windowToContents(document()->frame()->eventHandler()->currentMousePosition());
+
+ int endIndex = scrollToward(pos);
+ if (endIndex >= 0) {
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ m_inAutoscroll = true;
+
+ if (!select->multiple())
+ select->setActiveSelectionAnchorIndex(endIndex);
+
+ select->setActiveSelectionEndIndex(endIndex);
+ select->updateListBoxSelection(!select->multiple());
+ m_inAutoscroll = false;
+ }
+}
+
+void RenderListBox::stopAutoscroll()
+{
+ static_cast<HTMLSelectElement*>(node())->listBoxOnChange();
+}
+
+bool RenderListBox::scrollToRevealElementAtListIndex(int index)
+{
+ if (index < 0 || index >= numItems() || listIndexIsVisible(index))
+ return false;
+
+ int newOffset;
+ if (index < m_indexOffset)
+ newOffset = index;
+ else
+ newOffset = index - numVisibleItems() + 1;
+
+ m_indexOffset = newOffset;
+ if (m_vBar)
+ m_vBar->setValue(m_indexOffset);
+
+ return true;
+}
+
+bool RenderListBox::listIndexIsVisible(int index)
+{
+ return index >= m_indexOffset && index < m_indexOffset + numVisibleItems();
+}
+
+bool RenderListBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
+{
+ return m_vBar && m_vBar->scroll(direction, granularity, multiplier);
+}
+
+void RenderListBox::valueChanged(unsigned listIndex)
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ select->setSelectedIndex(select->listToOptionIndex(listIndex));
+ select->onChange();
+}
+
+void RenderListBox::valueChanged(Scrollbar*)
+{
+ int newOffset = m_vBar->value();
+ if (newOffset != m_indexOffset) {
+ m_indexOffset = newOffset;
+ repaint();
+ // Fire the scroll DOM event.
+ EventTargetNodeCast(node())->dispatchEventForType(eventNames().scrollEvent, false, false);
+ }
+}
+
+int RenderListBox::itemHeight() const
+{
+ return style()->font().height() + rowSpacing;
+}
+
+int RenderListBox::verticalScrollbarWidth() const
+{
+ return m_vBar ? m_vBar->width() : 0;
+}
+
+// FIXME: We ignore padding in the vertical direction as far as these values are concerned, since that's
+// how the control currently paints.
+int RenderListBox::scrollWidth() const
+{
+ // There is no horizontal scrolling allowed.
+ return clientWidth();
+}
+
+int RenderListBox::scrollHeight() const
+{
+ return max(clientHeight(), listHeight());
+}
+
+int RenderListBox::scrollLeft() const
+{
+ return 0;
+}
+
+void RenderListBox::setScrollLeft(int)
+{
+}
+
+int RenderListBox::scrollTop() const
+{
+ return m_indexOffset * itemHeight();
+}
+
+void RenderListBox::setScrollTop(int newTop)
+{
+ // Determine an index and scroll to it.
+ int index = newTop / itemHeight();
+ if (index < 0 || index >= numItems() || index == m_indexOffset)
+ return;
+ m_indexOffset = index;
+ if (m_vBar)
+ m_vBar->setValue(index);
+}
+
+IntRect RenderListBox::controlClipRect(int tx, int ty) const
+{
+ IntRect clipRect = contentBox();
+ clipRect.move(tx, ty);
+ return clipRect;
+}
+
+bool RenderListBox::isActive() const
+{
+ Page* page = document()->frame()->page();
+ return page && page->focusController()->isActive();
+}
+
+void RenderListBox::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
+{
+ IntRect scrollRect = rect;
+ scrollRect.move(width() - borderRight() - scrollbar->width(), borderTop());
+ repaintRectangle(scrollRect);
+}
+
+bool RenderListBox::isScrollable() const
+{
+ if (numVisibleItems() < numItems())
+ return true;
+ return RenderObject::isScrollable();
+}
+
+PassRefPtr<Scrollbar> RenderListBox::createScrollbar()
+{
+ RefPtr<Scrollbar> widget;
+ bool hasCustomScrollbarStyle = style()->hasPseudoStyle(RenderStyle::SCROLLBAR);
+ if (hasCustomScrollbarStyle)
+ widget = RenderScrollbar::createCustomScrollbar(this, VerticalScrollbar, this);
+ else
+ widget = Scrollbar::createNativeScrollbar(this, VerticalScrollbar, SmallScrollbar);
+ document()->view()->addChild(widget.get());
+ return widget.release();
+}
+
+void RenderListBox::destroyScrollbar()
+{
+ if (!m_vBar)
+ return;
+
+ m_vBar->removeFromParent();
+ m_vBar->setClient(0);
+ m_vBar = 0;
+}
+
+void RenderListBox::setHasVerticalScrollbar(bool hasScrollbar)
+{
+ if (hasScrollbar == (m_vBar != 0))
+ return;
+
+ if (hasScrollbar)
+ m_vBar = createScrollbar();
+ else
+ destroyScrollbar();
+
+ if (m_vBar)
+ m_vBar->styleChanged();
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ // Force an update since we know the scrollbars have changed things.
+ if (document()->hasDashboardRegions())
+ document()->setDashboardRegionsDirty(true);
+#endif
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListBox.h b/src/3rdparty/webkit/WebCore/rendering/RenderListBox.h
new file mode 100644
index 0000000..ccc6847
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderListBox.h
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the select element renderer in WebCore.
+ *
+ * Copyright (C) 2006, 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderListBox_h
+#define RenderListBox_h
+
+#include "RenderBlock.h"
+#include "ScrollbarClient.h"
+
+namespace WebCore {
+
+class HTMLSelectElement;
+
+class RenderListBox : public RenderBlock, private ScrollbarClient {
+public:
+ RenderListBox(HTMLSelectElement*);
+ ~RenderListBox();
+
+ virtual const char* renderName() const { return "RenderListBox"; }
+
+ virtual bool isListBox() const { return true; }
+
+ virtual void updateFromElement();
+
+ virtual bool canHaveChildren() const { return false; }
+
+ virtual bool hasControlClip() const { return true; }
+ virtual void paintObject(PaintInfo&, int tx, int ty);
+ virtual IntRect controlClipRect(int tx, int ty) const;
+
+ virtual bool isPointInOverflowControl(HitTestResult&, int x, int y, int tx, int ty);
+
+ virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f);
+ virtual bool isScrollable() const;
+
+ virtual void calcPrefWidths();
+ virtual int baselinePosition(bool firstLine, bool isRootLineBox) const;
+ virtual void calcHeight();
+
+ virtual void layout();
+
+ void selectionChanged();
+
+ void setOptionsChanged(bool changed) { m_optionsChanged = changed; }
+
+ int listIndexAtOffset(int x, int y);
+ IntRect itemBoundingBoxRect(int tx, int ty, int index);
+
+ bool scrollToRevealElementAtListIndex(int index);
+ bool listIndexIsVisible(int index);
+
+ virtual bool canBeProgramaticallyScrolled(bool) const { return true; }
+ virtual void autoscroll();
+ virtual void stopAutoscroll();
+
+ virtual bool shouldPanScroll() const { return true; }
+ virtual void panScroll(const IntPoint&);
+
+ int scrollToward(const IntPoint&); // Returns the new index or -1 if no scroll occurred
+
+ virtual int verticalScrollbarWidth() const;
+ virtual int scrollLeft() const;
+ virtual int scrollTop() const;
+ virtual int scrollWidth() const;
+ virtual int scrollHeight() const;
+ virtual void setScrollLeft(int);
+ virtual void setScrollTop(int);
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+private:
+ // ScrollbarClient interface.
+ virtual void valueChanged(Scrollbar*);
+ virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&);
+ virtual bool isActive() const;
+ virtual bool scrollbarCornerPresent() const { return false; } // We don't support resize on list boxes yet. If we did this would have to change.
+
+ void setHasVerticalScrollbar(bool hasScrollbar);
+ PassRefPtr<Scrollbar> createScrollbar();
+ void destroyScrollbar();
+
+ int itemHeight() const;
+ void valueChanged(unsigned listIndex);
+ int size() const;
+ int numVisibleItems() const;
+ int numItems() const;
+ int listHeight() const;
+ void paintScrollbar(PaintInfo&, int tx, int ty);
+ void paintItemForeground(PaintInfo&, int tx, int ty, int listIndex);
+ void paintItemBackground(PaintInfo&, int tx, int ty, int listIndex);
+ void scrollToRevealSelection();
+
+ bool m_optionsChanged;
+ bool m_scrollToRevealSelectionAfterLayout;
+ bool m_inAutoscroll;
+ int m_optionsWidth;
+ int m_indexOffset;
+
+ RefPtr<Scrollbar> m_vBar;
+};
+
+} // namepace WebCore
+
+#endif // RenderListBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp
new file mode 100644
index 0000000..f88f131
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderListItem.cpp
@@ -0,0 +1,335 @@
+/**
+ * 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) 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 "RenderListItem.h"
+
+#include "CachedImage.h"
+#include "HTMLNames.h"
+#include "HTMLOListElement.h"
+#include "RenderListMarker.h"
+#include "RenderView.h"
+#include <wtf/StdLibExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderListItem::RenderListItem(Node* node)
+ : RenderBlock(node)
+ , m_marker(0)
+ , m_hasExplicitValue(false)
+ , m_isValueUpToDate(false)
+ , m_notInList(false)
+{
+ setInline(false);
+}
+
+void RenderListItem::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+
+ if (style()->listStyleType() != LNONE ||
+ (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.
+ newStyle->inheritFrom(style());
+ if (!m_marker)
+ m_marker = new (renderArena()) RenderListMarker(this);
+ m_marker->setStyle(newStyle.release());
+ } else if (m_marker) {
+ m_marker->destroy();
+ m_marker = 0;
+ }
+}
+
+void RenderListItem::destroy()
+{
+ if (m_marker) {
+ m_marker->destroy();
+ m_marker = 0;
+ }
+ RenderBlock::destroy();
+}
+
+static Node* enclosingList(Node* node)
+{
+ Node* parent = node->parentNode();
+ for (Node* n = parent; n; n = n->parentNode())
+ if (n->hasTagName(ulTag) || n->hasTagName(olTag))
+ 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
+ // numbered as part of the same list.
+ return parent;
+}
+
+static RenderListItem* previousListItem(Node* list, const RenderListItem* item)
+{
+ for (Node* n = item->node()->traversePreviousNode(); n != list; n = n->traversePreviousNode()) {
+ RenderObject* o = n->renderer();
+ if (o && o->isListItem()) {
+ Node* otherList = enclosingList(n);
+ // This item is part of our current list, so it's what we're looking for.
+ if (list == otherList)
+ return static_cast<RenderListItem*>(o);
+ // We found ourself inside another list; lets skip the rest of it.
+ // Use traverseNextNode() 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.
+ if (otherList)
+ n = otherList->traverseNextNode();
+ }
+ }
+ return 0;
+}
+
+inline int RenderListItem::calcValue() const
+{
+ if (m_hasExplicitValue)
+ return m_explicitValue;
+ Node* list = enclosingList(node());
+ // 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))
+ return previousItem->value() + 1;
+ if (list && list->hasTagName(olTag))
+ return static_cast<HTMLOListElement*>(list)->start();
+ return 1;
+}
+
+void RenderListItem::updateValueNow() const
+{
+ m_value = calcValue();
+ m_isValueUpToDate = true;
+}
+
+bool RenderListItem::isEmpty() const
+{
+ return lastChild() == m_marker;
+}
+
+static RenderObject* getParentOfFirstLineBox(RenderBlock* curr, RenderObject* marker)
+{
+ RenderObject* firstChild = curr->firstChild();
+ if (!firstChild)
+ return 0;
+
+ for (RenderObject* currChild = firstChild; currChild; currChild = currChild->nextSibling()) {
+ if (currChild == marker)
+ continue;
+
+ if (currChild->isInline() && (!currChild->isInlineFlow() || curr->generatesLineBoxesForInlineChild(currChild)))
+ return curr;
+
+ if (currChild->isFloating() || currChild->isPositioned())
+ continue;
+
+ if (currChild->isTable() || !currChild->isRenderBlock())
+ break;
+
+ if (curr->isListItem() && currChild->style()->htmlHacks() && currChild->element() &&
+ (currChild->element()->hasTagName(ulTag)|| currChild->element()->hasTagName(olTag)))
+ break;
+
+ RenderObject* lineBox = getParentOfFirstLineBox(static_cast<RenderBlock*>(currChild), marker);
+ if (lineBox)
+ return lineBox;
+ }
+
+ return 0;
+}
+
+void RenderListItem::updateValue()
+{
+ if (!m_hasExplicitValue) {
+ m_isValueUpToDate = false;
+ if (m_marker)
+ m_marker->setNeedsLayoutAndPrefWidthsRecalc();
+ }
+}
+
+static RenderObject* firstNonMarkerChild(RenderObject* parent)
+{
+ RenderObject* result = parent->firstChild();
+ while (result && result->isListMarker())
+ result = result->nextSibling();
+ return result;
+}
+
+void RenderListItem::updateMarkerLocation()
+{
+ // Sanity check the location of our marker.
+ if (m_marker) {
+ RenderObject* markerPar = m_marker->parent();
+ RenderObject* lineBoxParent = getParentOfFirstLineBox(this, m_marker);
+ if (!lineBoxParent) {
+ // If the marker is currently contained inside an anonymous box,
+ // then we are the only item in that anonymous box (since no line box
+ // parent was found). It's ok to just leave the marker where it is
+ // in this case.
+ if (markerPar && markerPar->isAnonymousBlock())
+ lineBoxParent = markerPar;
+ else
+ lineBoxParent = this;
+ }
+
+ if (markerPar != lineBoxParent || m_marker->prefWidthsDirty()) {
+ // Removing and adding the marker can trigger repainting in
+ // containers other than ourselves, so we need to disable LayoutState.
+ view()->disableLayoutState();
+ updateFirstLetter();
+ m_marker->remove();
+ if (!lineBoxParent)
+ lineBoxParent = this;
+ lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent));
+ if (m_marker->prefWidthsDirty())
+ m_marker->calcPrefWidths();
+ view()->enableLayoutState();
+ }
+ }
+}
+
+void RenderListItem::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ updateMarkerLocation();
+
+ RenderBlock::calcPrefWidths();
+}
+
+void RenderListItem::layout()
+{
+ ASSERT(needsLayout());
+
+ updateMarkerLocation();
+ RenderBlock::layout();
+}
+
+void RenderListItem::positionListMarker()
+{
+ if (m_marker && !m_marker->isInside() && m_marker->inlineBoxWrapper()) {
+ int markerOldX = m_marker->xPos();
+ int yOffset = 0;
+ int xOffset = 0;
+ for (RenderObject* o = m_marker->parent(); o != this; o = o->parent()) {
+ yOffset += o->yPos();
+ xOffset += o->xPos();
+ }
+
+ bool adjustOverflow = false;
+ int markerXPos;
+ RootInlineBox* root = m_marker->inlineBoxWrapper()->root();
+
+ if (style()->direction() == LTR) {
+ int leftLineOffset = leftRelOffset(yOffset, leftOffset(yOffset));
+ 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;
+ }
+ } else {
+ int rightLineOffset = rightRelOffset(yOffset, rightOffset(yOffset));
+ 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;
+ }
+ }
+
+ if (adjustOverflow) {
+ IntRect markerRect(markerXPos + xOffset, yOffset, m_marker->width(), m_marker->height());
+ RenderObject* o = m_marker;
+ do {
+ o = o->parent();
+ if (o->isRenderBlock())
+ static_cast<RenderBlock*>(o)->addVisualOverflow(markerRect);
+ markerRect.move(-o->xPos(), -o->yPos());
+ } while (o != this);
+ }
+ }
+}
+
+void RenderListItem::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (!m_height)
+ return;
+
+ RenderBlock::paint(paintInfo, tx, ty);
+}
+
+const String& RenderListItem::markerText() const
+{
+ if (m_marker)
+ return m_marker->text();
+ DEFINE_STATIC_LOCAL(String, staticNullString, ());
+ return staticNullString;
+}
+
+void RenderListItem::explicitValueChanged()
+{
+ if (m_marker)
+ m_marker->setNeedsLayoutAndPrefWidthsRecalc();
+ Node* listNode = enclosingList(node());
+ RenderObject* listRenderer = 0;
+ if (listNode)
+ listRenderer = listNode->renderer();
+ for (RenderObject* r = this; r; r = r->nextInPreOrder(listRenderer))
+ if (r->isListItem()) {
+ RenderListItem* item = static_cast<RenderListItem*>(r);
+ if (!item->m_hasExplicitValue) {
+ item->m_isValueUpToDate = false;
+ if (RenderListMarker* marker = item->m_marker)
+ marker->setNeedsLayoutAndPrefWidthsRecalc();
+ }
+ }
+}
+
+void RenderListItem::setExplicitValue(int value)
+{
+ if (m_hasExplicitValue && m_explicitValue == value)
+ return;
+ m_explicitValue = value;
+ m_value = value;
+ m_hasExplicitValue = true;
+ explicitValueChanged();
+}
+
+void RenderListItem::clearExplicitValue()
+{
+ if (!m_hasExplicitValue)
+ return;
+ m_hasExplicitValue = false;
+ m_isValueUpToDate = false;
+ explicitValueChanged();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListItem.h b/src/3rdparty/webkit/WebCore/rendering/RenderListItem.h
new file mode 100644
index 0000000..d4dd675
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderListItem.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 RenderListItem_h
+#define RenderListItem_h
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class RenderListMarker;
+
+class RenderListItem : public RenderBlock {
+public:
+ RenderListItem(Node*);
+
+ virtual const char* renderName() const { return "RenderListItem"; }
+
+ virtual bool isListItem() const { return true; }
+
+ virtual void destroy();
+
+ int value() const { if (!m_isValueUpToDate) updateValueNow(); return m_value; }
+ void updateValue();
+
+ bool hasExplicitValue() const { return m_hasExplicitValue; }
+ int explicitValue() const { return m_explicitValue; }
+ void setExplicitValue(int value);
+ void clearExplicitValue();
+
+ virtual bool isEmpty() const;
+ virtual void paint(PaintInfo&, int tx, int ty);
+
+ virtual void layout();
+ virtual void calcPrefWidths();
+
+ virtual void positionListMarker();
+
+ void setNotInList(bool notInList) { m_notInList = notInList; }
+ bool notInList() const { return m_notInList; }
+
+ const String& markerText() const;
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+private:
+ void updateMarkerLocation();
+ inline int calcValue() const;
+ void updateValueNow() const;
+ void explicitValueChanged();
+
+ RenderListMarker* m_marker;
+ int m_explicitValue;
+ mutable int m_value;
+
+ bool m_hasExplicitValue : 1;
+ mutable bool m_isValueUpToDate : 1;
+ bool m_notInList : 1;
+};
+
+} // namespace WebCore
+
+#endif // RenderListItem_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp
new file mode 100644
index 0000000..4209906
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.cpp
@@ -0,0 +1,905 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (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)
+ *
+ * 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 "RenderListMarker.h"
+
+#include "CachedImage.h"
+#include "CharacterNames.h"
+#include "Document.h"
+#include "GraphicsContext.h"
+#include "ListMarkerBox.h"
+#include "RenderLayer.h"
+#include "RenderListItem.h"
+#include "RenderView.h"
+
+using namespace std;
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+const int cMarkerPadding = 7;
+
+static String toRoman(int number, bool upper)
+{
+ // FIXME: CSS3 describes how to make this work for much larger numbers,
+ // using overbars and special characters. It also specifies the characters
+ // in the range U+2160 to U+217F instead of standard ASCII ones.
+ if (number < 1 || number > 3999)
+ return String::number(number);
+
+ const int lettersSize = 12; // big enough for three each of I, X, C, and M
+ UChar letters[lettersSize];
+
+ int length = 0;
+ const UChar ldigits[] = { 'i', 'v', 'x', 'l', 'c', 'd', 'm' };
+ const UChar udigits[] = { 'I', 'V', 'X', 'L', 'C', 'D', 'M' };
+ const UChar* digits = upper ? udigits : ldigits;
+ int d = 0;
+ do {
+ int num = number % 10;
+ if (num % 5 < 4)
+ for (int i = num % 5; i > 0; i--)
+ letters[lettersSize - ++length] = digits[d];
+ if (num >= 4 && num <= 8)
+ letters[lettersSize - ++length] = digits[d + 1];
+ if (num == 9)
+ letters[lettersSize - ++length] = digits[d + 2];
+ if (num % 5 == 4)
+ letters[lettersSize - ++length] = digits[d];
+ number /= 10;
+ d += 2;
+ } while (number);
+
+ ASSERT(length <= lettersSize);
+ return String(&letters[lettersSize - length], length);
+}
+
+static String toAlphabetic(int number, const UChar* alphabet, int alphabetSize)
+{
+ ASSERT(alphabetSize >= 10);
+
+ if (number < 1)
+ return String::number(number);
+
+ 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];
+ int length = 1;
+ while ((number /= alphabetSize) > 0)
+ letters[lettersSize - ++length] = alphabet[number % alphabetSize - 1];
+
+ ASSERT(length <= lettersSize);
+ return String(&letters[lettersSize - length], length);
+}
+
+static int toHebrewUnder1000(int number, UChar letters[5])
+{
+ // FIXME: CSS3 mentions various refinements not implemented here.
+ // FIXME: Should take a look at Mozilla's HebrewToText function (in nsBulletFrame).
+ ASSERT(number >= 0 && number < 1000);
+ int length = 0;
+ int fourHundreds = number / 400;
+ for (int i = 0; i < fourHundreds; i++)
+ letters[length++] = 1511 + 3;
+ number %= 400;
+ if (number / 100)
+ letters[length++] = 1511 + (number / 100) - 1;
+ number %= 100;
+ if (number == 15 || number == 16) {
+ letters[length++] = 1487 + 9;
+ letters[length++] = 1487 + number - 9;
+ } else {
+ if (int tens = number / 10) {
+ static const UChar hebrewTens[9] = { 1497, 1499, 1500, 1502, 1504, 1505, 1506, 1508, 1510 };
+ letters[length++] = hebrewTens[tens - 1];
+ }
+ if (int ones = number % 10)
+ letters[length++] = 1487 + ones;
+ }
+ ASSERT(length <= 5);
+ return length;
+}
+
+static String toHebrew(int number)
+{
+ // FIXME: CSS3 mentions ways to make this work for much larger numbers.
+ if (number < 0 || number > 999999)
+ return String::number(number);
+
+ if (number == 0) {
+ static const UChar hebrewZero[3] = { 0x05D0, 0x05E4, 0x05E1 };
+ return String(hebrewZero, 3);
+ }
+
+ const int lettersSize = 11; // big enough for two 5-digit sequences plus a quote mark between
+ UChar letters[lettersSize];
+
+ int length;
+ if (number < 1000)
+ length = 0;
+ else {
+ length = toHebrewUnder1000(number / 1000, letters);
+ letters[length++] = '\'';
+ number = number % 1000;
+ }
+ length += toHebrewUnder1000(number, letters + length);
+
+ ASSERT(length <= lettersSize);
+ return String(letters, length);
+}
+
+static int toArmenianUnder10000(int number, bool upper, bool addCircumflex, UChar letters[9])
+{
+ ASSERT(number >= 0 && number < 10000);
+ int length = 0;
+
+ int lowerOffset = upper ? 0 : 0x0030;
+
+ if (int thousands = number / 1000)
+ if (thousands == 7) {
+ letters[length++] = 0x0548 + lowerOffset;
+ letters[length++] = 0x0552 + lowerOffset;
+ if (addCircumflex)
+ letters[length++] = 0x0302;
+ } else {
+ letters[length++] = (0x054C - 1 + lowerOffset) + thousands;
+ if (addCircumflex)
+ letters[length++] = 0x0302;
+ }
+
+ if (int hundreds = (number / 100) % 10) {
+ letters[length++] = (0x0543 - 1 + lowerOffset) + hundreds;
+ if (addCircumflex)
+ letters[length++] = 0x0302;
+ }
+
+ if (int tens = (number / 10) % 10) {
+ letters[length++] = (0x053A - 1 + lowerOffset) + tens;
+ if (addCircumflex)
+ letters[length++] = 0x0302;
+ }
+
+ if (int ones = number % 10) {
+ letters[length++] = (0x531 - 1 + lowerOffset) + ones;
+ if (addCircumflex)
+ letters[length++] = 0x0302;
+ }
+
+ return length;
+}
+
+static String toArmenian(int number, bool upper)
+{
+ if (number < 1 || number > 99999999)
+ return String::number(number);
+
+ const int lettersSize = 18; // twice what toArmenianUnder10000 needs
+ UChar letters[lettersSize];
+
+ int length = toArmenianUnder10000(number / 10000, upper, true, letters);
+ length += toArmenianUnder10000(number % 10000, upper, false, letters + length);
+
+ ASSERT(length <= lettersSize);
+ return String(letters, length);
+}
+
+static String toGeorgian(int number)
+{
+ if (number < 1 || number > 19999)
+ return String::number(number);
+
+ const int lettersSize = 5;
+ UChar letters[lettersSize];
+
+ int length = 0;
+
+ if (number > 9999)
+ letters[length++] = 0x10F5;
+
+ if (int thousands = (number / 1000) % 10) {
+ static const UChar georgianThousands[9] = {
+ 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10F4, 0x10EF, 0x10F0
+ };
+ letters[length++] = georgianThousands[thousands - 1];
+ }
+
+ if (int hundreds = (number / 100) % 10) {
+ static const UChar georgianHundreds[9] = {
+ 0x10E0, 0x10E1, 0x10E2, 0x10F3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8
+ };
+ letters[length++] = georgianHundreds[hundreds - 1];
+ }
+
+ if (int tens = (number / 10) % 10) {
+ static const UChar georgianTens[9] = {
+ 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10F2, 0x10DD, 0x10DE, 0x10DF
+ };
+ letters[length++] = georgianTens[tens - 1];
+ }
+
+ if (int ones = number % 10) {
+ static const UChar georgianOnes[9] = {
+ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10F1, 0x10D7
+ };
+ letters[length++] = georgianOnes[ones - 1];
+ }
+
+ ASSERT(length <= lettersSize);
+ return String(letters, length);
+}
+
+// The table uses the order from the CSS3 specification:
+// first 3 group markers, then 3 digit markers, then ten digits.
+static String toCJKIdeographic(int number, const UChar table[16])
+{
+ if (number < 0)
+ return String::number(number);
+
+ enum AbstractCJKChar {
+ noChar,
+ secondGroupMarker, thirdGroupMarker, fourthGroupMarker,
+ secondDigitMarker, thirdDigitMarker, fourthDigitMarker,
+ digit0, digit1, digit2, digit3, digit4,
+ digit5, digit6, digit7, digit8, digit9
+ };
+
+ if (number == 0)
+ return String(&table[digit0 - 1], 1);
+
+ const int groupLength = 8; // 4 digits, 3 digit markers, and a group marker
+ const int bufferLength = 4 * groupLength;
+ AbstractCJKChar buffer[bufferLength] = { noChar };
+
+ for (int i = 0; i < 4; ++i) {
+ int groupValue = number % 10000;
+ number /= 10000;
+
+ // Process least-significant group first, but put it in the buffer last.
+ AbstractCJKChar* group = &buffer[(3 - i) * groupLength];
+
+ if (groupValue && i)
+ group[7] = static_cast<AbstractCJKChar>(secondGroupMarker - 1 + i);
+
+ // Put in the four digits and digit markers for any non-zero digits.
+ group[6] = static_cast<AbstractCJKChar>(digit0 + (groupValue % 10));
+ if (number != 0 || groupValue > 9) {
+ int digitValue = ((groupValue / 10) % 10);
+ group[4] = static_cast<AbstractCJKChar>(digit0 + digitValue);
+ if (digitValue)
+ group[5] = secondDigitMarker;
+ }
+ if (number != 0 || groupValue > 99) {
+ int digitValue = ((groupValue / 100) % 10);
+ group[2] = static_cast<AbstractCJKChar>(digit0 + digitValue);
+ if (digitValue)
+ group[3] = thirdDigitMarker;
+ }
+ if (number != 0 || groupValue > 999) {
+ int digitValue = groupValue / 1000;
+ group[0] = static_cast<AbstractCJKChar>(digit0 + digitValue);
+ if (digitValue)
+ group[1] = fourthDigitMarker;
+ }
+
+ // Remove the tens digit, but leave the marker, for any group that has
+ // a value of less than 20.
+ if (groupValue < 20) {
+ ASSERT(group[4] == noChar || group[4] == digit0 || group[4] == digit1);
+ group[4] = noChar;
+ }
+
+ if (number == 0)
+ break;
+ }
+
+ // Convert into characters, omitting consecutive runs of digit0 and
+ // any trailing digit0.
+ int length = 0;
+ UChar characters[bufferLength];
+ AbstractCJKChar last = noChar;
+ for (int i = 0; i < bufferLength; ++i) {
+ AbstractCJKChar a = buffer[i];
+ if (a != noChar) {
+ if (a != digit0 || last != digit0)
+ characters[length++] = table[a - 1];
+ last = a;
+ }
+ }
+ if (last == digit0)
+ --length;
+
+ return String(characters, length);
+}
+
+String listMarkerText(EListStyleType type, int value)
+{
+ switch (type) {
+ case LNONE:
+ return "";
+
+ // We use the same characters for text security.
+ // See RenderText::setInternalString.
+ case CIRCLE:
+ return String(&whiteBullet, 1);
+ case DISC:
+ return String(&bullet, 1);
+ 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:
+ return String::number(value);
+ case DECIMAL_LEADING_ZERO:
+ 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: {
+ 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);
+ }
+ case UPPER_ALPHA:
+ case UPPER_LATIN: {
+ 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);
+ }
+ case LOWER_GREEK: {
+ 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);
+ }
+
+ 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] = {
+ 0x3042, 0x3044, 0x3046, 0x3048, 0x304A, 0x304B, 0x304D, 0x304F,
+ 0x3051, 0x3053, 0x3055, 0x3057, 0x3059, 0x305B, 0x305D, 0x305F,
+ 0x3061, 0x3064, 0x3066, 0x3068, 0x306A, 0x306B, 0x306C, 0x306D,
+ 0x306E, 0x306F, 0x3072, 0x3075, 0x3078, 0x307B, 0x307E, 0x307F,
+ 0x3080, 0x3081, 0x3082, 0x3084, 0x3086, 0x3088, 0x3089, 0x308A,
+ 0x308B, 0x308C, 0x308D, 0x308F, 0x3090, 0x3091, 0x3092, 0x3093
+ };
+ return toAlphabetic(value, hiraganaAlphabet, 48);
+ }
+ case HIRAGANA_IROHA: {
+ // FIXME: This table comes from the CSS3 draft, and is probably
+ // incorrect, given the comments in that draft.
+ static const UChar hiraganaIrohaAlphabet[47] = {
+ 0x3044, 0x308D, 0x306F, 0x306B, 0x307B, 0x3078, 0x3068, 0x3061,
+ 0x308A, 0x306C, 0x308B, 0x3092, 0x308F, 0x304B, 0x3088, 0x305F,
+ 0x308C, 0x305D, 0x3064, 0x306D, 0x306A, 0x3089, 0x3080, 0x3046,
+ 0x3090, 0x306E, 0x304A, 0x304F, 0x3084, 0x307E, 0x3051, 0x3075,
+ 0x3053, 0x3048, 0x3066, 0x3042, 0x3055, 0x304D, 0x3086, 0x3081,
+ 0x307F, 0x3057, 0x3091, 0x3072, 0x3082, 0x305B, 0x3059
+ };
+ return toAlphabetic(value, hiraganaIrohaAlphabet, 47);
+ }
+ 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] = {
+ 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD, 0x30AF,
+ 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, 0x30BF,
+ 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, 0x30CB, 0x30CC, 0x30CD,
+ 0x30CE, 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, 0x30DE, 0x30DF,
+ 0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9, 0x30EA,
+ 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F0, 0x30F1, 0x30F2, 0x30F3
+ };
+ return toAlphabetic(value, katakanaAlphabet, 48);
+ }
+ case KATAKANA_IROHA: {
+ // FIXME: This table comes from the CSS3 draft, and is probably
+ // incorrect, given the comments in that draft.
+ static const UChar katakanaIrohaAlphabet[47] = {
+ 0x30A4, 0x30ED, 0x30CF, 0x30CB, 0x30DB, 0x30D8, 0x30C8, 0x30C1,
+ 0x30EA, 0x30CC, 0x30EB, 0x30F2, 0x30EF, 0x30AB, 0x30E8, 0x30BF,
+ 0x30EC, 0x30BD, 0x30C4, 0x30CD, 0x30CA, 0x30E9, 0x30E0, 0x30A6,
+ 0x30F0, 0x30CE, 0x30AA, 0x30AF, 0x30E4, 0x30DE, 0x30B1, 0x30D5,
+ 0x30B3, 0x30A8, 0x30C6, 0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1,
+ 0x30DF, 0x30B7, 0x30F1, 0x30D2, 0x30E2, 0x30BB, 0x30B9
+ };
+ return toAlphabetic(value, katakanaIrohaAlphabet, 47);
+ }
+
+ case CJK_IDEOGRAPHIC: {
+ static const UChar traditionalChineseInformalTable[16] = {
+ 0x842C, 0x5104, 0x5146,
+ 0x5341, 0x767E, 0x5343,
+ 0x96F6, 0x4E00, 0x4E8C, 0x4E09, 0x56DB,
+ 0x4E94, 0x516D, 0x4E03, 0x516B, 0x4E5D
+ };
+ return toCJKIdeographic(value, traditionalChineseInformalTable);
+ }
+
+ case LOWER_ROMAN:
+ return toRoman(value, false);
+ case UPPER_ROMAN:
+ return toRoman(value, true);
+
+ 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:
+ return toGeorgian(value);
+ case HEBREW:
+ return toHebrew(value);
+ }
+
+ ASSERT_NOT_REACHED();
+ return "";
+}
+
+RenderListMarker::RenderListMarker(RenderListItem* item)
+ : RenderBox(item->document())
+ , m_listItem(item)
+ , m_selectionState(SelectionNone)
+{
+ // init RenderObject attributes
+ setInline(true); // our object is Inline
+ setReplaced(true); // pretend to be replaced
+}
+
+RenderListMarker::~RenderListMarker()
+{
+ if (m_image)
+ m_image->removeClient(this);
+}
+
+void RenderListMarker::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
+{
+ if (style() && (newStyle->listStylePosition() != style()->listStylePosition() || newStyle->listStyleType() != style()->listStyleType()))
+ setNeedsLayoutAndPrefWidthsRecalc();
+
+ RenderBox::styleWillChange(diff, newStyle);
+}
+
+void RenderListMarker::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBox::styleDidChange(diff, oldStyle);
+
+ if (m_image != style()->listStyleImage()) {
+ if (m_image)
+ m_image->removeClient(this);
+ m_image = style()->listStyleImage();
+ if (m_image)
+ m_image->addClient(this);
+ }
+}
+
+InlineBox* RenderListMarker::createInlineBox(bool, bool isRootLineBox, bool)
+{
+ ASSERT(!isRootLineBox);
+ ListMarkerBox* box = new (renderArena()) ListMarkerBox(this);
+ m_inlineBoxWrapper = box;
+ return box;
+}
+
+bool RenderListMarker::isImage() const
+{
+ return m_image && !m_image->errorOccurred();
+}
+
+void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (paintInfo.phase != PaintPhaseForeground)
+ return;
+
+ if (style()->visibility() != VISIBLE)
+ return;
+
+ IntRect marker = getRelativeMarkerRect();
+ marker.move(tx, ty);
+
+ IntRect box(tx + m_x, ty + m_y, m_width, m_height);
+
+ if (box.y() > paintInfo.rect.bottom() || box.y() + box.height() < paintInfo.rect.y())
+ return;
+
+ if (hasBoxDecorations())
+ paintBoxDecorations(paintInfo, box.x(), box.y());
+
+ GraphicsContext* context = paintInfo.context;
+ context->setFont(style()->font());
+
+ if (isImage()) {
+#if PLATFORM(MAC)
+ if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
+ paintCustomHighlight(tx, ty, style()->highlight(), true);
+#endif
+ context->drawImage(m_image->image(this, marker.size()), marker.location());
+ if (selectionState() != SelectionNone)
+ context->fillRect(selectionRect(), selectionBackgroundColor());
+ return;
+ }
+
+#if PLATFORM(MAC)
+ // FIXME: paint gap between marker and list item proper
+ if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
+ paintCustomHighlight(tx, ty, style()->highlight(), true);
+#endif
+
+ if (selectionState() != SelectionNone)
+ context->fillRect(selectionRect(), selectionBackgroundColor());
+
+ const Color color(style()->color());
+ context->setStrokeColor(color);
+ context->setStrokeStyle(SolidStroke);
+ context->setStrokeThickness(1.0f);
+ context->setFillColor(color);
+
+ switch (style()->listStyleType()) {
+ case DISC:
+ context->drawEllipse(marker);
+ return;
+ case CIRCLE:
+ context->setFillColor(Color::transparent);
+ context->drawEllipse(marker);
+ return;
+ case SQUARE:
+ context->drawRect(marker);
+ return;
+ case LNONE:
+ 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:
+ break;
+ }
+ if (m_text.isEmpty())
+ return;
+
+ TextRun textRun(m_text);
+
+ // Text is not arbitrary. We can judge whether it's RTL from the first character,
+ // and we only need to handle the direction RightToLeft for now.
+ bool textNeedsReversing = direction(m_text[0]) == RightToLeft;
+ Vector<UChar> reversedText;
+ if (textNeedsReversing) {
+ int length = m_text.length();
+ reversedText.grow(length);
+ for (int i = 0; i < length; ++i)
+ reversedText[length - i - 1] = m_text[i];
+ textRun = TextRun(reversedText.data(), length);
+ }
+
+ const Font& font = style()->font();
+ if (style()->direction() == LTR) {
+ int width = font.width(textRun);
+ context->drawText(textRun, marker.location());
+ const UChar periodSpace[2] = { '.', ' ' };
+ context->drawText(TextRun(periodSpace, 2), marker.location() + IntSize(width, 0));
+ } else {
+ const UChar spacePeriod[2] = { ' ', '.' };
+ TextRun spacePeriodRun(spacePeriod, 2);
+ int width = font.width(spacePeriodRun);
+ context->drawText(spacePeriodRun, marker.location());
+ context->drawText(textRun, marker.location() + IntSize(width, 0));
+ }
+}
+
+void RenderListMarker::layout()
+{
+ ASSERT(needsLayout());
+ ASSERT(!prefWidthsDirty());
+
+ if (isImage()) {
+ m_width = m_image->imageSize(this, style()->effectiveZoom()).width();
+ m_height = m_image->imageSize(this, style()->effectiveZoom()).height();
+ } else {
+ m_width = minPrefWidth();
+ m_height = style()->font().height();
+ }
+
+ m_marginLeft = m_marginRight = 0;
+
+ Length leftMargin = style()->marginLeft();
+ Length rightMargin = style()->marginRight();
+ if (leftMargin.isFixed())
+ m_marginLeft = leftMargin.value();
+ if (rightMargin.isFixed())
+ m_marginRight = rightMargin.value();
+
+ setNeedsLayout(false);
+}
+
+void RenderListMarker::imageChanged(WrappedImagePtr o, const IntRect*)
+{
+ // A list marker can't have a background or border image, so no need to call the base class method.
+ if (o != m_image->data())
+ return;
+
+ if (m_width != m_image->imageSize(this, style()->effectiveZoom()).width() || m_height != m_image->imageSize(this, style()->effectiveZoom()).height() || m_image->errorOccurred())
+ setNeedsLayoutAndPrefWidthsRecalc();
+ else
+ repaint();
+}
+
+void RenderListMarker::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ m_text = "";
+
+ const Font& font = style()->font();
+
+ if (isImage()) {
+ // FIXME: This is a somewhat arbitrary width. Generated images for markers really won't become particularly useful
+ // until we support the CSS3 marker pseudoclass to allow control over the width and height of the marker box.
+ int bulletWidth = font.ascent() / 2;
+ m_image->setImageContainerSize(IntSize(bulletWidth, bulletWidth));
+ m_minPrefWidth = m_maxPrefWidth = m_image->imageSize(this, style()->effectiveZoom()).width();
+ setPrefWidthsDirty(false);
+ updateMargins();
+ return;
+ }
+
+ int width = 0;
+ EListStyleType type = style()->listStyleType();
+ switch (type) {
+ case LNONE:
+ break;
+ 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:
+ 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;
+ }
+ break;
+ }
+
+ m_minPrefWidth = width;
+ m_maxPrefWidth = width;
+
+ setPrefWidthsDirty(false);
+
+ updateMargins();
+}
+
+void RenderListMarker::updateMargins()
+{
+ const Font& font = style()->font();
+
+ int marginLeft = 0;
+ int marginRight = 0;
+
+ if (isInside()) {
+ if (isImage()) {
+ if (style()->direction() == LTR)
+ marginRight = cMarkerPadding;
+ else
+ marginLeft = cMarkerPadding;
+ } else switch (style()->listStyleType()) {
+ case DISC:
+ case CIRCLE:
+ case SQUARE:
+ if (style()->direction() == LTR) {
+ marginLeft = -1;
+ marginRight = font.ascent() - minPrefWidth() + 1;
+ } else {
+ marginLeft = font.ascent() - minPrefWidth() + 1;
+ marginRight = -1;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (style()->direction() == LTR) {
+ if (isImage())
+ marginLeft = -minPrefWidth() - cMarkerPadding;
+ else {
+ int offset = font.ascent() * 2 / 3;
+ switch (style()->listStyleType()) {
+ case DISC:
+ case CIRCLE:
+ case SQUARE:
+ marginLeft = -offset - cMarkerPadding - 1;
+ break;
+ case LNONE:
+ break;
+ default:
+ marginLeft = m_text.isEmpty() ? 0 : -minPrefWidth() - offset / 2;
+ }
+ }
+ } else {
+ if (isImage())
+ marginLeft = cMarkerPadding;
+ else {
+ int offset = font.ascent() * 2 / 3;
+ switch (style()->listStyleType()) {
+ case DISC:
+ case CIRCLE:
+ case SQUARE:
+ marginLeft = offset + cMarkerPadding + 1 - minPrefWidth();
+ break;
+ case LNONE:
+ break;
+ default:
+ marginLeft = m_text.isEmpty() ? 0 : offset / 2;
+ }
+ }
+ }
+ marginRight = -marginLeft - minPrefWidth();
+ }
+
+ style()->setMarginLeft(Length(marginLeft, Fixed));
+ style()->setMarginRight(Length(marginRight, Fixed));
+}
+
+int RenderListMarker::lineHeight(bool, bool) const
+{
+ if (!isImage())
+ return m_listItem->lineHeight(false, true);
+ return height();
+}
+
+int RenderListMarker::baselinePosition(bool, bool) const
+{
+ if (!isImage()) {
+ const Font& font = style()->font();
+ return font.ascent() + (lineHeight(false) - font.height())/2;
+ }
+ return height();
+}
+
+bool RenderListMarker::isInside() const
+{
+ return m_listItem->notInList() || style()->listStylePosition() == INSIDE;
+}
+
+IntRect RenderListMarker::getRelativeMarkerRect()
+{
+ if (isImage())
+ return IntRect(m_x, m_y, m_image->imageSize(this, style()->effectiveZoom()).width(), m_image->imageSize(this, style()->effectiveZoom()).height());
+
+ switch (style()->listStyleType()) {
+ 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(m_x + 1, m_y + 3 * (ascent - ascent * 2 / 3) / 2, bulletWidth, bulletWidth);
+ }
+ case LNONE:
+ 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:
+ 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(m_x, m_y + font.ascent(), itemWidth + periodSpaceWidth, font.height());
+ }
+
+ return IntRect();
+}
+
+void RenderListMarker::setSelectionState(SelectionState state)
+{
+ m_selectionState = state;
+ if (InlineBox* box = inlineBoxWrapper())
+ if (RootInlineBox* root = box->root())
+ root->setHasSelectedChildren(state != SelectionNone);
+ containingBlock()->setSelectionState(state);
+}
+
+IntRect RenderListMarker::selectionRect(bool clipToVisibleContent)
+{
+ ASSERT(!needsLayout());
+
+ if (selectionState() == SelectionNone || !inlineBoxWrapper())
+ return IntRect();
+
+ RootInlineBox* root = inlineBoxWrapper()->root();
+ IntRect rect(0, root->selectionTop() - yPos(), width(), root->selectionHeight());
+
+ if (clipToVisibleContent)
+ computeAbsoluteRepaintRect(rect);
+ else {
+ FloatPoint absPos = localToAbsolute();
+ rect.move(absPos.x(), absPos.y());
+ }
+
+ return rect;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h
new file mode 100644
index 0000000..738427c
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderListMarker.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 RenderListMarker_h
+#define RenderListMarker_h
+
+#include "RenderBox.h"
+
+namespace WebCore {
+
+class RenderListItem;
+
+String listMarkerText(EListStyleType, int value);
+
+// Used to render the list item's marker.
+// The RenderListMarker always has to be a child of a RenderListItem.
+class RenderListMarker : public RenderBox {
+public:
+ RenderListMarker(RenderListItem*);
+ ~RenderListMarker();
+
+ virtual const char* renderName() const { return "RenderListMarker"; }
+
+ virtual bool isListMarker() const { return true; }
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+
+ virtual void layout();
+ virtual void calcPrefWidths();
+
+ virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+
+ virtual InlineBox* createInlineBox(bool, bool, bool);
+
+ virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
+ virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const;
+
+ bool isImage() const;
+ bool isText() const { return !isImage(); }
+ const String& text() const { return m_text; }
+
+ bool isInside() const;
+
+ virtual SelectionState selectionState() const { return m_selectionState; }
+ virtual void setSelectionState(SelectionState);
+ virtual IntRect selectionRect(bool clipToVisibleContent = true);
+ virtual bool canBeSelectionLeaf() const { return true; }
+
+ void updateMargins();
+
+protected:
+ virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle);
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+private:
+ IntRect getRelativeMarkerRect();
+
+ String m_text;
+ RefPtr<StyleImage> m_image;
+ RenderListItem* m_listItem;
+ SelectionState m_selectionState;
+};
+
+} // namespace WebCore
+
+#endif // RenderListMarker_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.cpp
new file mode 100644
index 0000000..96d26ea
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Portions are Copyright (C) 1998 Netscape Communications Corporation.
+ *
+ * Other contributors:
+ * Robert O'Callahan <roc+@cs.cmu.edu>
+ * David Baron <dbaron@fas.harvard.edu>
+ * Christian Biesinger <cbiesinger@web.de>
+ * Randall Jesup <rjesup@wgate.com>
+ * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
+ * Josh Soref <timeless@mac.com>
+ * Boris Zbarsky <bzbarsky@mit.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+ */
+
+#include "config.h"
+
+#include "RenderMarquee.h"
+
+#include "FrameView.h"
+#include "HTMLMarqueeElement.h"
+#include "HTMLNames.h"
+#include "RenderLayer.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderMarquee::RenderMarquee(RenderLayer* l)
+ : m_layer(l), m_currentLoop(0)
+ , m_totalLoops(0)
+ , m_timer(this, &RenderMarquee::timerFired)
+ , m_start(0), m_end(0), m_speed(0), m_reset(false)
+ , m_suspended(false), m_stopped(false), m_direction(MAUTO)
+{
+}
+
+int RenderMarquee::marqueeSpeed() const
+{
+ int result = m_layer->renderer()->style()->marqueeSpeed();
+ Node* elt = m_layer->renderer()->element();
+ if (elt && elt->hasTagName(marqueeTag)) {
+ HTMLMarqueeElement* marqueeElt = static_cast<HTMLMarqueeElement*>(elt);
+ result = max(result, marqueeElt->minimumDelay());
+ }
+ return result;
+}
+
+EMarqueeDirection RenderMarquee::direction() const
+{
+ // FIXME: Support the CSS3 "auto" value for determining the direction of the marquee.
+ // For now just map MAUTO to MBACKWARD
+ EMarqueeDirection result = m_layer->renderer()->style()->marqueeDirection();
+ TextDirection dir = m_layer->renderer()->style()->direction();
+ if (result == MAUTO)
+ result = MBACKWARD;
+ if (result == MFORWARD)
+ result = (dir == LTR) ? MRIGHT : MLEFT;
+ if (result == MBACKWARD)
+ result = (dir == LTR) ? MLEFT : MRIGHT;
+
+ // Now we have the real direction. Next we check to see if the increment is negative.
+ // If so, then we reverse the direction.
+ Length increment = m_layer->renderer()->style()->marqueeIncrement();
+ if (increment.isNegative())
+ result = static_cast<EMarqueeDirection>(-result);
+
+ return result;
+}
+
+bool RenderMarquee::isHorizontal() const
+{
+ return direction() == MLEFT || direction() == MRIGHT;
+}
+
+int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge)
+{
+ RenderObject* o = m_layer->renderer();
+ RenderStyle* s = o->style();
+ if (isHorizontal()) {
+ bool ltr = s->direction() == LTR;
+ int clientWidth = o->clientWidth();
+ int contentWidth = ltr ? o->rightmostPosition(true, false) : o->leftmostPosition(true, false);
+ if (ltr)
+ contentWidth += (o->paddingRight() - o->borderLeft());
+ else {
+ contentWidth = o->width() - contentWidth;
+ contentWidth += (o->paddingLeft() - o->borderRight());
+ }
+ if (dir == MRIGHT) {
+ if (stopAtContentEdge)
+ return max(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
+ else
+ return ltr ? contentWidth : clientWidth;
+ }
+ else {
+ if (stopAtContentEdge)
+ return min(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
+ else
+ return ltr ? -clientWidth : -contentWidth;
+ }
+ }
+ else {
+ int contentHeight = m_layer->renderer()->lowestPosition(true, false) -
+ m_layer->renderer()->borderTop() + m_layer->renderer()->paddingBottom();
+ int clientHeight = m_layer->renderer()->clientHeight();
+ if (dir == MUP) {
+ if (stopAtContentEdge)
+ return min(contentHeight - clientHeight, 0);
+ else
+ return -clientHeight;
+ }
+ else {
+ if (stopAtContentEdge)
+ return max(contentHeight - clientHeight, 0);
+ else
+ return contentHeight;
+ }
+ }
+}
+
+void RenderMarquee::start()
+{
+ if (m_timer.isActive() || m_layer->renderer()->style()->marqueeIncrement().isZero())
+ return;
+
+ // We may end up propagating a scroll event. It is important that we suspend events until
+ // the end of the function since they could delete the layer, including the marquee.
+ FrameView* frameView = m_layer->renderer()->document()->view();
+ if (frameView)
+ frameView->pauseScheduledEvents();
+
+ if (!m_suspended && !m_stopped) {
+ if (isHorizontal())
+ m_layer->scrollToOffset(m_start, 0, false, false);
+ else
+ m_layer->scrollToOffset(0, m_start, false, false);
+ }
+ else {
+ m_suspended = false;
+ m_stopped = false;
+ }
+
+ m_timer.startRepeating(speed() * 0.001);
+
+ if (frameView)
+ frameView->resumeScheduledEvents();
+}
+
+void RenderMarquee::suspend()
+{
+ m_timer.stop();
+ m_suspended = true;
+}
+
+void RenderMarquee::stop()
+{
+ m_timer.stop();
+ m_stopped = true;
+}
+
+void RenderMarquee::updateMarqueePosition()
+{
+ bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
+ if (activate) {
+ EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior();
+ m_start = computePosition(direction(), behavior == MALTERNATE);
+ m_end = computePosition(reverseDirection(), behavior == MALTERNATE || behavior == MSLIDE);
+ if (!m_stopped)
+ start();
+ }
+}
+
+void RenderMarquee::updateMarqueeStyle()
+{
+ RenderStyle* s = m_layer->renderer()->style();
+
+ if (m_direction != s->marqueeDirection() || (m_totalLoops != s->marqueeLoopCount() && m_currentLoop >= m_totalLoops))
+ m_currentLoop = 0; // When direction changes or our loopCount is a smaller number than our current loop, reset our loop.
+
+ m_totalLoops = s->marqueeLoopCount();
+ m_direction = s->marqueeDirection();
+
+ if (m_layer->renderer()->isHTMLMarquee()) {
+ // Hack for WinIE. In WinIE, a value of 0 or lower for the loop count for SLIDE means to only do
+ // one loop.
+ if (m_totalLoops <= 0 && s->marqueeBehavior() == MSLIDE)
+ m_totalLoops = 1;
+
+ // Hack alert: Set the white-space value to nowrap for horizontal marquees with inline children, thus ensuring
+ // all the text ends up on one line by default. Limit this hack to the <marquee> element to emulate
+ // WinIE's behavior. Someone using CSS3 can use white-space: nowrap on their own to get this effect.
+ // Second hack alert: Set the text-align back to auto. WinIE completely ignores text-align on the
+ // marquee element.
+ // FIXME: Bring these up with the CSS WG.
+ if (isHorizontal() && m_layer->renderer()->childrenInline()) {
+ s->setWhiteSpace(NOWRAP);
+ s->setTextAlign(TAAUTO);
+ }
+ }
+
+ // Marquee height hack!! Make sure that, if it is a horizontal marquee, the height attribute is overridden
+ // if it is smaller than the font size. If it is a vertical marquee and height is not specified, we default
+ // to a marquee of 200px.
+ if (isHorizontal()) {
+ if (s->height().isFixed() && s->height().value() < s->fontSize())
+ s->setHeight(Length(s->fontSize(),Fixed));
+ } else if (s->height().isAuto()) //vertical marquee with no specified height
+ s->setHeight(Length(200, Fixed));
+
+ if (speed() != marqueeSpeed()) {
+ m_speed = marqueeSpeed();
+ if (m_timer.isActive())
+ m_timer.startRepeating(speed() * 0.001);
+ }
+
+ // Check the loop count to see if we should now stop.
+ bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
+ if (activate && !m_timer.isActive())
+ m_layer->renderer()->setNeedsLayout(true);
+ else if (!activate && m_timer.isActive())
+ m_timer.stop();
+}
+
+void RenderMarquee::timerFired(Timer<RenderMarquee>*)
+{
+ if (m_layer->renderer()->needsLayout())
+ return;
+
+ if (m_reset) {
+ m_reset = false;
+ if (isHorizontal())
+ m_layer->scrollToXOffset(m_start);
+ else
+ m_layer->scrollToYOffset(m_start);
+ return;
+ }
+
+ RenderStyle* s = m_layer->renderer()->style();
+
+ int endPoint = m_end;
+ int range = m_end - m_start;
+ int newPos;
+ if (range == 0)
+ newPos = m_end;
+ else {
+ bool addIncrement = direction() == MUP || direction() == MLEFT;
+ bool isReversed = s->marqueeBehavior() == MALTERNATE && m_currentLoop % 2;
+ if (isReversed) {
+ // We're going in the reverse direction.
+ endPoint = m_start;
+ range = -range;
+ addIncrement = !addIncrement;
+ }
+ bool positive = range > 0;
+ int clientSize = (isHorizontal() ? m_layer->renderer()->clientWidth() : m_layer->renderer()->clientHeight());
+ int increment = max(1, abs(m_layer->renderer()->style()->marqueeIncrement().calcValue(clientSize)));
+ int currentPos = (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset());
+ newPos = currentPos + (addIncrement ? increment : -increment);
+ if (positive)
+ newPos = min(newPos, endPoint);
+ else
+ newPos = max(newPos, endPoint);
+ }
+
+ if (newPos == endPoint) {
+ m_currentLoop++;
+ if (m_totalLoops > 0 && m_currentLoop >= m_totalLoops)
+ m_timer.stop();
+ else if (s->marqueeBehavior() != MALTERNATE)
+ m_reset = true;
+ }
+
+ if (isHorizontal())
+ m_layer->scrollToXOffset(newPos);
+ else
+ m_layer->scrollToYOffset(newPos);
+}
+
+} // namespace WebCore
+
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h b/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h
new file mode 100644
index 0000000..d9d20cd
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderMarquee.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * Portions are Copyright (C) 1998 Netscape Communications Corporation.
+ *
+ * Other contributors:
+ * Robert O'Callahan <roc+@cs.cmu.edu>
+ * David Baron <dbaron@fas.harvard.edu>
+ * Christian Biesinger <cbiesinger@web.de>
+ * Randall Jesup <rjesup@wgate.com>
+ * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
+ * Josh Soref <timeless@mac.com>
+ * Boris Zbarsky <bzbarsky@mit.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+ */
+
+#ifndef RenderMarquee_h
+#define RenderMarquee_h
+
+#include "RenderStyle.h"
+#include "Timer.h"
+
+namespace WebCore {
+
+class RenderLayer;
+
+// This class handles the auto-scrolling of layers with overflow: marquee.
+class RenderMarquee {
+public:
+ RenderMarquee(RenderLayer*);
+
+ int speed() const { return m_speed; }
+ int marqueeSpeed() const;
+
+ EMarqueeDirection reverseDirection() const { return static_cast<EMarqueeDirection>(-direction()); }
+ EMarqueeDirection direction() const;
+
+ bool isHorizontal() const;
+
+ int computePosition(EMarqueeDirection, bool stopAtClientEdge);
+
+ void setEnd(int end) { m_end = end; }
+
+ void start();
+ void suspend();
+ void stop();
+
+ void updateMarqueeStyle();
+ void updateMarqueePosition();
+
+private:
+ void timerFired(Timer<RenderMarquee>*);
+
+ RenderLayer* m_layer;
+ int m_currentLoop;
+ int m_totalLoops;
+ Timer<RenderMarquee> m_timer;
+ int m_start;
+ int m_end;
+ int m_speed;
+ Length m_height;
+ bool m_reset: 1;
+ bool m_suspended : 1;
+ bool m_stopped : 1;
+ EMarqueeDirection m_direction : 4;
+};
+
+} // namespace WebCore
+
+#endif // RenderMarquee_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMedia.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.cpp
new file mode 100644
index 0000000..a224136
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO)
+#include "RenderMedia.h"
+
+#include "CSSStyleSelector.h"
+#include "Event.h"
+#include "EventNames.h"
+#include "FloatConversion.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLMediaElement.h"
+#include "HTMLNames.h"
+#include "MediaControlElements.h"
+#include "MouseEvent.h"
+#include "MediaPlayer.h"
+#include "RenderSlider.h"
+#include "SystemTime.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+static const double cTimeUpdateRepeatDelay = 0.2;
+static const double cOpacityAnimationRepeatDelay = 0.05;
+// FIXME get this from style
+static const double cOpacityAnimationDuration = 0.1;
+
+RenderMedia::RenderMedia(HTMLMediaElement* video)
+ : RenderReplaced(video)
+ , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
+ , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
+ , m_mouseOver(false)
+ , m_opacityAnimationStartTime(0)
+ , m_opacityAnimationFrom(0)
+ , m_opacityAnimationTo(1.0f)
+ , m_previousVisible(VISIBLE)
+{
+}
+
+RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize)
+ : RenderReplaced(video, intrinsicSize)
+ , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
+ , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
+ , m_mouseOver(false)
+ , m_opacityAnimationStartTime(0)
+ , m_opacityAnimationFrom(0)
+ , m_opacityAnimationTo(1.0f)
+{
+}
+
+RenderMedia::~RenderMedia()
+{
+}
+
+void RenderMedia::destroy()
+{
+ if (m_controlsShadowRoot && m_controlsShadowRoot->renderer()) {
+ removeChild(m_controlsShadowRoot->renderer());
+ m_controlsShadowRoot->detach();
+ }
+ RenderReplaced::destroy();
+}
+
+HTMLMediaElement* RenderMedia::mediaElement() const
+{
+ return static_cast<HTMLMediaElement*>(node());
+}
+
+MediaPlayer* RenderMedia::player() const
+{
+ return mediaElement()->player();
+}
+
+void RenderMedia::layout()
+{
+ IntSize oldSize = contentBox().size();
+
+ RenderReplaced::layout();
+
+ RenderObject* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderer() : 0;
+ if (!controlsRenderer)
+ return;
+ IntSize newSize = contentBox().size();
+ if (newSize != oldSize || controlsRenderer->needsLayout()) {
+ controlsRenderer->setPos(borderLeft() + paddingLeft(), borderTop() + paddingTop());
+ controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed));
+ controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed));
+ controlsRenderer->setNeedsLayout(true, false);
+ controlsRenderer->layout();
+ setChildNeedsLayout(false);
+ }
+}
+
+RenderObject* RenderMedia::firstChild() const
+{
+ return m_controlsShadowRoot ? m_controlsShadowRoot->renderer() : 0;
+}
+
+RenderObject* RenderMedia::lastChild() const
+{
+ return m_controlsShadowRoot ? m_controlsShadowRoot->renderer() : 0;
+}
+
+void RenderMedia::removeChild(RenderObject* child)
+{
+ ASSERT(m_controlsShadowRoot);
+ ASSERT(child == m_controlsShadowRoot->renderer());
+ child->removeLayers(enclosingLayer());
+ static_cast<RenderMediaControlShadowRoot*>(child)->setParent(0);
+}
+
+void RenderMedia::createControlsShadowRoot()
+{
+ ASSERT(!m_controlsShadowRoot);
+ m_controlsShadowRoot = new MediaControlShadowRootElement(document(), mediaElement());
+}
+
+void RenderMedia::createPanel()
+{
+ ASSERT(!m_panel);
+ RenderStyle* style = getCachedPseudoStyle(RenderStyle::MEDIA_CONTROLS_PANEL);
+ m_panel = new HTMLDivElement(HTMLNames::divTag, document());
+ RenderObject* renderer = m_panel->createRenderer(renderArena(), style);
+ if (renderer) {
+ m_panel->setRenderer(renderer);
+ renderer->setStyle(style);
+ m_panel->setAttached();
+ m_panel->setInDocument(true);
+ m_controlsShadowRoot->addChild(m_panel);
+ m_controlsShadowRoot->renderer()->addChild(renderer);
+ }
+}
+
+void RenderMedia::createMuteButton()
+{
+ ASSERT(!m_muteButton);
+ m_muteButton = new MediaControlMuteButtonElement(document(), mediaElement());
+ m_muteButton->attachToParent(m_panel.get());
+}
+
+void RenderMedia::createPlayButton()
+{
+ ASSERT(!m_playButton);
+ m_playButton = new MediaControlPlayButtonElement(document(), mediaElement());
+ m_playButton->attachToParent(m_panel.get());
+}
+
+void RenderMedia::createSeekBackButton()
+{
+ ASSERT(!m_seekBackButton);
+ m_seekBackButton = new MediaControlSeekButtonElement(document(), mediaElement(), false);
+ m_seekBackButton->attachToParent(m_panel.get());
+}
+
+void RenderMedia::createSeekForwardButton()
+{
+ ASSERT(!m_seekForwardButton);
+ m_seekForwardButton = new MediaControlSeekButtonElement(document(), mediaElement(), true);
+ m_seekForwardButton->attachToParent(m_panel.get());
+}
+
+void RenderMedia::createTimeline()
+{
+ ASSERT(!m_timeline);
+ m_timeline = new MediaControlTimelineElement(document(), mediaElement());
+ m_timeline->attachToParent(m_panel.get());
+}
+
+void RenderMedia::createTimeDisplay()
+{
+ ASSERT(!m_timeDisplay);
+ RenderStyle* style = getCachedPseudoStyle(RenderStyle::MEDIA_CONTROLS_TIME_DISPLAY);
+ m_timeDisplay = new HTMLDivElement(HTMLNames::divTag, document());
+ RenderObject* renderer = m_timeDisplay->createRenderer(renderArena(), style);
+ if (renderer) {
+ m_timeDisplay->setRenderer(renderer);
+ renderer->setStyle(style);
+ m_timeDisplay->setAttached();
+ m_timeDisplay->setInDocument(true);
+ m_panel->addChild(m_timeDisplay);
+ m_panel->renderer()->addChild(renderer);
+ }
+}
+
+void RenderMedia::createFullscreenButton()
+{
+ ASSERT(!m_fullscreenButton);
+ m_fullscreenButton = new MediaControlFullscreenButtonElement(document(), mediaElement());
+ m_fullscreenButton->attachToParent(m_panel.get());
+}
+
+void RenderMedia::updateFromElement()
+{
+ updateControls();
+}
+
+void RenderMedia::updateControls()
+{
+ HTMLMediaElement* media = mediaElement();
+ if (!media->controls() || !media->inActiveDocument()) {
+ if (m_controlsShadowRoot) {
+ m_controlsShadowRoot->detach();
+ m_panel = 0;
+ m_muteButton = 0;
+ m_playButton = 0;
+ m_timeline = 0;
+ m_seekBackButton = 0;
+ m_seekForwardButton = 0;
+ m_timeDisplay = 0;
+ m_fullscreenButton = 0;
+ m_controlsShadowRoot = 0;
+ }
+ m_opacityAnimationTo = 1.0f;
+ m_opacityAnimationTimer.stop();
+ m_timeUpdateTimer.stop();
+ return;
+ }
+
+ if (!m_controlsShadowRoot) {
+ createControlsShadowRoot();
+ createPanel();
+ createMuteButton();
+ createPlayButton();
+ createTimeline();
+ createSeekBackButton();
+ createSeekForwardButton();
+ createTimeDisplay();
+ createFullscreenButton();
+ }
+
+ if (media->paused() || media->ended() || media->networkState() < HTMLMediaElement::LOADED_METADATA)
+ m_timeUpdateTimer.stop();
+ else
+ m_timeUpdateTimer.startRepeating(cTimeUpdateRepeatDelay);
+
+ if (m_muteButton)
+ m_muteButton->update();
+ if (m_playButton)
+ m_playButton->update();
+ if (m_timeline)
+ m_timeline->update();
+ if (m_seekBackButton)
+ m_seekBackButton->update();
+ if (m_seekForwardButton)
+ m_seekForwardButton->update();
+ if (m_fullscreenButton)
+ m_fullscreenButton->update();
+ updateTimeDisplay();
+ updateControlVisibility();
+}
+
+void RenderMedia::timeUpdateTimerFired(Timer<RenderMedia>*)
+{
+ if (m_timeline)
+ m_timeline->update(false);
+ updateTimeDisplay();
+}
+
+String RenderMedia::formatTime(float time)
+{
+ if (!isfinite(time))
+ time = 0;
+ int seconds = (int)time;
+ int hours = seconds / (60 * 60);
+ int minutes = (seconds / 60) % 60;
+ seconds %= 60;
+ return String::format("%02d:%02d:%02d", hours, minutes, seconds);
+}
+
+void RenderMedia::updateTimeDisplay()
+{
+ if (!m_timeDisplay)
+ return;
+ String timeString = formatTime(mediaElement()->currentTime());
+ ExceptionCode ec;
+ m_timeDisplay->setInnerText(timeString, ec);
+}
+
+void RenderMedia::updateControlVisibility()
+{
+ if (!m_panel || !m_panel->renderer())
+ return;
+ // Don't fade for audio controls.
+ HTMLMediaElement* media = mediaElement();
+ if (player() && !player()->hasVideo() || !media->isVideo())
+ return;
+ // do fading manually, css animations don't work well with shadow trees
+ bool visible = style()->visibility() == VISIBLE && (m_mouseOver || media->paused() || media->ended() || media->networkState() < HTMLMediaElement::LOADED_METADATA);
+ if (visible == (m_opacityAnimationTo > 0))
+ return;
+
+ if (style()->visibility() != m_previousVisible) {
+ // don't fade gradually if it the element has just changed visibility
+ m_previousVisible = style()->visibility();
+ m_opacityAnimationTo = m_previousVisible == VISIBLE ? 1.0f : 0;
+ changeOpacity(m_panel.get(), 0);
+ return;
+ }
+
+ if (visible) {
+ m_opacityAnimationFrom = m_panel->renderer()->style()->opacity();
+ m_opacityAnimationTo = 1.0f;
+ } else {
+ m_opacityAnimationFrom = m_panel->renderer()->style()->opacity();
+ m_opacityAnimationTo = 0;
+ }
+ m_opacityAnimationStartTime = currentTime();
+ m_opacityAnimationTimer.startRepeating(cOpacityAnimationRepeatDelay);
+}
+
+void RenderMedia::changeOpacity(HTMLElement* e, float opacity)
+{
+ if (!e || !e->renderer() || !e->renderer()->style())
+ return;
+ RefPtr<RenderStyle> s = RenderStyle::clone(e->renderer()->style());
+ s->setOpacity(opacity);
+ // z-index can't be auto if opacity is used
+ s->setZIndex(0);
+ e->renderer()->setStyle(s.release());
+}
+
+void RenderMedia::opacityAnimationTimerFired(Timer<RenderMedia>*)
+{
+ double time = currentTime() - m_opacityAnimationStartTime;
+ if (time >= cOpacityAnimationDuration) {
+ time = cOpacityAnimationDuration;
+ m_opacityAnimationTimer.stop();
+ }
+ float opacity = narrowPrecisionToFloat(m_opacityAnimationFrom + (m_opacityAnimationTo - m_opacityAnimationFrom) * time / cOpacityAnimationDuration);
+ changeOpacity(m_panel.get(), opacity);
+}
+
+void RenderMedia::forwardEvent(Event* event)
+{
+ if (event->isMouseEvent() && m_controlsShadowRoot) {
+ MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+ IntPoint point(mouseEvent->pageX(), mouseEvent->pageY());
+ if (m_muteButton && m_muteButton->hitTest(point))
+ m_muteButton->defaultEventHandler(event);
+
+ if (m_playButton && m_playButton->hitTest(point))
+ m_playButton->defaultEventHandler(event);
+
+ if (m_seekBackButton && m_seekBackButton->hitTest(point))
+ m_seekBackButton->defaultEventHandler(event);
+
+ if (m_seekForwardButton && m_seekForwardButton->hitTest(point))
+ m_seekForwardButton->defaultEventHandler(event);
+
+ if (m_timeline && m_timeline->hitTest(point))
+ m_timeline->defaultEventHandler(event);
+
+ if (m_fullscreenButton && m_fullscreenButton->hitTest(point))
+ m_fullscreenButton->defaultEventHandler(event);
+
+ if (event->type() == eventNames().mouseoverEvent) {
+ m_mouseOver = true;
+ updateControlVisibility();
+ }
+ if (event->type() == eventNames().mouseoutEvent) {
+ // FIXME: moving over scrollbar thumb generates mouseout for the ancestor media element for some reason
+ m_mouseOver = absoluteBoundingBoxRect().contains(point);
+ updateControlVisibility();
+ }
+ }
+}
+
+int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int bottom = RenderReplaced::lowestPosition(includeOverflowInterior, includeSelf);
+ if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
+ return bottom;
+
+ return max(bottom, m_controlsShadowRoot->renderer()->yPos() + m_controlsShadowRoot->renderer()->lowestPosition(includeOverflowInterior, includeSelf));
+}
+
+int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int right = RenderReplaced::rightmostPosition(includeOverflowInterior, includeSelf);
+ if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
+ return right;
+
+ return max(right, m_controlsShadowRoot->renderer()->xPos() + m_controlsShadowRoot->renderer()->rightmostPosition(includeOverflowInterior, includeSelf));
+}
+
+int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int left = RenderReplaced::leftmostPosition(includeOverflowInterior, includeSelf);
+ if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
+ return left;
+
+ return min(left, m_controlsShadowRoot->renderer()->xPos() + m_controlsShadowRoot->renderer()->leftmostPosition(includeOverflowInterior, includeSelf));
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h
new file mode 100644
index 0000000..8f48caf
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderMedia.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderMedia_h
+#define RenderMedia_h
+
+#if ENABLE(VIDEO)
+
+#include "RenderReplaced.h"
+#include "Timer.h"
+
+namespace WebCore {
+
+class HTMLInputElement;
+class HTMLMediaElement;
+class MediaControlMuteButtonElement;
+class MediaControlPlayButtonElement;
+class MediaControlSeekButtonElement;
+class MediaControlTimelineElement;
+class MediaControlFullscreenButtonElement;
+class MediaPlayer;
+
+class RenderMedia : public RenderReplaced {
+public:
+ RenderMedia(HTMLMediaElement*);
+ RenderMedia(HTMLMediaElement*, const IntSize& intrinsicSize);
+ virtual ~RenderMedia();
+
+ virtual RenderObject* firstChild() const;
+ virtual RenderObject* lastChild() const;
+ virtual void removeChild(RenderObject*);
+ virtual void destroy();
+
+ virtual void layout();
+
+ virtual const char* renderName() const { return "RenderMedia"; }
+ virtual bool isMedia() const { return true; }
+
+ HTMLMediaElement* mediaElement() const;
+ MediaPlayer* player() const;
+
+ static String formatTime(float time);
+
+ void updateFromElement();
+ void updatePlayer();
+ void updateControls();
+
+ void forwardEvent(Event*);
+
+ 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;
+
+private:
+ void createControlsShadowRoot();
+ void createPanel();
+ void createMuteButton();
+ void createPlayButton();
+ void createSeekBackButton();
+ void createSeekForwardButton();
+ void createTimeline();
+ void createTimeDisplay();
+ void createFullscreenButton();
+
+ void timeUpdateTimerFired(Timer<RenderMedia>*);
+ void updateTimeDisplay();
+
+ void updateControlVisibility();
+ void changeOpacity(HTMLElement*, float opacity);
+ void opacityAnimationTimerFired(Timer<RenderMedia>*);
+
+ RefPtr<HTMLElement> m_controlsShadowRoot;
+ RefPtr<HTMLElement> m_panel;
+ RefPtr<MediaControlMuteButtonElement> m_muteButton;
+ RefPtr<MediaControlPlayButtonElement> m_playButton;
+ RefPtr<MediaControlSeekButtonElement> m_seekBackButton;
+ RefPtr<MediaControlSeekButtonElement> m_seekForwardButton;
+ RefPtr<MediaControlTimelineElement> m_timeline;
+ RefPtr<MediaControlFullscreenButtonElement> m_fullscreenButton;
+ RefPtr<HTMLElement> m_timeDisplay;
+ EventTargetNode* m_lastUnderNode;
+ EventTargetNode* m_nodeUnderMouse;
+
+ Timer<RenderMedia> m_timeUpdateTimer;
+ Timer<RenderMedia> m_opacityAnimationTimer;
+ bool m_mouseOver;
+ double m_opacityAnimationStartTime;
+ float m_opacityAnimationFrom;
+ float m_opacityAnimationTo;
+ EVisibility m_previousVisible;
+};
+
+} // namespace WebCore
+
+#endif
+#endif // RenderMedia_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.cpp
new file mode 100644
index 0000000..baec309
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.cpp
@@ -0,0 +1,441 @@
+/**
+ * This file is part of the select element renderer in WebCore.
+ *
+ * Copyright (C) 2006, 2007 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 "RenderMenuList.h"
+
+#include "CSSStyleSelector.h"
+#include "Document.h"
+#include "FontSelector.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLOptionElement.h"
+#include "HTMLOptGroupElement.h"
+#include "HTMLSelectElement.h"
+#include "PopupMenu.h"
+#include "RenderBR.h"
+#include "RenderScrollbar.h"
+#include "RenderText.h"
+#include "RenderTheme.h"
+#include "NodeRenderStyle.h"
+#include <math.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderMenuList::RenderMenuList(HTMLSelectElement* element)
+ : RenderFlexibleBox(element)
+ , m_buttonText(0)
+ , m_innerBlock(0)
+ , m_optionsChanged(true)
+ , m_optionsWidth(0)
+ , m_popup(0)
+ , m_popupIsVisible(false)
+{
+}
+
+RenderMenuList::~RenderMenuList()
+{
+ if (m_popup)
+ m_popup->disconnectClient();
+ m_popup = 0;
+}
+
+// this static cast is safe because RenderMenuLists are only created for HTMLSelectElements
+HTMLSelectElement* RenderMenuList::selectElement()
+{
+ return static_cast<HTMLSelectElement*>(node());
+}
+
+void RenderMenuList::createInnerBlock()
+{
+ if (m_innerBlock) {
+ ASSERT(firstChild() == m_innerBlock);
+ ASSERT(!m_innerBlock->nextSibling());
+ return;
+ }
+
+ // Create an anonymous block.
+ ASSERT(!firstChild());
+ m_innerBlock = createAnonymousBlock();
+ adjustInnerStyle();
+ RenderFlexibleBox::addChild(m_innerBlock);
+}
+
+void RenderMenuList::adjustInnerStyle()
+{
+ m_innerBlock->style()->setBoxFlex(1.0f);
+
+ m_innerBlock->style()->setPaddingLeft(Length(theme()->popupInternalPaddingLeft(style()), Fixed));
+ m_innerBlock->style()->setPaddingRight(Length(theme()->popupInternalPaddingRight(style()), Fixed));
+ m_innerBlock->style()->setPaddingTop(Length(theme()->popupInternalPaddingTop(style()), Fixed));
+ m_innerBlock->style()->setPaddingBottom(Length(theme()->popupInternalPaddingBottom(style()), Fixed));
+
+ if (PopupMenu::itemWritingDirectionIsNatural()) {
+ // Items in the popup will not respect the CSS text-align and direction properties,
+ // so we must adjust our own style to match.
+ m_innerBlock->style()->setTextAlign(LEFT);
+ TextDirection direction = (m_buttonText && m_buttonText->text()->defaultWritingDirection() == WTF::Unicode::RightToLeft) ? RTL : LTR;
+ m_innerBlock->style()->setDirection(direction);
+ }
+}
+
+void RenderMenuList::addChild(RenderObject* newChild, RenderObject* beforeChild)
+{
+ createInnerBlock();
+ m_innerBlock->addChild(newChild, beforeChild);
+}
+
+void RenderMenuList::removeChild(RenderObject* oldChild)
+{
+ if (oldChild == m_innerBlock || !m_innerBlock) {
+ RenderFlexibleBox::removeChild(oldChild);
+ m_innerBlock = 0;
+ } else
+ m_innerBlock->removeChild(oldChild);
+}
+
+void RenderMenuList::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+
+ if (m_buttonText)
+ m_buttonText->setStyle(style());
+ if (m_innerBlock) // RenderBlock handled updating the anonymous block's style.
+ adjustInnerStyle();
+
+ setReplaced(isInline());
+
+ bool fontChanged = !oldStyle || oldStyle->font() != style()->font();
+ if (fontChanged)
+ updateOptionsWidth();
+}
+
+void RenderMenuList::updateOptionsWidth()
+{
+ float maxOptionWidth = 0;
+ const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(node())->listItems();
+ int size = listItems.size();
+ for (int i = 0; i < size; ++i) {
+ HTMLElement* element = listItems[i];
+ if (element->hasTagName(optionTag)) {
+ String text = static_cast<HTMLOptionElement*>(element)->optionText();
+ if (!text.isEmpty())
+ maxOptionWidth = max(maxOptionWidth, style()->font().floatWidth(text));
+ }
+ }
+
+ int width = static_cast<int>(ceilf(maxOptionWidth));
+ if (m_optionsWidth == width)
+ return;
+
+ m_optionsWidth = width;
+ setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+void RenderMenuList::updateFromElement()
+{
+ if (m_optionsChanged) {
+ updateOptionsWidth();
+ m_optionsChanged = false;
+ }
+
+ if (m_popupIsVisible)
+ m_popup->updateFromElement();
+ else
+ setTextFromOption(static_cast<HTMLSelectElement*>(node())->selectedIndex());
+}
+
+void RenderMenuList::setTextFromOption(int optionIndex)
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ const Vector<HTMLElement*>& listItems = select->listItems();
+ int size = listItems.size();
+
+ int i = select->optionToListIndex(optionIndex);
+ String text = "";
+ if (i >= 0 && i < size) {
+ HTMLElement* element = listItems[i];
+ if (element->hasTagName(optionTag))
+ text = static_cast<HTMLOptionElement*>(listItems[i])->optionText();
+ }
+ setText(text.stripWhiteSpace());
+}
+
+void RenderMenuList::setText(const String& s)
+{
+ if (s.isEmpty()) {
+ if (!m_buttonText || !m_buttonText->isBR()) {
+ if (m_buttonText)
+ m_buttonText->destroy();
+ m_buttonText = new (renderArena()) RenderBR(document());
+ m_buttonText->setStyle(style());
+ addChild(m_buttonText);
+ }
+ } else {
+ if (m_buttonText && !m_buttonText->isBR())
+ m_buttonText->setText(s.impl());
+ else {
+ if (m_buttonText)
+ m_buttonText->destroy();
+ m_buttonText = new (renderArena()) RenderText(document(), s.impl());
+ m_buttonText->setStyle(style());
+ addChild(m_buttonText);
+ }
+ adjustInnerStyle();
+ }
+}
+
+String RenderMenuList::text() const
+{
+ return m_buttonText ? m_buttonText->text() : 0;
+}
+
+IntRect RenderMenuList::controlClipRect(int tx, int ty) const
+{
+ // Clip to the intersection of the content box and the content box for the inner box
+ // This will leave room for the arrows which sit in the inner box padding,
+ // and if the inner box ever spills out of the outer box, that will get clipped too.
+ IntRect outerBox(tx + borderLeft() + paddingLeft(),
+ ty + borderTop() + paddingTop(),
+ contentWidth(),
+ contentHeight());
+
+ IntRect innerBox(tx + m_innerBlock->xPos() + m_innerBlock->paddingLeft(),
+ ty + m_innerBlock->yPos() + m_innerBlock->paddingTop(),
+ m_innerBlock->contentWidth(),
+ m_innerBlock->contentHeight());
+
+ return intersection(outerBox, innerBox);
+}
+
+void RenderMenuList::calcPrefWidths()
+{
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = 0;
+
+ if (style()->width().isFixed() && style()->width().value() > 0)
+ m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
+ else
+ m_maxPrefWidth = max(m_optionsWidth, theme()->minimumMenuListSize(style())) + m_innerBlock->paddingLeft() + m_innerBlock->paddingRight();
+
+ if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
+ m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
+ m_minPrefWidth = 0;
+ else
+ m_minPrefWidth = m_maxPrefWidth;
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
+ m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ }
+
+ int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+ m_minPrefWidth += toAdd;
+ m_maxPrefWidth += toAdd;
+
+ setPrefWidthsDirty(false);
+}
+
+void RenderMenuList::showPopup()
+{
+ if (m_popupIsVisible)
+ return;
+
+ // Create m_innerBlock here so it ends up as the first child.
+ // This is important because otherwise we might try to create m_innerBlock
+ // inside the showPopup call and it would fail.
+ createInnerBlock();
+ if (!m_popup)
+ m_popup = PopupMenu::create(this);
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ m_popupIsVisible = true;
+
+ // Compute the top left taking transforms into account, but use
+ // the actual width of the element to size the popup.
+ FloatPoint absTopLeft = localToAbsolute(FloatPoint(), false, true);
+ IntRect absBounds = absoluteBoundingBoxRect();
+ absBounds.setLocation(roundedIntPoint(absTopLeft));
+ m_popup->show(absBounds, document()->view(),
+ select->optionToListIndex(select->selectedIndex()));
+}
+
+void RenderMenuList::hidePopup()
+{
+ if (m_popup)
+ m_popup->hide();
+ m_popupIsVisible = false;
+}
+
+void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange)
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ select->setSelectedIndex(select->listToOptionIndex(listIndex), true, fireOnChange);
+}
+
+String RenderMenuList::itemText(unsigned listIndex) const
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ HTMLElement* element = select->listItems()[listIndex];
+ if (element->hasTagName(optgroupTag))
+ return static_cast<HTMLOptGroupElement*>(element)->groupLabelText();
+ else if (element->hasTagName(optionTag))
+ return static_cast<HTMLOptionElement*>(element)->optionText();
+ return String();
+}
+
+bool RenderMenuList::itemIsEnabled(unsigned listIndex) const
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ HTMLElement* element = select->listItems()[listIndex];
+ if (!element->hasTagName(optionTag))
+ return false;
+ bool groupEnabled = true;
+ if (element->parentNode() && element->parentNode()->hasTagName(optgroupTag))
+ groupEnabled = element->parentNode()->isEnabled();
+ return element->isEnabled() && groupEnabled;
+}
+
+PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ HTMLElement* element = select->listItems()[listIndex];
+
+ RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle();
+ return style ? PopupMenuStyle(style->color(), itemBackgroundColor(listIndex), style->font(), style->visibility() == VISIBLE) : menuStyle();
+}
+
+Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ HTMLElement* element = select->listItems()[listIndex];
+
+ Color backgroundColor;
+ if (element->renderStyle())
+ backgroundColor = element->renderStyle()->backgroundColor();
+ // If the item has an opaque background color, return that.
+ if (!backgroundColor.hasAlpha())
+ return backgroundColor;
+
+ // Otherwise, the item's background is overlayed on top of the menu background.
+ backgroundColor = style()->backgroundColor().blend(backgroundColor);
+ if (!backgroundColor.hasAlpha())
+ return backgroundColor;
+
+ // If the menu background is not opaque, then add an opaque white background behind.
+ return Color(Color::white).blend(backgroundColor);
+}
+
+PopupMenuStyle RenderMenuList::menuStyle() const
+{
+
+ RenderStyle* s = m_innerBlock ? m_innerBlock->style() : style();
+ return PopupMenuStyle(s->color(), s->backgroundColor(), s->font(), s->visibility() == VISIBLE);
+}
+
+HostWindow* RenderMenuList::hostWindow() const
+{
+ return document()->view()->hostWindow();
+}
+
+PassRefPtr<Scrollbar> RenderMenuList::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
+{
+ RefPtr<Scrollbar> widget;
+ bool hasCustomScrollbarStyle = style()->hasPseudoStyle(RenderStyle::SCROLLBAR);
+ if (hasCustomScrollbarStyle)
+ widget = RenderScrollbar::createCustomScrollbar(client, orientation, this);
+ else
+ widget = Scrollbar::createNativeScrollbar(client, orientation, controlSize);
+ return widget.release();
+}
+
+int RenderMenuList::clientInsetLeft() const
+{
+ return 0;
+}
+
+int RenderMenuList::clientInsetRight() const
+{
+ return 0;
+}
+
+int RenderMenuList::clientPaddingLeft() const
+{
+ return paddingLeft();
+}
+
+int RenderMenuList::clientPaddingRight() const
+{
+ return paddingRight();
+}
+
+int RenderMenuList::listSize() const
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ return select->listItems().size();
+}
+
+int RenderMenuList::selectedIndex() const
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ return select->optionToListIndex(select->selectedIndex());
+}
+
+bool RenderMenuList::itemIsSeparator(unsigned listIndex) const
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ HTMLElement* element = select->listItems()[listIndex];
+ return element->hasTagName(hrTag);
+}
+
+bool RenderMenuList::itemIsLabel(unsigned listIndex) const
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ HTMLElement* element = select->listItems()[listIndex];
+ return element->hasTagName(optgroupTag);
+}
+
+bool RenderMenuList::itemIsSelected(unsigned listIndex) const
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ HTMLElement* element = select->listItems()[listIndex];
+ return element->hasTagName(optionTag)&& static_cast<HTMLOptionElement*>(element)->selected();
+}
+
+void RenderMenuList::setTextFromItem(unsigned listIndex)
+{
+ HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
+ setTextFromOption(select->listToOptionIndex(listIndex));
+}
+
+FontSelector* RenderMenuList::fontSelector() const
+{
+ return document()->styleSelector()->fontSelector();
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h
new file mode 100644
index 0000000..f31ef32
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderMenuList.h
@@ -0,0 +1,119 @@
+/*
+ * This file is part of the select element renderer in WebCore.
+ *
+ * Copyright (C) 2006, 2007 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 RenderMenuList_h
+#define RenderMenuList_h
+
+#include "RenderFlexibleBox.h"
+#include "PopupMenuClient.h"
+
+#if PLATFORM(MAC)
+#define POPUP_MENU_PULLS_DOWN 0
+#else
+#define POPUP_MENU_PULLS_DOWN 1
+#endif
+
+namespace WebCore {
+
+class HTMLSelectElement;
+class PopupMenu;
+
+class RenderMenuList : public RenderFlexibleBox, private PopupMenuClient {
+public:
+ RenderMenuList(HTMLSelectElement*);
+ ~RenderMenuList();
+
+ HTMLSelectElement* selectElement();
+
+ virtual bool isMenuList() const { return true; }
+
+ virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0);
+ virtual void removeChild(RenderObject*);
+ virtual bool createsAnonymousWrapper() const { return true; }
+ virtual bool canHaveChildren() const { return false; }
+
+ virtual void updateFromElement();
+
+ virtual bool hasControlClip() const { return true; }
+ virtual IntRect controlClipRect(int tx, int ty) const;
+
+ virtual const char* renderName() const { return "RenderMenuList"; }
+
+ virtual void calcPrefWidths();
+
+ bool popupIsVisible() const { return m_popupIsVisible; }
+ void showPopup();
+ void hidePopup();
+
+ void setOptionsChanged(bool changed) { m_optionsChanged = changed; }
+
+ String text() const;
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+private:
+ // PopupMenuClient methods
+ virtual String itemText(unsigned listIndex) const;
+ virtual bool itemIsEnabled(unsigned listIndex) const;
+ virtual PopupMenuStyle itemStyle(unsigned listIndex) const;
+ virtual PopupMenuStyle menuStyle() const;
+ virtual int clientInsetLeft() const;
+ virtual int clientInsetRight() const;
+ virtual int clientPaddingLeft() const;
+ virtual int clientPaddingRight() const;
+ virtual int listSize() const;
+ virtual int selectedIndex() const;
+ virtual bool itemIsSeparator(unsigned listIndex) const;
+ virtual bool itemIsLabel(unsigned listIndex) const;
+ virtual bool itemIsSelected(unsigned listIndex) const;
+ virtual void setTextFromItem(unsigned listIndex);
+ virtual bool valueShouldChangeOnHotTrack() const { return true; }
+ virtual bool shouldPopOver() const { return !POPUP_MENU_PULLS_DOWN; }
+ virtual void valueChanged(unsigned listIndex, bool fireOnChange = true);
+ virtual FontSelector* fontSelector() const;
+ virtual HostWindow* hostWindow() const;
+ virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize);
+
+ virtual bool hasLineIfEmpty() const { return true; }
+
+ Color itemBackgroundColor(unsigned listIndex) const;
+
+ void createInnerBlock();
+ void adjustInnerStyle();
+ void setText(const String&);
+ void setTextFromOption(int optionIndex);
+ void updateOptionsWidth();
+
+ RenderText* m_buttonText;
+ RenderBlock* m_innerBlock;
+
+ bool m_optionsChanged;
+ int m_optionsWidth;
+
+ RefPtr<PopupMenu> m_popup;
+ bool m_popupIsVisible;
+};
+
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp
new file mode 100644
index 0000000..3ef7af7
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderObject.cpp
@@ -0,0 +1,3303 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (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.
+ *
+ * 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 "RenderObject.h"
+
+#include "AXObjectCache.h"
+#include "TransformationMatrix.h"
+#include "AnimationController.h"
+#include "CSSStyleSelector.h"
+#include "CachedImage.h"
+#include "Chrome.h"
+#include "Document.h"
+#include "Element.h"
+#include "EventHandler.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLOListElement.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "KURL.h"
+#include "Page.h"
+#include "PlatformScreen.h"
+#include "Position.h"
+#include "RenderArena.h"
+#include "RenderCounter.h"
+#include "RenderFlexibleBox.h"
+#include "RenderImageGeneratedContent.h"
+#include "RenderInline.h"
+#include "RenderListItem.h"
+#include "RenderTableCell.h"
+#include "RenderTableCol.h"
+#include "RenderTableRow.h"
+#include "RenderText.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "SelectionController.h"
+#include "TextResourceDecoder.h"
+#include <algorithm>
+#include <stdio.h>
+#include <wtf/RefCountedLeakCounter.h>
+
+#if ENABLE(WML)
+#include "WMLNames.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#ifndef NDEBUG
+static void* baseOfRenderObjectBeingDeleted;
+#endif
+
+bool RenderObject::s_affectsParentBlock = false;
+
+void* RenderObject::operator new(size_t sz, RenderArena* renderArena) throw()
+{
+ return renderArena->allocate(sz);
+}
+
+void RenderObject::operator delete(void* ptr, size_t sz)
+{
+ ASSERT(baseOfRenderObjectBeingDeleted == ptr);
+
+ // Stash size where destroy can find it.
+ *(size_t *)ptr = sz;
+}
+
+RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
+{
+ Document* doc = node->document();
+ RenderArena* arena = doc->renderArena();
+
+ // Minimal support for content properties replacing an entire element.
+ // Works only if we have exactly one piece of content and it's a URL.
+ // Otherwise acts as if we didn't support this feature.
+ const ContentData* contentData = style->contentData();
+ if (contentData && !contentData->m_next && contentData->m_type == CONTENT_OBJECT && doc != node) {
+ RenderImageGeneratedContent* image = new (arena) RenderImageGeneratedContent(node);
+ image->setStyle(style);
+ if (StyleImage* styleImage = contentData->m_content.m_image)
+ image->setStyleImage(styleImage);
+ return image;
+ }
+
+ RenderObject* o = 0;
+
+ switch (style->display()) {
+ case NONE:
+ break;
+ case INLINE:
+ o = new (arena) RenderInline(node);
+ break;
+ 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;
+ case TABLE:
+ case INLINE_TABLE:
+ o = new (arena) RenderTable(node);
+ break;
+ case TABLE_ROW_GROUP:
+ case TABLE_HEADER_GROUP:
+ case TABLE_FOOTER_GROUP:
+ o = new (arena) RenderTableSection(node);
+ break;
+ case TABLE_ROW:
+ o = new (arena) RenderTableRow(node);
+ break;
+ case TABLE_COLUMN_GROUP:
+ case TABLE_COLUMN:
+ o = new (arena) RenderTableCol(node);
+ break;
+ case TABLE_CELL:
+ o = new (arena) RenderTableCell(node);
+ break;
+ case TABLE_CAPTION:
+ o = new (arena) RenderBlock(node);
+ break;
+ case BOX:
+ case INLINE_BOX:
+ o = new (arena) RenderFlexibleBox(node);
+ break;
+ }
+
+ return o;
+}
+
+#ifndef NDEBUG
+static WTF::RefCountedLeakCounter renderObjectCounter("RenderObject");
+#endif
+
+RenderObject::RenderObject(Node* node)
+ : CachedResourceClient()
+ , m_style(0)
+ , m_node(node)
+ , m_parent(0)
+ , m_previous(0)
+ , m_next(0)
+#ifndef NDEBUG
+ , m_hasAXObject(false)
+#endif
+ , m_verticalPosition(PositionUndefined)
+ , m_needsLayout(false)
+ , m_needsPositionedMovementLayout(false)
+ , m_normalChildNeedsLayout(false)
+ , m_posChildNeedsLayout(false)
+ , m_prefWidthsDirty(false)
+ , m_floating(false)
+ , m_positioned(false)
+ , m_relPositioned(false)
+ , m_paintBackground(false)
+ , m_isAnonymous(node == node->document())
+ , m_isText(false)
+ , m_inline(true)
+ , m_replaced(false)
+ , m_isDragging(false)
+ , m_hasLayer(false)
+ , m_hasOverflowClip(false)
+ , m_hasTransform(false)
+ , m_hasReflection(false)
+ , m_hasOverrideSize(false)
+ , m_hasCounterNodeMap(false)
+ , m_everHadLayout(false)
+{
+#ifndef NDEBUG
+ renderObjectCounter.increment();
+#endif
+}
+
+RenderObject::~RenderObject()
+{
+ ASSERT(!node() || documentBeingDestroyed() || !document()->frame()->view() || document()->frame()->view()->layoutRoot() != this);
+#ifndef NDEBUG
+ ASSERT(!m_hasAXObject);
+ renderObjectCounter.decrement();
+#endif
+}
+
+bool RenderObject::isDescendantOf(const RenderObject* obj) const
+{
+ for (const RenderObject* r = this; r; r = r->m_parent) {
+ if (r == obj)
+ return true;
+ }
+ return false;
+}
+
+bool RenderObject::isBody() const
+{
+ return node()->hasTagName(bodyTag);
+}
+
+bool RenderObject::isHR() const
+{
+ return element() && element()->hasTagName(hrTag);
+}
+
+bool RenderObject::isHTMLMarquee() const
+{
+ return element() && element()->renderer() == this && element()->hasTagName(marqueeTag);
+}
+
+bool RenderObject::canHaveChildren() const
+{
+ return false;
+}
+
+RenderFlow* RenderObject::continuation() const
+{
+ return 0;
+}
+
+bool RenderObject::isInlineContinuation() const
+{
+ return false;
+}
+
+void RenderObject::addChild(RenderObject*, RenderObject*)
+{
+ ASSERT_NOT_REACHED();
+}
+
+RenderObject* RenderObject::removeChildNode(RenderObject*, bool)
+{
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void RenderObject::removeChild(RenderObject*)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void RenderObject::moveChildNode(RenderObject*)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void RenderObject::appendChildNode(RenderObject*, bool)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void RenderObject::insertChildNode(RenderObject*, RenderObject*, bool)
+{
+ ASSERT_NOT_REACHED();
+}
+
+RenderObject* RenderObject::nextInPreOrder() const
+{
+ if (RenderObject* o = firstChild())
+ return o;
+
+ return nextInPreOrderAfterChildren();
+}
+
+RenderObject* RenderObject::nextInPreOrderAfterChildren() const
+{
+ RenderObject* o;
+ if (!(o = nextSibling())) {
+ o = parent();
+ while (o && !o->nextSibling())
+ o = o->parent();
+ if (o)
+ o = o->nextSibling();
+ }
+
+ return o;
+}
+
+RenderObject* RenderObject::nextInPreOrder(RenderObject* stayWithin) const
+{
+ if (RenderObject* o = firstChild())
+ return o;
+
+ return nextInPreOrderAfterChildren(stayWithin);
+}
+
+RenderObject* RenderObject::nextInPreOrderAfterChildren(RenderObject* stayWithin) const
+{
+ 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();
+ }
+
+ return o;
+}
+
+RenderObject* RenderObject::previousInPreOrder() const
+{
+ if (RenderObject* o = previousSibling()) {
+ while (o->lastChild())
+ o = o->lastChild();
+ return o;
+ }
+
+ return parent();
+}
+
+RenderObject* RenderObject::childAt(unsigned index) const
+{
+ RenderObject* child = firstChild();
+ for (unsigned i = 0; child && i < index; i++)
+ child = child->nextSibling();
+ return child;
+}
+
+bool RenderObject::isEditable() const
+{
+ RenderText* textRenderer = 0;
+ if (isText())
+ textRenderer = static_cast<RenderText*>(const_cast<RenderObject*>(this));
+
+ return style()->visibility() == VISIBLE &&
+ element() && element()->isContentEditable() &&
+ ((isBlockFlow() && !firstChild()) ||
+ isReplaced() ||
+ isBR() ||
+ (textRenderer && textRenderer->firstTextBox()));
+}
+
+RenderObject* RenderObject::firstLeafChild() const
+{
+ RenderObject* r = firstChild();
+ while (r) {
+ RenderObject* n = 0;
+ n = r->firstChild();
+ if (!n)
+ break;
+ r = n;
+ }
+ return r;
+}
+
+RenderObject* RenderObject::lastLeafChild() const
+{
+ RenderObject* r = lastChild();
+ while (r) {
+ RenderObject* n = 0;
+ n = r->lastChild();
+ if (!n)
+ break;
+ r = n;
+ }
+ return r;
+}
+
+static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject,
+ RenderLayer*& beforeChild)
+{
+ if (obj->hasLayer()) {
+ if (!beforeChild && newObject) {
+ // We need to figure out the layer that follows newObject. We only do
+ // this the first time we find a child layer, and then we update the
+ // pointer values for newObject and beforeChild used by everyone else.
+ beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
+ newObject = 0;
+ }
+ parentLayer->addChild(obj->layer(), beforeChild);
+ return;
+ }
+
+ for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling())
+ addLayers(curr, parentLayer, newObject, beforeChild);
+}
+
+void RenderObject::addLayers(RenderLayer* parentLayer, RenderObject* newObject)
+{
+ if (!parentLayer)
+ return;
+
+ RenderObject* object = newObject;
+ RenderLayer* beforeChild = 0;
+ WebCore::addLayers(this, parentLayer, object, beforeChild);
+}
+
+void RenderObject::removeLayers(RenderLayer* parentLayer)
+{
+ if (!parentLayer)
+ return;
+
+ if (hasLayer()) {
+ parentLayer->removeChild(layer());
+ return;
+ }
+
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
+ curr->removeLayers(parentLayer);
+}
+
+void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
+{
+ if (!newParent)
+ return;
+
+ if (hasLayer()) {
+ if (oldParent)
+ oldParent->removeChild(layer());
+ newParent->addChild(layer());
+ return;
+ }
+
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
+ curr->moveLayers(oldParent, newParent);
+}
+
+RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint,
+ bool checkParent)
+{
+ // Error check the parent layer passed in. If it's null, we can't find anything.
+ if (!parentLayer)
+ return 0;
+
+ // Step 1: If our layer is a child of the desired parent, then return our layer.
+ RenderLayer* ourLayer = layer();
+ if (ourLayer && ourLayer->parent() == parentLayer)
+ return ourLayer;
+
+ // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
+ // into our siblings trying to find the next layer whose parent is the desired parent.
+ if (!ourLayer || ourLayer == parentLayer) {
+ for (RenderObject* curr = startPoint ? startPoint->nextSibling() : firstChild();
+ curr; curr = curr->nextSibling()) {
+ RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false);
+ if (nextLayer)
+ return nextLayer;
+ }
+ }
+
+ // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
+ // find anything.
+ if (parentLayer == ourLayer)
+ return 0;
+
+ // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
+ // follow us to see if we can locate a layer.
+ if (checkParent && parent())
+ return parent()->findNextLayer(parentLayer, this, true);
+
+ return 0;
+}
+
+RenderLayer* RenderObject::enclosingLayer() const
+{
+ const RenderObject* curr = this;
+ while (curr) {
+ RenderLayer* layer = curr->layer();
+ if (layer)
+ return layer;
+ curr = curr->parent();
+ }
+ return 0;
+}
+
+bool RenderObject::requiresLayer()
+{
+ return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection();
+}
+
+RenderBlock* RenderObject::firstLineBlock() const
+{
+ return 0;
+}
+
+int RenderObject::offsetLeft() const
+{
+ RenderObject* offsetPar = offsetParent();
+ if (!offsetPar)
+ return 0;
+ int x = xPos() - offsetPar->borderLeft();
+ if (!isPositioned()) {
+ if (isRelPositioned())
+ x += static_cast<const RenderBox*>(this)->relativePositionOffsetX();
+ RenderObject* curr = parent();
+ while (curr && curr != offsetPar) {
+ x += curr->xPos();
+ curr = curr->parent();
+ }
+ if (offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned())
+ x += offsetPar->xPos();
+ }
+ return x;
+}
+
+int RenderObject::offsetTop() const
+{
+ RenderObject* offsetPar = offsetParent();
+ if (!offsetPar)
+ return 0;
+ int y = yPos() - borderTopExtra() - offsetPar->borderTop();
+ if (!isPositioned()) {
+ if (isRelPositioned())
+ y += static_cast<const RenderBox*>(this)->relativePositionOffsetY();
+ RenderObject* curr = parent();
+ while (curr && curr != offsetPar) {
+ if (!curr->isTableRow())
+ y += curr->yPos();
+ curr = curr->parent();
+ }
+ if (offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned())
+ y += offsetPar->yPos();
+ }
+ return y;
+}
+
+RenderObject* RenderObject::offsetParent() const
+{
+ // FIXME: It feels like this function could almost be written using containing blocks.
+ if (isBody())
+ return 0;
+
+ bool skipTables = isPositioned() || isRelPositioned();
+ float currZoom = style()->effectiveZoom();
+ RenderObject* curr = parent();
+ while (curr && (!curr->element() ||
+ (!curr->isPositioned() && !curr->isRelPositioned() && !curr->isBody()))) {
+ Node* element = curr->element();
+ if (!skipTables && element) {
+ bool isTableElement = element->hasTagName(tableTag) ||
+ element->hasTagName(tdTag) ||
+ element->hasTagName(thTag);
+
+#if ENABLE(WML)
+ if (!isTableElement && element->isWMLElement())
+ isTableElement = element->hasTagName(WMLNames::tableTag) ||
+ element->hasTagName(WMLNames::tdTag);
+#endif
+
+ if (isTableElement)
+ break;
+ }
+
+ float newZoom = curr->style()->effectiveZoom();
+ if (currZoom != newZoom)
+ break;
+ currZoom = newZoom;
+ curr = curr->parent();
+ }
+ return curr;
+}
+
+int RenderObject::verticalScrollbarWidth() const
+{
+ return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0;
+}
+
+int RenderObject::horizontalScrollbarHeight() const
+{
+ return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
+}
+
+// More IE extensions. clientWidth and clientHeight represent the interior of an object
+// excluding border and scrollbar.
+int RenderObject::clientWidth() const
+{
+ return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
+}
+
+int RenderObject::clientHeight() const
+{
+ return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
+}
+
+// scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the
+// object has overflow:hidden/scroll/auto specified and also has overflow.
+int RenderObject::scrollWidth() const
+{
+ return hasOverflowClip() ? layer()->scrollWidth() : overflowWidth();
+}
+
+int RenderObject::scrollHeight() const
+{
+ return hasOverflowClip() ? layer()->scrollHeight() : overflowHeight();
+}
+
+int RenderObject::scrollLeft() const
+{
+ return hasOverflowClip() ? layer()->scrollXOffset() : 0;
+}
+
+int RenderObject::scrollTop() const
+{
+ return hasOverflowClip() ? layer()->scrollYOffset() : 0;
+}
+
+void RenderObject::setScrollLeft(int newLeft)
+{
+ if (hasOverflowClip())
+ layer()->scrollToXOffset(newLeft);
+}
+
+void RenderObject::setScrollTop(int newTop)
+{
+ if (hasOverflowClip())
+ layer()->scrollToYOffset(newTop);
+}
+
+bool RenderObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
+{
+ RenderLayer* l = layer();
+ if (l && l->scroll(direction, granularity, multiplier))
+ return true;
+ RenderBlock* b = containingBlock();
+ if (b && !b->isRenderView())
+ return b->scroll(direction, granularity, multiplier);
+ return false;
+}
+
+bool RenderObject::canBeProgramaticallyScrolled(bool) const
+{
+ if (!layer())
+ return false;
+
+ return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))) || (node() && node()->isDocumentNode());
+}
+
+void RenderObject::autoscroll()
+{
+ layer()->autoscroll();
+}
+
+void RenderObject::panScroll(const IntPoint& source)
+{
+ layer()->panScrollFromPoint(source);
+}
+
+bool RenderObject::hasStaticX() const
+{
+ return (style()->left().isAuto() && style()->right().isAuto()) || style()->left().isStatic() || style()->right().isStatic();
+}
+
+bool RenderObject::hasStaticY() const
+{
+ return (style()->top().isAuto() && style()->bottom().isAuto()) || style()->top().isStatic();
+}
+
+void RenderObject::markAllDescendantsWithFloatsForLayout(RenderObject*)
+{
+}
+
+void RenderObject::setPrefWidthsDirty(bool b, bool markParents)
+{
+ bool alreadyDirty = m_prefWidthsDirty;
+ m_prefWidthsDirty = b;
+ if (b && !alreadyDirty && markParents && (isText() || (style()->position() != FixedPosition && style()->position() != AbsolutePosition)))
+ invalidateContainerPrefWidths();
+}
+
+void RenderObject::invalidateContainerPrefWidths()
+{
+ // In order to avoid pathological behavior when inlines are deeply nested, we do include them
+ // in the chain that we mark dirty (even though they're kind of irrelevant).
+ RenderObject* o = isTableCell() ? containingBlock() : container();
+ while (o && !o->m_prefWidthsDirty) {
+ o->m_prefWidthsDirty = true;
+ if (o->style()->position() == FixedPosition || o->style()->position() == AbsolutePosition)
+ // A positioned object has no effect on the min/max width of its containing block ever.
+ // We can optimize this case and not go up any further.
+ break;
+ o = o->isTableCell() ? o->containingBlock() : o->container();
+ }
+}
+
+void RenderObject::setNeedsLayout(bool b, bool markParents)
+{
+ bool alreadyNeededLayout = m_needsLayout;
+ m_needsLayout = b;
+ if (b) {
+ if (!alreadyNeededLayout) {
+ if (markParents)
+ markContainingBlocksForLayout();
+ if (hasLayer())
+ layer()->setNeedsFullRepaint();
+ }
+ } else {
+ m_everHadLayout = true;
+ m_posChildNeedsLayout = false;
+ m_normalChildNeedsLayout = false;
+ m_needsPositionedMovementLayout = false;
+ }
+}
+
+void RenderObject::setChildNeedsLayout(bool b, bool markParents)
+{
+ bool alreadyNeededLayout = m_normalChildNeedsLayout;
+ m_normalChildNeedsLayout = b;
+ if (b) {
+ if (!alreadyNeededLayout && markParents)
+ markContainingBlocksForLayout();
+ } else {
+ m_posChildNeedsLayout = false;
+ m_normalChildNeedsLayout = false;
+ m_needsPositionedMovementLayout = false;
+ }
+}
+
+void RenderObject::setNeedsPositionedMovementLayout()
+{
+ bool alreadyNeededLayout = needsLayout();
+ m_needsPositionedMovementLayout = true;
+ if (!alreadyNeededLayout) {
+ markContainingBlocksForLayout();
+ if (hasLayer())
+ layer()->setNeedsFullRepaint();
+ }
+}
+
+static inline bool objectIsRelayoutBoundary(const RenderObject *obj)
+{
+ // FIXME: In future it may be possible to broaden this condition in order to improve performance.
+ // Table cells are excluded because even when their CSS height is fixed, their height()
+ // may depend on their contents.
+ return obj->isTextField() || obj->isTextArea()
+ || obj->hasOverflowClip() && !obj->style()->width().isIntrinsicOrAuto() && !obj->style()->height().isIntrinsicOrAuto() && !obj->style()->height().isPercent() && !obj->isTableCell()
+#if ENABLE(SVG)
+ || obj->isSVGRoot()
+#endif
+ ;
+}
+
+void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderObject* newRoot)
+{
+ ASSERT(!scheduleRelayout || !newRoot);
+
+ RenderObject* o = container();
+ RenderObject* last = this;
+
+ while (o) {
+ if (!last->isText() && (last->style()->position() == FixedPosition || last->style()->position() == AbsolutePosition)) {
+ if (last->hasStaticY()) {
+ RenderObject* parent = last->parent();
+ if (!parent->normalChildNeedsLayout()) {
+ parent->setChildNeedsLayout(true, false);
+ if (parent != newRoot)
+ parent->markContainingBlocksForLayout(scheduleRelayout, newRoot);
+ }
+ }
+ if (o->m_posChildNeedsLayout)
+ return;
+ o->m_posChildNeedsLayout = true;
+ } else {
+ if (o->m_normalChildNeedsLayout)
+ return;
+ o->m_normalChildNeedsLayout = true;
+ }
+
+ if (o == newRoot)
+ return;
+
+ last = o;
+ if (scheduleRelayout && objectIsRelayoutBoundary(last))
+ break;
+ o = o->container();
+ }
+
+ if (scheduleRelayout)
+ last->scheduleRelayout();
+}
+
+RenderBlock* RenderObject::containingBlock() const
+{
+ if (isTableCell()) {
+ const RenderTableCell* cell = static_cast<const RenderTableCell*>(this);
+ if (parent() && cell->section())
+ return cell->table();
+ return 0;
+ }
+
+ if (isRenderView())
+ return const_cast<RenderBlock*>(static_cast<const RenderBlock*>(this));
+
+ RenderObject* o = parent();
+ if (!isText() && m_style->position() == FixedPosition) {
+ while (o && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock()))
+ o = o->parent();
+ } else if (!isText() && m_style->position() == AbsolutePosition) {
+ while (o && (o->style()->position() == StaticPosition || (o->isInline() && !o->isReplaced())) && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock())) {
+ // For relpositioned inlines, we return the nearest enclosing block. We don't try
+ // to return the inline itself. This allows us to avoid having a positioned objects
+ // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result
+ // from this method. The container() method can actually be used to obtain the
+ // inline directly.
+ if (o->style()->position() == RelativePosition && o->isInline() && !o->isReplaced())
+ return o->containingBlock();
+ o = o->parent();
+ }
+ } else {
+ while (o && ((o->isInline() && !o->isReplaced()) || o->isTableRow() || o->isTableSection()
+ || o->isTableCol() || o->isFrameSet() || o->isMedia()
+#if ENABLE(SVG)
+ || o->isSVGContainer() || o->isSVGRoot()
+#endif
+ ))
+ o = o->parent();
+ }
+
+ if (!o || !o->isRenderBlock())
+ return 0; // Probably doesn't happen any more, but leave just in case. -dwh
+
+ return static_cast<RenderBlock*>(o);
+}
+
+int RenderObject::containingBlockWidth() const
+{
+ // FIXME ?
+ return containingBlock()->availableWidth();
+}
+
+int RenderObject::containingBlockHeight() const
+{
+ // FIXME ?
+ return containingBlock()->contentHeight();
+}
+
+static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer* layer)
+{
+ // Nobody will use multiple layers without wanting fancy positioning.
+ if (layer->next())
+ return true;
+
+ // Make sure we have a valid image.
+ StyleImage* img = layer->image();
+ bool shouldPaintBackgroundImage = img && img->canRender(renderer->style()->effectiveZoom());
+
+ // These are always percents or auto.
+ if (shouldPaintBackgroundImage &&
+ (!layer->xPosition().isZero() || !layer->yPosition().isZero() ||
+ layer->size().width().isPercent() || layer->size().height().isPercent()))
+ // The image will shift unpredictably if the size changes.
+ return true;
+
+ return false;
+}
+
+bool RenderObject::mustRepaintBackgroundOrBorder() const
+{
+ if (hasMask() && mustRepaintFillLayers(this, style()->maskLayers()))
+ return true;
+
+ // If we don't have a background/border/mask, then nothing to do.
+ if (!hasBoxDecorations())
+ return false;
+
+ if (mustRepaintFillLayers(this, style()->backgroundLayers()))
+ return true;
+
+ // Our fill layers are ok. Let's check border.
+ if (style()->hasBorder()) {
+ // Border images are not ok.
+ StyleImage* borderImage = style()->borderImage().image();
+ bool shouldPaintBorderImage = borderImage && borderImage->canRender(style()->effectiveZoom());
+
+ // If the image hasn't loaded, we're still using the normal border style.
+ if (shouldPaintBorderImage && borderImage->isLoaded())
+ return true;
+ }
+
+ return false;
+}
+
+void RenderObject::drawBorderArc(GraphicsContext* graphicsContext, int x, int y, float thickness, IntSize radius,
+ int angleStart, int angleSpan, BorderSide s, Color c, const Color& textColor,
+ EBorderStyle style, bool firstCorner)
+{
+ if ((style == DOUBLE && thickness / 2 < 3) || ((style == RIDGE || style == GROOVE) && thickness / 2 < 2))
+ style = SOLID;
+
+ if (!c.isValid()) {
+ if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE)
+ c.setRGB(238, 238, 238);
+ else
+ c = textColor;
+ }
+
+ switch (style) {
+ case BNONE:
+ case BHIDDEN:
+ return;
+ case DOTTED:
+ case DASHED:
+ graphicsContext->setStrokeColor(c);
+ graphicsContext->setStrokeStyle(style == DOTTED ? DottedStroke : DashedStroke);
+ graphicsContext->setStrokeThickness(thickness);
+ graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan);
+ break;
+ case DOUBLE: {
+ float third = thickness / 3.0f;
+ float innerThird = (thickness + 1.0f) / 6.0f;
+ int shiftForInner = static_cast<int>(innerThird * 2.5f);
+
+ int outerY = y;
+ int outerHeight = radius.height() * 2;
+ int innerX = x + shiftForInner;
+ int innerY = y + shiftForInner;
+ int innerWidth = (radius.width() - shiftForInner) * 2;
+ int innerHeight = (radius.height() - shiftForInner) * 2;
+ if (innerThird > 1 && (s == BSTop || (firstCorner && (s == BSLeft || s == BSRight)))) {
+ outerHeight += 2;
+ innerHeight += 2;
+ }
+
+ graphicsContext->setStrokeStyle(SolidStroke);
+ graphicsContext->setStrokeColor(c);
+ graphicsContext->setStrokeThickness(third);
+ graphicsContext->strokeArc(IntRect(x, outerY, radius.width() * 2, outerHeight), angleStart, angleSpan);
+ graphicsContext->setStrokeThickness(innerThird > 2 ? innerThird - 1 : innerThird);
+ graphicsContext->strokeArc(IntRect(innerX, innerY, innerWidth, innerHeight), angleStart, angleSpan);
+ break;
+ }
+ case GROOVE:
+ case RIDGE: {
+ Color c2;
+ if ((style == RIDGE && (s == BSTop || s == BSLeft)) ||
+ (style == GROOVE && (s == BSBottom || s == BSRight)))
+ c2 = c.dark();
+ else {
+ c2 = c;
+ c = c.dark();
+ }
+
+ graphicsContext->setStrokeStyle(SolidStroke);
+ graphicsContext->setStrokeColor(c);
+ 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->setStrokeThickness(halfThickness > 2 ? halfThickness - 1 : halfThickness);
+ graphicsContext->strokeArc(IntRect(x + shiftForInner, y + shiftForInner, (radius.width() - shiftForInner) * 2,
+ (radius.height() - shiftForInner) * 2), angleStart, angleSpan);
+ break;
+ }
+ case INSET:
+ if (s == BSTop || s == BSLeft)
+ c = c.dark();
+ case OUTSET:
+ if (style == OUTSET && (s == BSBottom || s == BSRight))
+ c = c.dark();
+ case SOLID:
+ graphicsContext->setStrokeStyle(SolidStroke);
+ graphicsContext->setStrokeColor(c);
+ graphicsContext->setStrokeThickness(thickness);
+ graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan);
+ break;
+ }
+}
+
+void RenderObject::drawBorder(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2,
+ BorderSide s, Color c, const Color& textcolor, EBorderStyle style,
+ int adjbw1, int adjbw2)
+{
+ int width = (s == BSTop || s == BSBottom ? y2 - y1 : x2 - x1);
+
+ if (style == DOUBLE && width < 3)
+ style = SOLID;
+
+ if (!c.isValid()) {
+ if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE)
+ c.setRGB(238, 238, 238);
+ else
+ c = textcolor;
+ }
+
+ switch (style) {
+ case BNONE:
+ case BHIDDEN:
+ return;
+ case DOTTED:
+ case DASHED:
+ graphicsContext->setStrokeColor(c);
+ graphicsContext->setStrokeThickness(width);
+ graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke);
+
+ if (width > 0)
+ switch (s) {
+ case BSBottom:
+ case BSTop:
+ graphicsContext->drawLine(IntPoint(x1, (y1 + y2) / 2), IntPoint(x2, (y1 + y2) / 2));
+ break;
+ case BSRight:
+ case BSLeft:
+ graphicsContext->drawLine(IntPoint((x1 + x2) / 2, y1), IntPoint((x1 + x2) / 2, y2));
+ break;
+ }
+ break;
+ case DOUBLE: {
+ int third = (width + 1) / 3;
+
+ if (adjbw1 == 0 && adjbw2 == 0) {
+ graphicsContext->setStrokeStyle(NoStroke);
+ graphicsContext->setFillColor(c);
+ switch (s) {
+ case BSTop:
+ case BSBottom:
+ graphicsContext->drawRect(IntRect(x1, y1, x2 - x1, third));
+ graphicsContext->drawRect(IntRect(x1, y2 - third, x2 - x1, third));
+ break;
+ case BSLeft:
+ graphicsContext->drawRect(IntRect(x1, y1 + 1, third, y2 - y1 - 1));
+ graphicsContext->drawRect(IntRect(x2 - third, y1 + 1, third, y2 - y1 - 1));
+ break;
+ case BSRight:
+ graphicsContext->drawRect(IntRect(x1, y1 + 1, third, y2 - y1 - 1));
+ graphicsContext->drawRect(IntRect(x2 - third, y1 + 1, third, y2 - y1 - 1));
+ break;
+ }
+ } else {
+ int adjbw1bigthird = ((adjbw1 > 0) ? adjbw1 + 1 : adjbw1 - 1) / 3;
+ int adjbw2bigthird = ((adjbw2 > 0) ? adjbw2 + 1 : adjbw2 - 1) / 3;
+
+ switch (s) {
+ case BSTop:
+ drawBorder(graphicsContext, x1 + max((-adjbw1 * 2 + 1) / 3, 0),
+ y1, x2 - max((-adjbw2 * 2 + 1) / 3, 0), y1 + third,
+ s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
+ drawBorder(graphicsContext, x1 + max((adjbw1 * 2 + 1) / 3, 0),
+ y2 - third, x2 - max((adjbw2 * 2 + 1) / 3, 0), y2,
+ s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
+ break;
+ case BSLeft:
+ drawBorder(graphicsContext, x1, y1 + max((-adjbw1 * 2 + 1) / 3, 0),
+ x1 + third, y2 - max((-adjbw2 * 2 + 1) / 3, 0),
+ s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
+ drawBorder(graphicsContext, x2 - third, y1 + max((adjbw1 * 2 + 1) / 3, 0),
+ x2, y2 - max((adjbw2 * 2 + 1) / 3, 0),
+ s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
+ break;
+ case BSBottom:
+ drawBorder(graphicsContext, x1 + max((adjbw1 * 2 + 1) / 3, 0),
+ y1, x2 - max((adjbw2 * 2 + 1) / 3, 0), y1 + third,
+ s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
+ drawBorder(graphicsContext, x1 + max((-adjbw1 * 2 + 1) / 3, 0),
+ y2 - third, x2 - max((-adjbw2 * 2 + 1) / 3, 0), y2,
+ s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
+ break;
+ case BSRight:
+ drawBorder(graphicsContext, x1, y1 + max((adjbw1 * 2 + 1) / 3, 0),
+ x1 + third, y2 - max(( adjbw2 * 2 + 1) / 3, 0),
+ s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
+ drawBorder(graphicsContext, x2 - third, y1 + max((-adjbw1 * 2 + 1) / 3, 0),
+ x2, y2 - max((-adjbw2 * 2 + 1) / 3, 0),
+ s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ case RIDGE:
+ case GROOVE:
+ {
+ EBorderStyle s1;
+ EBorderStyle s2;
+ if (style == GROOVE) {
+ s1 = INSET;
+ s2 = OUTSET;
+ } else {
+ s1 = OUTSET;
+ s2 = INSET;
+ }
+
+ int adjbw1bighalf = ((adjbw1 > 0) ? adjbw1 + 1 : adjbw1 - 1) / 2;
+ int adjbw2bighalf = ((adjbw2 > 0) ? adjbw2 + 1 : adjbw2 - 1) / 2;
+
+ switch (s) {
+ case BSTop:
+ drawBorder(graphicsContext, x1 + max(-adjbw1, 0) / 2, y1, x2 - max(-adjbw2, 0) / 2, (y1 + y2 + 1) / 2,
+ s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
+ drawBorder(graphicsContext, x1 + max(adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(adjbw2 + 1, 0) / 2, y2,
+ s, c, textcolor, s2, adjbw1 / 2, adjbw2 / 2);
+ break;
+ case BSLeft:
+ drawBorder(graphicsContext, x1, y1 + max(-adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(-adjbw2, 0) / 2,
+ s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
+ drawBorder(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(adjbw1 + 1, 0) / 2, x2, y2 - max(adjbw2 + 1, 0) / 2,
+ s, c, textcolor, s2, adjbw1 / 2, adjbw2 / 2);
+ break;
+ case BSBottom:
+ drawBorder(graphicsContext, x1 + max(adjbw1, 0) / 2, y1, x2 - max(adjbw2, 0) / 2, (y1 + y2 + 1) / 2,
+ s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
+ drawBorder(graphicsContext, x1 + max(-adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(-adjbw2 + 1, 0) / 2, y2,
+ s, c, textcolor, s1, adjbw1/2, adjbw2/2);
+ break;
+ case BSRight:
+ drawBorder(graphicsContext, x1, y1 + max(adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(adjbw2, 0) / 2,
+ s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
+ drawBorder(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(-adjbw1 + 1, 0) / 2, x2, y2 - max(-adjbw2 + 1, 0) / 2,
+ s, c, textcolor, s1, adjbw1/2, adjbw2/2);
+ break;
+ }
+ break;
+ }
+ case INSET:
+ if (s == BSTop || s == BSLeft)
+ c = c.dark();
+ // fall through
+ case OUTSET:
+ if (style == OUTSET && (s == BSBottom || s == BSRight))
+ c = c.dark();
+ // fall through
+ case SOLID: {
+ graphicsContext->setStrokeStyle(NoStroke);
+ graphicsContext->setFillColor(c);
+ ASSERT(x2 >= x1);
+ ASSERT(y2 >= y1);
+ if (!adjbw1 && !adjbw2) {
+ graphicsContext->drawRect(IntRect(x1, y1, x2 - x1, y2 - y1));
+ return;
+ }
+ FloatPoint quad[4];
+ switch (s) {
+ case BSTop:
+ quad[0] = FloatPoint(x1 + max(-adjbw1, 0), y1);
+ quad[1] = FloatPoint(x1 + max(adjbw1, 0), y2);
+ quad[2] = FloatPoint(x2 - max(adjbw2, 0), y2);
+ quad[3] = FloatPoint(x2 - max(-adjbw2, 0), y1);
+ break;
+ case BSBottom:
+ quad[0] = FloatPoint(x1 + max(adjbw1, 0), y1);
+ quad[1] = FloatPoint(x1 + max(-adjbw1, 0), y2);
+ quad[2] = FloatPoint(x2 - max(-adjbw2, 0), y2);
+ quad[3] = FloatPoint(x2 - max(adjbw2, 0), y1);
+ break;
+ case BSLeft:
+ quad[0] = FloatPoint(x1, y1 + max(-adjbw1, 0));
+ quad[1] = FloatPoint(x1, y2 - max(-adjbw2, 0));
+ quad[2] = FloatPoint(x2, y2 - max(adjbw2, 0));
+ quad[3] = FloatPoint(x2, y1 + max(adjbw1, 0));
+ break;
+ case BSRight:
+ quad[0] = FloatPoint(x1, y1 + max(adjbw1, 0));
+ quad[1] = FloatPoint(x1, y2 - max(adjbw2, 0));
+ quad[2] = FloatPoint(x2, y2 - max(-adjbw2, 0));
+ quad[3] = FloatPoint(x2, y1 + max(-adjbw1, 0));
+ break;
+ }
+ graphicsContext->drawConvexPolygon(4, quad);
+ break;
+ }
+ }
+}
+
+bool RenderObject::paintNinePieceImage(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, const RenderStyle* style,
+ const NinePieceImage& ninePieceImage, CompositeOperator op)
+{
+ StyleImage* styleImage = ninePieceImage.image();
+ if (!styleImage || !styleImage->canRender(style->effectiveZoom()))
+ return false;
+
+ if (!styleImage->isLoaded())
+ return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either.
+
+ // If we have a border radius, the image gets clipped to the rounded rect.
+ bool clipped = false;
+ if (style->hasBorderRadius()) {
+ IntRect clipRect(tx, ty, w, h);
+ graphicsContext->save();
+ graphicsContext->addRoundedRectClip(clipRect, style->borderTopLeftRadius(), style->borderTopRightRadius(),
+ style->borderBottomLeftRadius(), style->borderBottomRightRadius());
+ clipped = true;
+ }
+
+ // FIXME: border-image is broken with full page zooming when tiling has to happen, since the tiling function
+ // doesn't have any understanding of the zoom that is in effect on the tile.
+ styleImage->setImageContainerSize(IntSize(w, h));
+ IntSize imageSize = styleImage->imageSize(this, 1.0f);
+ int imageWidth = imageSize.width();
+ int imageHeight = imageSize.height();
+
+ int topSlice = min(imageHeight, ninePieceImage.m_slices.top().calcValue(imageHeight));
+ int bottomSlice = min(imageHeight, ninePieceImage.m_slices.bottom().calcValue(imageHeight));
+ int leftSlice = min(imageWidth, ninePieceImage.m_slices.left().calcValue(imageWidth));
+ int rightSlice = min(imageWidth, ninePieceImage.m_slices.right().calcValue(imageWidth));
+
+ ENinePieceImageRule hRule = ninePieceImage.horizontalRule();
+ ENinePieceImageRule vRule = ninePieceImage.verticalRule();
+
+ bool fitToBorder = style->borderImage() == ninePieceImage;
+
+ int leftWidth = fitToBorder ? style->borderLeftWidth() : leftSlice;
+ int topWidth = fitToBorder ? style->borderTopWidth() : topSlice;
+ int rightWidth = fitToBorder ? style->borderRightWidth() : rightSlice;
+ int bottomWidth = fitToBorder ? style->borderBottomWidth() : bottomSlice;
+
+ bool drawLeft = leftSlice > 0 && leftWidth > 0;
+ bool drawTop = topSlice > 0 && topWidth > 0;
+ bool drawRight = rightSlice > 0 && rightWidth > 0;
+ bool drawBottom = bottomSlice > 0 && bottomWidth > 0;
+ bool drawMiddle = (imageWidth - leftSlice - rightSlice) > 0 && (w - leftWidth - rightWidth) > 0 &&
+ (imageHeight - topSlice - bottomSlice) > 0 && (h - topWidth - bottomWidth) > 0;
+
+ Image* image = styleImage->image(this, imageSize);
+
+ if (drawLeft) {
+ // Paint the top and bottom left corners.
+
+ // 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),
+ 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),
+ 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,
+ h - topWidth - bottomWidth),
+ IntRect(0, topSlice, leftSlice, imageHeight - topSlice - bottomSlice),
+ Image::StretchTile, (Image::TileRule)vRule, op);
+ }
+
+ if (drawRight) {
+ // Paint the top and bottom right corners
+ // 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),
+ 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),
+ IntRect(imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice), op);
+
+ // Paint the right edge.
+ graphicsContext->drawTiledImage(image, IntRect(tx + w - rightWidth, ty + topWidth, rightWidth,
+ h - topWidth - bottomWidth),
+ IntRect(imageWidth - rightSlice, topSlice, rightSlice, imageHeight - topSlice - bottomSlice),
+ Image::StretchTile, (Image::TileRule)vRule, op);
+ }
+
+ // Paint the top edge.
+ if (drawTop)
+ graphicsContext->drawTiledImage(image, 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,
+ 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,
+ h - topWidth - bottomWidth),
+ IntRect(leftSlice, topSlice, imageWidth - rightSlice - leftSlice, imageHeight - topSlice - bottomSlice),
+ (Image::TileRule)hRule, (Image::TileRule)vRule, op);
+
+ // Clear the clip for the border radius.
+ if (clipped)
+ graphicsContext->restore();
+
+ return true;
+}
+
+void RenderObject::paintBorder(GraphicsContext* graphicsContext, int tx, int ty, int w, int h,
+ const RenderStyle* style, bool begin, bool end)
+{
+ if (paintNinePieceImage(graphicsContext, tx, ty, w, h, style, style->borderImage()))
+ return;
+
+ const Color& tc = style->borderTopColor();
+ const Color& bc = style->borderBottomColor();
+ const Color& lc = style->borderLeftColor();
+ const Color& rc = style->borderRightColor();
+
+ bool tt = style->borderTopIsTransparent();
+ bool bt = style->borderBottomIsTransparent();
+ bool rt = style->borderRightIsTransparent();
+ bool lt = style->borderLeftIsTransparent();
+
+ EBorderStyle ts = style->borderTopStyle();
+ EBorderStyle bs = style->borderBottomStyle();
+ EBorderStyle ls = style->borderLeftStyle();
+ EBorderStyle rs = style->borderRightStyle();
+
+ bool renderTop = ts > BHIDDEN && !tt;
+ bool renderLeft = ls > BHIDDEN && begin && !lt;
+ bool renderRight = rs > BHIDDEN && end && !rt;
+ bool renderBottom = bs > BHIDDEN && !bt;
+
+ // Need sufficient width and height to contain border radius curves. Sanity check our border radii
+ // and our width/height values to make sure the curves can all fit. If not, then we won't paint
+ // any border radii.
+ bool renderRadii = false;
+ IntSize topLeft = style->borderTopLeftRadius();
+ IntSize topRight = style->borderTopRightRadius();
+ IntSize bottomLeft = style->borderBottomLeftRadius();
+ IntSize bottomRight = style->borderBottomRightRadius();
+
+ if (style->hasBorderRadius() &&
+ static_cast<unsigned>(w) >= static_cast<unsigned>(topLeft.width()) + static_cast<unsigned>(topRight.width()) &&
+ static_cast<unsigned>(w) >= static_cast<unsigned>(bottomLeft.width()) + static_cast<unsigned>(bottomRight.width()) &&
+ static_cast<unsigned>(h) >= static_cast<unsigned>(topLeft.height()) + static_cast<unsigned>(bottomLeft.height()) &&
+ static_cast<unsigned>(h) >= static_cast<unsigned>(topRight.height()) + static_cast<unsigned>(bottomRight.height()))
+ renderRadii = true;
+
+ // Clip to the rounded rectangle.
+ if (renderRadii) {
+ graphicsContext->save();
+ graphicsContext->addRoundedRectClip(IntRect(tx, ty, w, h), topLeft, topRight, bottomLeft, bottomRight);
+ }
+
+ int firstAngleStart, secondAngleStart, firstAngleSpan, secondAngleSpan;
+ float thickness;
+ bool upperLeftBorderStylesMatch = renderLeft && (ts == ls) && (tc == lc);
+ bool upperRightBorderStylesMatch = renderRight && (ts == rs) && (tc == rc) && (ts != OUTSET) && (ts != RIDGE) && (ts != INSET) && (ts != GROOVE);
+ bool lowerLeftBorderStylesMatch = renderLeft && (bs == ls) && (bc == lc) && (bs != OUTSET) && (bs != RIDGE) && (bs != INSET) && (bs != GROOVE);
+ bool lowerRightBorderStylesMatch = renderRight && (bs == rs) && (bc == rc);
+
+ if (renderTop) {
+ bool ignore_left = (renderRadii && topLeft.width() > 0) ||
+ (tc == lc && tt == lt && ts >= OUTSET &&
+ (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
+
+ bool ignore_right = (renderRadii && topRight.width() > 0) ||
+ (tc == rc && tt == rt && ts >= OUTSET &&
+ (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
+
+ int x = tx;
+ int x2 = tx + w;
+ if (renderRadii) {
+ x += topLeft.width();
+ x2 -= topRight.width();
+ }
+
+ drawBorder(graphicsContext, x, ty, x2, ty + style->borderTopWidth(), BSTop, tc, style->color(), ts,
+ ignore_left ? 0 : style->borderLeftWidth(), ignore_right ? 0 : style->borderRightWidth());
+
+ if (renderRadii) {
+ int leftY = ty;
+
+ // We make the arc double thick and let the clip rect take care of clipping the extra off.
+ // We're doing this because it doesn't seem possible to match the curve of the clip exactly
+ // with the arc-drawing function.
+ thickness = style->borderTopWidth() * 2;
+
+ if (topLeft.width()) {
+ int leftX = tx;
+ // The inner clip clips inside the arc. This is especially important for 1px borders.
+ bool applyLeftInnerClip = (style->borderLeftWidth() < topLeft.width())
+ && (style->borderTopWidth() < topLeft.height())
+ && (ts != DOUBLE || style->borderTopWidth() > 6);
+ if (applyLeftInnerClip) {
+ graphicsContext->save();
+ graphicsContext->addInnerRoundedRectClip(IntRect(leftX, leftY, topLeft.width() * 2, topLeft.height() * 2),
+ style->borderTopWidth());
+ }
+
+ firstAngleStart = 90;
+ firstAngleSpan = upperLeftBorderStylesMatch ? 90 : 45;
+
+ // Draw upper left arc
+ drawBorderArc(graphicsContext, leftX, leftY, thickness, topLeft, firstAngleStart, firstAngleSpan,
+ BSTop, tc, style->color(), ts, true);
+ if (applyLeftInnerClip)
+ graphicsContext->restore();
+ }
+
+ if (topRight.width()) {
+ int rightX = tx + w - topRight.width() * 2;
+ bool applyRightInnerClip = (style->borderRightWidth() < topRight.width())
+ && (style->borderTopWidth() < topRight.height())
+ && (ts != DOUBLE || style->borderTopWidth() > 6);
+ if (applyRightInnerClip) {
+ graphicsContext->save();
+ graphicsContext->addInnerRoundedRectClip(IntRect(rightX, leftY, topRight.width() * 2, topRight.height() * 2),
+ style->borderTopWidth());
+ }
+
+ if (upperRightBorderStylesMatch) {
+ secondAngleStart = 0;
+ secondAngleSpan = 90;
+ } else {
+ secondAngleStart = 45;
+ secondAngleSpan = 45;
+ }
+
+ // Draw upper right arc
+ drawBorderArc(graphicsContext, rightX, leftY, thickness, topRight, secondAngleStart, secondAngleSpan,
+ BSTop, tc, style->color(), ts, false);
+ if (applyRightInnerClip)
+ graphicsContext->restore();
+ }
+ }
+ }
+
+ if (renderBottom) {
+ bool ignore_left = (renderRadii && bottomLeft.width() > 0) ||
+ (bc == lc && bt == lt && bs >= OUTSET &&
+ (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
+
+ bool ignore_right = (renderRadii && bottomRight.width() > 0) ||
+ (bc == rc && bt == rt && bs >= OUTSET &&
+ (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
+
+ int x = tx;
+ int x2 = tx + w;
+ if (renderRadii) {
+ x += bottomLeft.width();
+ x2 -= bottomRight.width();
+ }
+
+ drawBorder(graphicsContext, x, ty + h - style->borderBottomWidth(), x2, ty + h, BSBottom, bc, style->color(), bs,
+ ignore_left ? 0 : style->borderLeftWidth(), ignore_right ? 0 : style->borderRightWidth());
+
+ if (renderRadii) {
+ thickness = style->borderBottomWidth() * 2;
+
+ if (bottomLeft.width()) {
+ int leftX = tx;
+ int leftY = ty + h - bottomLeft.height() * 2;
+ bool applyLeftInnerClip = (style->borderLeftWidth() < bottomLeft.width())
+ && (style->borderBottomWidth() < bottomLeft.height())
+ && (bs != DOUBLE || style->borderBottomWidth() > 6);
+ if (applyLeftInnerClip) {
+ graphicsContext->save();
+ graphicsContext->addInnerRoundedRectClip(IntRect(leftX, leftY, bottomLeft.width() * 2, bottomLeft.height() * 2),
+ style->borderBottomWidth());
+ }
+
+ if (lowerLeftBorderStylesMatch) {
+ firstAngleStart = 180;
+ firstAngleSpan = 90;
+ } else {
+ firstAngleStart = 225;
+ firstAngleSpan = 45;
+ }
+
+ // Draw lower left arc
+ drawBorderArc(graphicsContext, leftX, leftY, thickness, bottomLeft, firstAngleStart, firstAngleSpan,
+ BSBottom, bc, style->color(), bs, true);
+ if (applyLeftInnerClip)
+ graphicsContext->restore();
+ }
+
+ if (bottomRight.width()) {
+ int rightY = ty + h - bottomRight.height() * 2;
+ int rightX = tx + w - bottomRight.width() * 2;
+ bool applyRightInnerClip = (style->borderRightWidth() < bottomRight.width())
+ && (style->borderBottomWidth() < bottomRight.height())
+ && (bs != DOUBLE || style->borderBottomWidth() > 6);
+ if (applyRightInnerClip) {
+ graphicsContext->save();
+ graphicsContext->addInnerRoundedRectClip(IntRect(rightX, rightY, bottomRight.width() * 2, bottomRight.height() * 2),
+ style->borderBottomWidth());
+ }
+
+ secondAngleStart = 270;
+ secondAngleSpan = lowerRightBorderStylesMatch ? 90 : 45;
+
+ // Draw lower right arc
+ drawBorderArc(graphicsContext, rightX, rightY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
+ BSBottom, bc, style->color(), bs, false);
+ if (applyRightInnerClip)
+ graphicsContext->restore();
+ }
+ }
+ }
+
+ if (renderLeft) {
+ bool ignore_top = (renderRadii && topLeft.height() > 0) ||
+ (tc == lc && tt == lt && ls >= OUTSET &&
+ (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
+
+ bool ignore_bottom = (renderRadii && bottomLeft.height() > 0) ||
+ (bc == lc && bt == lt && ls >= OUTSET &&
+ (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
+
+ int y = ty;
+ int y2 = ty + h;
+ if (renderRadii) {
+ y += topLeft.height();
+ y2 -= bottomLeft.height();
+ }
+
+ drawBorder(graphicsContext, tx, y, tx + style->borderLeftWidth(), y2, BSLeft, lc, style->color(), ls,
+ ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth());
+
+ if (renderRadii && (!upperLeftBorderStylesMatch || !lowerLeftBorderStylesMatch)) {
+ int topX = tx;
+ thickness = style->borderLeftWidth() * 2;
+
+ if (!upperLeftBorderStylesMatch && topLeft.width()) {
+ int topY = ty;
+ bool applyTopInnerClip = (style->borderLeftWidth() < topLeft.width())
+ && (style->borderTopWidth() < topLeft.height())
+ && (ls != DOUBLE || style->borderLeftWidth() > 6);
+ if (applyTopInnerClip) {
+ graphicsContext->save();
+ graphicsContext->addInnerRoundedRectClip(IntRect(topX, topY, topLeft.width() * 2, topLeft.height() * 2),
+ style->borderLeftWidth());
+ }
+
+ firstAngleStart = 135;
+ firstAngleSpan = 45;
+
+ // Draw top left arc
+ drawBorderArc(graphicsContext, topX, topY, thickness, topLeft, firstAngleStart, firstAngleSpan,
+ BSLeft, lc, style->color(), ls, true);
+ if (applyTopInnerClip)
+ graphicsContext->restore();
+ }
+
+ if (!lowerLeftBorderStylesMatch && bottomLeft.width()) {
+ int bottomY = ty + h - bottomLeft.height() * 2;
+ bool applyBottomInnerClip = (style->borderLeftWidth() < bottomLeft.width())
+ && (style->borderBottomWidth() < bottomLeft.height())
+ && (ls != DOUBLE || style->borderLeftWidth() > 6);
+ if (applyBottomInnerClip) {
+ graphicsContext->save();
+ graphicsContext->addInnerRoundedRectClip(IntRect(topX, bottomY, bottomLeft.width() * 2, bottomLeft.height() * 2),
+ style->borderLeftWidth());
+ }
+
+ secondAngleStart = 180;
+ secondAngleSpan = 45;
+
+ // Draw bottom left arc
+ drawBorderArc(graphicsContext, topX, bottomY, thickness, bottomLeft, secondAngleStart, secondAngleSpan,
+ BSLeft, lc, style->color(), ls, false);
+ if (applyBottomInnerClip)
+ graphicsContext->restore();
+ }
+ }
+ }
+
+ if (renderRight) {
+ bool ignore_top = (renderRadii && topRight.height() > 0) ||
+ ((tc == rc) && (tt == rt) &&
+ (rs >= DOTTED || rs == INSET) &&
+ (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
+
+ bool ignore_bottom = (renderRadii && bottomRight.height() > 0) ||
+ ((bc == rc) && (bt == rt) &&
+ (rs >= DOTTED || rs == INSET) &&
+ (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
+
+ int y = ty;
+ int y2 = ty + h;
+ if (renderRadii) {
+ y += topRight.height();
+ y2 -= bottomRight.height();
+ }
+
+ drawBorder(graphicsContext, tx + w - style->borderRightWidth(), y, tx + w, y2, BSRight, rc, style->color(), rs,
+ ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth());
+
+ if (renderRadii && (!upperRightBorderStylesMatch || !lowerRightBorderStylesMatch)) {
+ thickness = style->borderRightWidth() * 2;
+
+ if (!upperRightBorderStylesMatch && topRight.width()) {
+ int topX = tx + w - topRight.width() * 2;
+ int topY = ty;
+ bool applyTopInnerClip = (style->borderRightWidth() < topRight.width())
+ && (style->borderTopWidth() < topRight.height())
+ && (rs != DOUBLE || style->borderRightWidth() > 6);
+ if (applyTopInnerClip) {
+ graphicsContext->save();
+ graphicsContext->addInnerRoundedRectClip(IntRect(topX, topY, topRight.width() * 2, topRight.height() * 2),
+ style->borderRightWidth());
+ }
+
+ firstAngleStart = 0;
+ firstAngleSpan = 45;
+
+ // Draw top right arc
+ drawBorderArc(graphicsContext, topX, topY, thickness, topRight, firstAngleStart, firstAngleSpan,
+ BSRight, rc, style->color(), rs, true);
+ if (applyTopInnerClip)
+ graphicsContext->restore();
+ }
+
+ if (!lowerRightBorderStylesMatch && bottomRight.width()) {
+ int bottomX = tx + w - bottomRight.width() * 2;
+ int bottomY = ty + h - bottomRight.height() * 2;
+ bool applyBottomInnerClip = (style->borderRightWidth() < bottomRight.width())
+ && (style->borderBottomWidth() < bottomRight.height())
+ && (rs != DOUBLE || style->borderRightWidth() > 6);
+ if (applyBottomInnerClip) {
+ graphicsContext->save();
+ graphicsContext->addInnerRoundedRectClip(IntRect(bottomX, bottomY, bottomRight.width() * 2, bottomRight.height() * 2),
+ style->borderRightWidth());
+ }
+
+ secondAngleStart = 315;
+ secondAngleSpan = 45;
+
+ // Draw bottom right arc
+ drawBorderArc(graphicsContext, bottomX, bottomY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
+ BSRight, rc, style->color(), rs, false);
+ if (applyBottomInnerClip)
+ graphicsContext->restore();
+ }
+ }
+ }
+
+ if (renderRadii)
+ graphicsContext->restore();
+}
+
+void RenderObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, bool begin, bool end)
+{
+ // FIXME: Deal with border-image. Would be great to use border-image as a mask.
+
+ IntRect rect(tx, ty, w, h);
+ bool hasBorderRadius = s->hasBorderRadius();
+ bool hasOpaqueBackground = s->backgroundColor().isValid() && s->backgroundColor().alpha() == 255;
+ for (ShadowData* shadow = s->boxShadow(); shadow; shadow = shadow->next) {
+ context->save();
+
+ IntSize shadowOffset(shadow->x, shadow->y);
+ int shadowBlur = shadow->blur;
+ IntRect fillRect(rect);
+
+ if (hasBorderRadius) {
+ IntRect shadowRect(rect);
+ shadowRect.inflate(shadowBlur);
+ shadowRect.move(shadowOffset);
+ context->clip(shadowRect);
+
+ // Move the fill just outside the clip, adding 1 pixel separation so that the fill does not
+ // bleed in (due to antialiasing) if the context is transformed.
+ IntSize extraOffset(w + max(0, shadowOffset.width()) + shadowBlur + 1, 0);
+ shadowOffset -= extraOffset;
+ fillRect.move(extraOffset);
+ }
+
+ context->setShadow(shadowOffset, shadowBlur, shadow->color);
+ if (hasBorderRadius) {
+ IntSize topLeft = begin ? s->borderTopLeftRadius() : IntSize();
+ IntSize topRight = end ? s->borderTopRightRadius() : IntSize();
+ IntSize bottomLeft = begin ? s->borderBottomLeftRadius() : IntSize();
+ IntSize bottomRight = end ? s->borderBottomRightRadius() : IntSize();
+ if (!hasOpaqueBackground)
+ context->clipOutRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+ context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black);
+ } else {
+ if (!hasOpaqueBackground)
+ context->clipOut(rect);
+ context->fillRect(fillRect, Color::black);
+ }
+ context->restore();
+ }
+}
+
+void RenderObject::addLineBoxRects(Vector<IntRect>&, unsigned, unsigned, bool)
+{
+}
+
+void RenderObject::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel)
+{
+ // 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
+ // shape).
+ if (topLevel && continuation()) {
+ rects.append(IntRect(tx, ty - collapsedMarginTop(),
+ width(), height() + collapsedMarginTop() + collapsedMarginBottom()));
+ continuation()->absoluteRects(rects,
+ tx - xPos() + continuation()->containingBlock()->xPos(),
+ ty - yPos() + continuation()->containingBlock()->yPos(), topLevel);
+ } else
+ rects.append(IntRect(tx, ty, width(), height() + borderTopExtra() + borderBottomExtra()));
+}
+
+IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms)
+{
+ if (useTransforms) {
+ Vector<FloatQuad> quads;
+ absoluteQuads(quads);
+
+ size_t n = quads.size();
+ if (!n)
+ return IntRect();
+
+ IntRect result = quads[0].enclosingBoundingBox();
+ for (size_t i = 1; i < n; ++i)
+ result.unite(quads[i].enclosingBoundingBox());
+ return result;
+ }
+
+ FloatPoint absPos = localToAbsolute();
+ Vector<IntRect> rects;
+ absoluteRects(rects, absPos.x(), absPos.y());
+
+ size_t n = rects.size();
+ if (!n)
+ return IntRect();
+
+ IntRect result = rects[0];
+ for (size_t i = 1; i < n; ++i)
+ result.unite(rects[i]);
+ return result;
+}
+
+void RenderObject::collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned, unsigned, bool)
+{
+}
+
+void RenderObject::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+ // 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
+ // shape).
+ if (topLevel && continuation()) {
+ FloatRect localRect(0, -collapsedMarginTop(),
+ width(), height() + collapsedMarginTop() + collapsedMarginBottom());
+ quads.append(localToAbsoluteQuad(localRect));
+ continuation()->absoluteQuads(quads, topLevel);
+ } else
+ quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height() + borderTopExtra() + borderBottomExtra())));
+}
+
+void RenderObject::addAbsoluteRectForLayer(IntRect& result)
+{
+ if (hasLayer())
+ result.unite(absoluteBoundingBoxRect());
+ for (RenderObject* current = firstChild(); current; current = current->nextSibling())
+ current->addAbsoluteRectForLayer(result);
+}
+
+IntRect RenderObject::paintingRootRect(IntRect& topLevelRect)
+{
+ IntRect result = absoluteBoundingBoxRect();
+ topLevelRect = result;
+ for (RenderObject* current = firstChild(); current; current = current->nextSibling())
+ current->addAbsoluteRectForLayer(result);
+ return result;
+}
+
+void RenderObject::addPDFURLRect(GraphicsContext* context, const IntRect& rect)
+{
+ if (rect.isEmpty())
+ return;
+ Node* node = element();
+ if (!node || !node->isLink() || !node->isElementNode())
+ return;
+ const AtomicString& href = static_cast<Element*>(node)->getAttribute(hrefAttr);
+ if (href.isNull())
+ return;
+ context->setURLForRect(node->document()->completeURL(href), rect);
+}
+
+
+void RenderObject::addFocusRingRects(GraphicsContext* graphicsContext, 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
+ // shape).
+ if (continuation()) {
+ graphicsContext->addFocusRingRect(IntRect(tx, ty - collapsedMarginTop(), width(), height() + collapsedMarginTop() + collapsedMarginBottom()));
+ continuation()->addFocusRingRects(graphicsContext,
+ tx - xPos() + continuation()->containingBlock()->xPos(),
+ ty - yPos() + continuation()->containingBlock()->yPos());
+ } else
+ graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
+}
+
+void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, const RenderStyle* style)
+{
+ if (!hasOutline())
+ return;
+
+ int ow = style->outlineWidth();
+
+ EBorderStyle os = style->outlineStyle();
+
+ Color oc = style->outlineColor();
+ if (!oc.isValid())
+ oc = style->color();
+
+ int offset = style->outlineOffset();
+
+ 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);
+ if (style->outlineStyleIsAuto())
+ addFocusRingRects(graphicsContext, tx, ty);
+ else
+ addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect());
+ graphicsContext->drawFocusRing(oc);
+ graphicsContext->clearFocusRing();
+ }
+ }
+
+ if (style->outlineStyleIsAuto() || style->outlineStyle() == BNONE)
+ return;
+
+ tx -= offset;
+ ty -= offset;
+ w += 2 * offset;
+ h += 2 * offset;
+
+ if (h < 0 || w < 0)
+ return;
+
+ drawBorder(graphicsContext, tx - ow, ty - ow, tx, ty + h + ow,
+ BSLeft, Color(oc), style->color(), os, ow, ow);
+
+ drawBorder(graphicsContext, tx - ow, ty - ow, tx + w + ow, ty,
+ BSTop, Color(oc), style->color(), os, ow, ow);
+
+ drawBorder(graphicsContext, tx + w, ty - ow, tx + w + ow, ty + h + ow,
+ BSRight, Color(oc), style->color(), os, ow, ow);
+
+ drawBorder(graphicsContext, tx - ow, ty + h, tx + w + ow, ty + h + ow,
+ BSBottom, Color(oc), style->color(), os, ow, ow);
+}
+
+void RenderObject::paint(PaintInfo& /*paintInfo*/, int /*tx*/, int /*ty*/)
+{
+}
+
+void RenderObject::repaint(bool immediate)
+{
+ // Can't use view(), since we might be unrooted.
+ RenderObject* o = this;
+ while (o->parent())
+ o = o->parent();
+ if (!o->isRenderView())
+ return;
+ RenderView* view = static_cast<RenderView*>(o);
+ if (view->printing())
+ return; // Don't repaint if we're printing.
+ view->repaintViewRectangle(absoluteClippedOverflowRect(), immediate);
+}
+
+void RenderObject::repaintRectangle(const IntRect& r, bool immediate)
+{
+ // Can't use view(), since we might be unrooted.
+ RenderObject* o = this;
+ while (o->parent())
+ o = o->parent();
+ if (!o->isRenderView())
+ return;
+ RenderView* view = static_cast<RenderView*>(o);
+ if (view->printing())
+ return; // Don't repaint if we're printing.
+ IntRect absRect(r);
+ absRect.move(view->layoutDelta());
+ computeAbsoluteRepaintRect(absRect);
+ view->repaintViewRectangle(absRect, immediate);
+}
+
+bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const IntRect& oldOutlineBox)
+{
+ RenderView* v = view();
+ if (v->printing())
+ return false; // Don't repaint if we're printing.
+
+ IntRect newBounds = absoluteClippedOverflowRect();
+ IntRect newOutlineBox;
+
+ bool fullRepaint = selfNeedsLayout();
+ // Presumably a background or a border exists if border-fit:lines was specified.
+ if (!fullRepaint && style()->borderFit() == BorderFitLines)
+ fullRepaint = true;
+ if (!fullRepaint) {
+ newOutlineBox = absoluteOutlineBounds();
+ if (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder() && (newBounds != oldBounds || newOutlineBox != oldOutlineBox)))
+ fullRepaint = true;
+ }
+ if (fullRepaint) {
+ v->repaintViewRectangle(oldBounds);
+ if (newBounds != oldBounds)
+ v->repaintViewRectangle(newBounds);
+ return true;
+ }
+
+ if (newBounds == oldBounds && newOutlineBox == oldOutlineBox)
+ return false;
+
+ int deltaLeft = newBounds.x() - oldBounds.x();
+ if (deltaLeft > 0)
+ v->repaintViewRectangle(IntRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height()));
+ else if (deltaLeft < 0)
+ v->repaintViewRectangle(IntRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height()));
+
+ int deltaRight = newBounds.right() - oldBounds.right();
+ if (deltaRight > 0)
+ v->repaintViewRectangle(IntRect(oldBounds.right(), newBounds.y(), deltaRight, newBounds.height()));
+ else if (deltaRight < 0)
+ v->repaintViewRectangle(IntRect(newBounds.right(), oldBounds.y(), -deltaRight, oldBounds.height()));
+
+ int deltaTop = newBounds.y() - oldBounds.y();
+ if (deltaTop > 0)
+ v->repaintViewRectangle(IntRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop));
+ else if (deltaTop < 0)
+ v->repaintViewRectangle(IntRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop));
+
+ int deltaBottom = newBounds.bottom() - oldBounds.bottom();
+ if (deltaBottom > 0)
+ v->repaintViewRectangle(IntRect(newBounds.x(), oldBounds.bottom(), newBounds.width(), deltaBottom));
+ else if (deltaBottom < 0)
+ v->repaintViewRectangle(IntRect(oldBounds.x(), newBounds.bottom(), oldBounds.width(), -deltaBottom));
+
+ if (newOutlineBox == oldOutlineBox)
+ return false;
+
+ // We didn't move, but we did change size. Invalidate the delta, which will consist of possibly
+ // two rectangles (but typically only one).
+ RenderStyle* outlineStyle = !isInline() && continuation() ? continuation()->style() : style();
+ int ow = outlineStyle->outlineSize();
+ ShadowData* boxShadow = style()->boxShadow();
+ int width = abs(newOutlineBox.width() - oldOutlineBox.width());
+ if (width) {
+ int shadowRight = 0;
+ for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next)
+ shadowRight = max(shadow->x + shadow->blur, shadowRight);
+
+ int borderWidth = max(-outlineStyle->outlineOffset(), max(borderRight(), max(style()->borderTopRightRadius().width(), style()->borderBottomRightRadius().width()))) + max(ow, shadowRight);
+ IntRect rightRect(newOutlineBox.x() + min(newOutlineBox.width(), oldOutlineBox.width()) - borderWidth,
+ newOutlineBox.y(),
+ width + borderWidth,
+ max(newOutlineBox.height(), oldOutlineBox.height()));
+ int right = min(newBounds.right(), oldBounds.right());
+ if (rightRect.x() < right) {
+ rightRect.setWidth(min(rightRect.width(), right - rightRect.x()));
+ v->repaintViewRectangle(rightRect);
+ }
+ }
+ int height = abs(newOutlineBox.height() - oldOutlineBox.height());
+ if (height) {
+ int shadowBottom = 0;
+ for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next)
+ shadowBottom = max(shadow->y + shadow->blur, shadowBottom);
+
+ int borderHeight = max(-outlineStyle->outlineOffset(), max(borderBottom(), max(style()->borderBottomLeftRadius().height(), style()->borderBottomRightRadius().height()))) + max(ow, shadowBottom);
+ IntRect bottomRect(newOutlineBox.x(),
+ min(newOutlineBox.bottom(), oldOutlineBox.bottom()) - borderHeight,
+ max(newOutlineBox.width(), oldOutlineBox.width()),
+ height + borderHeight);
+ int bottom = min(newBounds.bottom(), oldBounds.bottom());
+ if (bottomRect.y() < bottom) {
+ bottomRect.setHeight(min(bottomRect.height(), bottom - bottomRect.y()));
+ v->repaintViewRectangle(bottomRect);
+ }
+ }
+ return false;
+}
+
+void RenderObject::repaintDuringLayoutIfMoved(const IntRect&)
+{
+}
+
+void RenderObject::repaintOverhangingFloats(bool)
+{
+}
+
+bool RenderObject::checkForRepaintDuringLayout() const
+{
+ // FIXME: <https://bugs.webkit.org/show_bug.cgi?id=20885> It is probably safe to also require
+ // m_everHadLayout. Currently, only RenderBlock::layoutBlock() adds this condition. See also
+ // <https://bugs.webkit.org/show_bug.cgi?id=15129>.
+ return !document()->view()->needsFullRepaint() && !hasLayer();
+}
+
+IntRect RenderObject::getAbsoluteRepaintRectWithOutline(int ow)
+{
+ IntRect r(absoluteClippedOverflowRect());
+ r.inflate(ow);
+
+ if (continuation() && !isInline())
+ r.inflateY(collapsedMarginTop());
+
+ if (isInlineFlow()) {
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+ if (!curr->isText())
+ r.unite(curr->getAbsoluteRepaintRectWithOutline(ow));
+ }
+ }
+
+ return r;
+}
+
+IntRect RenderObject::absoluteClippedOverflowRect()
+{
+ if (parent())
+ return parent()->absoluteClippedOverflowRect();
+ return IntRect();
+}
+
+void RenderObject::computeAbsoluteRepaintRect(IntRect& rect, bool fixed)
+{
+ if (RenderObject* o = parent()) {
+ if (o->isBlockFlow()) {
+ RenderBlock* cb = static_cast<RenderBlock*>(o);
+ if (cb->hasColumns())
+ cb->adjustRectForColumns(rect);
+ }
+
+ if (o->hasOverflowClip()) {
+ // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
+ // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
+ // anyway if its size does change.
+ IntRect boxRect(0, 0, o->layer()->width(), o->layer()->height());
+ int x = rect.x();
+ int y = rect.y();
+ o->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden.
+ IntRect repaintRect(x, y, rect.width(), rect.height());
+ rect = intersection(repaintRect, boxRect);
+ if (rect.isEmpty())
+ return;
+ }
+
+ o->computeAbsoluteRepaintRect(rect, fixed);
+ }
+}
+
+void RenderObject::dirtyLinesFromChangedChild(RenderObject*)
+{
+}
+
+#ifndef NDEBUG
+
+void RenderObject::showTreeForThis() const
+{
+ if (element())
+ element()->showTreeForThis();
+}
+
+#endif // NDEBUG
+
+Color RenderObject::selectionBackgroundColor() const
+{
+ Color color;
+ if (style()->userSelect() != SELECT_NONE) {
+ RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::SELECTION);
+ if (pseudoStyle && pseudoStyle->backgroundColor().isValid())
+ color = pseudoStyle->backgroundColor().blendWithWhite();
+ else
+ color = document()->frame()->selection()->isFocusedAndActive() ?
+ theme()->activeSelectionBackgroundColor() :
+ theme()->inactiveSelectionBackgroundColor();
+ }
+
+ return color;
+}
+
+Color RenderObject::selectionForegroundColor() const
+{
+ Color color;
+ if (style()->userSelect() == SELECT_NONE)
+ return color;
+
+ if (RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::SELECTION)) {
+ color = pseudoStyle->textFillColor();
+ if (!color.isValid())
+ color = pseudoStyle->color();
+ } else
+ color = document()->frame()->selection()->isFocusedAndActive() ?
+ theme()->platformActiveSelectionForegroundColor() :
+ theme()->platformInactiveSelectionForegroundColor();
+
+ return color;
+}
+
+Node* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
+{
+ if (!dhtmlOK && !uaOK)
+ return 0;
+
+ for (const RenderObject* curr = this; curr; curr = curr->parent()) {
+ Node* elt = curr->element();
+ if (elt && elt->nodeType() == Node::TEXT_NODE) {
+ // Since there's no way for the author to address the -webkit-user-drag style for a text node,
+ // we use our own judgement.
+ if (uaOK && view()->frameView()->frame()->eventHandler()->shouldDragAutoNode(curr->node(), IntPoint(x, y))) {
+ dhtmlWillDrag = false;
+ return curr->node();
+ }
+ if (elt->canStartSelection())
+ // In this case we have a click in the unselected portion of text. If this text is
+ // selectable, we want to start the selection process instead of looking for a parent
+ // to try to drag.
+ return 0;
+ } else {
+ EUserDrag dragMode = curr->style()->userDrag();
+ if (dhtmlOK && dragMode == DRAG_ELEMENT) {
+ dhtmlWillDrag = true;
+ return curr->node();
+ }
+ if (uaOK && dragMode == DRAG_AUTO
+ && view()->frameView()->frame()->eventHandler()->shouldDragAutoNode(curr->node(), IntPoint(x, y))) {
+ dhtmlWillDrag = false;
+ return curr->node();
+ }
+ }
+ }
+ return 0;
+}
+
+void RenderObject::selectionStartEnd(int& spos, int& epos) const
+{
+ view()->selectionStartEnd(spos, epos);
+}
+
+RenderBlock* RenderObject::createAnonymousBlock()
+{
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(m_style.get());
+ newStyle->setDisplay(BLOCK);
+
+ RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
+ newBox->setStyle(newStyle.release());
+ return newBox;
+}
+
+void RenderObject::handleDynamicFloatPositionChange()
+{
+ // We have gone from not affecting the inline status of the parent flow to suddenly
+ // having an impact. See if there is a mismatch between the parent flow's
+ // childrenInline() state and our state.
+ setInline(style()->isDisplayInlineType());
+ if (isInline() != parent()->childrenInline()) {
+ if (!isInline()) {
+ if (parent()->isRenderInline()) {
+ // We have to split the parent flow.
+ RenderInline* parentInline = static_cast<RenderInline*>(parent());
+ RenderBlock* newBox = parentInline->createAnonymousBlock();
+
+ RenderFlow* oldContinuation = parent()->continuation();
+ parentInline->setContinuation(newBox);
+
+ RenderObject* beforeChild = nextSibling();
+ parent()->removeChildNode(this);
+ parentInline->splitFlow(beforeChild, newBox, this, oldContinuation);
+ } else if (parent()->isRenderBlock()) {
+ RenderBlock* o = static_cast<RenderBlock*>(parent());
+ o->makeChildrenNonInline();
+ if (o->isAnonymousBlock() && o->parent())
+ o->parent()->removeLeftoverAnonymousBlock(o);
+ // o may be dead here
+ }
+ } else {
+ // An anonymous block must be made to wrap this inline.
+ RenderBlock* box = createAnonymousBlock();
+ parent()->insertChildNode(box, this);
+ box->appendChildNode(parent()->removeChildNode(this));
+ }
+ }
+}
+
+void RenderObject::setAnimatableStyle(PassRefPtr<RenderStyle> style)
+{
+ if (!isText() && style)
+ setStyle(animation()->updateAnimations(this, style.get()));
+ else
+ setStyle(style);
+}
+
+void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
+{
+ if (m_style == style)
+ return;
+
+ RenderStyle::Diff diff = RenderStyle::Equal;
+ if (m_style)
+ diff = m_style->diff(style.get());
+
+ // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint.
+ if (diff == RenderStyle::RepaintLayer && !hasLayer())
+ diff = RenderStyle::Repaint;
+
+ styleWillChange(diff, style.get());
+
+ RefPtr<RenderStyle> oldStyle = m_style.release();
+ m_style = style;
+
+ updateFillImages(oldStyle ? oldStyle->backgroundLayers() : 0, m_style ? m_style->backgroundLayers() : 0);
+ updateFillImages(oldStyle ? oldStyle->maskLayers() : 0, m_style ? m_style->maskLayers() : 0);
+
+ updateImage(oldStyle ? oldStyle->borderImage().image() : 0, m_style ? m_style->borderImage().image() : 0);
+ updateImage(oldStyle ? oldStyle->maskBoxImage().image() : 0, m_style ? m_style->maskBoxImage().image() : 0);
+
+ styleDidChange(diff, oldStyle.get());
+}
+
+void RenderObject::setStyleInternal(PassRefPtr<RenderStyle> style)
+{
+ m_style = style;
+}
+
+void RenderObject::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
+{
+ if (m_style) {
+ // If our z-index changes value or our visibility changes,
+ // we need to dirty our stacking context's z-order list.
+ if (newStyle) {
+#if ENABLE(DASHBOARD_SUPPORT)
+ if (m_style->visibility() != newStyle->visibility() ||
+ m_style->zIndex() != newStyle->zIndex() ||
+ m_style->hasAutoZIndex() != newStyle->hasAutoZIndex())
+ document()->setDashboardRegionsDirty(true);
+#endif
+
+ if ((m_style->hasAutoZIndex() != newStyle->hasAutoZIndex() ||
+ m_style->zIndex() != newStyle->zIndex() ||
+ m_style->visibility() != newStyle->visibility()) && hasLayer()) {
+ layer()->dirtyStackingContextZOrderLists();
+ if (m_style->hasAutoZIndex() != newStyle->hasAutoZIndex() ||
+ m_style->visibility() != newStyle->visibility())
+ layer()->dirtyZOrderLists();
+ }
+ // keep layer hierarchy visibility bits up to date if visibility changes
+ if (m_style->visibility() != newStyle->visibility()) {
+ if (RenderLayer* l = enclosingLayer()) {
+ if (newStyle->visibility() == VISIBLE)
+ l->setHasVisibleContent(true);
+ else if (l->hasVisibleContent() && (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE)) {
+ l->dirtyVisibleContentStatus();
+ if (diff > RenderStyle::RepaintLayer)
+ repaint();
+ }
+ }
+ }
+ }
+
+ // The background of the root element or the body element could propagate up to
+ // the canvas. Just dirty the entire canvas when our style changes substantially.
+ if (diff >= RenderStyle::Repaint && element() &&
+ (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag)))
+ view()->repaint();
+ else if (m_parent && !isText()) {
+ // Do a repaint with the old style first, e.g., for example if we go from
+ // having an outline to not having an outline.
+ if (diff == RenderStyle::RepaintLayer) {
+ layer()->repaintIncludingDescendants();
+ if (!(m_style->clip() == newStyle->clip()))
+ layer()->clearClipRectsIncludingDescendants();
+ } else if (diff == RenderStyle::Repaint || newStyle->outlineSize() < m_style->outlineSize())
+ repaint();
+ }
+
+ if (diff == RenderStyle::Layout) {
+ // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could
+ // end up being destroyed.
+ if (hasLayer()) {
+ if (m_style->position() != newStyle->position() ||
+ m_style->zIndex() != newStyle->zIndex() ||
+ m_style->hasAutoZIndex() != newStyle->hasAutoZIndex() ||
+ !(m_style->clip() == newStyle->clip()) ||
+ m_style->hasClip() != newStyle->hasClip() ||
+ m_style->opacity() != newStyle->opacity() ||
+ m_style->transform() != newStyle->transform())
+ layer()->repaintIncludingDescendants();
+ } else if (newStyle->hasTransform() || newStyle->opacity() < 1) {
+ // If we don't have a layer yet, but we are going to get one because of transform or opacity,
+ // then we need to repaint the old position of the object.
+ repaint();
+ }
+ }
+
+ // When a layout hint happens and an object's position style changes, we have to do a layout
+ // to dirty the render tree using the old position value now.
+ if (diff == RenderStyle::Layout && m_parent && m_style->position() != newStyle->position()) {
+ markContainingBlocksForLayout();
+ if (m_style->position() == StaticPosition)
+ repaint();
+ if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
+ removeFromObjectLists();
+ if (isRenderBlock()) {
+ if (newStyle->position() == StaticPosition)
+ // Clear our positioned objects list. Our absolutely positioned descendants will be
+ // inserted into our containing block's positioned objects list during layout.
+ removePositionedObjects(0);
+ else if (m_style->position() == StaticPosition) {
+ // Remove our absolutely positioned descendants from their current containing block.
+ // They will be inserted into our positioned objects list during layout.
+ RenderObject* cb = parent();
+ while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
+ if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
+ cb = cb->containingBlock();
+ break;
+ }
+ cb = cb->parent();
+ }
+ cb->removePositionedObjects(static_cast<RenderBlock*>(this));
+ }
+ }
+ }
+
+ if (isFloating() && (m_style->floating() != newStyle->floating()))
+ // For changes in float styles, we need to conceivably remove ourselves
+ // from the floating objects list.
+ removeFromObjectLists();
+ else if (isPositioned() && (newStyle->position() != AbsolutePosition && newStyle->position() != FixedPosition))
+ // For changes in positioning styles, we need to conceivably remove ourselves
+ // from the positioned objects list.
+ removeFromObjectLists();
+
+ s_affectsParentBlock = isFloatingOrPositioned() &&
+ (!newStyle->isFloating() && newStyle->position() != AbsolutePosition && newStyle->position() != FixedPosition)
+ && parent() && (parent()->isBlockFlow() || parent()->isInlineFlow());
+
+ // reset style flags
+ if (diff == RenderStyle::Layout || diff == RenderStyle::LayoutPositionedMovementOnly) {
+ m_floating = false;
+ m_positioned = false;
+ m_relPositioned = false;
+ }
+ m_paintBackground = false;
+ m_hasOverflowClip = false;
+ m_hasTransform = false;
+ m_hasReflection = false;
+ } else
+ s_affectsParentBlock = false;
+
+ 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());
+ if (oldStyleSlowScroll != newStyleSlowScroll) {
+ if (oldStyleSlowScroll)
+ view()->frameView()->removeSlowRepaintObject();
+ if (newStyleSlowScroll)
+ view()->frameView()->addSlowRepaintObject();
+ }
+ }
+}
+
+void RenderObject::styleDidChange(RenderStyle::Diff diff, const RenderStyle*)
+{
+ setHasBoxDecorations(m_style->hasBorder() || m_style->hasBackground() || m_style->hasAppearance() || m_style->boxShadow());
+
+ if (s_affectsParentBlock)
+ handleDynamicFloatPositionChange();
+
+ // No need to ever schedule repaints from a style change of a text run, since
+ // we already did this for the parent of the text run.
+ // We do have to schedule layouts, though, since a style change can force us to
+ // need to relayout.
+ if (diff == RenderStyle::Layout && m_parent)
+ setNeedsLayoutAndPrefWidthsRecalc();
+ else if (diff == RenderStyle::LayoutPositionedMovementOnly && m_parent && !isText())
+ setNeedsPositionedMovementLayout();
+ else if (m_parent && !isText() && (diff == RenderStyle::RepaintLayer || diff == RenderStyle::Repaint))
+ // Do a repaint with the new style now, e.g., for example if we go from
+ // not having an outline to having an outline.
+ repaint();
+}
+
+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);
+ }
+ for (const FillLayer* currNew = newLayers; currNew; currNew = currNew->next()) {
+ if (currNew->image() && (!oldLayers || !oldLayers->containsImage(currNew->image())))
+ currNew->image()->addClient(this);
+ }
+}
+
+void RenderObject::updateImage(StyleImage* oldImage, StyleImage* newImage)
+{
+ if (oldImage != newImage) {
+ if (oldImage)
+ oldImage->removeClient(this);
+ if (newImage)
+ newImage->addClient(this);
+ }
+}
+
+IntRect RenderObject::viewRect() const
+{
+ return view()->viewRect();
+}
+
+FloatPoint RenderObject::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const
+{
+ RenderObject* o = parent();
+ if (o) {
+ localPoint.move(0.0f, static_cast<float>(o->borderTopExtra()));
+ if (o->hasOverflowClip())
+ localPoint -= o->layer()->scrolledContentOffset();
+ return o->localToAbsolute(localPoint, fixed, useTransforms);
+ }
+
+ return FloatPoint();
+}
+
+FloatPoint RenderObject::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const
+{
+ RenderObject* o = parent();
+ if (o) {
+ FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms);
+ localPoint.move(0.0f, -static_cast<float>(o->borderTopExtra()));
+ if (o->hasOverflowClip())
+ localPoint += o->layer()->scrolledContentOffset();
+ return localPoint;
+ }
+ return FloatPoint();
+}
+
+FloatQuad RenderObject::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const
+{
+ RenderObject* o = parent();
+ if (o) {
+ FloatQuad quad = localQuad;
+ quad.move(0.0f, static_cast<float>(o->borderTopExtra()));
+ if (o->hasOverflowClip())
+ quad -= o->layer()->scrolledContentOffset();
+ return o->localToAbsoluteQuad(quad, fixed);
+ }
+
+ return FloatQuad();
+}
+
+IntSize RenderObject::offsetFromContainer(RenderObject* o) const
+{
+ ASSERT(o == container());
+
+ IntSize offset;
+ offset.expand(0, o->borderTopExtra());
+
+ if (o->hasOverflowClip())
+ offset -= o->layer()->scrolledContentOffset();
+
+ return offset;
+}
+
+IntRect RenderObject::localCaretRect(InlineBox*, int, int* extraWidthToEndOfLine)
+{
+ if (extraWidthToEndOfLine)
+ *extraWidthToEndOfLine = 0;
+
+ return IntRect();
+}
+
+int RenderObject::paddingTop() const
+{
+ int w = 0;
+ Length padding = m_style->paddingTop();
+ if (padding.isPercent())
+ w = containingBlock()->availableWidth();
+ return padding.calcMinValue(w);
+}
+
+int RenderObject::paddingBottom() const
+{
+ int w = 0;
+ Length padding = style()->paddingBottom();
+ if (padding.isPercent())
+ w = containingBlock()->availableWidth();
+ return padding.calcMinValue(w);
+}
+
+int RenderObject::paddingLeft() const
+{
+ int w = 0;
+ Length padding = style()->paddingLeft();
+ if (padding.isPercent())
+ w = containingBlock()->availableWidth();
+ return padding.calcMinValue(w);
+}
+
+int RenderObject::paddingRight() const
+{
+ int w = 0;
+ Length padding = style()->paddingRight();
+ if (padding.isPercent())
+ w = containingBlock()->availableWidth();
+ return padding.calcMinValue(w);
+}
+
+RenderView* RenderObject::view() const
+{
+ return static_cast<RenderView*>(document()->renderer());
+}
+
+bool RenderObject::hasOutlineAnnotation() const
+{
+ return element() && element()->isLink() && document()->printing();
+}
+
+RenderObject* RenderObject::container() const
+{
+ // 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
+ // the object is not part of the primary document subtree yet.
+ // (2) For normal flow elements, it just returns the parent.
+ // (3) For absolute positioned elements, it will return a relative positioned inline.
+ // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
+ // the layout of the positioned object. This does mean that calcAbsoluteHorizontal and
+ // calcAbsoluteVertical have to use container().
+ RenderObject* o = parent();
+
+ if (isText())
+ return o;
+
+ EPosition pos = m_style->position();
+ if (pos == FixedPosition) {
+ // container() can be called on an object that is not in the
+ // tree yet. We don't call view() since it will assert if it
+ // can't get back to the canvas. Instead we just walk as high up
+ // as we can. If we're in the tree, we'll get the root. If we
+ // aren't we'll get the root of our little subtree (most likely
+ // we'll just return 0).
+ while (o && o->parent() && !(o->hasTransform() && o->isRenderBlock()))
+ 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()))
+ o = o->parent();
+ }
+
+ return o;
+}
+
+// This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
+// content (and perhaps XBL). That's why it uses the render tree and not the DOM tree.
+RenderObject* RenderObject::hoverAncestor() const
+{
+ return (!isInline() && continuation()) ? continuation() : parent();
+}
+
+bool RenderObject::isSelectionBorder() const
+{
+ SelectionState st = selectionState();
+ return st == SelectionStart || st == SelectionEnd || st == SelectionBoth;
+}
+
+void RenderObject::removeFromObjectLists()
+{
+ if (documentBeingDestroyed())
+ return;
+
+ if (isFloating()) {
+ RenderBlock* outermostBlock = containingBlock();
+ for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) {
+ if (p->containsFloat(this))
+ outermostBlock = p;
+ }
+
+ if (outermostBlock)
+ outermostBlock->markAllDescendantsWithFloatsForLayout(this);
+ }
+
+ if (isPositioned()) {
+ RenderObject* p;
+ for (p = parent(); p; p = p->parent()) {
+ if (p->isRenderBlock())
+ static_cast<RenderBlock*>(p)->removePositionedObject(this);
+ }
+ }
+}
+
+bool RenderObject::documentBeingDestroyed() const
+{
+ return !document()->renderer();
+}
+
+void RenderObject::destroy()
+{
+ // If this renderer is being autoscrolled, stop the autoscroll timer
+ if (document()->frame() && document()->frame()->eventHandler()->autoscrollRenderer() == this)
+ document()->frame()->eventHandler()->stopAutoscrollTimer(true);
+
+ if (m_hasCounterNodeMap)
+ RenderCounter::destroyCounterNodes(this);
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->remove(this);
+
+ animation()->cancelAnimations(this);
+
+ // By default no ref-counting. RenderWidget::destroy() doesn't call
+ // this function because it needs to do ref-counting. If anything
+ // in this function changes, be sure to fix RenderWidget::destroy() as well.
+
+ remove();
+
+ RenderArena* arena = renderArena();
+
+ if (hasLayer())
+ layer()->destroy(arena);
+
+ arenaDelete(arena, this);
+}
+
+void RenderObject::arenaDelete(RenderArena* arena, void* base)
+{
+ if (m_style) {
+ for (const FillLayer* bgLayer = m_style->backgroundLayers(); bgLayer; bgLayer = bgLayer->next()) {
+ if (StyleImage* backgroundImage = bgLayer->image())
+ backgroundImage->removeClient(this);
+ }
+
+ for (const FillLayer* maskLayer = m_style->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
+ if (StyleImage* maskImage = maskLayer->image())
+ maskImage->removeClient(this);
+ }
+
+ if (StyleImage* borderImage = m_style->borderImage().image())
+ borderImage->removeClient(this);
+
+ if (StyleImage* maskBoxImage = m_style->maskBoxImage().image())
+ maskBoxImage->removeClient(this);
+ }
+
+#ifndef NDEBUG
+ void* savedBase = baseOfRenderObjectBeingDeleted;
+ baseOfRenderObjectBeingDeleted = base;
+#endif
+ delete this;
+#ifndef NDEBUG
+ baseOfRenderObjectBeingDeleted = savedBase;
+#endif
+
+ // Recover the size left there for us by operator delete and free the memory.
+ arena->free(*(size_t*)base, base);
+}
+
+VisiblePosition RenderObject::positionForCoordinates(int, int)
+{
+ return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM);
+}
+
+void RenderObject::updateDragState(bool dragOn)
+{
+ bool valueChanged = (dragOn != m_isDragging);
+ m_isDragging = dragOn;
+ if (valueChanged && style()->affectedByDragRules())
+ element()->setChanged();
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
+ curr->updateDragState(dragOn);
+ if (continuation())
+ continuation()->updateDragState(dragOn);
+}
+
+bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const IntPoint& point, int tx, int ty, HitTestFilter hitTestFilter)
+{
+ bool inside = false;
+ if (hitTestFilter != HitTestSelf) {
+ // First test the foreground layer (lines and inlines).
+ inside = nodeAtPoint(request, result, point.x(), point.y(), tx, ty, HitTestForeground);
+
+ // Test floats next.
+ if (!inside)
+ inside = nodeAtPoint(request, result, point.x(), point.y(), tx, ty, HitTestFloat);
+
+ // Finally test to see if the mouse is in the background (within a child block's background).
+ if (!inside)
+ inside = nodeAtPoint(request, result, point.x(), point.y(), tx, ty, HitTestChildBlockBackgrounds);
+ }
+
+ // See if the mouse is inside us but not any of our descendants
+ if (hitTestFilter != HitTestDescendants && !inside)
+ inside = nodeAtPoint(request, result, point.x(), point.y(), tx, ty, HitTestBlockBackground);
+
+ return inside;
+}
+
+void RenderObject::updateHitTestResult(HitTestResult& result, const IntPoint& point)
+{
+ if (result.innerNode())
+ return;
+
+ Node* node = element();
+ IntPoint localPoint(point);
+ if (isRenderView())
+ node = document()->documentElement();
+ else if (!isInline() && continuation())
+ // We are in the margins of block elements that are part of a continuation. In
+ // this case we're actually still inside the enclosing inline element that was
+ // split. Go ahead and set our inner node accordingly.
+ node = continuation()->element();
+
+ if (node) {
+ if (node->renderer() && node->renderer()->continuation() && node->renderer() != this) {
+ // We're in the continuation of a split inline. Adjust our local point to be in the coordinate space
+ // of the principal renderer's containing block. This will end up being the innerNonSharedNode.
+ RenderObject* firstBlock = node->renderer()->containingBlock();
+
+ // Get our containing block.
+ RenderObject* block = this;
+ if (isInline())
+ block = containingBlock();
+
+ localPoint.move(block->xPos() - firstBlock->xPos(), block->yPos() - firstBlock->yPos());
+ }
+
+ result.setInnerNode(node);
+ if (!result.innerNonSharedNode())
+ result.setInnerNonSharedNode(node);
+ result.setLocalPoint(localPoint);
+ }
+}
+
+bool RenderObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int /*x*/, int /*y*/, int /*tx*/, int /*ty*/, HitTestAction)
+{
+ return false;
+}
+
+int RenderObject::verticalPositionHint(bool firstLine) const
+{
+ if (firstLine) // We're only really a first-line style if the document actually uses first-line rules.
+ firstLine = document()->usesFirstLineRules();
+ int vpos = m_verticalPosition;
+ if (m_verticalPosition == PositionUndefined || firstLine) {
+ vpos = getVerticalPosition(firstLine);
+ if (!firstLine)
+ m_verticalPosition = vpos;
+ }
+
+ return vpos;
+}
+
+int RenderObject::getVerticalPosition(bool firstLine) const
+{
+ if (!isInline())
+ return 0;
+
+ // This method determines the vertical position for inline elements.
+ int vpos = 0;
+ EVerticalAlign va = style()->verticalAlign();
+ if (va == TOP)
+ vpos = PositionTop;
+ else if (va == BOTTOM)
+ vpos = PositionBottom;
+ else {
+ bool checkParent = parent()->isInline() && !parent()->isInlineBlockOrInlineTable() && parent()->style()->verticalAlign() != TOP && parent()->style()->verticalAlign() != BOTTOM;
+ vpos = checkParent ? parent()->verticalPositionHint(firstLine) : 0;
+ // don't allow elements nested inside text-top to have a different valignment.
+ if (va == BASELINE)
+ return vpos;
+
+ const Font& f = parent()->style(firstLine)->font();
+ int fontsize = f.pixelSize();
+
+ if (va == SUB)
+ vpos += fontsize / 5 + 1;
+ else if (va == SUPER)
+ vpos -= fontsize / 3 + 1;
+ else if (va == TEXT_TOP)
+ vpos += baselinePosition(firstLine) - f.ascent();
+ else if (va == MIDDLE)
+ vpos += -static_cast<int>(f.xHeight() / 2) - lineHeight(firstLine) / 2 + baselinePosition(firstLine);
+ else if (va == TEXT_BOTTOM) {
+ vpos += f.descent();
+ if (!isReplaced())
+ vpos -= style(firstLine)->font().descent();
+ } else if (va == BASELINE_MIDDLE)
+ vpos += -lineHeight(firstLine) / 2 + baselinePosition(firstLine);
+ else if (va == LENGTH)
+ vpos -= style()->verticalAlignLength().calcValue(lineHeight(firstLine));
+ }
+
+ return vpos;
+}
+
+int RenderObject::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
+{
+ RenderStyle* s = style(firstLine);
+
+ Length lh = s->lineHeight();
+
+ // its "unset", choose nice default
+ if (lh.isNegative())
+ return s->font().lineSpacing();
+
+ if (lh.isPercent())
+ return lh.calcMinValue(s->fontSize());
+
+ // its fixed
+ return lh.value();
+}
+
+int RenderObject::baselinePosition(bool firstLine, bool isRootLineBox) const
+{
+ const Font& f = style(firstLine)->font();
+ return f.ascent() + (lineHeight(firstLine, isRootLineBox) - f.height()) / 2;
+}
+
+void RenderObject::scheduleRelayout()
+{
+ if (isRenderView()) {
+ FrameView* view = static_cast<RenderView*>(this)->frameView();
+ if (view)
+ view->scheduleRelayout();
+ } else if (parent()) {
+ FrameView* v = view() ? view()->frameView() : 0;
+ if (v)
+ v->scheduleRelayoutOfSubtree(this);
+ }
+}
+
+void RenderObject::removeLeftoverAnonymousBlock(RenderBlock*)
+{
+}
+
+InlineBox* RenderObject::createInlineBox(bool, bool isRootLineBox, bool)
+{
+ ASSERT(!isRootLineBox);
+ return new (renderArena()) InlineBox(this);
+}
+
+void RenderObject::dirtyLineBoxes(bool, bool)
+{
+}
+
+InlineBox* RenderObject::inlineBoxWrapper() const
+{
+ return 0;
+}
+
+void RenderObject::setInlineBoxWrapper(InlineBox*)
+{
+}
+
+void RenderObject::deleteLineBoxWrapper()
+{
+}
+
+RenderStyle* RenderObject::firstLineStyle() const
+{
+ if (!document()->usesFirstLineRules())
+ return m_style.get();
+
+ RenderStyle* s = m_style.get();
+ const RenderObject* obj = isText() ? parent() : this;
+ if (obj->isBlockFlow()) {
+ RenderBlock* firstLineBlock = obj->firstLineBlock();
+ if (firstLineBlock)
+ s = firstLineBlock->getCachedPseudoStyle(RenderStyle::FIRST_LINE, style());
+ } else if (!obj->isAnonymous() && obj->isInlineFlow()) {
+ RenderStyle* parentStyle = obj->parent()->firstLineStyle();
+ if (parentStyle != obj->parent()->style()) {
+ // A first-line style is in effect. We need to cache a first-line style
+ // for ourselves.
+ style()->setHasPseudoStyle(RenderStyle::FIRST_LINE_INHERITED);
+ s = obj->getCachedPseudoStyle(RenderStyle::FIRST_LINE_INHERITED, parentStyle);
+ }
+ }
+ return s;
+}
+
+RenderStyle* RenderObject::getCachedPseudoStyle(RenderStyle::PseudoId pseudo, RenderStyle* parentStyle) const
+{
+ if (pseudo < RenderStyle::FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo))
+ return 0;
+
+ RenderStyle* cachedStyle = style()->getCachedPseudoStyle(pseudo);
+ if (cachedStyle)
+ return cachedStyle;
+
+ RefPtr<RenderStyle> result = getUncachedPseudoStyle(pseudo, parentStyle);
+ if (result)
+ return style()->addCachedPseudoStyle(result.release());
+ return 0;
+}
+
+PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(RenderStyle::PseudoId pseudo, RenderStyle* parentStyle) const
+{
+ if (pseudo < RenderStyle::FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo))
+ return 0;
+
+ if (!parentStyle)
+ parentStyle = style();
+
+ Node* node = element();
+ while (node && !node->isElementNode())
+ node = node->parentNode();
+ if (!node)
+ return 0;
+
+ RefPtr<RenderStyle> result;
+ if (pseudo == RenderStyle::FIRST_LINE_INHERITED) {
+ result = document()->styleSelector()->styleForElement(static_cast<Element*>(node), parentStyle, false);
+ result->setStyleType(RenderStyle::FIRST_LINE_INHERITED);
+ } else
+ result = document()->styleSelector()->pseudoStyleForElement(pseudo, static_cast<Element*>(node), parentStyle);
+ return result.release();
+}
+
+static Color decorationColor(RenderStyle* style)
+{
+ Color result;
+ if (style->textStrokeWidth() > 0) {
+ // Prefer stroke color if possible but not if it's fully transparent.
+ result = style->textStrokeColor();
+ if (!result.isValid())
+ result = style->color();
+ if (result.alpha())
+ return result;
+ }
+
+ result = style->textFillColor();
+ if (!result.isValid())
+ result = style->color();
+ return result;
+}
+
+void RenderObject::getTextDecorationColors(int decorations, Color& underline, Color& overline,
+ Color& linethrough, bool quirksMode)
+{
+ RenderObject* curr = this;
+ do {
+ int currDecs = curr->style()->textDecoration();
+ if (currDecs) {
+ if (currDecs & UNDERLINE) {
+ decorations &= ~UNDERLINE;
+ underline = decorationColor(curr->style());
+ }
+ if (currDecs & OVERLINE) {
+ decorations &= ~OVERLINE;
+ overline = decorationColor(curr->style());
+ }
+ if (currDecs & LINE_THROUGH) {
+ decorations &= ~LINE_THROUGH;
+ linethrough = decorationColor(curr->style());
+ }
+ }
+ curr = curr->parent();
+ if (curr && curr->isRenderBlock() && curr->continuation())
+ curr = curr->continuation();
+ } while (curr && decorations && (!quirksMode || !curr->element() ||
+ (!curr->element()->hasTagName(aTag) && !curr->element()->hasTagName(fontTag))));
+
+ // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
+ if (decorations && curr) {
+ if (decorations & UNDERLINE)
+ underline = decorationColor(curr->style());
+ if (decorations & OVERLINE)
+ overline = decorationColor(curr->style());
+ if (decorations & LINE_THROUGH)
+ linethrough = decorationColor(curr->style());
+ }
+}
+
+void RenderObject::updateWidgetPosition()
+{
+}
+
+#if ENABLE(DASHBOARD_SUPPORT)
+void RenderObject::addDashboardRegions(Vector<DashboardRegionValue>& regions)
+{
+ // Convert the style regions to absolute coordinates.
+ if (style()->visibility() != VISIBLE)
+ return;
+
+ const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
+ unsigned i, count = styleRegions.size();
+ for (i = 0; i < count; i++) {
+ StyleDashboardRegion styleRegion = styleRegions[i];
+
+ int w = width();
+ int h = height();
+
+ DashboardRegionValue region;
+ region.label = styleRegion.label;
+ region.bounds = IntRect(styleRegion.offset.left().value(),
+ styleRegion.offset.top().value(),
+ w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
+ h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
+ region.type = styleRegion.type;
+
+ region.clip = region.bounds;
+ computeAbsoluteRepaintRect(region.clip);
+ if (region.clip.height() < 0) {
+ region.clip.setHeight(0);
+ region.clip.setWidth(0);
+ }
+
+ FloatPoint absPos = localToAbsolute();
+ region.bounds.setX(absPos.x() + styleRegion.offset.left().value());
+ region.bounds.setY(absPos.y() + styleRegion.offset.top().value());
+
+ if (document()->frame()) {
+ float pageScaleFactor = document()->frame()->page()->chrome()->scaleFactor();
+ if (pageScaleFactor != 1.0f) {
+ region.bounds.scale(pageScaleFactor);
+ region.clip.scale(pageScaleFactor);
+ }
+ }
+
+ regions.append(region);
+ }
+}
+
+void RenderObject::collectDashboardRegions(Vector<DashboardRegionValue>& regions)
+{
+ // RenderTexts don't have their own style, they just use their parent's style,
+ // so we don't want to include them.
+ if (isText())
+ return;
+
+ addDashboardRegions(regions);
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
+ curr->collectDashboardRegions(regions);
+}
+#endif
+
+bool RenderObject::avoidsFloats() const
+{
+ return isReplaced() || hasOverflowClip() || isHR();
+}
+
+bool RenderObject::shrinkToAvoidFloats() const
+{
+ // FIXME: Technically we should be able to shrink replaced elements on a line, but this is difficult to accomplish, since this
+ // involves doing a relayout during findNextLineBreak and somehow overriding the containingBlockWidth method to return the
+ // current remaining width on a line.
+ if (isInline() && !isHTMLMarquee() || !avoidsFloats())
+ return false;
+
+ // All auto-width objects that avoid floats should always use lineWidth.
+ return style()->width().isAuto();
+}
+
+UChar RenderObject::backslashAsCurrencySymbol() const
+{
+ if (Node *node = element()) {
+ if (TextResourceDecoder* decoder = node->document()->decoder())
+ return decoder->encoding().backslashAsCurrencySymbol();
+ }
+ return '\\';
+}
+
+bool RenderObject::willRenderImage(CachedImage*)
+{
+ // Without visibility we won't render (and therefore don't care about animation).
+ if (style()->visibility() != VISIBLE)
+ return false;
+
+ // If we're not in a window (i.e., we're dormant from being put in the b/f cache or in a background tab)
+ // then we don't want to render either.
+ return !document()->inPageCache() && !document()->view()->isOffscreen();
+}
+
+int RenderObject::maximalOutlineSize(PaintPhase p) const
+{
+ if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines)
+ return 0;
+ return static_cast<RenderView*>(document()->renderer())->maximalOutlineSize();
+}
+
+int RenderObject::caretMinOffset() const
+{
+ return 0;
+}
+
+int RenderObject::caretMaxOffset() const
+{
+ if (isReplaced())
+ return element() ? max(1U, element()->childNodeCount()) : 1;
+ if (isHR())
+ return 1;
+ return 0;
+}
+
+unsigned RenderObject::caretMaxRenderedOffset() const
+{
+ return 0;
+}
+
+int RenderObject::previousOffset(int current) const
+{
+ return current - 1;
+}
+
+int RenderObject::nextOffset(int current) const
+{
+ return current + 1;
+}
+
+int RenderObject::maxTopMargin(bool positive) const
+{
+ return positive ? max(0, marginTop()) : -min(0, marginTop());
+}
+
+int RenderObject::maxBottomMargin(bool positive) const
+{
+ return positive ? max(0, marginBottom()) : -min(0, marginBottom());
+}
+
+IntRect RenderObject::contentBox() const
+{
+ return IntRect(borderLeft() + paddingLeft(), borderTop() + paddingTop(),
+ contentWidth(), contentHeight());
+}
+
+IntRect RenderObject::absoluteContentBox() const
+{
+ IntRect rect = contentBox();
+ FloatPoint absPos = localToAbsoluteForContent(FloatPoint());
+ rect.move(absPos.x(), absPos.y());
+ return rect;
+}
+
+FloatQuad RenderObject::absoluteContentQuad() const
+{
+ IntRect rect = contentBox();
+ return localToAbsoluteQuad(FloatRect(rect));
+}
+
+void RenderObject::adjustRectForOutlineAndShadow(IntRect& rect) const
+{
+ int outlineSize = !isInline() && continuation() ? continuation()->style()->outlineSize() : style()->outlineSize();
+ if (ShadowData* boxShadow = style()->boxShadow()) {
+ int shadowLeft = 0;
+ int shadowRight = 0;
+ int shadowTop = 0;
+ int shadowBottom = 0;
+
+ do {
+ shadowLeft = min(boxShadow->x - boxShadow->blur - outlineSize, shadowLeft);
+ shadowRight = max(boxShadow->x + boxShadow->blur + outlineSize, shadowRight);
+ shadowTop = min(boxShadow->y - boxShadow->blur - outlineSize, shadowTop);
+ shadowBottom = max(boxShadow->y + boxShadow->blur + outlineSize, shadowBottom);
+
+ boxShadow = boxShadow->next;
+ } while (boxShadow);
+
+ rect.move(shadowLeft, shadowTop);
+ rect.setWidth(rect.width() - shadowLeft + shadowRight);
+ rect.setHeight(rect.height() - shadowTop + shadowBottom);
+ } else
+ rect.inflate(outlineSize);
+}
+
+IntRect RenderObject::absoluteOutlineBounds() const
+{
+ IntRect box = borderBox();
+ adjustRectForOutlineAndShadow(box);
+
+ FloatQuad absOutlineQuad = localToAbsoluteQuad(FloatRect(box));
+ box = absOutlineQuad.enclosingBoundingBox();
+ box.move(view()->layoutDelta());
+
+ return box;
+}
+
+bool RenderObject::isScrollable() const
+{
+ RenderLayer* l = enclosingLayer();
+ return l && (l->verticalScrollbar() || l->horizontalScrollbar());
+}
+
+AnimationController* RenderObject::animation() const
+{
+ return document()->frame()->animation();
+}
+
+void RenderObject::imageChanged(CachedImage* image, const IntRect* rect)
+{
+ imageChanged(static_cast<WrappedImagePtr>(image), rect);
+}
+
+IntRect RenderObject::reflectionBox() const
+{
+ IntRect result;
+ if (!m_style->boxReflect())
+ return result;
+ IntRect box = borderBox();
+ result = box;
+ switch (m_style->boxReflect()->direction()) {
+ case ReflectionBelow:
+ result.move(0, box.height() + reflectionOffset());
+ break;
+ case ReflectionAbove:
+ result.move(0, -box.height() - reflectionOffset());
+ break;
+ case ReflectionLeft:
+ result.move(-box.width() - reflectionOffset(), 0);
+ break;
+ case ReflectionRight:
+ result.move(box.width() + reflectionOffset(), 0);
+ break;
+ }
+ return result;
+}
+
+int RenderObject::reflectionOffset() const
+{
+ if (!m_style->boxReflect())
+ return 0;
+ if (m_style->boxReflect()->direction() == ReflectionLeft || m_style->boxReflect()->direction() == ReflectionRight)
+ return m_style->boxReflect()->offset().calcValue(borderBox().width());
+ return m_style->boxReflect()->offset().calcValue(borderBox().height());
+}
+
+IntRect RenderObject::reflectedRect(const IntRect& r) const
+{
+ if (!m_style->boxReflect())
+ return IntRect();
+
+ IntRect box = borderBox();
+ IntRect result = r;
+ switch (m_style->boxReflect()->direction()) {
+ case ReflectionBelow:
+ result.setY(box.bottom() + reflectionOffset() + (box.bottom() - r.bottom()));
+ break;
+ case ReflectionAbove:
+ result.setY(box.y() - reflectionOffset() - box.height() + (box.bottom() - r.bottom()));
+ break;
+ case ReflectionLeft:
+ result.setX(box.x() - reflectionOffset() - box.width() + (box.right() - r.right()));
+ break;
+ case ReflectionRight:
+ result.setX(box.right() + reflectionOffset() + (box.right() - r.right()));
+ break;
+ }
+ return result;
+}
+
+#if ENABLE(SVG)
+
+FloatRect RenderObject::relativeBBox(bool) const
+{
+ return FloatRect();
+}
+
+TransformationMatrix RenderObject::localTransform() const
+{
+ return TransformationMatrix(1, 0, 0, 1, xPos(), yPos());
+}
+
+TransformationMatrix RenderObject::absoluteTransform() const
+{
+ if (parent())
+ return localTransform() * parent()->absoluteTransform();
+ return localTransform();
+}
+
+#endif // ENABLE(SVG)
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+
+void showTree(const WebCore::RenderObject* ro)
+{
+ if (ro)
+ ro->showTreeForThis();
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderObject.h
new file mode 100644
index 0000000..70841b7
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderObject.h
@@ -0,0 +1,991 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 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 RenderObject_h
+#define RenderObject_h
+
+#include "CachedResourceClient.h"
+#include "Document.h"
+#include "FloatQuad.h"
+#include "RenderStyle.h"
+#include "ScrollTypes.h"
+#include "VisiblePosition.h"
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class TransformationMatrix;
+class AnimationController;
+class Color;
+class Document;
+class Element;
+class Event;
+class FloatRect;
+class FrameView;
+class HTMLAreaElement;
+class HitTestResult;
+class InlineBox;
+class InlineFlowBox;
+class Position;
+class RenderArena;
+class RenderBlock;
+class RenderFlow;
+class RenderFrameSet;
+class RenderLayer;
+class RenderTable;
+class RenderText;
+class RenderView;
+class String;
+
+struct HitTestRequest;
+
+/*
+ * The painting of a layer occurs in three distinct phases. Each phase involves
+ * a recursive descent into the layer's render objects. The first phase is the background phase.
+ * The backgrounds and borders of all blocks are painted. Inlines are not painted at all.
+ * Floats must paint above block backgrounds but entirely below inline content that can overlap them.
+ * In the foreground phase, all inlines are fully painted. Inline replaced elements will get all
+ * three phases invoked on them during this phase.
+ */
+
+enum PaintPhase {
+ PaintPhaseBlockBackground,
+ PaintPhaseChildBlockBackground,
+ PaintPhaseChildBlockBackgrounds,
+ PaintPhaseFloat,
+ PaintPhaseForeground,
+ PaintPhaseOutline,
+ PaintPhaseChildOutlines,
+ PaintPhaseSelfOutline,
+ PaintPhaseSelection,
+ PaintPhaseCollapsedTableBorders,
+ PaintPhaseTextClip,
+ PaintPhaseMask
+};
+
+enum PaintRestriction {
+ PaintRestrictionNone,
+ PaintRestrictionSelectionOnly,
+ PaintRestrictionSelectionOnlyBlackText
+};
+
+enum HitTestFilter {
+ HitTestAll,
+ HitTestSelf,
+ HitTestDescendants
+};
+
+enum HitTestAction {
+ HitTestBlockBackground,
+ HitTestChildBlockBackground,
+ HitTestChildBlockBackgrounds,
+ HitTestFloat,
+ HitTestForeground
+};
+
+enum VerticalPositionHint {
+ PositionTop = -0x7fffffff,
+ PositionBottom = 0x7fffffff,
+ PositionUndefined = static_cast<int>(0x80000000)
+};
+
+#if ENABLE(DASHBOARD_SUPPORT)
+struct DashboardRegionValue {
+ bool operator==(const DashboardRegionValue& o) const
+ {
+ return type == o.type && bounds == o.bounds && clip == o.clip && label == o.label;
+ }
+ bool operator!=(const DashboardRegionValue& o) const
+ {
+ return !(*this == o);
+ }
+
+ String label;
+ IntRect bounds;
+ IntRect clip;
+ int type;
+};
+#endif
+
+// FIXME: This should be a HashSequencedSet, but we don't have that data structure yet.
+// This means the paint order of outlines will be wrong, although this is a minor issue.
+typedef HashSet<RenderFlow*> RenderFlowSequencedSet;
+
+// Base class for all rendering tree objects.
+class RenderObject : public CachedResourceClient {
+ friend class RenderContainer;
+ friend class RenderSVGContainer;
+ friend class RenderLayer;
+public:
+ // Anonymous objects should pass the document as their node, and they will then automatically be
+ // marked as anonymous in the constructor.
+ RenderObject(Node*);
+ virtual ~RenderObject();
+
+ virtual const char* renderName() const { return "RenderObject"; }
+
+ RenderObject* parent() const { return m_parent; }
+ bool isDescendantOf(const RenderObject*) const;
+
+ RenderObject* previousSibling() const { return m_previous; }
+ RenderObject* nextSibling() const { return m_next; }
+
+ virtual RenderObject* firstChild() const { return 0; }
+ virtual RenderObject* lastChild() const { return 0; }
+
+ RenderObject* nextInPreOrder() const;
+ RenderObject* nextInPreOrder(RenderObject* stayWithin) const;
+ RenderObject* nextInPreOrderAfterChildren() const;
+ RenderObject* nextInPreOrderAfterChildren(RenderObject* stayWithin) const;
+ RenderObject* previousInPreOrder() const;
+ RenderObject* childAt(unsigned) const;
+
+ RenderObject* firstLeafChild() const;
+ RenderObject* lastLeafChild() const;
+
+ virtual RenderLayer* layer() const { return 0; }
+ RenderLayer* enclosingLayer() const;
+ void addLayers(RenderLayer* parentLayer, RenderObject* newObject);
+ void removeLayers(RenderLayer* parentLayer);
+ void moveLayers(RenderLayer* oldParent, RenderLayer* newParent);
+ RenderLayer* findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint, bool checkParent = true);
+ virtual void positionChildLayers() { }
+ virtual bool requiresLayer();
+
+ virtual IntRect getOverflowClipRect(int /*tx*/, int /*ty*/) { return IntRect(0, 0, 0, 0); }
+ virtual IntRect getClipRect(int /*tx*/, int /*ty*/) { return IntRect(0, 0, 0, 0); }
+ bool hasClip() { return isPositioned() && style()->hasClip(); }
+
+ virtual int getBaselineOfFirstLineBox() const { return -1; }
+ virtual int getBaselineOfLastLineBox() const { return -1; }
+
+ virtual bool isEmpty() const { return firstChild() == 0; }
+
+ virtual bool isEdited() const { return false; }
+ virtual void setEdited(bool) { }
+
+#ifndef NDEBUG
+ void setHasAXObject(bool flag) { m_hasAXObject = flag; }
+ bool hasAXObject() const { return m_hasAXObject; }
+#endif
+
+ // Obtains the nearest enclosing block (including this block) that contributes a first-line style to our inline
+ // children.
+ virtual RenderBlock* firstLineBlock() const;
+
+ // Called when an object that was floating or positioned becomes a normal flow object
+ // again. We have to make sure the render tree updates as needed to accommodate the new
+ // normal flow object.
+ void handleDynamicFloatPositionChange();
+
+ // This function is a convenience helper for creating an anonymous block that inherits its
+ // style from this RenderObject.
+ RenderBlock* createAnonymousBlock();
+
+ // Whether or not a positioned element requires normal flow x/y to be computed
+ // to determine its position.
+ bool hasStaticX() const;
+ bool hasStaticY() const;
+ virtual void setStaticX(int /*staticX*/) { }
+ virtual void setStaticY(int /*staticY*/) { }
+ virtual int staticX() const { return 0; }
+ virtual int staticY() const { return 0; }
+
+ // RenderObject tree manipulation
+ //////////////////////////////////////////
+ virtual bool canHaveChildren() const;
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const { return true; }
+ virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0);
+ virtual void removeChild(RenderObject*);
+ virtual bool createsAnonymousWrapper() const { return false; }
+
+ // raw tree manipulation
+ virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true);
+ virtual void appendChildNode(RenderObject*, bool fullAppend = true);
+ virtual void insertChildNode(RenderObject* child, RenderObject* before, bool fullInsert = true);
+ // Designed for speed. Don't waste time doing a bunch of work like layer updating and repainting when we know that our
+ // change in parentage is not going to affect anything.
+ virtual void moveChildNode(RenderObject*);
+ //////////////////////////////////////////
+
+protected:
+ //////////////////////////////////////////
+ // Helper functions. Dangerous to use!
+ void setPreviousSibling(RenderObject* previous) { m_previous = previous; }
+ void setNextSibling(RenderObject* next) { m_next = next; }
+ void setParent(RenderObject* parent) { m_parent = parent; }
+ //////////////////////////////////////////
+private:
+ void addAbsoluteRectForLayer(IntRect& result);
+
+public:
+#ifndef NDEBUG
+ void showTreeForThis() const;
+#endif
+
+ static RenderObject* createObject(Node*, RenderStyle*);
+
+ // Overloaded new operator. Derived classes must override operator new
+ // in order to allocate out of the RenderArena.
+ void* operator new(size_t, RenderArena*) throw();
+
+ // Overridden to prevent the normal delete from being called.
+ void operator delete(void*, size_t);
+
+private:
+ // The normal operator new is disallowed on all render objects.
+ void* operator new(size_t) throw();
+
+public:
+ RenderArena* renderArena() const { return document()->renderArena(); }
+
+ virtual bool isApplet() const { return false; }
+ virtual bool isBR() const { return false; }
+ virtual bool isBlockFlow() const { return false; }
+ virtual bool isCounter() const { return false; }
+ virtual bool isFieldset() const { return false; }
+ virtual bool isFrame() const { return false; }
+ virtual bool isFrameSet() const { return false; }
+ virtual bool isImage() const { return false; }
+ virtual bool isInlineBlockOrInlineTable() const { return false; }
+ virtual bool isInlineContinuation() const;
+ virtual bool isInlineFlow() const { return false; }
+ virtual bool isListBox() const { return false; }
+ virtual bool isListItem() const { return false; }
+ virtual bool isListMarker() const { return false; }
+ virtual bool isMedia() const { return false; }
+ virtual bool isMenuList() const { return false; }
+ virtual bool isRenderBlock() const { return false; }
+ virtual bool isRenderImage() const { return false; }
+ virtual bool isRenderInline() const { return false; }
+ virtual bool isRenderPart() const { return false; }
+ virtual bool isRenderView() const { return false; }
+ virtual bool isSlider() const { return false; }
+ virtual bool isTable() const { return false; }
+ virtual bool isTableCell() const { return false; }
+ virtual bool isTableCol() const { return false; }
+ virtual bool isTableRow() const { return false; }
+ virtual bool isTableSection() const { return false; }
+ virtual bool isTextArea() const { return false; }
+ virtual bool isTextField() const { return false; }
+ virtual bool isWidget() const { return false; }
+
+
+ bool isRoot() const { return document()->documentElement() == node(); }
+ bool isBody() const;
+ bool isHR() const;
+
+ bool isHTMLMarquee() const;
+
+ virtual bool childrenInline() const { return false; }
+ virtual void setChildrenInline(bool) { }
+
+ virtual RenderFlow* continuation() const;
+
+#if ENABLE(SVG)
+ virtual bool isSVGRoot() const { return false; }
+ virtual bool isSVGContainer() const { return false; }
+ virtual bool isSVGHiddenContainer() const { return false; }
+ virtual bool isRenderPath() const { return false; }
+ virtual bool isSVGText() const { return false; }
+
+ virtual FloatRect relativeBBox(bool includeStroke = true) const;
+
+ virtual TransformationMatrix localTransform() const;
+ virtual TransformationMatrix absoluteTransform() const;
+#endif
+
+ virtual bool isEditable() const;
+
+ bool isAnonymous() const { return m_isAnonymous; }
+ void setIsAnonymous(bool b) { m_isAnonymous = b; }
+ bool isAnonymousBlock() const
+ {
+ return m_isAnonymous && style()->display() == BLOCK && style()->styleType() == RenderStyle::NOPSEUDO && !isListMarker();
+ }
+
+ bool isFloating() const { return m_floating; }
+ bool isPositioned() const { return m_positioned; } // absolute or fixed positioning
+ bool isRelPositioned() const { return m_relPositioned; } // relative positioning
+ bool isText() const { return m_isText; }
+ bool isInline() const { return m_inline; } // inline object
+ bool isCompact() const { return style()->display() == COMPACT; } // compact object
+ bool isRunIn() const { return style()->display() == RUN_IN; } // run-in object
+ bool isDragging() const { return m_isDragging; }
+ bool isReplaced() const { return m_replaced; } // a "replaced" element (see CSS)
+
+ bool hasLayer() const { return m_hasLayer; }
+
+ bool hasBoxDecorations() const { return m_paintBackground; }
+ bool mustRepaintBackgroundOrBorder() const;
+
+ bool hasHorizontalBordersPaddingOrMargin() const { return hasHorizontalBordersOrPadding() || marginLeft() != 0 || marginRight() != 0; }
+ bool hasHorizontalBordersOrPadding() const { return borderLeft() != 0 || borderRight() != 0 || paddingLeft() != 0 || paddingRight() != 0; }
+
+ bool needsLayout() const { return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout || m_needsPositionedMovementLayout; }
+ bool selfNeedsLayout() const { return m_needsLayout; }
+ bool needsPositionedMovementLayout() const { return m_needsPositionedMovementLayout; }
+ bool needsPositionedMovementLayoutOnly() const { return m_needsPositionedMovementLayout && !m_needsLayout && !m_normalChildNeedsLayout && !m_posChildNeedsLayout; }
+ bool posChildNeedsLayout() const { return m_posChildNeedsLayout; }
+ bool normalChildNeedsLayout() const { return m_normalChildNeedsLayout; }
+
+ bool prefWidthsDirty() const { return m_prefWidthsDirty; }
+
+ bool isSelectionBorder() const;
+
+ bool hasOverflowClip() const { return m_hasOverflowClip; }
+ virtual bool hasControlClip() const { return false; }
+ virtual IntRect controlClipRect(int /*tx*/, int /*ty*/) const { return IntRect(); }
+
+ bool hasAutoVerticalScrollbar() const { return hasOverflowClip() && (style()->overflowY() == OAUTO || style()->overflowY() == OOVERLAY); }
+ bool hasAutoHorizontalScrollbar() const { return hasOverflowClip() && (style()->overflowX() == OAUTO || style()->overflowX() == OOVERLAY); }
+
+ bool scrollsOverflow() const { return scrollsOverflowX() || scrollsOverflowY(); }
+ bool scrollsOverflowX() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || hasAutoHorizontalScrollbar()); }
+ bool scrollsOverflowY() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || hasAutoVerticalScrollbar()); }
+
+ virtual int verticalScrollbarWidth() const;
+ virtual int horizontalScrollbarHeight() const;
+
+ bool hasTransform() const { return m_hasTransform; }
+ bool hasMask() const { return style() && style()->hasMask(); }
+ virtual IntRect maskClipRect() { return borderBox(); }
+
+private:
+ bool includeVerticalScrollbarSize() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO); }
+ bool includeHorizontalScrollbarSize() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO); }
+
+public:
+ // The pseudo element style can be cached or uncached. Use the cached method if the pseudo element doesn't respect
+ // any pseudo classes (and therefore has no concept of changing state).
+ RenderStyle* getCachedPseudoStyle(RenderStyle::PseudoId, RenderStyle* parentStyle = 0) const;
+ PassRefPtr<RenderStyle> getUncachedPseudoStyle(RenderStyle::PseudoId, RenderStyle* parentStyle = 0) const;
+
+ void updateDragState(bool dragOn);
+
+ RenderView* view() const;
+
+ // don't even think about making this method virtual!
+ Node* element() const { return m_isAnonymous ? 0 : m_node; }
+ Document* document() const { return m_node->document(); }
+ void setNode(Node* node) { m_node = node; }
+ Node* node() const { return m_node; }
+
+ 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;
+ RenderObject* hoverAncestor() const;
+
+ virtual void markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove = 0);
+ void markContainingBlocksForLayout(bool scheduleRelayout = true, RenderObject* newRoot = 0);
+ void setNeedsLayout(bool b, bool markParents = true);
+ void setChildNeedsLayout(bool b, bool markParents = true);
+ void setNeedsPositionedMovementLayout();
+ void setPrefWidthsDirty(bool, bool markParents = true);
+ void invalidateContainerPrefWidths();
+ virtual void invalidateCounters() { }
+
+ void setNeedsLayoutAndPrefWidthsRecalc()
+ {
+ setNeedsLayout(true);
+ setPrefWidthsDirty(true);
+ }
+
+ void setPositioned(bool b = true) { m_positioned = b; }
+ void setRelPositioned(bool b = true) { m_relPositioned = b; }
+ void setFloating(bool b = true) { m_floating = b; }
+ void setInline(bool b = true) { m_inline = b; }
+ void setHasBoxDecorations(bool b = true) { m_paintBackground = b; }
+ void setRenderText() { m_isText = true; }
+ void setReplaced(bool b = true) { m_replaced = b; }
+ void setHasOverflowClip(bool b = true) { m_hasOverflowClip = b; }
+ void setHasLayer(bool b = true) { m_hasLayer = b; }
+ void setHasTransform(bool b = true) { m_hasTransform = b; }
+ void setHasReflection(bool b = true) { m_hasReflection = b; }
+
+ void scheduleRelayout();
+
+ void updateFillImages(const FillLayer*, const FillLayer*);
+ void updateImage(StyleImage*, StyleImage*);
+
+ virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false);
+ virtual void dirtyLineBoxes(bool fullLayout, bool isRootLineBox = false);
+
+ // For inline replaced elements, this function returns the inline box that owns us. Enables
+ // the replaced RenderObject to quickly determine what line it is contained on and to easily
+ // iterate over structures on the line.
+ virtual InlineBox* inlineBoxWrapper() const;
+ virtual void setInlineBoxWrapper(InlineBox*);
+ virtual void deleteLineBoxWrapper();
+
+ // for discussion of lineHeight see CSS2 spec
+ virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
+ // for the vertical-align property of inline elements
+ // the difference between this objects baseline position and the lines baseline position.
+ virtual int verticalPositionHint(bool firstLine) const;
+ // the offset of baseline from the top of the object.
+ virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const;
+
+ /*
+ * Paint the object and its children, clipped by (x|y|w|h).
+ * (tx|ty) is the calculated position of the parent
+ */
+ struct PaintInfo {
+ PaintInfo(GraphicsContext* newContext, const IntRect& newRect, PaintPhase newPhase, bool newForceBlackText,
+ RenderObject* newPaintingRoot, RenderFlowSequencedSet* newOutlineObjects)
+ : context(newContext)
+ , rect(newRect)
+ , phase(newPhase)
+ , forceBlackText(newForceBlackText)
+ , paintingRoot(newPaintingRoot)
+ , outlineObjects(newOutlineObjects)
+ {
+ }
+
+ GraphicsContext* context;
+ IntRect rect;
+ PaintPhase phase;
+ bool forceBlackText;
+ RenderObject* paintingRoot; // used to draw just one element and its visual kids
+ RenderFlowSequencedSet* outlineObjects; // used to list outlines that should be painted by a block with inline children
+ };
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+ 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 paintOutline(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*);
+ void paintBoxShadow(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, bool begin = true, bool end = true);
+
+ // RenderBox implements this.
+ virtual void paintBoxDecorations(PaintInfo&, int /*tx*/, int /*ty*/) { }
+ virtual void paintMask(PaintInfo&, int /*tx*/, int /*ty*/) { }
+ virtual void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*,
+ int /*clipY*/, int /*clipH*/, int /*tx*/, int /*ty*/, int /*width*/, int /*height*/,
+ InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver) { }
+
+
+ /*
+ * Calculates the actual width of the object (only for non inline
+ * objects)
+ */
+ virtual void calcWidth() { }
+
+ /*
+ * This function should cause the Element to calculate its
+ * width and height and the layout of its content
+ *
+ * when the Element calls setNeedsLayout(false), layout() is no
+ * longer called during relayouts, as long as there is no
+ * style sheet change. When that occurs, m_needsLayout will be
+ * set to true and the Element receives layout() calls
+ * again.
+ */
+ virtual void layout() = 0;
+
+ /* This function performs a layout only if one is needed. */
+ void layoutIfNeeded() { if (needsLayout()) layout(); }
+
+ // Called when a positioned object moves but doesn't necessarily change size. A simplified layout is attempted
+ // that just updates the object's position. If the size does change, the object remains dirty.
+ virtual void tryLayoutDoingPositionedMovementOnly() { }
+
+ // used for element state updates that cannot be fixed with a
+ // repaint and do not need a relayout
+ virtual void updateFromElement() { }
+
+ // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.)
+ virtual int availableWidth() const { return contentWidth(); }
+
+ virtual int availableHeight() const { return 0; }
+
+ virtual void updateWidgetPosition();
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ void addDashboardRegions(Vector<DashboardRegionValue>&);
+ void collectDashboardRegions(Vector<DashboardRegionValue>&);
+#endif
+
+ bool hitTest(const HitTestRequest&, HitTestResult&, const IntPoint&, int tx, int ty, HitTestFilter = HitTestAll);
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+ void updateHitTestResult(HitTestResult&, const IntPoint&);
+
+ virtual VisiblePosition positionForCoordinates(int x, int y);
+ VisiblePosition positionForPoint(const IntPoint& point) { return positionForCoordinates(point.x(), point.y()); }
+
+ virtual void dirtyLinesFromChangedChild(RenderObject*);
+
+ // Called to update a style that is allowed to trigger animations.
+ // FIXME: Right now this will typically be called only when updating happens from the DOM on explicit elements.
+ // We don't yet handle generated content animation such as first-letter or before/after (we'll worry about this later).
+ void setAnimatableStyle(PassRefPtr<RenderStyle>);
+
+ // Set the style of the object and update the state of the object accordingly.
+ virtual void setStyle(PassRefPtr<RenderStyle>);
+
+ // Updates only the local style ptr of the object. Does not update the state of the object,
+ // and so only should be called when the style is known not to have changed (or from setStyle).
+ void setStyleInternal(PassRefPtr<RenderStyle>);
+
+ // returns the containing block level element for this element.
+ RenderBlock* containingBlock() const;
+
+ // return just the width of the containing block
+ virtual int containingBlockWidth() const;
+ // return just the height of the containing block
+ virtual int containingBlockHeight() const;
+
+ // content area (box minus padding/border)
+ IntRect contentBox() const;
+ // absolute coords of content area. Ignores transforms.
+ IntRect absoluteContentBox() const;
+ // content rect converted to absolute coords, taking transforms into account
+ FloatQuad absoluteContentQuad() const;
+
+ int contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); }
+ int contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); }
+
+ // used by flexible boxes to impose a flexed width/height override
+ virtual int overrideSize() const { return 0; }
+ virtual int overrideWidth() const { return 0; }
+ virtual int overrideHeight() const { return 0; }
+ virtual void setOverrideSize(int /*overrideSize*/) { }
+
+ // relative to parent node
+ virtual void setPos(int /*xPos*/, int /*yPos*/) { }
+ virtual void setWidth(int /*width*/) { }
+ virtual void setHeight(int /*height*/) { }
+ virtual void setRect(const IntRect& rect) { setPos(rect.x(), rect.y()); setWidth(rect.width()); setHeight(rect.height()); }
+
+ virtual int xPos() const { return 0; }
+ virtual int yPos() const { return 0; }
+
+ // Convert the given local point to absolute coordinates
+ // FIXME: Temporary. If useTransforms is true, take transforms into account. Eventually localToAbsolute() will always be transform-aware.
+ virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const;
+ virtual FloatPoint absoluteToLocal(FloatPoint, bool fixed = false, bool useTransforms = false) const;
+
+ // This function is used to deal with the extra top space that can occur in table cells (called borderTopExtra).
+ // The children of the cell do not factor this space in, so we have to add it in. Any code that wants to
+ // accurately deal with the contents of a cell must call this function instad of absolutePosition.
+ FloatPoint localToAbsoluteForContent(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const
+ {
+ localPoint.move(0.0f, static_cast<float>(borderTopExtra()));
+ return localToAbsolute(localPoint, fixed, useTransforms);
+ }
+
+ // Convert a local quad to an absolute quad, taking transforms into account.
+ virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const;
+
+ // Return the offset from the container() renderer (excluding transforms)
+ virtual IntSize offsetFromContainer(RenderObject*) const;
+
+ // width and height are without margins but include paddings and borders
+ virtual int width() const { return 0; }
+ virtual int height() const { return 0; }
+
+ virtual IntRect borderBox() const { return IntRect(0, 0, width(), height()); }
+ // Bounds of the outline box in absolute coords. Respects transforms
+ IntRect absoluteOutlineBounds() 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 borderBox(); }
+
+ // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow)
+ // to return the remaining width on a given line (and the height of a single line).
+ virtual int offsetWidth() const { return width(); }
+ virtual int offsetHeight() const { return height() + borderTopExtra() + borderBottomExtra(); }
+
+ // IE extensions. Also supported by Gecko. We override in render flow to get the
+ // left and top correct. -dwh
+ virtual int offsetLeft() const;
+ virtual int offsetTop() const;
+ virtual RenderObject* offsetParent() const;
+
+ // More IE extensions. clientWidth and clientHeight represent the interior of an object
+ // excluding border and scrollbar. clientLeft/Top are just the borderLeftWidth and borderTopWidth.
+ int clientLeft() const { return borderLeft(); }
+ int clientTop() const { return borderTop(); }
+ int clientWidth() const;
+ int clientHeight() const;
+
+ // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the
+ // object has overflow:hidden/scroll/auto specified and also has overflow.
+ // scrollLeft/Top return the current scroll position. These methods are virtual so that objects like
+ // textareas can scroll shadow content (but pretend that they are the objects that are
+ // scrolling).
+ virtual int scrollLeft() const;
+ virtual int scrollTop() const;
+ virtual int scrollWidth() const;
+ virtual int scrollHeight() const;
+ virtual void setScrollLeft(int);
+ virtual void setScrollTop(int);
+
+ virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f);
+ virtual bool canBeProgramaticallyScrolled(bool) const;
+ virtual void autoscroll();
+ virtual void stopAutoscroll() { }
+
+ virtual void panScroll(const IntPoint&);
+
+ virtual bool isScrollable() const;
+
+ // The following seven functions are used to implement collapsing margins.
+ // All objects know their maximal positive and negative margins. The
+ // formula for computing a collapsed margin is |maxPosMargin|-|maxNegmargin|.
+ // For a non-collapsing, e.g., a leaf element, this formula will simply return
+ // the margin of the element. Blocks override the maxTopMargin and maxBottomMargin
+ // methods.
+ virtual bool isSelfCollapsingBlock() const { return false; }
+ virtual int collapsedMarginTop() const { return maxTopMargin(true) - maxTopMargin(false); }
+ virtual int collapsedMarginBottom() const { return maxBottomMargin(true) - maxBottomMargin(false); }
+ virtual bool isTopMarginQuirk() const { return false; }
+ virtual bool isBottomMarginQuirk() const { return false; }
+
+ virtual int maxTopMargin(bool positive) const;
+ virtual int maxBottomMargin(bool positive) const;
+
+ virtual int marginTop() const { return 0; }
+ virtual int marginBottom() const { return 0; }
+ virtual int marginLeft() const { return 0; }
+ virtual int marginRight() const { return 0; }
+
+ // Virtual since table cells override
+ virtual int paddingTop() const;
+ virtual int paddingBottom() const;
+ virtual int paddingLeft() const;
+ virtual int paddingRight() const;
+
+ virtual int borderTop() const { return style()->borderTopWidth(); }
+ virtual int borderBottom() const { return style()->borderBottomWidth(); }
+ virtual int borderTopExtra() const { return 0; }
+ virtual int borderBottomExtra() const { return 0; }
+ virtual int borderLeft() const { return style()->borderLeftWidth(); }
+ virtual int borderRight() const { return style()->borderRightWidth(); }
+
+ virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+
+ virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+ // FIXME: useTransforms should go away eventually
+ IntRect absoluteBoundingBoxRect(bool useTransforms = false);
+
+ // Build an array of quads in absolute coords for line boxes
+ virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+
+ // the rect that will be painted if this object is passed as the paintingRoot
+ IntRect paintingRootRect(IntRect& topLevelRect);
+
+ void addPDFURLRect(GraphicsContext*, const IntRect&);
+
+ virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+
+ virtual int minPrefWidth() const { return 0; }
+ virtual int maxPrefWidth() const { return 0; }
+
+ RenderStyle* style() const { return m_style.get(); }
+ RenderStyle* firstLineStyle() const;
+ RenderStyle* style(bool firstLine) const { return firstLine ? firstLineStyle() : style(); }
+
+ void getTextDecorationColors(int decorations, Color& underline, Color& overline,
+ Color& linethrough, bool quirksMode = false);
+
+ enum BorderSide {
+ BSTop,
+ BSBottom,
+ BSLeft,
+ BSRight
+ };
+
+ void drawBorderArc(GraphicsContext*, int x, int y, float thickness, IntSize radius, int angleStart,
+ int angleSpan, BorderSide, Color, const Color& textcolor, EBorderStyle, bool firstCorner);
+ void drawBorder(GraphicsContext*, int x1, int y1, int x2, int y2, BorderSide,
+ Color, const Color& textcolor, EBorderStyle, int adjbw1, int adjbw2);
+
+ // Repaint the entire object. Called when, e.g., the color of a border changes, or when a border
+ // style changes.
+ void repaint(bool immediate = false);
+
+ // Repaint a specific subrectangle within a given object. The rect |r| is in the object's coordinate space.
+ void repaintRectangle(const IntRect&, bool immediate = false);
+
+ // Repaint only if our old bounds and new bounds are different.
+ bool repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const IntRect& oldOutlineBox);
+
+ // Repaint only if the object moved.
+ virtual void repaintDuringLayoutIfMoved(const IntRect& rect);
+
+ // Called to repaint a block's floats.
+ virtual void repaintOverhangingFloats(bool paintAllDescendants = false);
+
+ bool checkForRepaintDuringLayout() const;
+
+ // Returns the rect that should be repainted whenever this object changes. The rect is in the view's
+ // coordinate space. This method deals with outlines and overflow.
+ virtual IntRect absoluteClippedOverflowRect();
+
+ IntRect getAbsoluteRepaintRectWithOutline(int ow);
+
+ // Given a rect in the object's coordinate space, this method converts the rectangle to the view's
+ // coordinate space.
+ virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false);
+
+ virtual unsigned int length() const { return 1; }
+
+ bool isFloatingOrPositioned() const { return (isFloating() || isPositioned()); }
+ virtual bool containsFloats() { return false; }
+ virtual bool containsFloat(RenderObject*) { return false; }
+ virtual bool hasOverhangingFloats() { return false; }
+ virtual bool expandsToEncloseOverhangingFloats() const { return isFloating() && style()->height().isAuto(); }
+
+ virtual void removePositionedObjects(RenderBlock*) { }
+
+ virtual bool avoidsFloats() const;
+ bool shrinkToAvoidFloats() const;
+
+ // positioning of inline children (bidi)
+ virtual void position(InlineBox*) { }
+
+ bool isTransparent() const { return style()->opacity() < 1.0f; }
+ float opacity() const { return style()->opacity(); }
+
+ bool hasReflection() const { return m_hasReflection; }
+ IntRect reflectionBox() const;
+ int reflectionOffset() const;
+ // Given a rect in the object's coordinate space, returns the corresponding rect in the reflection.
+ IntRect reflectedRect(const IntRect&) const;
+
+ // Applied as a "slop" to dirty rect checks during the outline painting phase's dirty-rect checks.
+ int maximalOutlineSize(PaintPhase) const;
+
+ enum SelectionState {
+ SelectionNone, // The object is not selected.
+ SelectionStart, // The object either contains the start of a selection run or is the start of a run
+ SelectionInside, // The object is fully encompassed by a selection run
+ SelectionEnd, // The object either contains the end of a selection run or is the end of a run
+ SelectionBoth // The object contains an entire run or is the sole selected object in that run
+ };
+
+ // The current selection state for an object. For blocks, the state refers to the state of the leaf
+ // descendants (as described above in the SelectionState enum declaration).
+ virtual SelectionState selectionState() const { return SelectionNone; }
+
+ // Sets the selection state for an object.
+ virtual void setSelectionState(SelectionState state) { if (parent()) parent()->setSelectionState(state); }
+
+ // A single rectangle that encompasses all of the selected objects within this object. Used to determine the tightest
+ // possible bounding box for the selection.
+ virtual IntRect selectionRect(bool) { return IntRect(); }
+
+ // Whether or not an object can be part of the leaf elements of the selection.
+ virtual bool canBeSelectionLeaf() const { return false; }
+
+ // Whether or not a block has selected children.
+ virtual bool hasSelectedChildren() const { return false; }
+
+ // Obtains the selection colors that should be used when painting a selection.
+ Color selectionBackgroundColor() const;
+ Color selectionForegroundColor() const;
+
+ // Whether or not a given block needs to paint selection gaps.
+ virtual bool shouldPaintSelectionGaps() const { return false; }
+
+ // This struct is used when the selection changes to cache the old and new state of the selection for each RenderObject.
+ struct SelectionInfo {
+ SelectionInfo()
+ : m_object(0)
+ , m_state(SelectionNone)
+ {
+ }
+
+ SelectionInfo(RenderObject* o, bool clipToVisibleContent)
+ : m_object(o)
+ , m_rect(o->needsLayout() ? IntRect() : o->selectionRect(clipToVisibleContent))
+ , m_state(o->selectionState())
+ {
+ }
+
+ RenderObject* object() const { return m_object; }
+ IntRect rect() const { return m_rect; }
+ SelectionState state() const { return m_state; }
+
+ RenderObject* m_object;
+ IntRect m_rect;
+ SelectionState m_state;
+ };
+
+ Node* draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const;
+
+ /**
+ * Returns the local coordinates of the caret within this render object.
+ * @param caretOffset zero-based offset determining position within the render object.
+ * @param extraWidthToEndOfLine optional out arg to give extra width to end of line -
+ * useful for character range rect computations
+ */
+ virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
+
+ virtual int lowestPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const { return 0; }
+ virtual int rightmostPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const { return 0; }
+ virtual int leftmostPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const { return 0; }
+
+ virtual void calcVerticalMargins() { }
+ void removeFromObjectLists();
+
+ // When performing a global document tear-down, the renderer of the document is cleared. We use this
+ // as a hook to detect the case of document destruction and don't waste time doing unnecessary work.
+ bool documentBeingDestroyed() const;
+
+ virtual void destroy();
+
+ // Virtual function helpers for CSS3 Flexible Box Layout
+ virtual bool isFlexibleBox() const { return false; }
+ virtual bool isFlexingChildren() const { return false; }
+ virtual bool isStretchingChildren() const { return false; }
+
+ // Convenience, to avoid repeating the code to dig down to get this.
+ UChar backslashAsCurrencySymbol() const;
+
+ virtual int caretMinOffset() const;
+ virtual int caretMaxOffset() const;
+ virtual unsigned caretMaxRenderedOffset() const;
+
+ virtual int previousOffset(int current) const;
+ virtual int nextOffset(int current) const;
+
+ virtual void imageChanged(CachedImage*, const IntRect* = 0);
+ virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) { }
+ virtual bool willRenderImage(CachedImage*);
+
+ virtual void selectionStartEnd(int& spos, int& epos) const;
+
+ RenderObject* paintingRootForChildren(PaintInfo& paintInfo) const
+ {
+ // if we're the painting root, kids draw normally, and see root of 0
+ return (!paintInfo.paintingRoot || paintInfo.paintingRoot == this) ? 0 : paintInfo.paintingRoot;
+ }
+
+ bool shouldPaintWithinRoot(PaintInfo& paintInfo) const
+ {
+ return !paintInfo.paintingRoot || paintInfo.paintingRoot == this;
+ }
+
+ bool hasOverrideSize() const { return m_hasOverrideSize; }
+ void setHasOverrideSize(bool b) { m_hasOverrideSize = b; }
+
+ void remove() { if (parent()) parent()->removeChild(this); }
+
+ void invalidateVerticalPosition() { m_verticalPosition = PositionUndefined; }
+
+ virtual void removeLeftoverAnonymousBlock(RenderBlock* child);
+
+ virtual void capsLockStateMayHaveChanged() { }
+
+ AnimationController* animation() const;
+
+ bool visibleToHitTesting() const { return style()->visibility() == VISIBLE && style()->pointerEvents() != PE_NONE; }
+
+protected:
+ // Overrides should call the superclass at the end
+ virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle);
+ // Overrides should call the superclass at the start
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ virtual void printBoxDecorations(GraphicsContext*, int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*tx*/, int /*ty*/) { }
+
+ virtual IntRect viewRect() const;
+
+ int getVerticalPosition(bool firstLine) const;
+
+ void adjustRectForOutlineAndShadow(IntRect&) const;
+
+ void arenaDelete(RenderArena*, void* objectBase);
+
+private:
+ RefPtr<RenderStyle> m_style;
+
+ Node* m_node;
+
+ RenderObject* m_parent;
+ RenderObject* m_previous;
+ RenderObject* m_next;
+
+#ifndef NDEBUG
+ bool m_hasAXObject;
+#endif
+ mutable int m_verticalPosition;
+
+ bool m_needsLayout : 1;
+ bool m_needsPositionedMovementLayout :1;
+ bool m_normalChildNeedsLayout : 1;
+ bool m_posChildNeedsLayout : 1;
+ bool m_prefWidthsDirty : 1;
+ bool m_floating : 1;
+
+ bool m_positioned : 1;
+ bool m_relPositioned : 1;
+ bool m_paintBackground : 1; // if the box has something to paint in the
+ // background painting phase (background, border, etc)
+
+ bool m_isAnonymous : 1;
+ bool m_isText : 1;
+ bool m_inline : 1;
+ bool m_replaced : 1;
+ bool m_isDragging : 1;
+
+ bool m_hasLayer : 1;
+ bool m_hasOverflowClip : 1;
+ bool m_hasTransform : 1;
+ bool m_hasReflection : 1;
+
+ bool m_hasOverrideSize : 1;
+
+public:
+ bool m_hasCounterNodeMap : 1;
+ bool m_everHadLayout : 1;
+
+private:
+ // Store state between styleWillChange and styleDidChange
+ static bool s_affectsParentBlock;
+};
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showTree(const WebCore::RenderObject*);
+#endif
+
+#endif // RenderObject_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp
new file mode 100644
index 0000000..d840418
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderPart.cpp
@@ -0,0 +1,116 @@
+/**
+ * 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)
+ * Copyright (C) 2004, 2005, 2006 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
+ * 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 "RenderPart.h"
+
+#include "Document.h"
+#include "Frame.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HTMLNames.h"
+#include "Page.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderPart::RenderPart(HTMLFrameOwnerElement* node)
+ : RenderWidget(node)
+{
+ // init RenderObject attributes
+ setInline(false);
+}
+
+RenderPart::~RenderPart()
+{
+ // Since deref ends up calling setWidget back on us, need to make sure
+ // that widget is already 0 so it won't do any work.
+ Widget* widget = m_widget;
+ m_widget = 0;
+ if (widget && widget->isFrameView())
+ static_cast<FrameView*>(widget)->deref();
+ else
+ delete widget;
+}
+
+void RenderPart::setWidget(Widget* widget)
+{
+ if (widget != m_widget) {
+ if (widget && widget->isFrameView())
+ static_cast<FrameView*>(widget)->ref();
+ RenderWidget::setWidget(widget);
+
+ // make sure the scrollbars are set correctly for restore
+ // ### find better fix
+ viewCleared();
+ }
+}
+
+void RenderPart::viewCleared()
+{
+}
+
+void RenderPart::deleteWidget()
+{
+ if (m_widget && m_widget->isFrameView())
+ static_cast<FrameView*>(m_widget)->deref();
+ else
+ delete m_widget;
+}
+
+// FIXME: This should not be necessary. Remove this once WebKit knows to properly schedule
+// layouts using WebCore when objects resize.
+void RenderPart::updateWidgetPosition()
+{
+ if (!m_widget)
+ return;
+
+ int width, height;
+ FloatPoint absPos = localToAbsolute();
+ absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
+ width = m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight();
+ height = m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom();
+ IntRect newBounds(absPos.x(), absPos.y(), width, height);
+ bool boundsChanged = newBounds != m_widget->frameRect();
+ if (boundsChanged) {
+ // The widget changed positions. Update the frame geometry.
+ RenderArena *arena = ref();
+ element()->ref();
+ m_widget->setFrameRect(newBounds);
+ element()->deref();
+ deref(arena);
+ }
+
+ // 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
+ if (m_widget && m_widget->isFrameView()) {
+ FrameView* frameView = static_cast<FrameView*>(m_widget);
+ if (boundsChanged || frameView->needsLayout())
+ frameView->layout();
+ }
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPart.h b/src/3rdparty/webkit/WebCore/rendering/RenderPart.h
new file mode 100644
index 0000000..e339468
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderPart.h
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the KDE project.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2006 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
+ * 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 RenderPart_h
+#define RenderPart_h
+
+#include "RenderWidget.h"
+
+namespace WebCore {
+
+class Frame;
+class HTMLFrameOwnerElement;
+
+class RenderPart : public RenderWidget {
+public:
+ RenderPart(HTMLFrameOwnerElement*);
+ virtual ~RenderPart();
+
+ virtual bool isRenderPart() const { return true; }
+ virtual const char* renderName() const { return "RenderPart"; }
+
+ virtual void setWidget(Widget*);
+
+ // FIXME: This should not be necessary.
+ // Remove this once WebKit knows to properly schedule layouts using WebCore when objects resize.
+ virtual void updateWidgetPosition();
+
+ bool hasFallbackContent() const { return m_hasFallbackContent; }
+
+ virtual void viewCleared();
+
+protected:
+ bool m_hasFallbackContent;
+
+private:
+ virtual void deleteWidget();
+};
+
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp
new file mode 100644
index 0000000..e5200e2
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.cpp
@@ -0,0 +1,317 @@
+/*
+ * 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 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 "RenderPartObject.h"
+
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HTMLEmbedElement.h"
+#include "HTMLIFrameElement.h"
+#include "HTMLNames.h"
+#include "HTMLObjectElement.h"
+#include "HTMLParamElement.h"
+#include "MIMETypeRegistry.h"
+#include "Page.h"
+#include "PluginData.h"
+#include "RenderView.h"
+#include "Text.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderPartObject::RenderPartObject(HTMLFrameOwnerElement* element)
+ : RenderPart(element)
+{
+ // init RenderObject attributes
+ setInline(true);
+ m_hasFallbackContent = false;
+
+ if (element->hasTagName(embedTag) || element->hasTagName(objectTag))
+ view()->frameView()->setIsVisuallyNonEmpty();
+}
+
+RenderPartObject::~RenderPartObject()
+{
+ if (m_view)
+ m_view->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 (equalIgnoringRef(frame->loader()->url(), completeURL)) {
+ if (foundSelfReference)
+ return false;
+ foundSelfReference = true;
+ }
+ }
+ return true;
+}
+
+static inline void mapClassIdToServiceType(const String& classId, String& serviceType, 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;
+
+ typedef HashMap<String, String, CaseFoldingHash> ServiceTypeHashMap;
+ static ServiceTypeHashMap* serviceTypeFallbackForClassId = 0;
+ if (!serviceTypeFallbackForClassId) {
+ serviceTypeFallbackForClassId = new ServiceTypeHashMap;
+ serviceTypeFallbackForClassId->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash");
+ serviceTypeFallbackForClassId->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin");
+ serviceTypeFallbackForClassId->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime");
+ serviceTypeFallbackForClassId->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director");
+#if ENABLE(ACTIVEX_TYPE_CONVERSION_WMPLAYER)
+ serviceTypeFallbackForClassId->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2");
+ serviceTypeFallbackForClassId->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2");
+#endif
+ }
+
+ const String fallbackServiceType = serviceTypeFallbackForClassId->get(classId);
+ if (pluginData->supportsMimeType(fallbackServiceType))
+ serviceType = fallbackServiceType;
+ else if (pluginData->supportsMimeType("application/x-oleobject"))
+ serviceType = "application/x-oleobject";
+}
+
+static bool shouldUseChildEmbedOfObject(HTMLObjectElement* o, const PluginData* pluginData)
+{
+ // An OBJECT tag with a classId is some kind of ActiveX control. The most
+ // common controls have parallel plugin versions and thus possibly nested
+ // EMBED tags. If this is the case, the OBJECT's classId should map to some
+ // known plugin MIME type. If it doesn't, either the control is unlikely to
+ // have a parallel plugin implementation (so there's no point looking
+ // inside), or we've purposefully disabled conversion for this classId, in
+ // which case we want to use the ActiveX OBJECT instead of the EMBED anyway.
+ String serviceType;
+ mapClassIdToServiceType(o->classId(), serviceType, pluginData);
+ return serviceType != "application/x-oleobject";
+}
+
+void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins)
+{
+ String url;
+ String serviceType;
+ Vector<String> paramNames;
+ Vector<String> paramValues;
+ Frame* frame = m_view->frame();
+
+ if (element()->hasTagName(objectTag)) {
+ HTMLObjectElement* o = static_cast<HTMLObjectElement*>(element());
+
+ o->setNeedWidgetUpdate(false);
+ if (!o->isFinishedParsingChildren())
+ return;
+
+ // Check for a child EMBED tag.
+ HTMLEmbedElement* embed = 0;
+ const PluginData* pluginData = frame->page()->pluginData();
+ if (pluginData && shouldUseChildEmbedOfObject(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.
+ NamedAttrMap* 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());
+ }
+ }
+ }
+
+ // If we still don't have a type, try to map from a specific CLASSID to a type.
+ if (pluginData && serviceType.isEmpty())
+ mapClassIdToServiceType(o->classId(), serviceType, 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 (element()->hasTagName(embedTag)) {
+ HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(element());
+ 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
+ NamedAttrMap* 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);
+ }
+}
+
+void RenderPartObject::layout()
+{
+ ASSERT(needsLayout());
+
+ calcWidth();
+ calcHeight();
+ adjustOverflowForBoxShadow();
+
+ RenderPart::layout();
+
+ if (!m_widget && m_view)
+ m_view->addWidgetToUpdate(this);
+
+ setNeedsLayout(false);
+}
+
+void RenderPartObject::viewCleared()
+{
+ if (element() && m_widget && m_widget->isFrameView()) {
+ FrameView* view = static_cast<FrameView*>(m_widget);
+ int marginw = -1;
+ int marginh = -1;
+ if (element()->hasTagName(iframeTag)) {
+ HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(element());
+ marginw = frame->getMarginWidth();
+ marginh = frame->getMarginHeight();
+ }
+ if (marginw != -1)
+ view->setMarginWidth(marginw);
+ if (marginh != -1)
+ view->setMarginHeight(marginh);
+ }
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h
new file mode 100644
index 0000000..98de5b9
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderPartObject.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the KDE project.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2006 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
+ * 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 RenderPartObject_h
+#define RenderPartObject_h
+
+#include "RenderPart.h"
+
+namespace WebCore {
+
+class RenderPartObject : public RenderPart {
+public:
+ RenderPartObject(HTMLFrameOwnerElement*);
+ virtual ~RenderPartObject();
+
+ virtual const char* renderName() const { return "RenderPartObject"; }
+
+ virtual void layout();
+ void updateWidget(bool onlyCreateNonNetscapePlugins);
+
+ virtual void viewCleared();
+};
+
+} // namespace WebCore
+
+#endif // RenderPartObject_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp
new file mode 100644
index 0000000..e595745
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderPath.cpp
@@ -0,0 +1,484 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 2008 Rob Buis <buis@kde.org>
+ 2005, 2007 Eric Seidel <eric@webkit.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
+ 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 "RenderPath.h"
+
+#include <math.h>
+
+#include "FloatPoint.h"
+#include "GraphicsContext.h"
+#include "PointerEventsHitRules.h"
+#include "RenderSVGContainer.h"
+#include "StrokeStyleApplier.h"
+#include "SVGPaintServer.h"
+#include "SVGRenderSupport.h"
+#include "SVGResourceFilter.h"
+#include "SVGResourceMarker.h"
+#include "SVGResourceMasker.h"
+#include "SVGStyledTransformableElement.h"
+#include "SVGTransformList.h"
+#include "SVGURIReference.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+class BoundingRectStrokeStyleApplier : public StrokeStyleApplier {
+public:
+ BoundingRectStrokeStyleApplier(const RenderObject* object, RenderStyle* style)
+ : m_object(object)
+ , m_style(style)
+ {
+ ASSERT(style);
+ ASSERT(object);
+ }
+
+ void strokeStyle(GraphicsContext* gc)
+ {
+ applyStrokeStyleToContext(gc, m_style, m_object);
+ }
+
+private:
+ const RenderObject* m_object;
+ RenderStyle* m_style;
+};
+
+// RenderPath
+RenderPath::RenderPath(RenderStyle* style, SVGStyledTransformableElement* node)
+ : RenderObject(node)
+{
+ ASSERT(style != 0);
+ ASSERT(static_cast<SVGElement*>(node)->isStyledTransformable());
+}
+
+RenderPath::~RenderPath()
+{
+}
+
+TransformationMatrix RenderPath::localTransform() const
+{
+ return m_localTransform;
+}
+
+FloatPoint RenderPath::mapAbsolutePointToLocal(const FloatPoint& point) const
+{
+ // FIXME: does it make sense to map incoming points with the inverse of the
+ // absolute transform?
+ double localX;
+ double localY;
+ absoluteTransform().inverse().map(point.x(), point.y(), &localX, &localY);
+ return FloatPoint::narrowPrecision(localX, localY);
+}
+
+bool RenderPath::fillContains(const FloatPoint& point, bool requiresFill) const
+{
+ if (m_path.isEmpty())
+ return false;
+
+ if (requiresFill && !SVGPaintServer::fillPaintServer(style(), this))
+ return false;
+
+ return m_path.contains(point, style()->svgStyle()->fillRule());
+}
+
+FloatRect RenderPath::relativeBBox(bool includeStroke) const
+{
+ if (m_path.isEmpty())
+ return FloatRect();
+
+ if (includeStroke) {
+ if (m_strokeBbox.isEmpty()) {
+ if (style()->svgStyle()->hasStroke()) {
+ BoundingRectStrokeStyleApplier strokeStyle(this, style());
+ m_strokeBbox = m_path.strokeBoundingRect(&strokeStyle);
+ } else {
+ if (m_fillBBox.isEmpty())
+ m_fillBBox = m_path.boundingRect();
+
+ m_strokeBbox = m_fillBBox;
+ }
+ }
+
+ return m_strokeBbox;
+ }
+
+ if (m_fillBBox.isEmpty())
+ m_fillBBox = m_path.boundingRect();
+
+ return m_fillBBox;
+}
+
+void RenderPath::setPath(const Path& newPath)
+{
+ m_path = newPath;
+ m_strokeBbox = FloatRect();
+ m_fillBBox = FloatRect();
+}
+
+const Path& RenderPath::path() const
+{
+ return m_path;
+}
+
+bool RenderPath::calculateLocalTransform()
+{
+ TransformationMatrix oldTransform = m_localTransform;
+ m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform();
+ return (m_localTransform != oldTransform);
+}
+
+void RenderPath::layout()
+{
+ IntRect oldBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout();
+ if (checkForRepaint) {
+ oldBounds = m_absoluteBounds;
+ oldOutlineBox = absoluteOutlineBounds();
+ }
+
+ calculateLocalTransform();
+
+ setPath(static_cast<SVGStyledTransformableElement*>(element())->toPathData());
+
+ m_absoluteBounds = absoluteClippedOverflowRect();
+
+ setWidth(m_absoluteBounds.width());
+ setHeight(m_absoluteBounds.height());
+
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+
+ setNeedsLayout(false);
+}
+
+IntRect RenderPath::absoluteClippedOverflowRect()
+{
+ FloatRect repaintRect = absoluteTransform().mapRect(relativeBBox(true));
+
+ // Markers can expand the bounding box
+ repaintRect.unite(m_markerBounds);
+
+#if ENABLE(SVG_FILTERS)
+ // Filters can expand the bounding box
+ SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter());
+ if (filter)
+ repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect));
+#endif
+
+ if (!repaintRect.isEmpty())
+ repaintRect.inflate(1); // inflate 1 pixel for antialiasing
+
+ return enclosingIntRect(repaintRect);
+}
+
+bool RenderPath::requiresLayer()
+{
+ return false;
+}
+
+int RenderPath::lineHeight(bool, bool) const
+{
+ return relativeBBox(true).height();
+}
+
+int RenderPath::baselinePosition(bool, bool) const
+{
+ return relativeBBox(true).height();
+}
+
+static inline void fillAndStrokePath(const Path& path, GraphicsContext* context, RenderStyle* style, RenderPath* object)
+{
+ context->beginPath();
+
+ SVGPaintServer* fillPaintServer = SVGPaintServer::fillPaintServer(style, object);
+ if (fillPaintServer) {
+ context->addPath(path);
+ fillPaintServer->draw(context, object, ApplyToFillTargetType);
+ }
+
+ SVGPaintServer* strokePaintServer = SVGPaintServer::strokePaintServer(style, object);
+ if (strokePaintServer) {
+ context->addPath(path); // path is cleared when filled.
+ strokePaintServer->draw(context, object, ApplyToStrokeTargetType);
+ }
+}
+
+void RenderPath::paint(PaintInfo& paintInfo, int, int)
+{
+ if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || m_path.isEmpty())
+ return;
+
+ paintInfo.context->save();
+ paintInfo.context->concatCTM(localTransform());
+
+ SVGResourceFilter* filter = 0;
+
+ FloatRect boundingBox = relativeBBox(true);
+ if (paintInfo.phase == PaintPhaseForeground) {
+ PaintInfo savedInfo(paintInfo);
+
+ prepareToRenderSVGContent(this, paintInfo, boundingBox, filter);
+ if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES)
+ paintInfo.context->setUseAntialiasing(false);
+ fillAndStrokePath(m_path, paintInfo.context, style(), this);
+
+ if (static_cast<SVGStyledElement*>(element())->supportsMarkers())
+ m_markerBounds = drawMarkersIfNeeded(paintInfo.context, paintInfo.rect, m_path);
+
+ finishRenderSVGContent(this, paintInfo, boundingBox, 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()),
+ static_cast<int>(boundingBox.width()), static_cast<int>(boundingBox.height()), style());
+
+ paintInfo.context->restore();
+}
+
+void RenderPath::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+{
+ graphicsContext->addFocusRingRect(enclosingIntRect(relativeBBox(true)));
+}
+
+void RenderPath::absoluteRects(Vector<IntRect>& rects, int, int, bool)
+{
+ rects.append(absoluteClippedOverflowRect());
+}
+
+void RenderPath::absoluteQuads(Vector<FloatQuad>& quads, bool)
+{
+ quads.append(absoluteClippedOverflowRect());
+}
+
+bool RenderPath::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int _x, int _y, int, int, HitTestAction hitTestAction)
+{
+ // We only draw in the forground phase, so we only hit-test then.
+ if (hitTestAction != HitTestForeground)
+ return false;
+
+ IntPoint absolutePoint(_x, _y);
+
+ PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_PATH_HITTESTING, style()->pointerEvents());
+
+ bool isVisible = (style()->visibility() == VISIBLE);
+ if (isVisible || !hitRules.requireVisible) {
+ FloatPoint hitPoint = mapAbsolutePointToLocal(absolutePoint);
+ if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke) && strokeContains(hitPoint, hitRules.requireStroke))
+ || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill) && fillContains(hitPoint, hitRules.requireFill))) {
+ updateHitTestResult(result, absolutePoint);
+ return true;
+ }
+ }
+
+ 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
+{
+ Document* doc = document();
+
+ SVGElement* svgElement = static_cast<SVGElement*>(element());
+ ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
+
+ SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement);
+ 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);
+
+ if (!startMarker && !startMarkerId.isEmpty())
+ svgElement->document()->accessSVGExtensions()->addPendingResource(startMarkerId, styledElement);
+ else if (startMarker)
+ startMarker->addClient(styledElement);
+
+ if (!midMarker && !midMarkerId.isEmpty())
+ svgElement->document()->accessSVGExtensions()->addPendingResource(midMarkerId, styledElement);
+ else if (midMarker)
+ midMarker->addClient(styledElement);
+
+ if (!endMarker && !endMarkerId.isEmpty())
+ svgElement->document()->accessSVGExtensions()->addPendingResource(endMarkerId, styledElement);
+ else if (endMarker)
+ 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 bounds;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderPath.h b/src/3rdparty/webkit/WebCore/rendering/RenderPath.h
new file mode 100644
index 0000000..e96439d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderPath.h
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@webkit.org>
+ 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
+ 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 RenderPath_h
+#define RenderPath_h
+
+#if ENABLE(SVG)
+
+#include "TransformationMatrix.h"
+#include "FloatRect.h"
+
+#include "RenderObject.h"
+
+namespace WebCore {
+
+class FloatPoint;
+class Path;
+class RenderSVGContainer;
+class SVGStyledTransformableElement;
+
+class RenderPath : public RenderObject
+{
+public:
+ RenderPath(RenderStyle*, SVGStyledTransformableElement*);
+ virtual ~RenderPath();
+
+ // Hit-detection seperated for the fill and the stroke
+ bool fillContains(const FloatPoint&, bool requiresFill = true) const;
+ bool strokeContains(const FloatPoint&, bool requiresStroke = true) const;
+
+ // Returns an unscaled bounding box (not even including localTransform()) for this vector path
+ virtual FloatRect relativeBBox(bool includeStroke = true) const;
+
+ const Path& path() const;
+ void setPath(const Path& newPath);
+
+ virtual bool isRenderPath() const { return true; }
+ virtual const char* renderName() const { return "RenderPath"; }
+
+ bool calculateLocalTransform();
+ virtual TransformationMatrix localTransform() const;
+
+ virtual void layout();
+ virtual IntRect absoluteClippedOverflowRect();
+ virtual bool requiresLayer();
+ virtual int lineHeight(bool b, bool isRootLineBox = false) const;
+ virtual int baselinePosition(bool b, bool isRootLineBox = false) const;
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+
+ virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+ virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ FloatRect drawMarkersIfNeeded(GraphicsContext*, const FloatRect&, const Path&) const;
+
+private:
+ FloatPoint mapAbsolutePointToLocal(const FloatPoint&) const;
+
+ mutable Path m_path;
+ mutable FloatRect m_fillBBox;
+ mutable FloatRect m_strokeBbox;
+ FloatRect m_markerBounds;
+ TransformationMatrix m_localTransform;
+ IntRect m_absoluteBounds;
+};
+
+}
+
+#endif // ENABLE(SVG)
+#endif
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp
new file mode 100644
index 0000000..79df0f1
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.cpp
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 2007 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 "RenderReplaced.h"
+
+#include "GraphicsContext.h"
+#include "RenderBlock.h"
+#include "RenderLayer.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+
+using namespace std;
+
+namespace WebCore {
+
+typedef WTF::HashMap<const RenderReplaced*, IntRect> OverflowRectMap;
+static OverflowRectMap* gOverflowRectMap = 0;
+
+const int cDefaultWidth = 300;
+const int cDefaultHeight = 150;
+
+RenderReplaced::RenderReplaced(Node* node)
+ : RenderBox(node)
+ , m_intrinsicSize(cDefaultWidth, cDefaultHeight)
+ , m_selectionState(SelectionNone)
+ , m_hasOverflow(false)
+{
+ setReplaced(true);
+}
+
+RenderReplaced::RenderReplaced(Node* node, const IntSize& intrinsicSize)
+ : RenderBox(node)
+ , m_intrinsicSize(intrinsicSize)
+ , m_selectionState(SelectionNone)
+ , m_hasOverflow(false)
+{
+ setReplaced(true);
+}
+
+RenderReplaced::~RenderReplaced()
+{
+ if (m_hasOverflow)
+ gOverflowRectMap->remove(this);
+}
+
+void RenderReplaced::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBox::styleDidChange(diff, oldStyle);
+
+ bool hadStyle = (oldStyle != 0);
+ float oldZoom = hadStyle ? oldStyle->effectiveZoom() : RenderStyle::initialZoom();
+ if (hadStyle && style() && style()->effectiveZoom() != oldZoom)
+ intrinsicSizeChanged();
+}
+
+void RenderReplaced::layout()
+{
+ ASSERT(needsLayout());
+
+ IntRect oldBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout();
+ if (checkForRepaint) {
+ oldBounds = absoluteClippedOverflowRect();
+ oldOutlineBox = absoluteOutlineBounds();
+ }
+
+ m_height = minimumReplacedHeight();
+
+ calcWidth();
+ calcHeight();
+ adjustOverflowForBoxShadow();
+
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+
+ setNeedsLayout(false);
+}
+
+void RenderReplaced::intrinsicSizeChanged()
+{
+ int scaledWidth = static_cast<int>(cDefaultWidth * style()->effectiveZoom());
+ int scaledHeight = static_cast<int>(cDefaultHeight * style()->effectiveZoom());
+ m_intrinsicSize = IntSize(scaledWidth, scaledHeight);
+ setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+void RenderReplaced::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (!shouldPaint(paintInfo, tx, ty))
+ return;
+
+ tx += m_x;
+ ty += m_y;
+
+ if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
+ paintBoxDecorations(paintInfo, tx, ty);
+
+ if (paintInfo.phase == PaintPhaseMask) {
+ paintMask(paintInfo, tx, ty);
+ return;
+ }
+
+ if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth())
+ paintOutline(paintInfo.context, tx, ty, width(), height(), style());
+
+ if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)
+ return;
+
+ if (!shouldPaintWithinRoot(paintInfo))
+ return;
+
+ bool drawSelectionTint = selectionState() != SelectionNone && !document()->printing();
+ if (paintInfo.phase == PaintPhaseSelection) {
+ if (selectionState() == SelectionNone)
+ return;
+ drawSelectionTint = false;
+ }
+
+ paintReplaced(paintInfo, tx, ty);
+
+ if (drawSelectionTint) {
+ IntRect selectionPaintingRect = localSelectionRect();
+ selectionPaintingRect.move(tx, ty);
+ paintInfo.context->fillRect(selectionPaintingRect, selectionBackgroundColor());
+ }
+}
+
+bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, int& tx, int& ty)
+{
+ if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline
+ && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask)
+ return false;
+
+ if (!shouldPaintWithinRoot(paintInfo))
+ return false;
+
+ // if we're invisible or haven't received a layout yet, then just bail.
+ if (style()->visibility() != VISIBLE)
+ return false;
+
+ int currentTX = tx + m_x;
+ int currentTY = ty + m_y;
+
+ // Early exit if the element touches the edges.
+ int top = currentTY + overflowTop();
+ int bottom = currentTY + overflowHeight();
+ if (isSelected() && m_inlineBoxWrapper) {
+ int selTop = ty + m_inlineBoxWrapper->root()->selectionTop();
+ int selBottom = ty + selTop + m_inlineBoxWrapper->root()->selectionHeight();
+ top = min(selTop, top);
+ bottom = max(selBottom, bottom);
+ }
+
+ int os = 2 * maximalOutlineSize(paintInfo.phase);
+ if (currentTX + overflowLeft() >= paintInfo.rect.right() + os || currentTX + overflowWidth() <= paintInfo.rect.x() - os)
+ return false;
+ if (top >= paintInfo.rect.bottom() + os || bottom <= paintInfo.rect.y() - os)
+ return false;
+
+ return true;
+}
+
+void RenderReplaced::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ int paddingAndBorders = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+ int width = calcReplacedWidth(false) + paddingAndBorders;
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
+ width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? paddingAndBorders : 0));
+
+ if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) {
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = width;
+ } else
+ m_minPrefWidth = m_maxPrefWidth = width;
+
+ setPrefWidthsDirty(false);
+}
+
+int RenderReplaced::lineHeight(bool, bool) const
+{
+ return height() + marginTop() + marginBottom();
+}
+
+int RenderReplaced::baselinePosition(bool, bool) const
+{
+ return height() + marginTop() + marginBottom();
+}
+
+unsigned RenderReplaced::caretMaxRenderedOffset() const
+{
+ return 1;
+}
+
+VisiblePosition RenderReplaced::positionForCoordinates(int x, int y)
+{
+ InlineBox* box = inlineBoxWrapper();
+ if (!box)
+ return VisiblePosition(element(), 0, DOWNSTREAM);
+
+ // FIXME: This code is buggy if the replaced element is relative positioned.
+
+ RootInlineBox* root = box->root();
+
+ int top = root->topOverflow();
+ int bottom = root->nextRootBox() ? root->nextRootBox()->topOverflow() : root->bottomOverflow();
+
+ if (y + yPos() < top)
+ return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM); // coordinates are above
+
+ if (y + yPos() >= bottom)
+ return VisiblePosition(element(), caretMaxOffset(), DOWNSTREAM); // coordinates are below
+
+ if (element()) {
+ if (x <= width() / 2)
+ return VisiblePosition(element(), 0, DOWNSTREAM);
+ return VisiblePosition(element(), 1, DOWNSTREAM);
+ }
+
+ return RenderBox::positionForCoordinates(x, y);
+}
+
+IntRect RenderReplaced::selectionRect(bool clipToVisibleContent)
+{
+ ASSERT(!needsLayout());
+
+ if (!isSelected())
+ return IntRect();
+
+ IntRect rect = localSelectionRect();
+ if (clipToVisibleContent)
+ computeAbsoluteRepaintRect(rect);
+ else {
+ FloatPoint absPos = localToAbsoluteForContent(FloatPoint());
+ rect.move(absPos.x(), absPos.y());
+ }
+
+ return rect;
+}
+
+IntRect RenderReplaced::localSelectionRect(bool checkWhetherSelected) const
+{
+ if (checkWhetherSelected && !isSelected())
+ return IntRect();
+
+ if (!m_inlineBoxWrapper)
+ // We're a block-level replaced element. Just return our own dimensions.
+ return IntRect(0, 0, width(), height() + borderTopExtra() + borderBottomExtra());
+
+ RenderBlock* cb = containingBlock();
+ if (!cb)
+ return IntRect();
+
+ RootInlineBox* root = m_inlineBoxWrapper->root();
+ return IntRect(0, root->selectionTop() - yPos(), width(), root->selectionHeight());
+}
+
+void RenderReplaced::setSelectionState(SelectionState s)
+{
+ m_selectionState = s;
+ if (m_inlineBoxWrapper) {
+ RootInlineBox* line = m_inlineBoxWrapper->root();
+ if (line)
+ line->setHasSelectedChildren(isSelected());
+ }
+
+ containingBlock()->setSelectionState(s);
+}
+
+bool RenderReplaced::isSelected() const
+{
+ SelectionState s = selectionState();
+ if (s == SelectionNone)
+ return false;
+ if (s == SelectionInside)
+ return true;
+
+ int selectionStart, selectionEnd;
+ selectionStartEnd(selectionStart, selectionEnd);
+ if (s == SelectionStart)
+ return selectionStart == 0;
+
+ int end = element()->hasChildNodes() ? element()->childNodeCount() : 1;
+ if (s == SelectionEnd)
+ return selectionEnd == end;
+ if (s == SelectionBoth)
+ return selectionStart == 0 && selectionEnd == end;
+
+ ASSERT(0);
+ return false;
+}
+
+IntSize RenderReplaced::intrinsicSize() const
+{
+ return m_intrinsicSize;
+}
+
+void RenderReplaced::setIntrinsicSize(const IntSize& size)
+{
+ m_intrinsicSize = size;
+}
+
+void RenderReplaced::adjustOverflowForBoxShadow()
+{
+ IntRect overflow;
+ for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+ IntRect shadow = borderBox();
+ shadow.move(boxShadow->x, boxShadow->y);
+ shadow.inflate(boxShadow->blur);
+ overflow.unite(shadow);
+ }
+
+ if (!overflow.isEmpty()) {
+ if (!gOverflowRectMap)
+ gOverflowRectMap = new OverflowRectMap();
+ overflow.unite(borderBox());
+ gOverflowRectMap->set(this, overflow);
+ m_hasOverflow = true;
+ } else if (m_hasOverflow) {
+ gOverflowRectMap->remove(this);
+ m_hasOverflow = false;
+ }
+}
+
+int RenderReplaced::overflowHeight(bool) const
+{
+ if (m_hasOverflow) {
+ IntRect *r = &gOverflowRectMap->find(this)->second;
+ return r->height() + r->y();
+ }
+
+ return height();
+}
+
+int RenderReplaced::overflowWidth(bool) const
+{
+ if (m_hasOverflow) {
+ IntRect *r = &gOverflowRectMap->find(this)->second;
+ return r->width() + r->x();
+ }
+
+ return width();
+}
+
+int RenderReplaced::overflowLeft(bool) const
+{
+ if (m_hasOverflow)
+ return gOverflowRectMap->get(this).x();
+
+ return 0;
+}
+
+int RenderReplaced::overflowTop(bool) const
+{
+ if (m_hasOverflow)
+ return gOverflowRectMap->get(this).y();
+
+ return 0;
+}
+
+IntRect RenderReplaced::overflowRect(bool) const
+{
+ if (m_hasOverflow)
+ return gOverflowRectMap->find(this)->second;
+
+ return borderBox();
+}
+
+IntRect RenderReplaced::absoluteClippedOverflowRect()
+{
+ if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
+ return IntRect();
+
+ // The selectionRect can project outside of the overflowRect, so use
+ // that for repainting to avoid selection painting glitches
+ IntRect r = localSelectionRect(false);
+
+ RenderView* v = view();
+ if (v)
+ r.move(v->layoutDelta());
+
+ if (style()) {
+ if (style()->hasAppearance())
+ // The theme may wish to inflate the rect used when repainting.
+ theme()->adjustRepaintRect(this, r);
+ if (v)
+ r.inflate(style()->outlineSize());
+ }
+ computeAbsoluteRepaintRect(r);
+ return r;
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h
new file mode 100644
index 0000000..3186718
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplaced.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple 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
+ * 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 RenderReplaced_h
+#define RenderReplaced_h
+
+#include "RenderBox.h"
+
+namespace WebCore {
+
+class RenderReplaced : public RenderBox {
+public:
+ RenderReplaced(Node*);
+ RenderReplaced(Node*, const IntSize& intrinsicSize);
+ virtual ~RenderReplaced();
+
+ virtual const char* renderName() const { return "RenderReplaced"; }
+
+ virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
+ virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const;
+
+ virtual void calcPrefWidths();
+
+ virtual void layout();
+ virtual int minimumReplacedHeight() const { return 0; }
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void paintReplaced(PaintInfo&, int /*tx*/, int /*ty*/) { }
+
+ virtual IntSize intrinsicSize() const;
+
+ 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 absoluteClippedOverflowRect();
+
+ virtual unsigned caretMaxRenderedOffset() const;
+ virtual VisiblePosition positionForCoordinates(int x, int y);
+
+ virtual bool canBeSelectionLeaf() const { return true; }
+ virtual SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState); }
+ virtual void setSelectionState(SelectionState);
+ virtual IntRect selectionRect(bool clipToVisibleContent = true);
+
+ bool isSelected() const;
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ void setIntrinsicSize(const IntSize&);
+ virtual void intrinsicSizeChanged();
+
+ bool shouldPaint(PaintInfo&, int& tx, int& ty);
+ void adjustOverflowForBoxShadow();
+ IntRect localSelectionRect(bool checkWhetherSelected = true) const;
+
+private:
+ IntSize m_intrinsicSize;
+
+ unsigned m_selectionState : 3; // SelectionState
+ bool m_hasOverflow : 1;
+};
+
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp
new file mode 100644
index 0000000..9556980
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RenderReplica.h"
+
+#include "RenderLayer.h"
+
+namespace WebCore {
+
+RenderReplica::RenderReplica(Node* n)
+: RenderBox(n)
+{}
+
+RenderReplica::~RenderReplica()
+{}
+
+void RenderReplica::layout()
+{
+ IntRect box = parent()->borderBox();
+ m_x = box.x();
+ m_y = box.y();
+ m_width = box.width();
+ m_height = box.height();
+ setNeedsLayout(false);
+}
+
+void RenderReplica::calcPrefWidths()
+{
+ m_minPrefWidth = parent()->width();
+ m_maxPrefWidth = m_minPrefWidth;
+ setPrefWidthsDirty(false);
+}
+
+void RenderReplica::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseMask)
+ return;
+
+ tx += m_x;
+ ty += m_y;
+
+ if (paintInfo.phase == PaintPhaseForeground)
+ // Turn around and paint the parent layer. Use temporary clipRects, so that the layer doesn't end up caching clip rects
+ // computing using the wrong rootLayer
+ layer()->parent()->paintLayer(layer()->transform() ? layer()->parent() : layer()->enclosingTransformedAncestor(),
+ paintInfo.context, paintInfo.rect,
+ true, PaintRestrictionNone, 0,
+ true, // appliedTransform
+ true); // temporaryClipRects
+ else if (paintInfo.phase == PaintPhaseMask)
+ paintMask(paintInfo, tx, ty);
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderReplica.h b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.h
new file mode 100644
index 0000000..d3a9026
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderReplica.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderReplica_h
+#define RenderReplica_h
+
+#include "RenderBox.h"
+
+namespace WebCore {
+
+class RenderReplica : public RenderBox {
+public:
+ RenderReplica(Node*);
+ virtual ~RenderReplica();
+
+ virtual const char* renderName() const { return "RenderReplica"; }
+
+ virtual bool requiresLayer() { return true; }
+
+ virtual void layout();
+ virtual void calcPrefWidths();
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+};
+
+} // namespace WebCore
+
+#endif // RenderReplica_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.cpp
new file mode 100644
index 0000000..f065c44
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.cpp
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGBlock.h"
+
+#include "SVGElement.h"
+
+namespace WebCore {
+
+RenderSVGBlock::RenderSVGBlock(SVGElement* node)
+ : RenderBlock(node)
+{
+}
+
+void RenderSVGBlock::setStyle(PassRefPtr<RenderStyle> style)
+{
+ RefPtr<RenderStyle> useStyle = style;
+
+ // SVG text layout code expects us to be a block-level style element.
+ if (useStyle->display() == NONE)
+ setChildrenInline(false);
+ else if (useStyle->isDisplayInlineType()) {
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(useStyle.get());
+ newStyle->setDisplay(BLOCK);
+ useStyle = newStyle.release();
+ }
+
+ RenderBlock::setStyle(useStyle.release());
+ setReplaced(false);
+
+ //FIXME: Once overflow rules are supported by SVG we should
+ //probably map the CSS overflow rules rather than just ignoring
+ //them
+ setHasOverflowClip(false);
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h
new file mode 100644
index 0000000..d545fd0
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGBlock.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 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
+ * 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 RenderSVGBlock_h
+#define RenderSVGBlock_h
+#if ENABLE(SVG)
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class SVGElement;
+
+class RenderSVGBlock : public RenderBlock {
+public:
+ RenderSVGBlock(SVGElement*);
+ virtual void setStyle(PassRefPtr<RenderStyle>);
+};
+
+}
+#endif // ENABLE(SVG)
+#endif // !RenderSVGBlock_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp
new file mode 100644
index 0000000..2d6b57f
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.cpp
@@ -0,0 +1,438 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 2007, 2008 Rob Buis <buis@kde.org>
+ 2007 Eric Seidel <eric@webkit.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
+ 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 "RenderSVGContainer.h"
+
+#include "AXObjectCache.h"
+#include "GraphicsContext.h"
+#include "RenderView.h"
+#include "SVGRenderSupport.h"
+#include "SVGResourceFilter.h"
+#include "SVGStyledElement.h"
+#include "SVGURIReference.h"
+
+namespace WebCore {
+
+RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node)
+ : RenderObject(node)
+ , m_firstChild(0)
+ , m_lastChild(0)
+ , m_width(0)
+ , m_height(0)
+ , m_drawsContents(true)
+{
+ setReplaced(true);
+}
+
+RenderSVGContainer::~RenderSVGContainer()
+{
+}
+
+bool RenderSVGContainer::canHaveChildren() const
+{
+ return true;
+}
+
+void RenderSVGContainer::addChild(RenderObject* newChild, RenderObject* beforeChild)
+{
+ insertChildNode(newChild, beforeChild);
+}
+
+void RenderSVGContainer::removeChild(RenderObject* oldChild)
+{
+ // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode
+ // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on
+ // layout anyway).
+ oldChild->removeFromObjectLists();
+
+ removeChildNode(oldChild);
+}
+
+void RenderSVGContainer::destroy()
+{
+ destroyLeftoverChildren();
+ RenderObject::destroy();
+}
+
+void RenderSVGContainer::destroyLeftoverChildren()
+{
+ while (m_firstChild) {
+ // Destroy any anonymous children remaining in the render tree, as well as implicit (shadow) DOM elements like those used in the engine-based text fields.
+ if (m_firstChild->element())
+ m_firstChild->element()->setRenderer(0);
+
+ m_firstChild->destroy();
+ }
+}
+
+RenderObject* RenderSVGContainer::removeChildNode(RenderObject* oldChild, bool fullRemove)
+{
+ ASSERT(oldChild->parent() == this);
+
+ // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
+ // that a positioned child got yanked). We also repaint, so that the area exposed when the child
+ // disappears gets repainted properly.
+ if (!documentBeingDestroyed() && fullRemove) {
+ oldChild->setNeedsLayoutAndPrefWidthsRecalc();
+ oldChild->repaint();
+ }
+
+ // If we have a line box wrapper, delete it.
+ oldChild->deleteLineBoxWrapper();
+
+ if (!documentBeingDestroyed() && fullRemove) {
+ // If oldChild is the start or end of the selection, then clear the selection to
+ // avoid problems of invalid pointers.
+ // FIXME: The SelectionController should be responsible for this when it
+ // is notified of DOM mutations.
+ if (oldChild->isSelectionBorder())
+ view()->clearSelection();
+ }
+
+ // remove the child
+ if (oldChild->previousSibling())
+ oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
+ if (oldChild->nextSibling())
+ oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
+
+ if (m_firstChild == oldChild)
+ m_firstChild = oldChild->nextSibling();
+ if (m_lastChild == oldChild)
+ m_lastChild = oldChild->previousSibling();
+
+ oldChild->setPreviousSibling(0);
+ oldChild->setNextSibling(0);
+ oldChild->setParent(0);
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->childrenChanged(this);
+
+ return oldChild;
+}
+
+void RenderSVGContainer::appendChildNode(RenderObject* newChild, bool)
+{
+ ASSERT(!newChild->parent());
+ ASSERT(newChild->element()->isSVGElement());
+
+ newChild->setParent(this);
+ RenderObject* lChild = m_lastChild;
+
+ if (lChild) {
+ newChild->setPreviousSibling(lChild);
+ lChild->setNextSibling(newChild);
+ } else
+ m_firstChild = newChild;
+
+ m_lastChild = newChild;
+
+ newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
+ if (!normalChildNeedsLayout())
+ setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->childrenChanged(this);
+}
+
+void RenderSVGContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild, bool)
+{
+ if (!beforeChild) {
+ appendChildNode(child);
+ return;
+ }
+
+ ASSERT(!child->parent());
+ ASSERT(beforeChild->parent() == this);
+ ASSERT(child->element()->isSVGElement());
+
+ if (beforeChild == m_firstChild)
+ m_firstChild = child;
+
+ RenderObject* prev = beforeChild->previousSibling();
+ child->setNextSibling(beforeChild);
+ beforeChild->setPreviousSibling(child);
+ if (prev)
+ prev->setNextSibling(child);
+ child->setPreviousSibling(prev);
+
+ child->setParent(this);
+
+ child->setNeedsLayoutAndPrefWidthsRecalc();
+ if (!normalChildNeedsLayout())
+ setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->childrenChanged(this);
+}
+
+bool RenderSVGContainer::drawsContents() const
+{
+ return m_drawsContents;
+}
+
+void RenderSVGContainer::setDrawsContents(bool drawsContents)
+{
+ m_drawsContents = drawsContents;
+}
+
+TransformationMatrix RenderSVGContainer::localTransform() const
+{
+ return m_localTransform;
+}
+
+bool RenderSVGContainer::requiresLayer()
+{
+ // Only allow an <svg> element to generate a layer when it's positioned in a non-SVG context
+ return false;
+}
+
+int RenderSVGContainer::lineHeight(bool, bool) const
+{
+ return height() + marginTop() + marginBottom();
+}
+
+int RenderSVGContainer::baselinePosition(bool, bool) const
+{
+ return height() + marginTop() + marginBottom();
+}
+
+bool RenderSVGContainer::calculateLocalTransform()
+{
+ // subclasses can override this to add transform support
+ return false;
+}
+
+void RenderSVGContainer::layout()
+{
+ ASSERT(needsLayout());
+
+ // Arbitrary affine transforms are incompatible with LayoutState.
+ view()->disableLayoutState();
+
+ IntRect oldBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout() && selfWillPaint();
+ if (checkForRepaint) {
+ oldBounds = m_absoluteBounds;
+ oldOutlineBox = absoluteOutlineBounds();
+ }
+
+ calculateLocalTransform();
+
+ 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());
+ }
+
+ calcBounds();
+
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+
+ view()->enableLayoutState();
+ setNeedsLayout(false);
+}
+
+int RenderSVGContainer::calcReplacedWidth() const
+{
+ switch (style()->width().type()) {
+ case Fixed:
+ return max(0, style()->width().value());
+ case Percent:
+ {
+ const int cw = containingBlockWidth();
+ return cw > 0 ? max(0, style()->width().calcMinValue(cw)) : 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+int RenderSVGContainer::calcReplacedHeight() const
+{
+ switch (style()->height().type()) {
+ case Fixed:
+ return max(0, style()->height().value());
+ case Percent:
+ {
+ RenderBlock* cb = containingBlock();
+ return style()->height().calcValue(cb->availableHeight());
+ }
+ default:
+ return 0;
+ }
+}
+
+void RenderSVGContainer::applyContentTransforms(PaintInfo& paintInfo)
+{
+ if (!localTransform().isIdentity())
+ paintInfo.context->concatCTM(localTransform());
+}
+
+void RenderSVGContainer::applyAdditionalTransforms(PaintInfo&)
+{
+ // no-op
+}
+
+void RenderSVGContainer::calcBounds()
+{
+ m_width = calcReplacedWidth();
+ m_height = calcReplacedHeight();
+ m_absoluteBounds = absoluteClippedOverflowRect();
+}
+
+bool RenderSVGContainer::selfWillPaint() const
+{
+#if ENABLE(SVG_FILTERS)
+ const SVGRenderStyle* svgStyle = style()->svgStyle();
+ SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
+ if (filter)
+ return true;
+#endif
+ return false;
+}
+
+void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int)
+{
+ if (paintInfo.context->paintingDisabled() || !drawsContents())
+ return;
+
+ // Spec: groups w/o children still may render filter content.
+ if (!firstChild() && !selfWillPaint())
+ return;
+
+ paintInfo.context->save();
+ applyContentTransforms(paintInfo);
+
+ SVGResourceFilter* filter = 0;
+ PaintInfo savedInfo(paintInfo);
+
+ FloatRect boundingBox = relativeBBox(true);
+ if (paintInfo.phase == PaintPhaseForeground)
+ prepareToRenderSVGContent(this, paintInfo, boundingBox, filter);
+
+ applyAdditionalTransforms(paintInfo);
+
+ // default implementation. Just pass paint through to the children
+ PaintInfo childInfo(paintInfo);
+ childInfo.paintingRoot = paintingRootForChildren(paintInfo);
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling())
+ child->paint(childInfo, 0, 0);
+
+ if (paintInfo.phase == PaintPhaseForeground)
+ finishRenderSVGContent(this, paintInfo, boundingBox, filter, savedInfo.context);
+
+ paintInfo.context->restore();
+
+ if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
+ paintOutline(paintInfo.context, m_absoluteBounds.x(), m_absoluteBounds.y(), m_absoluteBounds.width(), m_absoluteBounds.height(), style());
+}
+
+TransformationMatrix RenderSVGContainer::viewportTransform() const
+{
+ return TransformationMatrix();
+}
+
+IntRect RenderSVGContainer::absoluteClippedOverflowRect()
+{
+ FloatRect repaintRect;
+
+ for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
+ repaintRect.unite(current->absoluteClippedOverflowRect());
+
+#if ENABLE(SVG_FILTERS)
+ // Filters can expand the bounding box
+ SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter());
+ if (filter)
+ repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect));
+#endif
+
+ if (!repaintRect.isEmpty())
+ repaintRect.inflate(1); // inflate 1 pixel for antialiasing
+
+ return enclosingIntRect(repaintRect);
+}
+
+void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+{
+ graphicsContext->addFocusRingRect(m_absoluteBounds);
+}
+
+void RenderSVGContainer::absoluteRects(Vector<IntRect>& rects, int, int, bool)
+{
+ rects.append(absoluteClippedOverflowRect());
+}
+
+void RenderSVGContainer::absoluteQuads(Vector<FloatQuad>& quads, bool)
+{
+ quads.append(absoluteClippedOverflowRect());
+}
+
+FloatRect RenderSVGContainer::relativeBBox(bool includeStroke) const
+{
+ FloatRect rect;
+
+ RenderObject* current = firstChild();
+ for (; current != 0; current = current->nextSibling()) {
+ FloatRect childBBox = current->relativeBBox(includeStroke);
+ FloatRect mappedBBox = current->localTransform().mapRect(childBBox);
+
+ // <svg> can have a viewBox contributing to the bbox
+ if (current->isSVGContainer())
+ mappedBBox = static_cast<RenderSVGContainer*>(current)->viewportTransform().mapRect(mappedBBox);
+
+ rect.unite(mappedBBox);
+ }
+
+ return rect;
+}
+
+bool RenderSVGContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
+{
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
+ if (child->nodeAtPoint(request, result, _x, _y, _tx, _ty, hitTestAction)) {
+ updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty));
+ return true;
+ }
+ }
+
+ // Spec: Only graphical elements can be targeted by the mouse, period.
+ // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched."
+ return false;
+}
+
+}
+
+#endif // ENABLE(SVG)
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h
new file mode 100644
index 0000000..48f5694
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGContainer.h
@@ -0,0 +1,122 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 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
+ 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 RenderSVGContainer_h
+#define RenderSVGContainer_h
+
+#if ENABLE(SVG)
+
+#include "RenderPath.h"
+#include "SVGPreserveAspectRatio.h"
+
+namespace WebCore {
+
+class SVGElement;
+
+class RenderSVGContainer : public RenderObject {
+public:
+ RenderSVGContainer(SVGStyledElement*);
+ ~RenderSVGContainer();
+
+ virtual RenderObject* firstChild() const { return m_firstChild; }
+ virtual RenderObject* lastChild() const { return m_lastChild; }
+
+ virtual int width() const { return m_width; }
+ virtual int height() const { return m_height; }
+
+ virtual bool canHaveChildren() const;
+ virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0);
+ virtual void removeChild(RenderObject*);
+
+ virtual void destroy();
+ void destroyLeftoverChildren();
+
+ virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true);
+ virtual void appendChildNode(RenderObject*, bool fullAppend = true);
+ virtual void insertChildNode(RenderObject* child, RenderObject* before, bool fullInsert = true);
+
+ // Designed for speed. Don't waste time doing a bunch of work like layer updating and repainting when we know that our
+ // change in parentage is not going to affect anything.
+ virtual void moveChildNode(RenderObject* child) { appendChildNode(child->parent()->removeChildNode(child, false), false); }
+
+ virtual void calcPrefWidths() { setPrefWidthsDirty(false); }
+
+ // Some containers do not want it's children
+ // to be drawn, because they may be 'referenced'
+ // Example: <marker> children in SVG
+ void setDrawsContents(bool);
+ bool drawsContents() const;
+
+ virtual bool isSVGContainer() const { return true; }
+ virtual const char* renderName() const { return "RenderSVGContainer"; }
+
+ virtual bool requiresLayer();
+ virtual int lineHeight(bool b, bool isRootLineBox = false) const;
+ virtual int baselinePosition(bool b, bool isRootLineBox = false) const;
+
+ virtual void layout();
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+
+ virtual IntRect absoluteClippedOverflowRect();
+ virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+ virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+
+ FloatRect relativeBBox(bool includeStroke = true) const;
+
+ virtual bool calculateLocalTransform();
+ virtual TransformationMatrix localTransform() const;
+ virtual TransformationMatrix viewportTransform() const;
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+protected:
+ virtual void applyContentTransforms(PaintInfo&);
+ virtual void applyAdditionalTransforms(PaintInfo&);
+
+ void calcBounds();
+
+private:
+ int calcReplacedWidth() const;
+ int calcReplacedHeight() const;
+
+ RenderObject* m_firstChild;
+ RenderObject* m_lastChild;
+
+ int m_width;
+ int m_height;
+
+ bool selfWillPaint() const;
+
+ bool m_drawsContents : 1;
+
+protected:
+ IntRect m_absoluteBounds;
+ TransformationMatrix m_localTransform;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGContainer_h
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp
new file mode 100644
index 0000000..d0dc881
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.cpp
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGGradientStop.h"
+
+#include "SVGGradientElement.h"
+#include "SVGNames.h"
+#include "SVGStopElement.h"
+
+namespace WebCore {
+
+using namespace SVGNames;
+
+RenderSVGGradientStop::RenderSVGGradientStop(SVGStopElement* element)
+ : RenderObject(element)
+{
+}
+
+RenderSVGGradientStop::~RenderSVGGradientStop()
+{
+}
+
+void RenderSVGGradientStop::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderObject::styleDidChange(diff, oldStyle);
+
+ // <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())
+ resource->invalidate();
+ }
+}
+
+void RenderSVGGradientStop::layout()
+{
+ setNeedsLayout(false);
+}
+
+SVGGradientElement* RenderSVGGradientStop::gradientElement() const
+{
+ Node* parentNode = element()->parent();
+ if (parentNode->hasTagName(linearGradientTag) || parentNode->hasTagName(radialGradientTag))
+ return static_cast<SVGGradientElement*>(parentNode);
+ return 0;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.h
new file mode 100644
index 0000000..86de6d0
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGGradientStop.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RenderSVGGradientStop_h
+#define RenderSVGGradientStop_h
+
+#if ENABLE(SVG)
+#include "RenderObject.h"
+
+namespace WebCore {
+
+ class SVGGradientElement;
+ class SVGStopElement;
+
+ // This class exists mostly so we can hear about gradient stop style changes
+ class RenderSVGGradientStop : public RenderObject {
+ public:
+ RenderSVGGradientStop(SVGStopElement*);
+ virtual ~RenderSVGGradientStop();
+
+ virtual const char* renderName() const { return "RenderSVGGradientStop"; }
+
+ virtual void layout();
+
+ // This override is needed to prevent crashing on <svg><stop /></svg>
+ // RenderObject's default impl asks the parent Object and RenderSVGRoot
+ // asks all child RenderObjects for overflow rects, thus infinite loop.
+ // https://bugs.webkit.org/show_bug.cgi?id=20400
+ virtual IntRect absoluteClippedOverflowRect() { return IntRect(); }
+
+ protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ private:
+ SVGGradientElement* gradientElement() const;
+ };
+}
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGGradientStop_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp
new file mode 100644
index 0000000..4a7d6b2
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.cpp
@@ -0,0 +1,116 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGHiddenContainer.h"
+
+#include "RenderPath.h"
+#include "SVGStyledElement.h"
+
+namespace WebCore {
+
+RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGStyledElement* element)
+ : RenderSVGContainer(element)
+{
+}
+
+RenderSVGHiddenContainer::~RenderSVGHiddenContainer()
+{
+}
+
+bool RenderSVGHiddenContainer::requiresLayer()
+{
+ return false;
+}
+
+int RenderSVGHiddenContainer::lineHeight(bool, bool) const
+{
+ return 0;
+}
+
+int RenderSVGHiddenContainer::baselinePosition(bool, bool) const
+{
+ return 0;
+}
+
+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());
+ }
+
+ setNeedsLayout(false);
+}
+
+void RenderSVGHiddenContainer::paint(PaintInfo&, int, int)
+{
+ // This subtree does not paint.
+}
+
+IntRect RenderSVGHiddenContainer::absoluteClippedOverflowRect()
+{
+ return IntRect();
+}
+
+void RenderSVGHiddenContainer::absoluteRects(Vector<IntRect>&, int, int, bool)
+{
+ // This subtree does not take up space or paint
+}
+
+void RenderSVGHiddenContainer::absoluteQuads(Vector<FloatQuad>&, bool)
+{
+ // This subtree does not take up space or paint
+}
+
+TransformationMatrix RenderSVGHiddenContainer::absoluteTransform() const
+{
+ return TransformationMatrix();
+}
+
+TransformationMatrix RenderSVGHiddenContainer::localTransform() const
+{
+ return TransformationMatrix();
+}
+
+bool RenderSVGHiddenContainer::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction)
+{
+ return false;
+}
+
+FloatRect RenderSVGHiddenContainer::relativeBBox(bool) const
+{
+ return FloatRect();
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h
new file mode 100644
index 0000000..24c7ddd
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGHiddenContainer.h
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RenderSVGHiddenContainer_h
+#define RenderSVGHiddenContainer_h
+
+#if ENABLE(SVG)
+
+#include "RenderSVGContainer.h"
+
+namespace WebCore {
+
+ class SVGStyledElement;
+
+ // This class is for containers which are never drawn, but do need to support style
+ // <defs>, <linearGradient>, <radialGradient> are all good examples
+ class RenderSVGHiddenContainer : public RenderSVGContainer {
+ public:
+ RenderSVGHiddenContainer(SVGStyledElement*);
+ virtual ~RenderSVGHiddenContainer();
+
+ virtual bool isSVGContainer() const { return true; }
+ virtual bool isSVGHiddenContainer() const { return true; }
+
+ virtual const char* renderName() const { return "RenderSVGHiddenContainer"; }
+
+ virtual bool requiresLayer();
+
+ virtual int lineHeight(bool b, bool isRootLineBox = false) const;
+ virtual int baselinePosition(bool b, bool isRootLineBox = false) const;
+
+ virtual void layout();
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+
+ virtual IntRect absoluteClippedOverflowRect();
+ virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+
+ virtual TransformationMatrix absoluteTransform() const;
+ virtual TransformationMatrix localTransform() const;
+
+ virtual FloatRect relativeBBox(bool includeStroke = true) const;
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+ };
+}
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGHiddenContainer_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp
new file mode 100644
index 0000000..61f65a0
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.cpp
@@ -0,0 +1,280 @@
+/*
+ Copyright (C) 2006 Alexander Kellett <lypanov@kde.org>
+ Copyright (C) 2006 Apple Computer, Inc.
+ Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ Copyright (C) 2007, 2008 Rob Buis <buis@kde.org>
+
+ This file is part of the WebKit 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
+ 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"
+
+#if ENABLE(SVG)
+#include "RenderSVGImage.h"
+
+#include "Attr.h"
+#include "FloatConversion.h"
+#include "GraphicsContext.h"
+#include "PointerEventsHitRules.h"
+#include "SVGImageElement.h"
+#include "SVGLength.h"
+#include "SVGPreserveAspectRatio.h"
+#include "SVGRenderSupport.h"
+#include "SVGResourceClipper.h"
+#include "SVGResourceFilter.h"
+#include "SVGResourceMasker.h"
+
+namespace WebCore {
+
+RenderSVGImage::RenderSVGImage(SVGImageElement* impl)
+ : RenderImage(impl)
+{
+}
+
+RenderSVGImage::~RenderSVGImage()
+{
+}
+
+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;
+ }
+ }
+ }
+}
+
+bool RenderSVGImage::calculateLocalTransform()
+{
+ TransformationMatrix oldTransform = m_localTransform;
+ m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform();
+ return (m_localTransform != oldTransform);
+}
+
+void RenderSVGImage::layout()
+{
+ ASSERT(needsLayout());
+
+ IntRect oldBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout();
+ if (checkForRepaint) {
+ oldBounds = absoluteClippedOverflowRect();
+ oldOutlineBox = absoluteOutlineBounds();
+ }
+
+ calculateLocalTransform();
+
+ // minimum height
+ m_height = errorOccurred() ? intrinsicSize().height() : 0;
+
+ calcWidth();
+ calcHeight();
+
+ SVGImageElement* image = static_cast<SVGImageElement*>(node());
+ m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image));
+
+ calculateAbsoluteBounds();
+
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+
+ setNeedsLayout(false);
+}
+
+void RenderSVGImage::paint(PaintInfo& paintInfo, int, int)
+{
+ if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN)
+ return;
+
+ paintInfo.context->save();
+ paintInfo.context->concatCTM(localTransform());
+
+ if (paintInfo.phase == PaintPhaseForeground) {
+ SVGResourceFilter* filter = 0;
+
+ PaintInfo savedInfo(paintInfo);
+
+ prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter);
+
+ 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)
+ adjustRectsForAspectRatio(destRect, srcRect, imageElt->preserveAspectRatio());
+
+ paintInfo.context->drawImage(image(), destRect, srcRect);
+
+ finishRenderSVGContent(this, paintInfo, m_localBounds, filter, savedInfo.context);
+ }
+
+ paintInfo.context->restore();
+}
+
+bool RenderSVGImage::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int _x, int _y, int, int, HitTestAction hitTestAction)
+{
+ // We only draw in the forground phase, so we only hit-test then.
+ if (hitTestAction != HitTestForeground)
+ return false;
+
+ PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_IMAGE_HITTESTING, style()->pointerEvents());
+
+ bool isVisible = (style()->visibility() == VISIBLE);
+ if (isVisible || !hitRules.requireVisible) {
+ double localX, localY;
+ absoluteTransform().inverse().map(_x, _y, &localX, &localY);
+
+ if (hitRules.canHitFill) {
+ if (m_localBounds.contains(narrowPrecisionToFloat(localX), narrowPrecisionToFloat(localY))) {
+ updateHitTestResult(result, IntPoint(_x, _y));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool RenderSVGImage::requiresLayer()
+{
+ return false;
+}
+
+FloatRect RenderSVGImage::relativeBBox(bool) const
+{
+ return m_localBounds;
+}
+
+void RenderSVGImage::imageChanged(WrappedImagePtr image, const IntRect* rect)
+{
+ RenderImage::imageChanged(image, rect);
+
+ // We override to invalidate a larger rect, since SVG images can draw outside their "bounds"
+ repaintRectangle(absoluteClippedOverflowRect());
+}
+
+void RenderSVGImage::calculateAbsoluteBounds()
+{
+ // FIXME: broken with CSS transforms
+ FloatRect absoluteRect = absoluteTransform().mapRect(relativeBBox(true));
+
+#if ENABLE(SVG_FILTERS)
+ // Filters can expand the bounding box
+ SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter());
+ if (filter)
+ absoluteRect.unite(filter->filterBBoxForItemBBox(absoluteRect));
+#endif
+
+ if (!absoluteRect.isEmpty())
+ absoluteRect.inflate(1); // inflate 1 pixel for antialiasing
+
+ m_absoluteBounds = enclosingIntRect(absoluteRect);
+}
+
+IntRect RenderSVGImage::absoluteClippedOverflowRect()
+{
+ return m_absoluteBounds;
+}
+
+void RenderSVGImage::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+{
+ // this is called from paint() after the localTransform has already been applied
+ IntRect contentRect = enclosingIntRect(relativeBBox());
+ graphicsContext->addFocusRingRect(contentRect);
+}
+
+void RenderSVGImage::absoluteRects(Vector<IntRect>& rects, int, int, bool)
+{
+ rects.append(absoluteClippedOverflowRect());
+}
+
+void RenderSVGImage::absoluteQuads(Vector<FloatQuad>& quads, bool)
+{
+ quads.append(FloatRect(absoluteClippedOverflowRect()));
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h
new file mode 100644
index 0000000..de8a2d3
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGImage.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2006 Alexander Kellett <lypanov@kde.org>
+ Copyright (C) 2006 Apple Computer, Inc.
+ Copyright (C) 2007 Rob Buis <buis@kde.org>
+
+ This file is part of the WebKit 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
+ 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 RenderSVGImage_h
+#define RenderSVGImage_h
+
+#if ENABLE(SVG)
+
+#include "TransformationMatrix.h"
+#include "FloatRect.h"
+#include "RenderImage.h"
+
+namespace WebCore {
+
+ class SVGImageElement;
+ class SVGPreserveAspectRatio;
+
+ class RenderSVGImage : public RenderImage {
+ public:
+ RenderSVGImage(SVGImageElement*);
+ virtual ~RenderSVGImage();
+
+ virtual TransformationMatrix localTransform() const { return m_localTransform; }
+
+ virtual FloatRect relativeBBox(bool includeStroke = true) const;
+ virtual IntRect absoluteClippedOverflowRect();
+ virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+ virtual void addFocusRingRects(GraphicsContext*, 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);
+
+ bool requiresLayer();
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int _x, int _y, int _tx, int _ty, HitTestAction);
+
+ bool calculateLocalTransform();
+
+ private:
+ void calculateAbsoluteBounds();
+ TransformationMatrix m_localTransform;
+ FloatRect m_localBounds;
+ IntRect m_absoluteBounds;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGImage_h
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp
new file mode 100644
index 0000000..11da004
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.cpp
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * (C) 2006 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
+ * 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"
+
+#if ENABLE(SVG)
+#include "RenderSVGInline.h"
+
+#include "SVGInlineFlowBox.h"
+
+namespace WebCore {
+
+RenderSVGInline::RenderSVGInline(Node* n)
+ : RenderInline(n)
+{
+}
+
+InlineBox* RenderSVGInline::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun)
+{
+ ASSERT(!(!isRootLineBox && (isReplaced() || makePlaceHolderBox)));
+ ASSERT(isInlineFlow());
+
+ InlineFlowBox* flowBox = new (renderArena()) SVGInlineFlowBox(this);
+
+ if (!m_firstLineBox)
+ m_firstLineBox = m_lastLineBox = flowBox;
+ else {
+ m_lastLineBox->setNextLineBox(flowBox);
+ flowBox->setPreviousLineBox(m_lastLineBox);
+ m_lastLineBox = flowBox;
+ }
+
+ return flowBox;
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h
new file mode 100644
index 0000000..42fdafc
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInline.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * (C) 2006 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
+ * 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 RenderSVGInline_h
+#define RenderSVGInline_h
+
+#if ENABLE(SVG)
+#include "RenderInline.h"
+
+namespace WebCore {
+class RenderSVGInline : public RenderInline {
+public:
+ RenderSVGInline(Node*);
+ virtual const char* renderName() const { return "RenderSVGInline"; }
+ virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false);
+ virtual bool requiresLayer() { return false; }
+ };
+}
+
+#endif // ENABLE(SVG)
+#endif // !RenderSVGTSpan_H
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.cpp
new file mode 100644
index 0000000..2212d78
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.cpp
@@ -0,0 +1,180 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * (C) 2006 Apple Computer Inc.
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * (C) 2008 Rob Buis <buis@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGInlineText.h"
+
+#include "FloatConversion.h"
+#include "RenderBlock.h"
+#include "RenderSVGRoot.h"
+#include "SVGInlineTextBox.h"
+#include "SVGRootInlineBox.h"
+
+namespace WebCore {
+
+static inline bool isChildOfHiddenContainer(RenderObject* start)
+{
+ while (start) {
+ if (start->isSVGHiddenContainer())
+ return true;
+
+ start = start->parent();
+ }
+
+ return false;
+}
+
+RenderSVGInlineText::RenderSVGInlineText(Node* n, PassRefPtr<StringImpl> str)
+ : RenderText(n, str)
+{
+}
+
+void RenderSVGInlineText::absoluteRects(Vector<IntRect>& rects, int, int, bool)
+{
+ rects.append(computeAbsoluteRectForRange(0, textLength()));
+}
+
+void RenderSVGInlineText::absoluteQuads(Vector<FloatQuad>& quads, bool)
+{
+ quads.append(FloatRect(computeAbsoluteRectForRange(0, textLength())));
+}
+
+IntRect RenderSVGInlineText::selectionRect(bool)
+{
+ ASSERT(!needsLayout());
+
+ IntRect rect;
+ if (selectionState() == SelectionNone)
+ return rect;
+
+ // Early exit if we're ie. a <text> within a <defs> section.
+ if (isChildOfHiddenContainer(this))
+ return rect;
+
+ // Now calculate startPos and endPos for painting selection.
+ // We include a selection while endPos > 0
+ int startPos, endPos;
+ if (selectionState() == SelectionInside) {
+ // We are fully selected.
+ startPos = 0;
+ endPos = textLength();
+ } else {
+ selectionStartEnd(startPos, endPos);
+ if (selectionState() == SelectionStart)
+ endPos = textLength();
+ else if (selectionState() == SelectionEnd)
+ startPos = 0;
+ }
+
+ if (startPos == endPos)
+ return rect;
+
+ return computeAbsoluteRectForRange(startPos, endPos);
+}
+
+IntRect RenderSVGInlineText::computeAbsoluteRectForRange(int startPos, int endPos)
+{
+ IntRect rect;
+
+ RenderBlock* cb = containingBlock();
+ if (!cb || !cb->container())
+ return rect;
+
+ RenderSVGRoot* root = findSVGRootObject(parent());
+ if (!root)
+ return rect;
+
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ rect.unite(box->selectionRect(0, 0, startPos, endPos));
+
+ // Mimic RenderBox::computeAbsoluteRepaintRect() functionality. But only the subset needed for SVG and respecting SVG transformations.
+ FloatPoint absPos = cb->container()->localToAbsolute();
+
+ // Remove HTML parent translation offsets here! These need to be retrieved from the RenderSVGRoot object.
+ // But do take the containingBlocks's container position into account, ie. SVG text in scrollable <div>.
+ TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform();
+
+ FloatRect fixedRect(narrowPrecisionToFloat(rect.x() + absPos.x() - xPos() - htmlParentCtm.e()),
+ narrowPrecisionToFloat(rect.y() + absPos.y() - yPos() - htmlParentCtm.f()), rect.width(), rect.height());
+ // FIXME: broken with CSS transforms
+ return enclosingIntRect(absoluteTransform().mapRect(fixedRect));
+}
+
+InlineTextBox* RenderSVGInlineText::createInlineTextBox()
+{
+ return new (renderArena()) SVGInlineTextBox(this);
+}
+
+IntRect RenderSVGInlineText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
+{
+ // SVG doesn't have any editable content where a caret rect would be needed
+ return IntRect();
+}
+
+VisiblePosition RenderSVGInlineText::positionForCoordinates(int x, int y)
+{
+ SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(firstTextBox());
+
+ if (!textBox || textLength() == 0)
+ return VisiblePosition(element(), 0, DOWNSTREAM);
+
+ SVGRootInlineBox* rootBox = textBox->svgRootInlineBox();
+ RenderObject* object = rootBox ? rootBox->object() : 0;
+
+ if (!object)
+ return VisiblePosition(element(), 0, DOWNSTREAM);
+
+ int offset = 0;
+
+ for (SVGInlineTextBox* box = textBox; box; box = static_cast<SVGInlineTextBox*>(box->nextTextBox())) {
+ if (box->svgCharacterHitsPosition(x + object->xPos(), y + object->yPos(), offset)) {
+ // If we're not at the end/start of the box, stop looking for other selected boxes.
+ if (box->direction() == LTR) {
+ if (offset <= (int) box->end() + 1)
+ break;
+ } else {
+ if (offset > (int) box->start())
+ break;
+ }
+ }
+ }
+
+ return VisiblePosition(element(), offset, DOWNSTREAM);
+}
+
+void RenderSVGInlineText::destroy()
+{
+ if (!documentBeingDestroyed()) {
+ setNeedsLayoutAndPrefWidthsRecalc();
+ repaint();
+ }
+ RenderText::destroy();
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h
new file mode 100644
index 0000000..cc37166
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGInlineText.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * (C) 2008 Rob Buis <buis@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RenderSVGInlineText_h
+#define RenderSVGInlineText_h
+
+#if ENABLE(SVG)
+
+#include "RenderText.h"
+
+namespace WebCore {
+class RenderSVGInlineText : public RenderText {
+public:
+ RenderSVGInlineText(Node*, PassRefPtr<StringImpl>);
+ virtual const char* renderName() const { return "RenderSVGInlineText"; }
+
+ virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+
+ virtual bool requiresLayer() { return false; }
+ virtual IntRect selectionRect(bool clipToVisibleContent = true);
+ virtual bool isSVGText() const { return true; }
+ virtual InlineTextBox* createInlineTextBox();
+
+ virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
+ virtual VisiblePosition positionForCoordinates(int x, int y);
+
+ virtual void destroy();
+
+private:
+ IntRect computeAbsoluteRectForRange(int startPos, int endPos);
+};
+
+}
+
+#endif // ENABLE(SVG)
+
+#endif // !RenderSVGInlineText_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp
new file mode 100644
index 0000000..457ac02
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.cpp
@@ -0,0 +1,347 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 2007, 2008, 2009 Rob Buis <buis@kde.org>
+ 2007 Eric Seidel <eric@webkit.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
+ 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 "RenderSVGRoot.h"
+
+#include "GraphicsContext.h"
+#include "RenderPath.h"
+#include "RenderSVGContainer.h"
+#include "RenderView.h"
+#include "SVGLength.h"
+#include "SVGRenderSupport.h"
+#include "SVGResourceClipper.h"
+#include "SVGResourceFilter.h"
+#include "SVGResourceMasker.h"
+#include "SVGSVGElement.h"
+#include "SVGStyledElement.h"
+#include "SVGURIReference.h"
+
+using namespace std;
+
+namespace WebCore {
+
+RenderSVGRoot::RenderSVGRoot(SVGStyledElement* node)
+ : RenderContainer(node)
+{
+ setReplaced(true);
+}
+
+RenderSVGRoot::~RenderSVGRoot()
+{
+}
+
+int RenderSVGRoot::lineHeight(bool, bool) const
+{
+ return height() + marginTop() + marginBottom();
+}
+
+int RenderSVGRoot::baselinePosition(bool, bool) const
+{
+ return height() + marginTop() + marginBottom();
+}
+
+void RenderSVGRoot::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ int paddingAndBorders = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+ int width = calcReplacedWidth(false) + paddingAndBorders;
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
+ width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? paddingAndBorders : 0));
+
+ if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) {
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = width;
+ } else
+ m_minPrefWidth = m_maxPrefWidth = width;
+
+ setPrefWidthsDirty(false);
+}
+
+void RenderSVGRoot::layout()
+{
+ ASSERT(needsLayout());
+
+ calcViewport();
+
+ // Arbitrary affine transforms are incompatible with LayoutState.
+ view()->disableLayoutState();
+
+ IntRect oldBounds = m_absoluteBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout();
+ if (checkForRepaint)
+ oldOutlineBox = absoluteOutlineBounds();
+
+ calcWidth();
+ calcHeight();
+
+ m_absoluteBounds = absoluteClippedOverflowRect();
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ m_width = static_cast<int>(m_width * svg->currentScale());
+ m_height = static_cast<int>(m_height * svg->currentScale());
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (selfNeedsLayout()) // either bounds or transform changed, force kids to relayout
+ child->setNeedsLayout(true);
+
+ child->layoutIfNeeded();
+ ASSERT(!child->needsLayout());
+ }
+
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+
+ view()->enableLayoutState();
+ setNeedsLayout(false);
+}
+
+void RenderSVGRoot::applyContentTransforms(PaintInfo& paintInfo, int parentX, int parentY)
+{
+ // Translate from parent offsets (html renderers) to a relative transform (svg renderers)
+ IntPoint origin;
+ origin.move(parentX, parentY);
+ origin.move(m_x, m_y);
+ origin.move(borderLeft(), borderTop());
+ origin.move(paddingLeft(), paddingTop());
+
+ if (origin.x() || origin.y()) {
+ paintInfo.context->concatCTM(TransformationMatrix().translate(origin.x(), origin.y()));
+ paintInfo.rect.move(-origin.x(), -origin.y());
+ }
+
+ // Respect scroll offset caused by html parents
+ TransformationMatrix ctm = RenderContainer::absoluteTransform();
+ paintInfo.rect.move(static_cast<int>(ctm.e()), static_cast<int>(ctm.f()));
+
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ paintInfo.context->concatCTM(TransformationMatrix().scale(svg->currentScale()));
+
+ if (!viewport().isEmpty()) {
+ if (style()->overflowX() != OVISIBLE)
+ paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping
+
+ paintInfo.context->concatCTM(TransformationMatrix().translate(viewport().x(), viewport().y()));
+ }
+
+ paintInfo.context->concatCTM(TransformationMatrix().translate(svg->currentTranslate().x(), svg->currentTranslate().y()));
+}
+
+void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
+{
+ if (paintInfo.context->paintingDisabled())
+ return;
+
+ calcViewport();
+
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ // A value of zero disables rendering of the element.
+ if (viewport().width() <= 0. || viewport().height() <= 0.)
+ return;
+
+ // This should only exist for <svg> renderers
+ if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
+ paintBoxDecorations(paintInfo, m_x + parentX, m_y + parentY);
+
+ if (!firstChild()) {
+#if ENABLE(SVG_FILTERS)
+ // Spec: groups w/o children still may render filter content.
+ const SVGRenderStyle* svgStyle = style()->svgStyle();
+ SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
+ if (!filter)
+#endif
+ return;
+ }
+
+ RenderObject::PaintInfo childPaintInfo(paintInfo);
+ childPaintInfo.context->save();
+
+ applyContentTransforms(childPaintInfo, parentX, parentY);
+
+ SVGResourceFilter* filter = 0;
+
+ FloatRect boundingBox = relativeBBox(true);
+ if (childPaintInfo.phase == PaintPhaseForeground)
+ prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
+
+ childPaintInfo.context->concatCTM(svg->viewBoxToViewTransform(width(), height()));
+ RenderContainer::paint(childPaintInfo, 0, 0);
+
+ if (childPaintInfo.phase == PaintPhaseForeground)
+ finishRenderSVGContent(this, childPaintInfo, boundingBox, filter, paintInfo.context);
+
+ childPaintInfo.context->restore();
+
+ if ((childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
+ paintOutline(childPaintInfo.context, m_absoluteBounds.x(), m_absoluteBounds.y(), m_absoluteBounds.width(), m_absoluteBounds.height(), style());
+}
+
+FloatRect RenderSVGRoot::viewport() const
+{
+ return m_viewport;
+}
+
+void RenderSVGRoot::calcViewport()
+{
+ SVGElement* svgelem = static_cast<SVGElement*>(element());
+ if (svgelem->hasTagName(SVGNames::svgTag)) {
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+
+ if (!selfNeedsLayout() && !svg->hasRelativeValues())
+ return;
+
+ float w, h;
+ SVGLength width = svg->width();
+ if (width.unitType() == LengthTypePercentage && svg->hasSetContainerSize())
+ w = svg->relativeWidthValue();
+ else
+ w = width.value(svg);
+
+ SVGLength height = svg->height();
+ if (height.unitType() == LengthTypePercentage && svg->hasSetContainerSize())
+ h = svg->relativeHeightValue();
+ else
+ h = height.value(svg);
+
+ m_viewport = FloatRect(0, 0, w, h);
+ }
+}
+
+IntRect RenderSVGRoot::absoluteClippedOverflowRect()
+{
+ IntRect repaintRect;
+
+ for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
+ repaintRect.unite(current->absoluteClippedOverflowRect());
+
+#if ENABLE(SVG_FILTERS)
+ // Filters can expand the bounding box
+ SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter());
+ if (filter)
+ repaintRect.unite(enclosingIntRect(filter->filterBBoxForItemBBox(repaintRect)));
+#endif
+
+ return repaintRect;
+}
+
+void RenderSVGRoot::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+{
+ graphicsContext->addFocusRingRect(m_absoluteBounds);
+}
+
+void RenderSVGRoot::absoluteRects(Vector<IntRect>& rects, int, int)
+{
+ for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
+ current->absoluteRects(rects, 0, 0);
+}
+
+void RenderSVGRoot::absoluteQuads(Vector<FloatQuad>& quads, bool)
+{
+ for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
+ current->absoluteQuads(quads);
+}
+
+TransformationMatrix RenderSVGRoot::absoluteTransform() const
+{
+ TransformationMatrix ctm = RenderContainer::absoluteTransform();
+ ctm.translate(m_x, m_y);
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ ctm.scale(svg->currentScale());
+ ctm.translate(svg->currentTranslate().x(), svg->currentTranslate().y());
+ ctm.translate(viewport().x(), viewport().y());
+ return svg->viewBoxToViewTransform(width(), height()) * ctm;
+}
+
+FloatRect RenderSVGRoot::relativeBBox(bool includeStroke) const
+{
+ FloatRect rect;
+
+ RenderObject* current = firstChild();
+ for (; current != 0; current = current->nextSibling()) {
+ FloatRect childBBox = current->relativeBBox(includeStroke);
+ FloatRect mappedBBox = current->localTransform().mapRect(childBBox);
+ // <svg> can have a viewBox contributing to the bbox
+ if (current->isSVGContainer())
+ mappedBBox = static_cast<RenderSVGContainer*>(current)->viewportTransform().mapRect(mappedBBox);
+ rect.unite(mappedBBox);
+ }
+
+ return rect;
+}
+
+TransformationMatrix RenderSVGRoot::localTransform() const
+{
+ return TransformationMatrix();
+}
+
+bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
+{
+ TransformationMatrix ctm = RenderContainer::absoluteTransform();
+
+ int sx = (_tx - static_cast<int>(ctm.e())); // scroll offset
+ int sy = (_ty - static_cast<int>(ctm.f())); // scroll offset
+
+ if (!viewport().isEmpty()
+ && style()->overflowX() == OHIDDEN
+ && style()->overflowY() == OHIDDEN) {
+ int tx = m_x - _tx + sx;
+ int ty = m_y - _ty + sy;
+
+ // Check if we need to do anything at all.
+ IntRect overflowBox = overflowRect(false);
+ overflowBox.move(tx, ty);
+ ctm.translate(viewport().x(), viewport().y());
+ double localX, localY;
+ ctm.inverse().map(_x - _tx, _y - _ty, &localX, &localY);
+ if (!overflowBox.contains((int)localX, (int)localY))
+ return false;
+ }
+
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
+ if (child->nodeAtPoint(request, result, _x - sx, _y - sy, 0, 0, hitTestAction)) {
+ updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty));
+ return true;
+ }
+ }
+
+ // Spec: Only graphical elements can be targeted by the mouse, period.
+ // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched."
+ return false;
+}
+
+void RenderSVGRoot::position(InlineBox* box)
+{
+ RenderContainer::position(box);
+ if (m_absoluteBounds.isEmpty())
+ setNeedsLayout(true, false);
+}
+
+}
+
+#endif // ENABLE(SVG)
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h
new file mode 100644
index 0000000..acac78b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGRoot.h
@@ -0,0 +1,82 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 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
+ 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 RenderSVGRoot_h
+#define RenderSVGRoot_h
+
+#if ENABLE(SVG)
+#include "RenderContainer.h"
+#include "FloatRect.h"
+
+namespace WebCore {
+
+class SVGStyledElement;
+class TransformationMatrix;
+
+class RenderSVGRoot : public RenderContainer {
+public:
+ RenderSVGRoot(SVGStyledElement*);
+ ~RenderSVGRoot();
+
+ virtual bool isSVGRoot() const { return true; }
+ virtual const char* renderName() const { return "RenderSVGRoot"; }
+
+ virtual int lineHeight(bool b, bool isRootLineBox = false) const;
+ virtual int baselinePosition(bool b, bool isRootLineBox = false) const;
+ virtual void calcPrefWidths();
+
+ virtual void layout();
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+
+ virtual IntRect absoluteClippedOverflowRect();
+ virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+ virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+
+ virtual TransformationMatrix absoluteTransform() const;
+
+ bool fillContains(const FloatPoint&) const;
+ bool strokeContains(const FloatPoint&) const;
+ FloatRect relativeBBox(bool includeStroke = true) const;
+
+ virtual TransformationMatrix localTransform() const;
+
+ FloatRect viewport() const;
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ virtual void position(InlineBox*);
+
+private:
+ void calcViewport();
+ void applyContentTransforms(PaintInfo&, int parentX, int parentY);
+
+ FloatRect m_viewport;
+ IntRect m_absoluteBounds;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGRoot_h
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.cpp
new file mode 100644
index 0000000..fd2d3dd
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.cpp
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * (C) 2006 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
+ * 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"
+
+#if ENABLE(SVG)
+#include "RenderSVGTSpan.h"
+
+#include "FloatRect.h"
+#include "SVGInlineTextBox.h"
+#include "SVGRootInlineBox.h"
+
+namespace WebCore {
+
+RenderSVGTSpan::RenderSVGTSpan(Node* n)
+ : RenderSVGInline(n)
+{
+}
+
+void RenderSVGTSpan::absoluteRects(Vector<IntRect>& rects, int, int, bool)
+{
+ InlineRunBox* firstBox = firstLineBox();
+
+ SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0;
+ RenderObject* object = rootBox ? rootBox->object() : 0;
+
+ if (!object)
+ return;
+
+ int xRef = object->xPos() + xPos();
+ int yRef = object->yPos() + yPos();
+
+ for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
+ FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+ // FIXME: broken with CSS transforms
+ rects.append(enclosingIntRect(absoluteTransform().mapRect(rect)));
+ }
+}
+
+void RenderSVGTSpan::absoluteQuads(Vector<FloatQuad>& quads, bool)
+{
+ InlineRunBox* firstBox = firstLineBox();
+
+ SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0;
+ RenderObject* object = rootBox ? rootBox->object() : 0;
+
+ if (!object)
+ return;
+
+ int xRef = object->xPos() + xPos();
+ int yRef = object->yPos() + yPos();
+
+ for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
+ FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+ // FIXME: broken with CSS transforms
+ quads.append(absoluteTransform().mapRect(rect));
+ }
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h
new file mode 100644
index 0000000..d34cd2f
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTSpan.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * (C) 2006 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
+ * 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 RenderSVGTSpan_h
+#define RenderSVGTSpan_h
+
+#if ENABLE(SVG)
+#include "RenderSVGInline.h"
+
+namespace WebCore {
+class RenderSVGTSpan : public RenderSVGInline {
+public:
+ RenderSVGTSpan(Node*);
+ virtual const char* renderName() const { return "RenderSVGTSpan"; }
+ virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+};
+}
+
+#endif // ENABLE(SVG)
+#endif // !RenderSVGTSpan_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.cpp
new file mode 100644
index 0000000..1a1196b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.cpp
@@ -0,0 +1,242 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * 2006 Alexander Kellett <lypanov@kde.org>
+ * 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * 2008 Rob Buis <buis@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGText.h"
+
+#include "FloatConversion.h"
+#include "GraphicsContext.h"
+#include "PointerEventsHitRules.h"
+#include "RenderSVGRoot.h"
+#include "SimpleFontData.h"
+#include "SVGLengthList.h"
+#include "SVGResourceFilter.h"
+#include "SVGRootInlineBox.h"
+#include "SVGTextElement.h"
+#include "SVGTransformList.h"
+#include "SVGURIReference.h"
+
+namespace WebCore {
+
+RenderSVGText::RenderSVGText(SVGTextElement* node)
+ : RenderSVGBlock(node)
+{
+}
+
+IntRect RenderSVGText::absoluteClippedOverflowRect()
+{
+ FloatRect repaintRect = absoluteTransform().mapRect(relativeBBox(true));
+
+#if ENABLE(SVG_FILTERS)
+ // Filters can expand the bounding box
+ SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter());
+ if (filter)
+ repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect));
+#endif
+
+ if (!repaintRect.isEmpty())
+ repaintRect.inflate(1); // inflate 1 pixel for antialiasing
+
+ return enclosingIntRect(repaintRect);
+}
+
+bool RenderSVGText::requiresLayer()
+{
+ return false;
+}
+
+bool RenderSVGText::calculateLocalTransform()
+{
+ TransformationMatrix oldTransform = m_localTransform;
+ m_localTransform = static_cast<SVGTextElement*>(element())->animatedLocalTransform();
+ return (oldTransform != m_localTransform);
+}
+
+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);
+
+ IntRect oldBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout();
+ if (checkForRepaint) {
+ oldBounds = m_absoluteBounds;
+ oldOutlineBox = absoluteOutlineBounds();
+ }
+
+ // Best guess for a relative starting point
+ SVGTextElement* text = static_cast<SVGTextElement*>(element());
+ int xOffset = (int)(text->x()->getFirst().value(text));
+ int yOffset = (int)(text->y()->getFirst().value(text));
+ setPos(xOffset, yOffset);
+
+ calculateLocalTransform();
+
+ RenderBlock::layout();
+
+ m_absoluteBounds = absoluteClippedOverflowRect();
+
+ bool repainted = false;
+ if (checkForRepaint)
+ repainted = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+
+ setNeedsLayout(false);
+}
+
+InlineBox* RenderSVGText::createInlineBox(bool, bool, bool)
+{
+ ASSERT(!isInlineFlow());
+ InlineFlowBox* flowBox = new (renderArena()) SVGRootInlineBox(this);
+
+ if (!m_firstLineBox)
+ m_firstLineBox = m_lastLineBox = flowBox;
+ else {
+ m_lastLineBox->setNextLineBox(flowBox);
+ flowBox->setPreviousLineBox(m_lastLineBox);
+ m_lastLineBox = flowBox;
+ }
+
+ return flowBox;
+}
+
+bool RenderSVGText::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
+{
+ PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, style()->pointerEvents());
+ bool isVisible = (style()->visibility() == VISIBLE);
+ if (isVisible || !hitRules.requireVisible) {
+ if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke))
+ || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill))) {
+ TransformationMatrix totalTransform = absoluteTransform();
+ double localX, localY;
+ totalTransform.inverse().map(_x, _y, &localX, &localY);
+ FloatPoint hitPoint(_x, _y);
+ return RenderBlock::nodeAtPoint(request, result, (int)localX, (int)localY, _tx, _ty, hitTestAction);
+ }
+ }
+
+ return false;
+}
+
+void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int, bool)
+{
+ RenderSVGRoot* root = findSVGRootObject(parent());
+ if (!root)
+ return;
+
+ FloatPoint absPos = localToAbsolute();
+
+ TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform();
+
+ // Don't use relativeBBox here, as it's unites the selection rects. Makes it hard
+ // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'.
+ for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) {
+ ASSERT(runBox->isInlineFlowBox());
+
+ InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox);
+ for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) {
+ FloatRect boxRect(box->xPos(), box->yPos(), box->width(), box->height());
+ boxRect.move(narrowPrecisionToFloat(absPos.x() - htmlParentCtm.e()), narrowPrecisionToFloat(absPos.y() - htmlParentCtm.f()));
+ // FIXME: broken with CSS transforms
+ rects.append(enclosingIntRect(absoluteTransform().mapRect(boxRect)));
+ }
+ }
+}
+
+void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool)
+{
+ RenderSVGRoot* root = findSVGRootObject(parent());
+ if (!root)
+ return;
+
+ FloatPoint absPos = localToAbsolute();
+
+ TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform();
+
+ // Don't use relativeBBox here, as it's unites the selection rects. Makes it hard
+ // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'.
+ for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) {
+ ASSERT(runBox->isInlineFlowBox());
+
+ InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox);
+ for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) {
+ FloatRect boxRect(box->xPos(), box->yPos(), box->width(), box->height());
+ boxRect.move(narrowPrecisionToFloat(absPos.x() - htmlParentCtm.e()), narrowPrecisionToFloat(absPos.y() - htmlParentCtm.f()));
+ // FIXME: broken with CSS transforms
+ quads.append(absoluteTransform().mapRect(boxRect));
+ }
+ }
+}
+
+void RenderSVGText::paint(PaintInfo& paintInfo, int, int)
+{
+ RenderObject::PaintInfo pi(paintInfo);
+ pi.rect = absoluteTransform().inverse().mapRect(pi.rect);
+ RenderBlock::paint(pi, 0, 0);
+}
+
+FloatRect RenderSVGText::relativeBBox(bool includeStroke) const
+{
+ FloatRect repaintRect;
+
+ for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) {
+ ASSERT(runBox->isInlineFlowBox());
+
+ InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox);
+ for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine())
+ repaintRect.unite(FloatRect(box->xPos(), box->yPos(), box->width(), box->height()));
+ }
+
+ // SVG needs to include the strokeWidth(), not the textStrokeWidth().
+ if (includeStroke && style()->svgStyle()->hasStroke()) {
+ float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, style()->svgStyle()->strokeWidth(), 0.0f);
+
+#if ENABLE(SVG_FONTS)
+ const Font& font = style()->font();
+ if (font.primaryFont()->isSVGFont()) {
+ float scale = font.unitsPerEm() > 0 ? font.size() / font.unitsPerEm() : 0.0f;
+
+ if (scale != 0.0f)
+ strokeWidth /= scale;
+ }
+#endif
+
+ repaintRect.inflate(strokeWidth);
+ }
+
+ repaintRect.move(xPos(), yPos());
+ return repaintRect;
+}
+
+}
+
+#endif // ENABLE(SVG)
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h
new file mode 100644
index 0000000..d76d451
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGText.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RenderSVGText_h
+#define RenderSVGText_h
+
+#if ENABLE(SVG)
+
+#include "TransformationMatrix.h"
+#include "RenderSVGBlock.h"
+
+namespace WebCore {
+
+class SVGTextElement;
+
+class RenderSVGText : public RenderSVGBlock {
+public:
+ RenderSVGText(SVGTextElement* node);
+
+ virtual const char* renderName() const { return "RenderSVGText"; }
+
+ virtual bool isSVGText() const { return true; }
+
+ bool calculateLocalTransform();
+ virtual TransformationMatrix localTransform() 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);
+
+ virtual bool requiresLayer();
+ virtual void layout();
+
+ virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+
+ virtual IntRect absoluteClippedOverflowRect();
+ virtual FloatRect relativeBBox(bool includeStroke = true) const;
+
+ virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false);
+
+private:
+ TransformationMatrix m_localTransform;
+ IntRect m_absoluteBounds;
+};
+
+}
+
+#endif // ENABLE(SVG)
+#endif
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.cpp
new file mode 100644
index 0000000..aa0209c
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.cpp
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGTextPath.h"
+
+#include "FloatRect.h"
+#include "SVGInlineTextBox.h"
+#include "SVGPathElement.h"
+#include "SVGRootInlineBox.h"
+#include "SVGTextPathElement.h"
+#include "SVGTransformList.h"
+
+namespace WebCore {
+
+RenderSVGTextPath::RenderSVGTextPath(Node* n)
+ : RenderSVGInline(n)
+ , m_startOffset(0.0f)
+ , m_exactAlignment(true)
+ , m_stretchMethod(false)
+{
+}
+
+Path RenderSVGTextPath::layoutPath() const
+{
+ SVGTextPathElement* textPathElement = static_cast<SVGTextPathElement*>(element());
+ String pathId = SVGURIReference::getTarget(textPathElement->href());
+ Element* targetElement = textPathElement->document()->getElementById(pathId);
+ if (!targetElement || !targetElement->hasTagName(SVGNames::pathTag))
+ return Path();
+
+ SVGPathElement* pathElement = static_cast<SVGPathElement*>(targetElement);
+
+ Path pathData = pathElement->toPathData();
+ // Spec: The transform attribute on the referenced 'path' element represents a
+ // supplemental transformation relative to the current user coordinate system for
+ // the current 'text' element, including any adjustments to the current user coordinate
+ // system due to a possible transform attribute on the current 'text' element.
+ // http://www.w3.org/TR/SVG/text.html#TextPathElement
+ pathData.transform(pathElement->animatedLocalTransform());
+ return pathData;
+}
+
+float RenderSVGTextPath::startOffset() const
+{
+ return static_cast<SVGTextPathElement*>(element())->startOffset().valueAsPercentage();
+}
+
+bool RenderSVGTextPath::exactAlignment() const
+{
+ return static_cast<SVGTextPathElement*>(element())->spacing() == SVG_TEXTPATH_SPACINGTYPE_EXACT;
+}
+
+bool RenderSVGTextPath::stretchMethod() const
+{
+ return static_cast<SVGTextPathElement*>(element())->method() == SVG_TEXTPATH_METHODTYPE_STRETCH;
+}
+
+void RenderSVGTextPath::absoluteRects(Vector<IntRect>& rects, int, int)
+{
+ InlineRunBox* firstBox = firstLineBox();
+
+ SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0;
+ RenderObject* object = rootBox ? rootBox->object() : 0;
+
+ if (!object)
+ return;
+
+ int xRef = object->xPos() + xPos();
+ int yRef = object->yPos() + yPos();
+
+ for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
+ FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+ // FIXME: broken with CSS transforms
+ rects.append(enclosingIntRect(absoluteTransform().mapRect(rect)));
+ }
+}
+
+void RenderSVGTextPath::absoluteQuads(Vector<FloatQuad>& quads, bool)
+{
+ InlineRunBox* firstBox = firstLineBox();
+
+ SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0;
+ RenderObject* object = rootBox ? rootBox->object() : 0;
+
+ if (!object)
+ return;
+
+ int xRef = object->xPos() + xPos();
+ int yRef = object->yPos() + yPos();
+
+ for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) {
+ FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height());
+ // FIXME: broken with CSS transforms
+ quads.append(absoluteTransform().mapRect(rect));
+ }
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.h
new file mode 100644
index 0000000..4fd4cc3
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTextPath.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RenderSVGTextPath_h
+#define RenderSVGTextPath_h
+
+#if ENABLE(SVG)
+#include "RenderSVGInline.h"
+
+namespace WebCore {
+
+ class RenderSVGTextPath : public RenderSVGInline {
+ public:
+ RenderSVGTextPath(Node*);
+
+ Path layoutPath() const;
+ float startOffset() const;
+ bool exactAlignment() const;
+ bool stretchMethod() const;
+
+ virtual const char* renderName() const { return "RenderSVGTextPath"; }
+ virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+
+ private:
+ float m_startOffset;
+
+ bool m_exactAlignment : 1;
+ bool m_stretchMethod : 1;
+
+ Path m_layoutPath;
+ };
+}
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGTextPath_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp
new file mode 100644
index 0000000..17d64f3
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.cpp
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
+ 2004, 2005, 2006 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
+ 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"
+#if ENABLE(SVG)
+
+#include "RenderSVGTransformableContainer.h"
+
+#include "SVGStyledTransformableElement.h"
+#include "SVGTransformList.h"
+
+namespace WebCore {
+
+RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransformableElement* node)
+ : RenderSVGContainer(node)
+{
+}
+
+bool RenderSVGTransformableContainer::calculateLocalTransform()
+{
+ TransformationMatrix oldTransform = m_localTransform;
+ m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform();
+ return (m_localTransform != oldTransform);
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h
new file mode 100644
index 0000000..897cc63
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGTransformableContainer.h
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 2007 Eric Seidel <eric@webkit.org
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ 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 RenderSVGTransformableContainer_h
+#define RenderSVGTransformableContainer_h
+
+#if ENABLE(SVG)
+#include "RenderSVGContainer.h"
+
+namespace WebCore {
+
+ class SVGStyledTransformableElement;
+ class RenderSVGTransformableContainer : public RenderSVGContainer {
+ public:
+ RenderSVGTransformableContainer(SVGStyledTransformableElement*);
+
+ virtual bool calculateLocalTransform();
+ };
+}
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGTransformableContainer_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp
new file mode 100644
index 0000000..f6ac424
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.cpp
@@ -0,0 +1,198 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 2007 Rob Buis <buis@kde.org>
+ 2007 Eric Seidel <eric@webkit.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
+ 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 "RenderSVGViewportContainer.h"
+
+#include "GraphicsContext.h"
+
+#include "RenderView.h"
+#include "SVGMarkerElement.h"
+#include "SVGSVGElement.h"
+
+namespace WebCore {
+
+RenderSVGViewportContainer::RenderSVGViewportContainer(SVGStyledElement* node)
+ : RenderSVGContainer(node)
+{
+ setReplaced(true);
+}
+
+RenderSVGViewportContainer::~RenderSVGViewportContainer()
+{
+}
+
+void RenderSVGViewportContainer::layout()
+{
+ ASSERT(needsLayout());
+
+ calcViewport();
+
+ // Arbitrary affine transforms are incompatible with LayoutState.
+ view()->disableLayoutState();
+
+ IntRect oldBounds = m_absoluteBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout();
+ if (checkForRepaint)
+ oldOutlineBox = absoluteOutlineBounds();
+
+ calcBounds();
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (selfNeedsLayout())
+ child->setNeedsLayout(true);
+
+ child->layoutIfNeeded();
+ ASSERT(!child->needsLayout());
+ }
+
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+
+ view()->enableLayoutState();
+ setNeedsLayout(false);
+}
+
+void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, int parentX, int parentY)
+{
+ // A value of zero disables rendering of the element.
+ if (!viewport().isEmpty() && (viewport().width() <= 0. || viewport().height() <= 0.))
+ return;
+
+ RenderSVGContainer::paint(paintInfo, parentX, parentY);
+}
+
+void RenderSVGViewportContainer::applyContentTransforms(PaintInfo& paintInfo)
+{
+ if (!viewport().isEmpty()) {
+ if (style()->overflowX() != OVISIBLE)
+ paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping
+
+ paintInfo.context->concatCTM(TransformationMatrix().translate(viewport().x(), viewport().y()));
+ }
+
+ RenderSVGContainer::applyContentTransforms(paintInfo);
+}
+
+void RenderSVGViewportContainer::applyAdditionalTransforms(PaintInfo& paintInfo)
+{
+ paintInfo.context->concatCTM(viewportTransform());
+ RenderSVGContainer::applyAdditionalTransforms(paintInfo);
+}
+
+FloatRect RenderSVGViewportContainer::viewport() const
+{
+ return m_viewport;
+}
+
+void RenderSVGViewportContainer::calcViewport()
+{
+ SVGElement* svgelem = static_cast<SVGElement*>(element());
+ if (svgelem->hasTagName(SVGNames::svgTag)) {
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+
+ if (!selfNeedsLayout() && !svg->hasRelativeValues())
+ return;
+
+ float x = svg->x().value(svg);
+ float y = svg->y().value(svg);
+ float w = svg->width().value(svg);
+ float h = svg->height().value(svg);
+ m_viewport = FloatRect(x, y, w, h);
+ } else if (svgelem->hasTagName(SVGNames::markerTag)) {
+ if (!selfNeedsLayout())
+ return;
+
+ SVGMarkerElement* svg = static_cast<SVGMarkerElement*>(element());
+ float w = svg->markerWidth().value(svg);
+ float h = svg->markerHeight().value(svg);
+ m_viewport = FloatRect(0, 0, w, h);
+ }
+}
+
+TransformationMatrix RenderSVGViewportContainer::viewportTransform() const
+{
+ if (element()->hasTagName(SVGNames::svgTag)) {
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ return svg->viewBoxToViewTransform(viewport().width(), viewport().height());
+ } else if (element()->hasTagName(SVGNames::markerTag)) {
+ SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(element());
+ return marker->viewBoxToViewTransform(viewport().width(), viewport().height());
+ }
+
+ return TransformationMatrix();
+}
+
+TransformationMatrix RenderSVGViewportContainer::absoluteTransform() const
+{
+ TransformationMatrix ctm = RenderObject::absoluteTransform();
+ ctm.translate(viewport().x(), viewport().y());
+ return viewportTransform() * ctm;
+}
+
+bool RenderSVGViewportContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
+{
+ if (!viewport().isEmpty()
+ && style()->overflowX() == OHIDDEN
+ && style()->overflowY() == OHIDDEN) {
+ // Check if we need to do anything at all.
+ IntRect overflowBox = overflowRect(false);
+ overflowBox.move(_tx, _ty);
+ TransformationMatrix ctm = RenderObject::absoluteTransform();
+ ctm.translate(viewport().x(), viewport().y());
+ double localX, localY;
+ ctm.inverse().map(_x - _tx, _y - _ty, &localX, &localY);
+ if (!overflowBox.contains((int)localX, (int)localY))
+ return false;
+ }
+
+ int sx = 0;
+ int sy = 0;
+
+ // Respect parent translation offset for non-outermost <svg> elements.
+ // Outermost <svg> element is handled by RenderSVGRoot.
+ if (element()->hasTagName(SVGNames::svgTag)) {
+ sx = _tx;
+ sy = _ty;
+ }
+
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
+ if (child->nodeAtPoint(request, result, _x - sx, _y - sy, _tx, _ty, hitTestAction)) {
+ updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty));
+ return true;
+ }
+ }
+
+ // Spec: Only graphical elements can be targeted by the mouse, period.
+ // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched."
+ return false;
+}
+
+}
+
+#endif // ENABLE(SVG)
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h
new file mode 100644
index 0000000..2e4a49c
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSVGViewportContainer.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 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
+ 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 RenderSVGViewportContainer_h
+#define RenderSVGViewportContainer_h
+
+#if ENABLE(SVG)
+
+#include "RenderSVGContainer.h"
+
+namespace WebCore {
+
+class RenderSVGViewportContainer : public RenderSVGContainer {
+public:
+ RenderSVGViewportContainer(SVGStyledElement*);
+ ~RenderSVGViewportContainer();
+
+ virtual bool isSVGContainer() const { return true; }
+ virtual const char* renderName() const { return "RenderSVGViewportContainer"; }
+
+ virtual void layout();
+ virtual void paint(PaintInfo&, int parentX, int parentY);
+
+ virtual TransformationMatrix absoluteTransform() const;
+ virtual TransformationMatrix viewportTransform() const;
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ FloatRect viewport() const;
+
+private:
+ void calcViewport();
+
+ virtual void applyContentTransforms(PaintInfo&);
+ virtual void applyAdditionalTransforms(PaintInfo&);
+
+ FloatRect m_viewport;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // RenderSVGViewportContainer_h
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.cpp
new file mode 100644
index 0000000..b7045d6
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include "config.h"
+#include "RenderScrollbar.h"
+#include "RenderScrollbarPart.h"
+#include "RenderScrollbarTheme.h"
+
+namespace WebCore {
+
+PassRefPtr<Scrollbar> RenderScrollbar::createCustomScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderObject* renderer)
+{
+ return adoptRef(new RenderScrollbar(client, orientation, renderer));
+}
+
+RenderScrollbar::RenderScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderObject* renderer)
+ : Scrollbar(client, orientation, RegularScrollbar, RenderScrollbarTheme::renderScrollbarTheme())
+ , m_owner(renderer)
+{
+}
+
+RenderScrollbar::~RenderScrollbar()
+{
+ ASSERT(m_parts.isEmpty());
+}
+
+void RenderScrollbar::setParent(ScrollView* parent)
+{
+ Scrollbar::setParent(parent);
+ if (!parent) {
+ // Destroy all of the scrollbar's RenderObjects.
+ updateScrollbarParts(true);
+ }
+}
+
+void RenderScrollbar::setEnabled(bool e)
+{
+ bool wasEnabled = enabled();
+ Scrollbar::setEnabled(e);
+ if (wasEnabled != e)
+ updateScrollbarParts();
+}
+
+void RenderScrollbar::styleChanged()
+{
+ updateScrollbarParts();
+}
+
+void RenderScrollbar::paint(GraphicsContext* context, const IntRect& damageRect)
+{
+ if (context->updatingControlTints()) {
+ updateScrollbarParts();
+ return;
+ }
+ Scrollbar::paint(context, damageRect);
+}
+
+void RenderScrollbar::setHoveredPart(ScrollbarPart part)
+{
+ if (part == m_hoveredPart)
+ return;
+
+ ScrollbarPart oldPart = m_hoveredPart;
+ m_hoveredPart = part;
+
+ updateScrollbarPart(oldPart);
+ updateScrollbarPart(m_hoveredPart);
+
+ updateScrollbarPart(ScrollbarBGPart);
+ updateScrollbarPart(TrackBGPart);
+}
+
+void RenderScrollbar::setPressedPart(ScrollbarPart part)
+{
+ ScrollbarPart oldPart = m_pressedPart;
+ Scrollbar::setPressedPart(part);
+
+ updateScrollbarPart(oldPart);
+ updateScrollbarPart(part);
+
+ updateScrollbarPart(ScrollbarBGPart);
+ updateScrollbarPart(TrackBGPart);
+}
+
+static ScrollbarPart s_styleResolvePart;
+static RenderScrollbar* s_styleResolveScrollbar;
+
+RenderScrollbar* RenderScrollbar::scrollbarForStyleResolve()
+{
+ return s_styleResolveScrollbar;
+}
+
+ScrollbarPart RenderScrollbar::partForStyleResolve()
+{
+ return s_styleResolvePart;
+}
+
+PassRefPtr<RenderStyle> RenderScrollbar::getScrollbarPseudoStyle(ScrollbarPart partType, RenderStyle::PseudoId pseudoId)
+{
+ s_styleResolvePart = partType;
+ s_styleResolveScrollbar = this;
+ RefPtr<RenderStyle> result = m_owner->getUncachedPseudoStyle(pseudoId, m_owner->style());
+ s_styleResolvePart = NoPart;
+ s_styleResolveScrollbar = 0;
+ return result;
+}
+
+void RenderScrollbar::updateScrollbarParts(bool destroy)
+{
+ updateScrollbarPart(ScrollbarBGPart, destroy);
+ updateScrollbarPart(BackButtonStartPart, destroy);
+ updateScrollbarPart(ForwardButtonStartPart, destroy);
+ updateScrollbarPart(BackTrackPart, destroy);
+ updateScrollbarPart(ThumbPart, destroy);
+ updateScrollbarPart(ForwardTrackPart, destroy);
+ updateScrollbarPart(BackButtonEndPart, destroy);
+ updateScrollbarPart(ForwardButtonEndPart, destroy);
+ updateScrollbarPart(TrackBGPart, destroy);
+
+ if (destroy)
+ return;
+
+ // See if the scrollbar's thickness changed. If so, we need to mark our owning object as needing a layout.
+ bool isHorizontal = orientation() == HorizontalScrollbar;
+ int oldThickness = isHorizontal ? height() : width();
+ int newThickness = 0;
+ RenderScrollbarPart* part = m_parts.get(ScrollbarBGPart);
+ if (part) {
+ part->layout();
+ newThickness = isHorizontal ? part->height() : part->width();
+ }
+
+ if (newThickness != oldThickness) {
+ setFrameRect(IntRect(x(), y(), isHorizontal ? width() : newThickness, isHorizontal ? newThickness : height()));
+ m_owner->setChildNeedsLayout(true);
+ }
+}
+
+static RenderStyle::PseudoId pseudoForScrollbarPart(ScrollbarPart part)
+{
+ switch (part) {
+ case BackButtonStartPart:
+ case ForwardButtonStartPart:
+ case BackButtonEndPart:
+ case ForwardButtonEndPart:
+ return RenderStyle::SCROLLBAR_BUTTON;
+ case BackTrackPart:
+ case ForwardTrackPart:
+ return RenderStyle::SCROLLBAR_TRACK_PIECE;
+ case ThumbPart:
+ return RenderStyle::SCROLLBAR_THUMB;
+ case TrackBGPart:
+ return RenderStyle::SCROLLBAR_TRACK;
+ default:
+ return RenderStyle::SCROLLBAR;
+ }
+}
+
+void RenderScrollbar::updateScrollbarPart(ScrollbarPart partType, bool destroy)
+{
+ if (partType == NoPart)
+ return;
+
+ RefPtr<RenderStyle> partStyle = !destroy ? getScrollbarPseudoStyle(partType, pseudoForScrollbarPart(partType)) : 0;
+
+ bool needRenderer = !destroy && partStyle && partStyle->display() != NONE && partStyle->visibility() == VISIBLE;
+
+ if (needRenderer && partStyle->display() != BLOCK) {
+ // See if we are a button that should not be visible according to OS settings.
+ ScrollbarButtonsPlacement buttonsPlacement = theme()->buttonsPlacement();
+ switch (partType) {
+ case BackButtonStartPart:
+ needRenderer = (buttonsPlacement == ScrollbarButtonsSingle || buttonsPlacement == ScrollbarButtonsDoubleStart ||
+ buttonsPlacement == ScrollbarButtonsDoubleBoth);
+ break;
+ case ForwardButtonStartPart:
+ needRenderer = (buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth);
+ break;
+ case BackButtonEndPart:
+ needRenderer = (buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth);
+ break;
+ case ForwardButtonEndPart:
+ needRenderer = (buttonsPlacement == ScrollbarButtonsSingle || buttonsPlacement == ScrollbarButtonsDoubleEnd ||
+ buttonsPlacement == ScrollbarButtonsDoubleBoth);
+ break;
+ default:
+ break;
+ }
+ }
+
+ RenderScrollbarPart* partRenderer = m_parts.get(partType);
+ if (!partRenderer && needRenderer) {
+ partRenderer = new (m_owner->renderArena()) RenderScrollbarPart(m_owner->document(), this, partType);
+ m_parts.set(partType, partRenderer);
+ } else if (partRenderer && !needRenderer) {
+ m_parts.remove(partType);
+ partRenderer->destroy();
+ partRenderer = 0;
+ }
+
+ if (partRenderer)
+ partRenderer->setStyle(partStyle.release());
+}
+
+void RenderScrollbar::paintPart(GraphicsContext* graphicsContext, ScrollbarPart partType, const IntRect& rect)
+{
+ RenderScrollbarPart* partRenderer = m_parts.get(partType);
+ if (!partRenderer)
+ return;
+ partRenderer->paintIntoRect(graphicsContext, x(), y(), rect);
+}
+
+IntRect RenderScrollbar::buttonRect(ScrollbarPart partType)
+{
+ RenderScrollbarPart* partRenderer = m_parts.get(partType);
+ if (!partRenderer)
+ return IntRect();
+
+ partRenderer->layout();
+
+ bool isHorizontal = orientation() == HorizontalScrollbar;
+ if (partType == BackButtonStartPart)
+ return IntRect(x(), y(), isHorizontal ? partRenderer->width() : width(), isHorizontal ? height() : partRenderer->height());
+ if (partType == ForwardButtonEndPart)
+ return IntRect(isHorizontal ? x() + width() - partRenderer->width() : x(),
+
+ isHorizontal ? y() : y() + height() - partRenderer->height(),
+ isHorizontal ? partRenderer->width() : width(),
+ isHorizontal ? height() : partRenderer->height());
+
+ if (partType == ForwardButtonStartPart) {
+ IntRect previousButton = buttonRect(BackButtonStartPart);
+ return IntRect(isHorizontal ? x() + previousButton.width() : x(),
+ isHorizontal ? y() : y() + previousButton.height(),
+ isHorizontal ? partRenderer->width() : width(),
+ isHorizontal ? height() : partRenderer->height());
+ }
+
+ IntRect followingButton = buttonRect(ForwardButtonEndPart);
+ return IntRect(isHorizontal ? x() + width() - followingButton.width() - partRenderer->width() : x(),
+ isHorizontal ? y() : y() + height() - followingButton.height() - partRenderer->height(),
+ isHorizontal ? partRenderer->width() : width(),
+ isHorizontal ? height() : partRenderer->height());
+}
+
+IntRect RenderScrollbar::trackRect(int startLength, int endLength)
+{
+ RenderScrollbarPart* part = m_parts.get(TrackBGPart);
+ if (part)
+ part->layout();
+
+ if (orientation() == HorizontalScrollbar) {
+ int marginLeft = part ? part->marginLeft() : 0;
+ int marginRight = part ? part->marginRight() : 0;
+ startLength += marginLeft;
+ endLength += marginRight;
+ int totalLength = startLength + endLength;
+ return IntRect(x() + startLength, y(), width() - totalLength, height());
+ }
+
+ int marginTop = part ? part->marginTop() : 0;
+ int marginBottom = part ? part->marginBottom() : 0;
+ startLength += marginTop;
+ endLength += marginBottom;
+ int totalLength = startLength + endLength;
+
+ return IntRect(x(), y() + startLength, width(), height() - totalLength);
+}
+
+IntRect RenderScrollbar::trackPieceRectWithMargins(ScrollbarPart partType, const IntRect& oldRect)
+{
+ RenderScrollbarPart* partRenderer = m_parts.get(partType);
+ if (!partRenderer)
+ return oldRect;
+
+ partRenderer->layout();
+
+ IntRect rect = oldRect;
+ if (orientation() == HorizontalScrollbar) {
+ rect.setX(rect.x() + partRenderer->marginLeft());
+ rect.setWidth(rect.width() - (partRenderer->marginLeft() + partRenderer->marginRight()));
+ } else {
+ rect.setY(rect.y() + partRenderer->marginTop());
+ rect.setHeight(rect.height() - (partRenderer->marginTop() + partRenderer->marginBottom()));
+ }
+ return rect;
+}
+
+int RenderScrollbar::minimumThumbLength()
+{
+ RenderScrollbarPart* partRenderer = m_parts.get(ThumbPart);
+ if (!partRenderer)
+ return 0;
+ partRenderer->layout();
+ return orientation() == HorizontalScrollbar ? partRenderer->width() : partRenderer->height();
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.h b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.h
new file mode 100644
index 0000000..ad97001
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbar.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 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 RenderScrollbar_h
+#define RenderScrollbar_h
+
+#include "Scrollbar.h"
+#include "RenderStyle.h"
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class RenderObject;
+class RenderScrollbarPart;
+class RenderStyle;
+
+class RenderScrollbar : public Scrollbar {
+protected:
+ RenderScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderObject*);
+
+public:
+ friend class Scrollbar;
+ static PassRefPtr<Scrollbar> createCustomScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderObject*);
+ virtual ~RenderScrollbar();
+
+ virtual void setParent(ScrollView*);
+ virtual void setEnabled(bool);
+
+ virtual void paint(GraphicsContext*, const IntRect& damageRect);
+
+ virtual void setHoveredPart(ScrollbarPart);
+ virtual void setPressedPart(ScrollbarPart);
+
+ void updateScrollbarParts(bool destroy = false);
+
+ static ScrollbarPart partForStyleResolve();
+ static RenderScrollbar* scrollbarForStyleResolve();
+
+ virtual void styleChanged();
+
+ RenderObject* owningRenderer() const { return m_owner; }
+
+ void paintPart(GraphicsContext*, ScrollbarPart, const IntRect&);
+
+ IntRect buttonRect(ScrollbarPart);
+ IntRect trackRect(int startLength, int endLength);
+ IntRect trackPieceRectWithMargins(ScrollbarPart, const IntRect&);
+
+ int minimumThumbLength();
+
+private:
+ PassRefPtr<RenderStyle> getScrollbarPseudoStyle(ScrollbarPart, RenderStyle::PseudoId);
+ void updateScrollbarPart(ScrollbarPart, bool destroy = false);
+
+ RenderObject* m_owner;
+ HashMap<unsigned, RenderScrollbarPart*> m_parts;
+};
+
+} // namespace WebCore
+
+#endif // RenderScrollbar_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.cpp
new file mode 100644
index 0000000..3f69ba6
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include "config.h"
+#include "RenderScrollbarPart.h"
+#include "RenderScrollbar.h"
+#include "RenderScrollbarTheme.h"
+
+using namespace std;
+
+namespace WebCore {
+
+RenderScrollbarPart::RenderScrollbarPart(Node* node, RenderScrollbar* scrollbar, ScrollbarPart part)
+ : RenderBlock(node)
+ , m_scrollbar(scrollbar)
+ , m_part(part)
+{
+}
+
+RenderScrollbarPart::~RenderScrollbarPart()
+{
+}
+
+void RenderScrollbarPart::layout()
+{
+ setPos(0, 0); // We don't worry about positioning ourselves. We're just determining our minimum width/height.
+ if (m_scrollbar->orientation() == HorizontalScrollbar)
+ layoutHorizontalPart();
+ else
+ layoutVerticalPart();
+
+ m_overflowWidth = max(m_width, m_overflowWidth);
+ m_overflowHeight = max(m_height, m_overflowHeight);
+
+ setNeedsLayout(false);
+}
+
+void RenderScrollbarPart::layoutHorizontalPart()
+{
+ if (m_part == ScrollbarBGPart) {
+ m_width = m_scrollbar->width();
+ computeScrollbarHeight();
+ } else {
+ computeScrollbarWidth();
+ m_height = m_scrollbar->height();
+ }
+}
+
+void RenderScrollbarPart::layoutVerticalPart()
+{
+ if (m_part == ScrollbarBGPart) {
+ computeScrollbarWidth();
+ m_height = m_scrollbar->height();
+ } else {
+ m_width = m_scrollbar->width();
+ computeScrollbarHeight();
+ }
+}
+
+static int calcScrollbarThicknessUsing(const Length& l, int containingLength)
+{
+ if (l.isIntrinsicOrAuto())
+ return ScrollbarTheme::nativeTheme()->scrollbarThickness();
+ return l.calcMinValue(containingLength);
+}
+
+void RenderScrollbarPart::computeScrollbarWidth()
+{
+ int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->borderLeft() - m_scrollbar->owningRenderer()->borderRight();
+ int width = calcScrollbarThicknessUsing(style()->width(), visibleSize);
+ int minWidth = calcScrollbarThicknessUsing(style()->minWidth(), visibleSize);
+ int maxWidth = style()->maxWidth().isUndefined() ? width : calcScrollbarThicknessUsing(style()->maxWidth(), visibleSize);
+ m_width = max(minWidth, min(maxWidth, width));
+
+ // Buttons and track pieces can all have margins along the axis of the scrollbar.
+ m_marginLeft = style()->marginLeft().calcMinValue(visibleSize);
+ m_marginRight = style()->marginRight().calcMinValue(visibleSize);
+}
+
+void RenderScrollbarPart::computeScrollbarHeight()
+{
+ int visibleSize = m_scrollbar->owningRenderer()->height() - m_scrollbar->owningRenderer()->borderTop() - m_scrollbar->owningRenderer()->borderBottom();
+ int height = calcScrollbarThicknessUsing(style()->height(), visibleSize);
+ int minHeight = calcScrollbarThicknessUsing(style()->minHeight(), visibleSize);
+ int maxHeight = style()->maxHeight().isUndefined() ? height : calcScrollbarThicknessUsing(style()->maxHeight(), visibleSize);
+ m_height = max(minHeight, min(maxHeight, height));
+
+ // Buttons and track pieces can all have margins along the axis of the scrollbar.
+ m_marginTop = style()->marginTop().calcMinValue(visibleSize);
+ m_marginBottom = style()->marginBottom().calcMinValue(visibleSize);
+}
+
+void RenderScrollbarPart::calcPrefWidths()
+{
+ if (!prefWidthsDirty())
+ return;
+
+ m_minPrefWidth = m_maxPrefWidth = 0;
+
+ setPrefWidthsDirty(false);
+}
+
+void RenderScrollbarPart::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+ setInline(false);
+ setPositioned(false);
+ setFloating(false);
+ setHasOverflowClip(false);
+ if (oldStyle && m_scrollbar && m_part != NoPart && diff >= RenderStyle::Repaint)
+ m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part);
+}
+
+void RenderScrollbarPart::imageChanged(WrappedImagePtr image, const IntRect* rect)
+{
+ if (m_scrollbar && m_part != NoPart)
+ m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part);
+ else
+ RenderBlock::imageChanged(image, rect);
+}
+
+void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, int tx, int ty, const IntRect& rect)
+{
+ // Make sure our dimensions match the rect.
+ setPos(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;
+
+ // Now do the paint.
+ RenderObject::PaintInfo paintInfo(graphicsContext, rect, PaintPhaseBlockBackground, false, 0, 0);
+ paint(paintInfo, tx, ty);
+ paintInfo.phase = PaintPhaseChildBlockBackgrounds;
+ paint(paintInfo, tx, ty);
+ paintInfo.phase = PaintPhaseFloat;
+ paint(paintInfo, tx, ty);
+ paintInfo.phase = PaintPhaseForeground;
+ paint(paintInfo, tx, ty);
+ paintInfo.phase = PaintPhaseOutline;
+ paint(paintInfo, tx, ty);
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.h b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.h
new file mode 100644
index 0000000..2010f97
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarPart.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 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 RenderScrollbarPart_h
+#define RenderScrollbarPart_h
+
+#include "RenderBlock.h"
+#include "ScrollTypes.h"
+
+namespace WebCore {
+
+class RenderScrollbar;
+
+class RenderScrollbarPart : public RenderBlock {
+public:
+ RenderScrollbarPart(Node*, RenderScrollbar* = 0, ScrollbarPart = NoPart);
+ virtual ~RenderScrollbarPart();
+
+ virtual const char* renderName() const { return "RenderScrollbarPart"; }
+
+ virtual bool requiresLayer() { return false; }
+
+ virtual void layout();
+ virtual void calcPrefWidths();
+
+ void paintIntoRect(GraphicsContext*, int tx, int ty, const IntRect&);
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+ virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+
+private:
+ void layoutHorizontalPart();
+ void layoutVerticalPart();
+
+ void computeScrollbarWidth();
+ void computeScrollbarHeight();
+
+ RenderScrollbar* m_scrollbar;
+ ScrollbarPart m_part;
+};
+
+} // namespace WebCore
+
+#endif // RenderScrollbarPart_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.cpp
new file mode 100644
index 0000000..d7cfb2b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include "config.h"
+#include "RenderScrollbarTheme.h"
+#include "RenderScrollbar.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+RenderScrollbarTheme* RenderScrollbarTheme::renderScrollbarTheme()
+{
+ DEFINE_STATIC_LOCAL(RenderScrollbarTheme, theme, ());
+ return &theme;
+}
+
+void RenderScrollbarTheme::buttonSizesAlongTrackAxis(Scrollbar* scrollbar, int& beforeSize, int& afterSize)
+{
+ IntRect firstButton = backButtonRect(scrollbar, BackButtonStartPart);
+ IntRect secondButton = forwardButtonRect(scrollbar, ForwardButtonStartPart);
+ IntRect thirdButton = backButtonRect(scrollbar, BackButtonEndPart);
+ IntRect fourthButton = forwardButtonRect(scrollbar, ForwardButtonEndPart);
+ if (scrollbar->orientation() == HorizontalScrollbar) {
+ beforeSize = firstButton.width() + secondButton.width();
+ afterSize = thirdButton.width() + fourthButton.width();
+ } else {
+ beforeSize = firstButton.height() + secondButton.height();
+ afterSize = thirdButton.height() + fourthButton.height();
+ }
+}
+
+bool RenderScrollbarTheme::hasButtons(Scrollbar* scrollbar)
+{
+ int startSize;
+ int endSize;
+ buttonSizesAlongTrackAxis(scrollbar, startSize, endSize);
+ return (startSize + endSize) <= (scrollbar->orientation() == HorizontalScrollbar ? scrollbar->width() : scrollbar->height());
+}
+
+bool RenderScrollbarTheme::hasThumb(Scrollbar* scrollbar)
+{
+ return trackLength(scrollbar) - thumbLength(scrollbar) >= 0;
+}
+
+int RenderScrollbarTheme::minimumThumbLength(Scrollbar* scrollbar)
+{
+ return static_cast<RenderScrollbar*>(scrollbar)->minimumThumbLength();
+}
+
+IntRect RenderScrollbarTheme::backButtonRect(Scrollbar* scrollbar, ScrollbarPart partType, bool)
+{
+ return static_cast<RenderScrollbar*>(scrollbar)->buttonRect(partType);
+}
+
+IntRect RenderScrollbarTheme::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart partType, bool)
+{
+ return static_cast<RenderScrollbar*>(scrollbar)->buttonRect(partType);
+}
+
+IntRect RenderScrollbarTheme::trackRect(Scrollbar* scrollbar, bool)
+{
+ if (!hasButtons(scrollbar))
+ return scrollbar->frameRect();
+
+ int startLength;
+ int endLength;
+ buttonSizesAlongTrackAxis(scrollbar, startLength, endLength);
+
+ return static_cast<RenderScrollbar*>(scrollbar)->trackRect(startLength, endLength);
+}
+
+IntRect RenderScrollbarTheme::constrainTrackRectToTrackPieces(Scrollbar* scrollbar, const IntRect& rect)
+{
+ IntRect backRect = static_cast<RenderScrollbar*>(scrollbar)->trackPieceRectWithMargins(BackTrackPart, rect);
+ IntRect forwardRect = static_cast<RenderScrollbar*>(scrollbar)->trackPieceRectWithMargins(ForwardTrackPart, rect);
+ IntRect result = rect;
+ if (scrollbar->orientation() == HorizontalScrollbar) {
+ result.setX(backRect.x());
+ result.setWidth(forwardRect.right() - backRect.x());
+ } else {
+ result.setY(backRect.y());
+ result.setHeight(forwardRect.bottom() - backRect.y());
+ }
+ return result;
+}
+
+void RenderScrollbarTheme::paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect)
+{
+ // FIXME: Implement.
+ context->fillRect(cornerRect, Color::white);
+}
+
+void RenderScrollbarTheme::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar)
+{
+ static_cast<RenderScrollbar*>(scrollbar)->paintPart(context, ScrollbarBGPart, scrollbar->frameRect());
+}
+
+void RenderScrollbarTheme::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
+{
+ static_cast<RenderScrollbar*>(scrollbar)->paintPart(context, TrackBGPart, rect);
+}
+
+void RenderScrollbarTheme::paintTrackPiece(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
+{
+ static_cast<RenderScrollbar*>(scrollbar)->paintPart(context, part, rect);
+}
+
+void RenderScrollbarTheme::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
+{
+ static_cast<RenderScrollbar*>(scrollbar)->paintPart(context, part, rect);
+}
+
+void RenderScrollbarTheme::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
+{
+ static_cast<RenderScrollbar*>(scrollbar)->paintPart(context, ThumbPart, rect);
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.h b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.h
new file mode 100644
index 0000000..9b8b2c1
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderScrollbarTheme.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2008 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 RenderScrollbarTheme_h
+#define RenderScrollbarTheme_h
+
+#include "ScrollbarThemeComposite.h"
+
+namespace WebCore {
+
+class PlatformMouseEvent;
+class Scrollbar;
+class ScrollView;
+
+class RenderScrollbarTheme : public ScrollbarThemeComposite {
+public:
+ virtual ~RenderScrollbarTheme() {};
+
+ virtual int scrollbarThickness(ScrollbarControlSize controlSize) { return ScrollbarTheme::nativeTheme()->scrollbarThickness(controlSize); }
+
+ virtual ScrollbarButtonsPlacement buttonsPlacement() const { return ScrollbarTheme::nativeTheme()->buttonsPlacement(); }
+
+ virtual bool supportsControlTints() const { return true; }
+
+ virtual void paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect);
+
+ virtual bool shouldCenterOnThumb(Scrollbar* scrollbar, const PlatformMouseEvent& event) { return ScrollbarTheme::nativeTheme()->shouldCenterOnThumb(scrollbar, event); }
+
+ virtual double initialAutoscrollTimerDelay() { return ScrollbarTheme::nativeTheme()->initialAutoscrollTimerDelay(); }
+ virtual double autoscrollTimerDelay() { return ScrollbarTheme::nativeTheme()->autoscrollTimerDelay(); }
+
+ virtual void registerScrollbar(Scrollbar* scrollbar) { return ScrollbarTheme::nativeTheme()->registerScrollbar(scrollbar); }
+ virtual void unregisterScrollbar(Scrollbar* scrollbar) { return ScrollbarTheme::nativeTheme()->unregisterScrollbar(scrollbar); }
+
+ virtual int minimumThumbLength(Scrollbar*);
+
+ void buttonSizesAlongTrackAxis(Scrollbar* scrollbar, int& beforeSize, int& afterSize);
+
+ static RenderScrollbarTheme* renderScrollbarTheme();
+
+protected:
+ virtual bool hasButtons(Scrollbar*);
+ virtual bool hasThumb(Scrollbar*);
+
+ virtual IntRect backButtonRect(Scrollbar*, ScrollbarPart, bool painting = false);
+ virtual IntRect forwardButtonRect(Scrollbar*, ScrollbarPart, bool painting = false);
+ virtual IntRect trackRect(Scrollbar*, bool painting = false);
+
+ virtual void paintScrollbarBackground(GraphicsContext*, Scrollbar*);
+ virtual void paintTrackBackground(GraphicsContext*, Scrollbar*, const IntRect&);
+ virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart);
+ virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart);
+ virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&);
+
+ virtual IntRect constrainTrackRectToTrackPieces(Scrollbar*, const IntRect&);
+};
+
+} // namespace WebCore
+
+#endif // RenderScrollbarTheme_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp
new file mode 100644
index 0000000..040fa31
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp
@@ -0,0 +1,402 @@
+/**
+ *
+ * Copyright (C) 2006, 2007, 2008 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
+ * 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 "RenderSlider.h"
+
+#include "CSSPropertyNames.h"
+#include "Document.h"
+#include "Event.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "HTMLInputElement.h"
+#include "HTMLDivElement.h"
+#include "HTMLNames.h"
+#include "MouseEvent.h"
+#include "RenderTheme.h"
+#include <wtf/MathExtras.h>
+
+using std::min;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+const int defaultTrackLength = 129;
+
+class HTMLSliderThumbElement : public HTMLDivElement {
+public:
+ HTMLSliderThumbElement(Document*, Node* shadowParent = 0);
+
+ virtual void defaultEventHandler(Event*);
+ virtual bool isShadowNode() const { return true; }
+ virtual Node* shadowParentNode() { return m_shadowParent; }
+
+ bool inDragMode() const { return m_inDragMode; }
+private:
+ Node* m_shadowParent;
+ FloatPoint m_initialClickPoint; // initial click point in RenderSlider-local coordinates
+ int m_initialPosition;
+ bool m_inDragMode;
+};
+
+HTMLSliderThumbElement::HTMLSliderThumbElement(Document* doc, Node* shadowParent)
+ : HTMLDivElement(divTag, doc)
+ , m_shadowParent(shadowParent)
+ , m_initialClickPoint(IntPoint())
+ , m_initialPosition(0)
+ , m_inDragMode(false)
+{
+}
+
+void HTMLSliderThumbElement::defaultEventHandler(Event* event)
+{
+ const AtomicString& eventType = event->type();
+ if (eventType == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+ MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+ RenderSlider* slider;
+ if (document()->frame() && renderer() && renderer()->parent() &&
+ (slider = static_cast<RenderSlider*>(renderer()->parent())) &&
+ slider->mouseEventIsInThumb(mouseEvent)) {
+ // Cache the initial point where the mouse down occurred, in slider coordinates
+ m_initialClickPoint = slider->absoluteToLocal(FloatPoint(mouseEvent->pageX(), mouseEvent->pageY()), false, true);
+ // Cache the initial position of the thumb.
+ m_initialPosition = slider->currentPosition();
+ m_inDragMode = true;
+
+ document()->frame()->eventHandler()->setCapturingMouseEventsNode(m_shadowParent);
+
+ event->setDefaultHandled();
+ return;
+ }
+ } else if (eventType == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+ if (m_inDragMode) {
+ if (Frame* frame = document()->frame())
+ frame->eventHandler()->setCapturingMouseEventsNode(0);
+ m_inDragMode = false;
+ event->setDefaultHandled();
+ return;
+ }
+ } else if (eventType == eventNames().mousemoveEvent && event->isMouseEvent()) {
+ if (m_inDragMode && renderer() && renderer()->parent()) {
+ // Move the slider
+ MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+ RenderSlider* slider = static_cast<RenderSlider*>(renderer()->parent());
+ FloatPoint curPoint = slider->absoluteToLocal(FloatPoint(mouseEvent->pageX(), mouseEvent->pageY()), false, true);
+ int newPosition = slider->positionForOffset(
+ IntPoint(m_initialPosition + curPoint.x() - m_initialClickPoint.x()
+ + (renderer()->width() / 2),
+ m_initialPosition + curPoint.y() - m_initialClickPoint.y()
+ + (renderer()->height() / 2)));
+ if (slider->currentPosition() != newPosition) {
+ slider->setCurrentPosition(newPosition);
+ slider->valueChanged();
+ }
+ event->setDefaultHandled();
+ return;
+ }
+ }
+
+ HTMLDivElement::defaultEventHandler(event);
+}
+
+RenderSlider::RenderSlider(HTMLInputElement* element)
+ : RenderBlock(element)
+ , m_thumb(0)
+{
+}
+
+RenderSlider::~RenderSlider()
+{
+ if (m_thumb)
+ m_thumb->detach();
+}
+
+int RenderSlider::baselinePosition(bool, bool) const
+{
+ return height() + marginTop();
+}
+
+void RenderSlider::calcPrefWidths()
+{
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = 0;
+
+ if (style()->width().isFixed() && style()->width().value() > 0)
+ m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
+ else
+ m_maxPrefWidth = defaultTrackLength * style()->effectiveZoom();
+
+ if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
+ m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
+ m_minPrefWidth = 0;
+ else
+ m_minPrefWidth = m_maxPrefWidth;
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
+ m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ }
+
+ int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+ m_minPrefWidth += toAdd;
+ m_maxPrefWidth += toAdd;
+
+ setPrefWidthsDirty(false);
+}
+
+void RenderSlider::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+
+ if (m_thumb)
+ m_thumb->renderer()->setStyle(createThumbStyle(style(), m_thumb->renderer()->style()));
+
+ setReplaced(isInline());
+}
+
+PassRefPtr<RenderStyle> RenderSlider::createThumbStyle(const RenderStyle* parentStyle, const RenderStyle* oldStyle)
+{
+ RefPtr<RenderStyle> style;
+ RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::SLIDER_THUMB);
+ if (pseudoStyle)
+ // We may be sharing style with another slider, but we must not share the thumb style.
+ style = RenderStyle::clone(pseudoStyle);
+ else
+ style = RenderStyle::create();
+
+ if (parentStyle)
+ style->inheritFrom(parentStyle);
+
+ style->setDisplay(BLOCK);
+ style->setPosition(RelativePosition);
+ if (oldStyle) {
+ style->setLeft(oldStyle->left());
+ style->setTop(oldStyle->top());
+ }
+
+ if (parentStyle->appearance() == SliderVerticalPart)
+ style->setAppearance(SliderThumbVerticalPart);
+ else if (parentStyle->appearance() == SliderHorizontalPart)
+ style->setAppearance(SliderThumbHorizontalPart);
+ else if (parentStyle->appearance() == MediaSliderPart)
+ style->setAppearance(MediaSliderThumbPart);
+
+ return style.release();
+}
+
+void RenderSlider::layout()
+{
+ bool relayoutChildren = false;
+
+ if (m_thumb && m_thumb->renderer()) {
+
+ int oldWidth = m_width;
+ calcWidth();
+ int oldHeight = m_height;
+ calcHeight();
+
+ if (oldWidth != m_width || oldHeight != m_height)
+ relayoutChildren = true;
+
+ // Allow the theme to set the size of the thumb
+ if (m_thumb->renderer()->style()->hasAppearance())
+ theme()->adjustSliderThumbSize(m_thumb->renderer());
+
+ if (style()->appearance() == SliderVerticalPart) {
+ // FIXME: Handle percentage widths correctly. See http://bugs.webkit.org/show_bug.cgi?id=12104
+ m_thumb->renderer()->style()->setLeft(Length(contentWidth() / 2 - m_thumb->renderer()->style()->width().value() / 2, Fixed));
+ } else {
+ // FIXME: Handle percentage heights correctly. See http://bugs.webkit.org/show_bug.cgi?id=12104
+ m_thumb->renderer()->style()->setTop(Length(contentHeight() / 2 - m_thumb->renderer()->style()->height().value() / 2, Fixed));
+ }
+
+ if (relayoutChildren)
+ setPositionFromValue(true);
+ }
+
+ RenderBlock::layoutBlock(relayoutChildren);
+}
+
+void RenderSlider::updateFromElement()
+{
+ if (!m_thumb) {
+ m_thumb = new HTMLSliderThumbElement(document(), node());
+ RefPtr<RenderStyle> thumbStyle = createThumbStyle(style());
+ m_thumb->setRenderer(m_thumb->createRenderer(renderArena(), thumbStyle.get()));
+ m_thumb->renderer()->setStyle(thumbStyle.release());
+ m_thumb->setAttached();
+ m_thumb->setInDocument(true);
+ addChild(m_thumb->renderer());
+ }
+ setPositionFromValue();
+ setNeedsLayout(true, false);
+}
+
+bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt)
+{
+ if (!m_thumb || !m_thumb->renderer())
+ return false;
+
+ FloatPoint localPoint = m_thumb->renderer()->absoluteToLocal(FloatPoint(evt->pageX(), evt->pageY()), false, true);
+ IntRect thumbBounds = m_thumb->renderer()->borderBox();
+ return thumbBounds.contains(roundedIntPoint(localPoint));
+}
+
+void RenderSlider::setValueForPosition(int position)
+{
+ if (!m_thumb || !m_thumb->renderer())
+ return;
+
+ const AtomicString& minStr = static_cast<HTMLInputElement*>(node())->getAttribute(minAttr);
+ const AtomicString& maxStr = static_cast<HTMLInputElement*>(node())->getAttribute(maxAttr);
+ const AtomicString& precision = static_cast<HTMLInputElement*>(node())->getAttribute(precisionAttr);
+
+ double minVal = minStr.isNull() ? 0.0 : minStr.toDouble();
+ double maxVal = maxStr.isNull() ? 100.0 : maxStr.toDouble();
+ minVal = min(minVal, maxVal); // Make sure the range is sane.
+
+ // Calculate the new value based on the position
+ double factor = (double)position / (double)trackSize();
+ if (style()->appearance() == SliderVerticalPart)
+ factor = 1.0 - factor;
+ double val = minVal + factor * (maxVal - minVal);
+
+ val = max(minVal, min(val, maxVal)); // Make sure val is within min/max.
+
+ // Force integer value if not float.
+ if (!equalIgnoringCase(precision, "float"))
+ val = lround(val);
+
+ static_cast<HTMLInputElement*>(node())->setValueFromRenderer(String::number(val));
+
+ if (position != currentPosition()) {
+ setCurrentPosition(position);
+ static_cast<HTMLInputElement*>(node())->onChange();
+ }
+}
+
+double RenderSlider::setPositionFromValue(bool inLayout)
+{
+ if (!m_thumb || !m_thumb->renderer())
+ return 0;
+
+ if (!inLayout)
+ document()->updateLayout();
+
+ String value = static_cast<HTMLInputElement*>(node())->value();
+ const AtomicString& minStr = static_cast<HTMLInputElement*>(node())->getAttribute(minAttr);
+ const AtomicString& maxStr = static_cast<HTMLInputElement*>(node())->getAttribute(maxAttr);
+ const AtomicString& precision = static_cast<HTMLInputElement*>(node())->getAttribute(precisionAttr);
+
+ double minVal = minStr.isNull() ? 0.0 : minStr.toDouble();
+ double maxVal = maxStr.isNull() ? 100.0 : maxStr.toDouble();
+ minVal = min(minVal, maxVal); // Make sure the range is sane.
+
+ double oldVal = value.isNull() ? (maxVal + minVal)/2.0 : value.toDouble();
+ double val = max(minVal, min(oldVal, maxVal)); // Make sure val is within min/max.
+
+ // Force integer value if not float.
+ if (!equalIgnoringCase(precision, "float"))
+ val = lround(val);
+
+ // Calculate the new position based on the value
+ double factor = (val - minVal) / (maxVal - minVal);
+ if (style()->appearance() == SliderVerticalPart)
+ factor = 1.0 - factor;
+
+ setCurrentPosition((int)(factor * trackSize()));
+
+ if (value.isNull() || val != oldVal)
+ static_cast<HTMLInputElement*>(node())->setValueFromRenderer(String::number(val));
+
+ return val;
+}
+
+int RenderSlider::positionForOffset(const IntPoint& p)
+{
+ if (!m_thumb || !m_thumb->renderer())
+ return 0;
+
+ int position;
+ if (style()->appearance() == SliderVerticalPart)
+ position = p.y() - m_thumb->renderer()->height() / 2;
+ else
+ position = p.x() - m_thumb->renderer()->width() / 2;
+
+ return max(0, min(position, trackSize()));
+}
+
+void RenderSlider::valueChanged()
+{
+ setValueForPosition(currentPosition());
+ static_cast<HTMLInputElement*>(node())->onChange();
+}
+
+int RenderSlider::currentPosition()
+{
+ if (!m_thumb || !m_thumb->renderer())
+ return 0;
+
+ if (style()->appearance() == SliderVerticalPart)
+ return m_thumb->renderer()->style()->top().value();
+ return m_thumb->renderer()->style()->left().value();
+}
+
+void RenderSlider::setCurrentPosition(int pos)
+{
+ if (!m_thumb || !m_thumb->renderer())
+ return;
+
+ if (style()->appearance() == SliderVerticalPart)
+ m_thumb->renderer()->style()->setTop(Length(pos, Fixed));
+ else
+ m_thumb->renderer()->style()->setLeft(Length(pos, Fixed));
+
+ m_thumb->renderer()->layer()->updateLayerPosition();
+ repaint();
+ m_thumb->renderer()->repaint();
+}
+
+int RenderSlider::trackSize()
+{
+ if (!m_thumb || !m_thumb->renderer())
+ return 0;
+
+ if (style()->appearance() == SliderVerticalPart)
+ return contentHeight() - m_thumb->renderer()->height();
+ return contentWidth() - m_thumb->renderer()->width();
+}
+
+void RenderSlider::forwardEvent(Event* evt)
+{
+ m_thumb->defaultEventHandler(evt);
+}
+
+bool RenderSlider::inDragMode() const
+{
+ return m_thumb->inDragMode();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderSlider.h b/src/3rdparty/webkit/WebCore/rendering/RenderSlider.h
new file mode 100644
index 0000000..2667672
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderSlider.h
@@ -0,0 +1,73 @@
+/**
+ *
+ * Copyright (C) 2006 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
+ * 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 RenderSlider_h
+#define RenderSlider_h
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+ class HTMLDivElement;
+ class HTMLInputElement;
+ class HTMLSliderThumbElement;
+ class MouseEvent;
+
+ class RenderSlider : public RenderBlock {
+ public:
+ RenderSlider(HTMLInputElement*);
+ ~RenderSlider();
+
+ virtual const char* renderName() const { return "RenderSlider"; }
+ virtual bool isSlider() const { return true; }
+
+ virtual int baselinePosition( bool, bool ) const;
+ virtual void calcPrefWidths();
+ virtual void layout();
+ virtual void updateFromElement();
+
+ bool mouseEventIsInThumb(MouseEvent*);
+
+ void setValueForPosition(int position);
+ double setPositionFromValue(bool inLayout = false);
+ int positionForOffset(const IntPoint&);
+
+ void valueChanged();
+
+ int currentPosition();
+ void setCurrentPosition(int pos);
+
+ void forwardEvent(Event*);
+ bool inDragMode() const;
+
+ protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ private:
+ PassRefPtr<RenderStyle> createThumbStyle(const RenderStyle* parentStyle, const RenderStyle* oldStyle = 0);
+ int trackSize();
+
+ RefPtr<HTMLSliderThumbElement> m_thumb;
+};
+
+} // namespace WebCore
+
+#endif // RenderSlider_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp
new file mode 100644
index 0000000..4561d57
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTable.cpp
@@ -0,0 +1,1152 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ * (C) 1997 Torben Weis (weis@kde.org)
+ * (C) 1998 Waldo Bastian (bastian@kde.org)
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * 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 "RenderTable.h"
+
+#include "AutoTableLayout.h"
+#include "DeleteButtonController.h"
+#include "Document.h"
+#include "FixedTableLayout.h"
+#include "FrameView.h"
+#include "HTMLNames.h"
+#include "RenderLayer.h"
+#include "RenderTableCell.h"
+#include "RenderTableCol.h"
+#include "RenderTableSection.h"
+#include "RenderView.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderTable::RenderTable(Node* node)
+ : RenderBlock(node)
+ , m_caption(0)
+ , m_head(0)
+ , m_foot(0)
+ , m_firstBody(0)
+ , m_tableLayout(0)
+ , m_currentBorder(0)
+ , m_frame(Void)
+ , m_rules(None)
+ , m_hasColElements(false)
+ , m_needsSectionRecalc(0)
+ , m_hSpacing(0)
+ , m_vSpacing(0)
+ , m_borderLeft(0)
+ , m_borderRight(0)
+{
+ m_columnPos.fill(0, 2);
+ m_columns.fill(ColumnStruct(), 1);
+}
+
+RenderTable::~RenderTable()
+{
+ delete m_tableLayout;
+}
+
+void RenderTable::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+
+ ETableLayout oldTableLayout = oldStyle ? oldStyle->tableLayout() : TAUTO;
+
+ // In the collapsed border model, there is no cell spacing.
+ m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
+ m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
+ m_columnPos[0] = m_hSpacing;
+
+ if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {
+ delete m_tableLayout;
+
+ // According to the CSS2 spec, you only use fixed table layout if an
+ // explicit width is specified on the table. Auto width implies auto table layout.
+ if (style()->tableLayout() == TFIXED && !style()->width().isAuto())
+ m_tableLayout = new FixedTableLayout(this);
+ else
+ m_tableLayout = new AutoTableLayout(this);
+ }
+}
+
+static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
+{
+ if (!before || !ptr)
+ return;
+ RenderObject* o = before->previousSibling();
+ while (o && o != ptr)
+ o = o->previousSibling();
+ if (!o)
+ ptr = 0;
+}
+
+void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
+{
+ // Make sure we don't append things after :after-generated content if we have it.
+ if (!beforeChild && isAfterContent(lastChild()))
+ beforeChild = lastChild();
+
+ bool wrapInAnonymousSection = true;
+ bool isTableElement = element() && element()->hasTagName(tableTag);
+
+ if (child->isRenderBlock() && child->style()->display() == TABLE_CAPTION) {
+ // First caption wins.
+ if (beforeChild && m_caption) {
+ RenderObject* o = beforeChild->previousSibling();
+ while (o && o != m_caption)
+ o = o->previousSibling();
+ if (!o)
+ m_caption = 0;
+ }
+ if (!m_caption)
+ m_caption = static_cast<RenderBlock*>(child);
+ wrapInAnonymousSection = false;
+ } else if (child->isTableCol()) {
+ m_hasColElements = true;
+ wrapInAnonymousSection = false;
+ } else if (child->isTableSection()) {
+ switch (child->style()->display()) {
+ case TABLE_HEADER_GROUP:
+ if (child->isTableSection()) {
+ resetSectionPointerIfNotBefore(m_head, beforeChild);
+ if (!m_head) {
+ m_head = static_cast<RenderTableSection*>(child);
+ } else {
+ resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
+ if (!m_firstBody)
+ m_firstBody = static_cast<RenderTableSection*>(child);
+ }
+ }
+ wrapInAnonymousSection = false;
+ break;
+ case TABLE_FOOTER_GROUP:
+ if (child->isTableSection()) {
+ resetSectionPointerIfNotBefore(m_foot, beforeChild);
+ if (!m_foot) {
+ m_foot = static_cast<RenderTableSection*>(child);
+ wrapInAnonymousSection = false;
+ break;
+ }
+ }
+ // Fall through.
+ case TABLE_ROW_GROUP:
+ if (child->isTableSection()) {
+ resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
+ if (!m_firstBody)
+ m_firstBody = static_cast<RenderTableSection*>(child);
+ }
+ wrapInAnonymousSection = false;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ } else if (child->isTableCell() || child->isTableRow()) {
+ wrapInAnonymousSection = true;
+ } else {
+ // Allow a form to just sit at the top level.
+ wrapInAnonymousSection = !isTableElement || !child->element() || !(child->element()->hasTagName(formTag) && document()->isHTMLDocument());
+
+ // FIXME: Allow the delete button container element to sit at the top level. This is needed until http://bugs.webkit.org/show_bug.cgi?id=11363 is fixed.
+ if (wrapInAnonymousSection && child->element() && child->element()->isHTMLElement() && static_cast<HTMLElement*>(child->element())->id() == DeleteButtonController::containerElementIdentifier)
+ wrapInAnonymousSection = false;
+ }
+
+ if (!wrapInAnonymousSection) {
+ // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that.
+ while (beforeChild && !beforeChild->isTableSection() && !beforeChild->isTableCol() && beforeChild->style()->display() != TABLE_CAPTION)
+ beforeChild = beforeChild->parent();
+
+ RenderContainer::addChild(child, beforeChild);
+ return;
+ }
+
+ if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous()) {
+ lastChild()->addChild(child);
+ return;
+ }
+
+ RenderObject* lastBox = beforeChild;
+ while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP)
+ lastBox = lastBox->parent();
+ if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
+ lastBox->addChild(child, beforeChild);
+ return;
+ }
+
+ if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP)
+ beforeChild = 0;
+ RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */);
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(style());
+ newStyle->setDisplay(TABLE_ROW_GROUP);
+ section->setStyle(newStyle.release());
+ addChild(section, beforeChild);
+ section->addChild(child);
+}
+
+void RenderTable::calcWidth()
+{
+ if (isPositioned())
+ calcAbsoluteHorizontal();
+
+ RenderBlock* cb = containingBlock();
+ int availableWidth = cb->availableWidth();
+
+ LengthType widthType = style()->width().type();
+ if (widthType > Relative && style()->width().isPositive()) {
+ // Percent or fixed table
+ m_width = style()->width().calcMinValue(availableWidth);
+ m_width = max(minPrefWidth(), m_width);
+ } else {
+ // An auto width table should shrink to fit within the line width if necessary in order to
+ // avoid overlapping floats.
+ availableWidth = cb->lineWidth(m_y);
+
+ // Subtract out any fixed margins from our available width for auto width tables.
+ int marginTotal = 0;
+ if (!style()->marginLeft().isAuto())
+ marginTotal += style()->marginLeft().calcValue(availableWidth);
+ if (!style()->marginRight().isAuto())
+ marginTotal += style()->marginRight().calcValue(availableWidth);
+
+ // Subtract out our margins to get the available content width.
+ int availContentWidth = max(0, availableWidth - marginTotal);
+
+ // Ensure we aren't bigger than our max width or smaller than our min width.
+ m_width = min(availContentWidth, maxPrefWidth());
+ }
+
+ m_width = max(m_width, minPrefWidth());
+
+ // Finally, with our true width determined, compute our margins for real.
+ m_marginRight = 0;
+ m_marginLeft = 0;
+ calcHorizontalMargins(style()->marginLeft(), style()->marginRight(), availableWidth);
+}
+
+void RenderTable::layout()
+{
+ ASSERT(needsLayout());
+
+ if (layoutOnlyPositionedObjects())
+ return;
+
+ recalcSectionsIfNeeded();
+
+ IntRect oldBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout();
+ if (checkForRepaint) {
+ oldBounds = absoluteClippedOverflowRect();
+ oldOutlineBox = absoluteOutlineBounds();
+ }
+
+ LayoutStateMaintainer statePusher(view(), this, IntSize(m_x, m_y));
+
+ m_height = 0;
+ m_overflowHeight = 0;
+ m_overflowTop = 0;
+ initMaxMarginValues();
+
+ int oldWidth = m_width;
+ calcWidth();
+
+ if (m_caption && m_width != oldWidth)
+ m_caption->setNeedsLayout(true, false);
+
+ // FIXME: The optimisation below doesn't work since the internal table
+ // layout could have changed. we need to add a flag to the table
+ // layout that tells us if something has changed in the min max
+ // calculations to do it correctly.
+// if ( oldWidth != m_width || columns.size() + 1 != columnPos.size() )
+ m_tableLayout->layout();
+
+ setCellWidths();
+
+ // layout child objects
+ int calculatedHeight = 0;
+ int oldTableTop = m_caption ? m_caption->height() + m_caption->marginTop() + m_caption->marginBottom() : 0;
+
+ bool collapsing = collapseBorders();
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ // FIXME: What about a form that has a display value that makes it a table section?
+ if (child->needsLayout() && !(child->element() && child->element()->hasTagName(formTag)))
+ child->layout();
+ if (child->isTableSection()) {
+ RenderTableSection* section = static_cast<RenderTableSection*>(child);
+ calculatedHeight += section->calcRowHeight();
+ if (collapsing)
+ section->recalcOuterBorder();
+ }
+ }
+
+ m_overflowWidth = m_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).
+ bool sectionMoved = false;
+ int movedSectionTop = 0;
+
+ // FIXME: Collapse caption margin.
+ if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) {
+ IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height());
+
+ m_caption->setPos(m_caption->marginLeft(), m_height);
+ if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
+ m_caption->repaintDuringLayoutIfMoved(captionRect);
+
+ m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom();
+ m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false));
+ m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false));
+ m_overflowTop = min(m_overflowTop, m_caption->yPos() + m_caption->overflowTop(false));
+ m_overflowHeight = max(m_overflowHeight, m_caption->yPos() + m_caption->overflowHeight(false));
+
+ if (m_height != oldTableTop) {
+ sectionMoved = true;
+ movedSectionTop = min(m_height, oldTableTop);
+ }
+ }
+
+ int bpTop = borderTop() + (collapsing ? 0 : paddingTop());
+ int bpBottom = borderBottom() + (collapsing ? 0 : paddingBottom());
+
+ m_height += bpTop;
+
+ if (!isPositioned())
+ calcHeight();
+
+ Length h = style()->height();
+ int th = 0;
+ if (h.isFixed())
+ // Tables size as though CSS height includes border/padding.
+ th = h.value() - (bpTop + bpBottom);
+ else if (h.isPercent())
+ th = calcPercentageHeight(h);
+ th = max(0, th);
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (!child->isTableSection())
+ continue;
+ // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one.
+ static_cast<RenderTableSection*>(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0);
+ }
+
+ if (!m_firstBody && th > calculatedHeight && !style()->htmlHacks()) {
+ // Completely empty tables (with no sections or anything) should at least honor specified height
+ // in strict mode.
+ m_height += th;
+ }
+
+ int bl = borderLeft();
+ if (!collapsing)
+ bl += paddingLeft();
+
+ // position the table sections
+ RenderTableSection* section = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
+ while (section) {
+ if (!sectionMoved && section->yPos() != m_height) {
+ sectionMoved = true;
+ movedSectionTop = min(m_height, section->yPos()) + section->overflowTop(false);
+ }
+ section->setPos(bl, m_height);
+
+ m_height += section->height();
+ m_overflowLeft = min(m_overflowLeft, section->xPos() + section->overflowLeft(false));
+ m_overflowWidth = max(m_overflowWidth, section->xPos() + section->overflowWidth(false));
+ m_overflowTop = min(m_overflowTop, section->yPos() + section->overflowTop(false));
+ m_overflowHeight = max(m_overflowHeight, section->yPos() + section->overflowHeight(false));
+ section = sectionBelow(section);
+ }
+
+ m_height += bpBottom;
+
+ if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) {
+ IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height());
+
+ m_caption->setPos(m_caption->marginLeft(), m_height);
+ if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
+ m_caption->repaintDuringLayoutIfMoved(captionRect);
+
+ m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom();
+ m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false));
+ m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false));
+ }
+
+ if (isPositioned())
+ calcHeight();
+
+ m_overflowHeight = max(m_overflowHeight, m_height);
+
+ // table can be containing block of positioned elements.
+ // FIXME: Only pass true if width or height changed.
+ layoutPositionedObjects(true);
+
+ if (!hasOverflowClip()) {
+ for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+ m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur);
+ m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur);
+ m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur);
+ m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur);
+ }
+
+ 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());
+ }
+ }
+
+ statePusher.pop();
+
+ bool didFullRepaint = true;
+ // Repaint with our new bounds if they are different from our old bounds.
+ if (checkForRepaint)
+ didFullRepaint = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+ if (!didFullRepaint && sectionMoved)
+ repaintRectangle(IntRect(m_overflowLeft, movedSectionTop, m_overflowWidth - m_overflowLeft, m_overflowHeight - movedSectionTop));
+
+ setNeedsLayout(false);
+}
+
+void RenderTable::setCellWidths()
+{
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isTableSection())
+ static_cast<RenderTableSection*>(child)->setCellWidths();
+ }
+}
+
+void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ tx += xPos();
+ ty += yPos();
+
+ PaintPhase paintPhase = paintInfo.phase;
+
+ int os = 2 * maximalOutlineSize(paintPhase);
+ if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + overflowHeight(false) <= paintInfo.rect.y() - os)
+ return;
+ if (tx + overflowLeft(false) >= paintInfo.rect.right() + os || tx + overflowWidth(false) <= paintInfo.rect.x() - os)
+ return;
+
+ if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
+ paintBoxDecorations(paintInfo, tx, ty);
+
+ if (paintPhase == PaintPhaseMask) {
+ paintMask(paintInfo, tx, ty);
+ return;
+ }
+
+ // We're done. We don't bother painting any children.
+ if (paintPhase == PaintPhaseBlockBackground)
+ return;
+
+ // We don't paint our own background, but we do let the kids paint their backgrounds.
+ if (paintPhase == PaintPhaseChildBlockBackgrounds)
+ paintPhase = PaintPhaseChildBlockBackground;
+ PaintInfo info(paintInfo);
+ info.phase = paintPhase;
+ info.paintingRoot = paintingRootForChildren(paintInfo);
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (!child->hasLayer() && (child->isTableSection() || child == m_caption))
+ child->paint(info, tx, ty);
+ }
+
+ if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
+ // Collect all the unique border styles that we want to paint in a sorted list. Once we
+ // have all the styles sorted, we then do individual passes, painting each style of border
+ // from lowest precedence to highest precedence.
+ info.phase = PaintPhaseCollapsedTableBorders;
+ RenderTableCell::CollapsedBorderStyles borderStyles;
+ RenderObject* stop = nextInPreOrderAfterChildren();
+ for (RenderObject* o = firstChild(); o && o != stop; o = o->nextInPreOrder())
+ if (o->isTableCell())
+ static_cast<RenderTableCell*>(o)->collectBorderStyles(borderStyles);
+ RenderTableCell::sortBorderStyles(borderStyles);
+ size_t count = borderStyles.size();
+ for (size_t i = 0; i < count; ++i) {
+ m_currentBorder = &borderStyles[i];
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling())
+ if (child->isTableSection())
+ child->paint(info, tx, ty);
+ }
+ m_currentBorder = 0;
+ }
+}
+
+void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
+{
+ int w = width();
+ int h = height();
+
+ // Account for the caption.
+ if (m_caption) {
+ int captionHeight = (m_caption->height() + m_caption->marginBottom() + m_caption->marginTop());
+ h -= captionHeight;
+ if (m_caption->style()->captionSide() != CAPBOTTOM)
+ ty += captionHeight;
+ }
+
+ int my = max(ty, paintInfo.rect.y());
+ int mh;
+ if (ty < paintInfo.rect.y())
+ mh = max(0, h - (paintInfo.rect.y() - ty));
+ else
+ mh = min(paintInfo.rect.height(), h);
+
+ paintBoxShadow(paintInfo.context, tx, ty, w, h, style());
+
+ paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h);
+
+ if (style()->hasBorder() && !collapseBorders())
+ paintBorder(paintInfo.context, tx, ty, w, h, style());
+}
+
+void RenderTable::paintMask(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
+ return;
+
+ int w = width();
+ int h = height();
+
+ // Account for the caption.
+ if (m_caption) {
+ int captionHeight = (m_caption->height() + m_caption->marginBottom() + m_caption->marginTop());
+ h -= captionHeight;
+ if (m_caption->style()->captionSide() != CAPBOTTOM)
+ ty += captionHeight;
+ }
+
+ int my = max(ty, paintInfo.rect.y());
+ int mh;
+ if (ty < paintInfo.rect.y())
+ mh = max(0, h - (paintInfo.rect.y() - ty));
+ else
+ mh = min(paintInfo.rect.height(), h);
+
+ paintMaskImages(paintInfo, my, mh, tx, ty, w, h);
+}
+
+void RenderTable::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ recalcSectionsIfNeeded();
+ recalcHorizontalBorders();
+
+ m_tableLayout->calcPrefWidths(m_minPrefWidth, m_maxPrefWidth);
+
+ if (m_caption)
+ m_minPrefWidth = max(m_minPrefWidth, m_caption->minPrefWidth());
+
+ setPrefWidthsDirty(false);
+}
+
+void RenderTable::splitColumn(int pos, int firstSpan)
+{
+ // we need to add a new columnStruct
+ int oldSize = m_columns.size();
+ m_columns.grow(oldSize + 1);
+ int oldSpan = m_columns[pos].span;
+ ASSERT(oldSpan > firstSpan);
+ m_columns[pos].span = firstSpan;
+ memmove(m_columns.data() + pos + 1, m_columns.data() + pos, (oldSize - pos) * sizeof(ColumnStruct));
+ m_columns[pos + 1].span = oldSpan - firstSpan;
+
+ // change width of all rows.
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isTableSection())
+ static_cast<RenderTableSection*>(child)->splitColumn(pos, oldSize + 1);
+ }
+
+ m_columnPos.grow(numEffCols() + 1);
+ setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+void RenderTable::appendColumn(int span)
+{
+ // easy case.
+ int pos = m_columns.size();
+ int newSize = pos + 1;
+ m_columns.grow(newSize);
+ m_columns[pos].span = span;
+
+ // change width of all rows.
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isTableSection())
+ static_cast<RenderTableSection*>(child)->appendColumn(pos);
+ }
+
+ m_columnPos.grow(numEffCols() + 1);
+ setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) const
+{
+ if (!m_hasColElements)
+ return 0;
+ RenderObject* child = firstChild();
+ int cCol = 0;
+
+ while (child) {
+ if (child->isTableCol()) {
+ RenderTableCol* colElem = static_cast<RenderTableCol*>(child);
+ int span = colElem->span();
+ if (!colElem->firstChild()) {
+ int startCol = cCol;
+ int endCol = cCol + span - 1;
+ cCol += span;
+ if (cCol > col) {
+ if (startEdge)
+ *startEdge = startCol == col;
+ if (endEdge)
+ *endEdge = endCol == col;
+ return colElem;
+ }
+ }
+
+ RenderObject* next = child->firstChild();
+ if (!next)
+ next = child->nextSibling();
+ if (!next && child->parent()->isTableCol())
+ next = child->parent()->nextSibling();
+ child = next;
+ } else if (child == m_caption)
+ child = child->nextSibling();
+ else
+ break;
+ }
+
+ return 0;
+}
+
+void RenderTable::recalcSections() const
+{
+ m_caption = 0;
+ m_head = 0;
+ m_foot = 0;
+ m_firstBody = 0;
+ m_hasColElements = false;
+
+ // We need to get valid pointers to caption, head, foot and first body again
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ switch (child->style()->display()) {
+ case TABLE_CAPTION:
+ if (!m_caption && child->isRenderBlock()) {
+ m_caption = static_cast<RenderBlock*>(child);
+ m_caption->setNeedsLayout(true);
+ }
+ break;
+ case TABLE_COLUMN:
+ case TABLE_COLUMN_GROUP:
+ m_hasColElements = true;
+ break;
+ case TABLE_HEADER_GROUP:
+ if (child->isTableSection()) {
+ RenderTableSection* section = static_cast<RenderTableSection*>(child);
+ if (!m_head)
+ m_head = section;
+ else if (!m_firstBody)
+ m_firstBody = section;
+ section->recalcCellsIfNeeded();
+ }
+ break;
+ case TABLE_FOOTER_GROUP:
+ if (child->isTableSection()) {
+ RenderTableSection* section = static_cast<RenderTableSection*>(child);
+ if (!m_foot)
+ m_foot = section;
+ else if (!m_firstBody)
+ m_firstBody = section;
+ section->recalcCellsIfNeeded();
+ }
+ break;
+ case TABLE_ROW_GROUP:
+ if (child->isTableSection()) {
+ RenderTableSection* section = static_cast<RenderTableSection*>(child);
+ if (!m_firstBody)
+ m_firstBody = section;
+ section->recalcCellsIfNeeded();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
+ int maxCols = 0;
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isTableSection()) {
+ RenderTableSection* section = static_cast<RenderTableSection*>(child);
+ int sectionCols = section->numColumns();
+ if (sectionCols > maxCols)
+ maxCols = sectionCols;
+ }
+ }
+
+ m_columns.resize(maxCols);
+ m_columnPos.resize(maxCols + 1);
+
+ ASSERT(selfNeedsLayout());
+
+ m_needsSectionRecalc = false;
+}
+
+RenderObject* RenderTable::removeChildNode(RenderObject* child, bool fullRemove)
+{
+ setNeedsSectionRecalc();
+ return RenderContainer::removeChildNode(child, fullRemove);
+}
+
+int RenderTable::calcBorderLeft() const
+{
+ if (collapseBorders()) {
+ // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
+ if (!numEffCols())
+ return 0;
+
+ unsigned borderWidth = 0;
+
+ const BorderValue& tb = style()->borderLeft();
+ if (tb.style() == BHIDDEN)
+ return 0;
+ if (tb.style() > BHIDDEN)
+ borderWidth = tb.width;
+
+ int leftmostColumn = style()->direction() == RTL ? numEffCols() - 1 : 0;
+ RenderTableCol* colGroup = colElement(leftmostColumn);
+ if (colGroup) {
+ const BorderValue& gb = style()->borderLeft();
+ if (gb.style() == BHIDDEN)
+ return 0;
+ if (gb.style() > BHIDDEN)
+ borderWidth = max(borderWidth, static_cast<unsigned>(gb.width));
+ }
+
+ RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
+ if (firstNonEmptySection && !firstNonEmptySection->numRows())
+ firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
+
+ if (firstNonEmptySection) {
+ const BorderValue& sb = firstNonEmptySection->style()->borderLeft();
+ if (sb.style() == BHIDDEN)
+ return 0;
+
+ if (sb.style() > BHIDDEN)
+ borderWidth = max(borderWidth, static_cast<unsigned>(sb.width));
+
+ const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, leftmostColumn);
+
+ if (cs.cell) {
+ const BorderValue& cb = cs.cell->style()->borderLeft();
+ if (cb.style() == BHIDDEN)
+ return 0;
+
+ const BorderValue& rb = cs.cell->parent()->style()->borderLeft();
+ if (rb.style() == BHIDDEN)
+ return 0;
+
+ if (cb.style() > BHIDDEN)
+ borderWidth = max(borderWidth, static_cast<unsigned>(cb.width));
+ if (rb.style() > BHIDDEN)
+ borderWidth = max(borderWidth, static_cast<unsigned>(rb.width));
+ }
+ }
+ return borderWidth / 2;
+ }
+ return RenderBlock::borderLeft();
+}
+
+int RenderTable::calcBorderRight() const
+{
+ if (collapseBorders()) {
+ // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
+ if (!numEffCols())
+ return 0;
+
+ unsigned borderWidth = 0;
+
+ const BorderValue& tb = style()->borderRight();
+ if (tb.style() == BHIDDEN)
+ return 0;
+ if (tb.style() > BHIDDEN)
+ borderWidth = tb.width;
+
+ int rightmostColumn = style()->direction() == RTL ? 0 : numEffCols() - 1;
+ RenderTableCol* colGroup = colElement(rightmostColumn);
+ if (colGroup) {
+ const BorderValue& gb = style()->borderRight();
+ if (gb.style() == BHIDDEN)
+ return 0;
+ if (gb.style() > BHIDDEN)
+ borderWidth = max(borderWidth, static_cast<unsigned>(gb.width));
+ }
+
+ RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
+ if (firstNonEmptySection && !firstNonEmptySection->numRows())
+ firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
+
+ if (firstNonEmptySection) {
+ const BorderValue& sb = firstNonEmptySection->style()->borderRight();
+ if (sb.style() == BHIDDEN)
+ return 0;
+
+ if (sb.style() > BHIDDEN)
+ borderWidth = max(borderWidth, static_cast<unsigned>(sb.width));
+
+ const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, rightmostColumn);
+
+ if (cs.cell) {
+ const BorderValue& cb = cs.cell->style()->borderRight();
+ if (cb.style() == BHIDDEN)
+ return 0;
+
+ const BorderValue& rb = cs.cell->parent()->style()->borderRight();
+ if (rb.style() == BHIDDEN)
+ return 0;
+
+ if (cb.style() > BHIDDEN)
+ borderWidth = max(borderWidth, static_cast<unsigned>(cb.width));
+ if (rb.style() > BHIDDEN)
+ borderWidth = max(borderWidth, static_cast<unsigned>(rb.width));
+ }
+ }
+ return (borderWidth + 1) / 2;
+ }
+ return RenderBlock::borderRight();
+}
+
+void RenderTable::recalcHorizontalBorders()
+{
+ m_borderLeft = calcBorderLeft();
+ m_borderRight = calcBorderRight();
+}
+
+int RenderTable::borderTop() const
+{
+ if (collapseBorders())
+ return outerBorderTop();
+ return RenderBlock::borderTop();
+}
+
+int RenderTable::borderBottom() const
+{
+ if (collapseBorders())
+ return outerBorderBottom();
+ return RenderBlock::borderBottom();
+}
+
+int RenderTable::outerBorderTop() const
+{
+ if (!collapseBorders())
+ return 0;
+ int borderWidth = 0;
+ RenderTableSection* topSection;
+ if (m_head)
+ topSection = m_head;
+ else if (m_firstBody)
+ topSection = m_firstBody;
+ else if (m_foot)
+ topSection = m_foot;
+ else
+ topSection = 0;
+ if (topSection) {
+ borderWidth = topSection->outerBorderTop();
+ if (borderWidth == -1)
+ return 0; // Overridden by hidden
+ }
+ const BorderValue& tb = style()->borderTop();
+ if (tb.style() == BHIDDEN)
+ return 0;
+ if (tb.style() > BHIDDEN)
+ borderWidth = max(borderWidth, static_cast<int>(tb.width / 2));
+ return borderWidth;
+}
+
+int RenderTable::outerBorderBottom() const
+{
+ if (!collapseBorders())
+ return 0;
+ int borderWidth = 0;
+ RenderTableSection* bottomSection;
+ if (m_foot)
+ bottomSection = m_foot;
+ else {
+ RenderObject* child;
+ for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling())
+ ;
+ bottomSection = child ? static_cast<RenderTableSection*>(child) : 0;
+ }
+ if (bottomSection) {
+ borderWidth = bottomSection->outerBorderBottom();
+ if (borderWidth == -1)
+ return 0; // Overridden by hidden
+ }
+ const BorderValue& tb = style()->borderBottom();
+ if (tb.style() == BHIDDEN)
+ return 0;
+ if (tb.style() > BHIDDEN)
+ borderWidth = max(borderWidth, static_cast<int>((tb.width + 1) / 2));
+ return borderWidth;
+}
+
+int RenderTable::outerBorderLeft() const
+{
+ if (!collapseBorders())
+ return 0;
+
+ int borderWidth = 0;
+
+ const BorderValue& tb = style()->borderLeft();
+ if (tb.style() == BHIDDEN)
+ return 0;
+ if (tb.style() > BHIDDEN)
+ borderWidth = tb.width / 2;
+
+ bool allHidden = true;
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (!child->isTableSection())
+ continue;
+ int sw = static_cast<RenderTableSection*>(child)->outerBorderLeft();
+ if (sw == -1)
+ continue;
+ else
+ allHidden = false;
+ borderWidth = max(borderWidth, sw);
+ }
+ if (allHidden)
+ return 0;
+
+ return borderWidth;
+}
+
+int RenderTable::outerBorderRight() const
+{
+ if (!collapseBorders())
+ return 0;
+
+ int borderWidth = 0;
+
+ const BorderValue& tb = style()->borderRight();
+ if (tb.style() == BHIDDEN)
+ return 0;
+ if (tb.style() > BHIDDEN)
+ borderWidth = (tb.width + 1) / 2;
+
+ bool allHidden = true;
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (!child->isTableSection())
+ continue;
+ int sw = static_cast<RenderTableSection*>(child)->outerBorderRight();
+ if (sw == -1)
+ continue;
+ else
+ allHidden = false;
+ borderWidth = max(borderWidth, sw);
+ }
+ if (allHidden)
+ return 0;
+
+ return borderWidth;
+}
+
+RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, bool skipEmptySections) const
+{
+ recalcSectionsIfNeeded();
+
+ if (section == m_head)
+ return 0;
+
+ RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
+ while (prevSection) {
+ if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (!skipEmptySections || static_cast<RenderTableSection*>(prevSection)->numRows()))
+ break;
+ prevSection = prevSection->previousSibling();
+ }
+ if (!prevSection && m_head && (!skipEmptySections || m_head->numRows()))
+ prevSection = m_head;
+ return static_cast<RenderTableSection*>(prevSection);
+}
+
+RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, bool skipEmptySections) const
+{
+ recalcSectionsIfNeeded();
+
+ if (section == m_foot)
+ return 0;
+
+ RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
+ while (nextSection) {
+ if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (!skipEmptySections || static_cast<RenderTableSection*>(nextSection)->numRows()))
+ break;
+ nextSection = nextSection->nextSibling();
+ }
+ if (!nextSection && m_foot && (!skipEmptySections || m_foot->numRows()))
+ nextSection = m_foot;
+ return static_cast<RenderTableSection*>(nextSection);
+}
+
+RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
+{
+ recalcSectionsIfNeeded();
+
+ // Find the section and row to look in
+ int r = cell->row();
+ RenderTableSection* section = 0;
+ int rAbove = 0;
+ if (r > 0) {
+ // cell is not in the first row, so use the above row in its own section
+ section = cell->section();
+ rAbove = r - 1;
+ } else {
+ section = sectionAbove(cell->section(), true);
+ if (section)
+ rAbove = section->numRows() - 1;
+ }
+
+ // Look up the cell in the section's grid, which requires effective col index
+ if (section) {
+ int effCol = colToEffCol(cell->col());
+ RenderTableSection::CellStruct aboveCell;
+ // If we hit a span back up to a real cell.
+ do {
+ aboveCell = section->cellAt(rAbove, effCol);
+ effCol--;
+ } while (!aboveCell.cell && aboveCell.inColSpan && effCol >= 0);
+ return aboveCell.cell;
+ } else
+ return 0;
+}
+
+RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
+{
+ recalcSectionsIfNeeded();
+
+ // Find the section and row to look in
+ int r = cell->row() + cell->rowSpan() - 1;
+ RenderTableSection* section = 0;
+ int rBelow = 0;
+ if (r < cell->section()->numRows() - 1) {
+ // The cell is not in the last row, so use the next row in the section.
+ section = cell->section();
+ rBelow = r + 1;
+ } else {
+ section = sectionBelow(cell->section(), true);
+ if (section)
+ rBelow = 0;
+ }
+
+ // Look up the cell in the section's grid, which requires effective col index
+ if (section) {
+ int effCol = colToEffCol(cell->col());
+ RenderTableSection::CellStruct belowCell;
+ // If we hit a colspan back up to a real cell.
+ do {
+ belowCell = section->cellAt(rBelow, effCol);
+ effCol--;
+ } while (!belowCell.cell && belowCell.inColSpan && effCol >= 0);
+ return belowCell.cell;
+ } else
+ return 0;
+}
+
+RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
+{
+ recalcSectionsIfNeeded();
+
+ RenderTableSection* section = cell->section();
+ int effCol = colToEffCol(cell->col());
+ if (!effCol)
+ return 0;
+
+ // If we hit a colspan back up to a real cell.
+ RenderTableSection::CellStruct prevCell;
+ do {
+ prevCell = section->cellAt(cell->row(), effCol - 1);
+ effCol--;
+ } while (!prevCell.cell && prevCell.inColSpan && effCol >= 0);
+ return prevCell.cell;
+}
+
+RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
+{
+ recalcSectionsIfNeeded();
+
+ int effCol = colToEffCol(cell->col() + cell->colSpan());
+ if (effCol >= numEffCols())
+ return 0;
+ return cell->section()->cellAt(cell->row(), effCol).cell;
+}
+
+RenderBlock* RenderTable::firstLineBlock() const
+{
+ return 0;
+}
+
+void RenderTable::updateFirstLetter()
+{
+}
+
+int RenderTable::getBaselineOfFirstLineBox() const
+{
+ RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
+ if (firstNonEmptySection && !firstNonEmptySection->numRows())
+ firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
+
+ if (!firstNonEmptySection)
+ return -1;
+
+ return firstNonEmptySection->yPos() + firstNonEmptySection->getBaselineOfFirstLineBox();
+}
+
+IntRect RenderTable::getOverflowClipRect(int tx, int ty)
+{
+ IntRect rect = RenderBlock::getOverflowClipRect(tx, ty);
+
+ // If we have a caption, expand the clip to include the caption.
+ // FIXME: Technically this is wrong, but it's virtually impossible to fix this
+ // for real until captions have been re-written.
+ // FIXME: This code assumes (like all our other caption code) that only top/bottom are
+ // supported. When we actually support left/right and stop mapping them to top/bottom,
+ // we might have to hack this code first (depending on what order we do these bug fixes in).
+ if (m_caption) {
+ rect.setHeight(height());
+ rect.setY(ty);
+ }
+
+ return rect;
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTable.h b/src/3rdparty/webkit/WebCore/rendering/RenderTable.h
new file mode 100644
index 0000000..59cb00e
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTable.h
@@ -0,0 +1,226 @@
+/*
+ * 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)
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 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
+ * 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 RenderTable_h
+#define RenderTable_h
+
+#include "RenderBlock.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class RenderTableCol;
+class RenderTableCell;
+class RenderTableSection;
+class TableLayout;
+
+class RenderTable : public RenderBlock {
+public:
+ enum Rules {
+ None = 0x00,
+ RGroups = 0x01,
+ CGroups = 0x02,
+ Groups = 0x03,
+ Rows = 0x05,
+ Cols = 0x0a,
+ All = 0x0f
+ };
+ enum Frame {
+ Void = 0x00,
+ Above = 0x01,
+ Below = 0x02,
+ Lhs = 0x04,
+ Rhs = 0x08,
+ Hsides = 0x03,
+ Vsides = 0x0c,
+ Box = 0x0f
+ };
+
+ RenderTable(Node*);
+ ~RenderTable();
+
+ virtual const char* renderName() const { return "RenderTable"; }
+
+ virtual bool isTable() const { return true; }
+
+ virtual bool avoidsFloats() const { return true; }
+
+ int getColumnPos(int col) const { return m_columnPos[col]; }
+
+ int hBorderSpacing() const { return m_hSpacing; }
+ int vBorderSpacing() const { return m_vSpacing; }
+
+ bool collapseBorders() const { return style()->borderCollapse(); }
+ int borderLeft() const { return m_borderLeft; }
+ int borderRight() const { return m_borderRight; }
+ int borderTop() const;
+ int borderBottom() const;
+
+ Rules getRules() const { return static_cast<Rules>(m_rules); }
+
+ const Color& bgColor() const { return style()->backgroundColor(); }
+
+ int outerBorderTop() const;
+ int outerBorderBottom() const;
+ int outerBorderLeft() const;
+ int outerBorderRight() const;
+
+ int calcBorderLeft() const;
+ int calcBorderRight() const;
+ void recalcHorizontalBorders();
+
+ // overrides
+ virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
+ virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void paintBoxDecorations(PaintInfo&, int tx, int ty);
+ virtual void paintMask(PaintInfo& paintInfo, int tx, int ty);
+ virtual void layout();
+ virtual void calcPrefWidths();
+
+ virtual int getBaselineOfFirstLineBox() const;
+
+ virtual RenderBlock* firstLineBlock() const;
+ virtual void updateFirstLetter();
+
+ virtual void setCellWidths();
+
+ virtual void calcWidth();
+
+ struct ColumnStruct {
+ enum {
+ WidthUndefined = 0xffff
+ };
+
+ ColumnStruct()
+ : span(1)
+ , width(WidthUndefined)
+ {
+ }
+
+ unsigned short span;
+ unsigned width; // the calculated position of the column
+ };
+
+ Vector<ColumnStruct>& columns() { return m_columns; }
+ Vector<int>& columnPositions() { return m_columnPos; }
+ RenderTableSection* header() const { return m_head; }
+ RenderTableSection* footer() const { return m_foot; }
+ RenderTableSection* firstBody() const { return m_firstBody; }
+
+ void splitColumn(int pos, int firstSpan);
+ void appendColumn(int span);
+ int numEffCols() const { return m_columns.size(); }
+ int spanOfEffCol(int effCol) const { return m_columns[effCol].span; }
+
+ int colToEffCol(int col) const
+ {
+ int i = 0;
+ int effCol = numEffCols();
+ for (int c = 0; c < col && i < effCol; ++i)
+ c += m_columns[i].span;
+ return i;
+ }
+
+ int effColToCol(int effCol) const
+ {
+ int c = 0;
+ for (int i = 0; i < effCol; i++)
+ c += m_columns[i].span;
+ return c;
+ }
+
+ int bordersPaddingAndSpacing() const
+ {
+ return borderLeft() + borderRight() +
+ (collapseBorders() ? 0 : (paddingLeft() + paddingRight() + (numEffCols() + 1) * hBorderSpacing()));
+ }
+
+ RenderTableCol* colElement(int col, bool* startEdge = 0, bool* endEdge = 0) const;
+
+ bool needsSectionRecalc() const { return m_needsSectionRecalc; }
+ void setNeedsSectionRecalc()
+ {
+ if (documentBeingDestroyed())
+ return;
+ m_needsSectionRecalc = true;
+ setNeedsLayout(true);
+ }
+
+ virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true);
+
+ RenderTableSection* sectionAbove(const RenderTableSection*, bool skipEmptySections = false) const;
+ RenderTableSection* sectionBelow(const RenderTableSection*, bool skipEmptySections = false) const;
+
+ RenderTableCell* cellAbove(const RenderTableCell*) const;
+ RenderTableCell* cellBelow(const RenderTableCell*) const;
+ RenderTableCell* cellBefore(const RenderTableCell*) const;
+ RenderTableCell* cellAfter(const RenderTableCell*) const;
+
+ const CollapsedBorderValue* currentBorderStyle() const { return m_currentBorder; }
+
+ bool hasSections() const { return m_head || m_foot || m_firstBody; }
+
+ virtual IntRect getOverflowClipRect(int tx, int ty);
+
+ void recalcSectionsIfNeeded() const
+ {
+ if (m_needsSectionRecalc)
+ recalcSections();
+ }
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+private:
+ void recalcSections() const;
+
+ mutable Vector<int> m_columnPos;
+ mutable Vector<ColumnStruct> m_columns;
+
+ mutable RenderBlock* m_caption;
+ mutable RenderTableSection* m_head;
+ mutable RenderTableSection* m_foot;
+ mutable RenderTableSection* m_firstBody;
+
+ TableLayout* m_tableLayout;
+
+ const CollapsedBorderValue* m_currentBorder;
+
+ unsigned m_frame : 4; // Frame
+ unsigned m_rules : 4; // Rules
+
+ mutable bool m_hasColElements : 1;
+ mutable bool m_needsSectionRecalc : 1;
+
+ short m_hSpacing;
+ short m_vSpacing;
+ int m_borderLeft;
+ int m_borderRight;
+};
+
+} // namespace WebCore
+
+#endif // RenderTable_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp
new file mode 100644
index 0000000..02e7729
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.cpp
@@ -0,0 +1,882 @@
+/**
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ * (C) 1997 Torben Weis (weis@kde.org)
+ * (C) 1998 Waldo Bastian (bastian@kde.org)
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "RenderTableCell.h"
+
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLTableCellElement.h"
+#include "RenderTableCol.h"
+#include "RenderView.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderTableCell::RenderTableCell(Node* node)
+ : RenderBlock(node)
+ , m_row(-1)
+ , m_column(-1)
+ , m_rowSpan(1)
+ , m_columnSpan(1)
+ , m_topExtra(0)
+ , m_bottomExtra(0)
+ , m_widthChanged(false)
+ , m_percentageHeight(0)
+{
+ updateFromElement();
+}
+
+void RenderTableCell::destroy()
+{
+ RenderTableSection* recalcSection = parent() ? section() : 0;
+
+ RenderBlock::destroy();
+
+ if (recalcSection)
+ recalcSection->setNeedsCellRecalc();
+}
+
+void RenderTableCell::updateFromElement()
+{
+ Node* node = element();
+ if (node && (node->hasTagName(tdTag) || node->hasTagName(thTag))) {
+ HTMLTableCellElement* tc = static_cast<HTMLTableCellElement*>(node);
+ int oldRSpan = m_rowSpan;
+ int oldCSpan = m_columnSpan;
+
+ m_columnSpan = tc->colSpan();
+ m_rowSpan = tc->rowSpan();
+ if ((oldRSpan != m_rowSpan || oldCSpan != m_columnSpan) && style() && parent()) {
+ setNeedsLayoutAndPrefWidthsRecalc();
+ if (section())
+ section()->setNeedsCellRecalc();
+ }
+ }
+}
+
+Length RenderTableCell::styleOrColWidth() const
+{
+ Length w = style()->width();
+ if (colSpan() > 1 || !w.isAuto())
+ return w;
+ RenderTableCol* tableCol = table()->colElement(col());
+ if (tableCol) {
+ w = tableCol->style()->width();
+
+ // Column widths specified on <col> apply to the border box of the cell.
+ // Percentages don't need to be handled since they're always treated this way (even when specified on the cells).
+ // See Bugzilla bug 8126 for details.
+ if (w.isFixed() && w.value() > 0)
+ w = Length(max(0, w.value() - borderLeft() - borderRight() - paddingLeft() - paddingRight()), Fixed);
+ }
+ return w;
+}
+
+void RenderTableCell::calcPrefWidths()
+{
+ // The child cells rely on the grids up in the sections to do their calcPrefWidths work. Normally the sections are set up early, as table
+ // cells are added, but relayout can cause the cells to be freed, leaving stale pointers in the sections'
+ // grids. We must refresh those grids before the child cells try to use them.
+ table()->recalcSectionsIfNeeded();
+
+ RenderBlock::calcPrefWidths();
+ if (element() && style()->autoWrap()) {
+ // See if nowrap was set.
+ Length w = styleOrColWidth();
+ String nowrap = static_cast<Element*>(element())->getAttribute(nowrapAttr);
+ if (!nowrap.isNull() && w.isFixed())
+ // Nowrap is set, but we didn't actually use it because of the
+ // fixed width set on the cell. Even so, it is a WinIE/Moz trait
+ // to make the minwidth of the cell into the fixed width. They do this
+ // even in strict mode, so do not make this a quirk. Affected the top
+ // of hiptop.com.
+ m_minPrefWidth = max(w.value(), m_minPrefWidth);
+ }
+}
+
+void RenderTableCell::calcWidth()
+{
+}
+
+void RenderTableCell::setWidth(int width)
+{
+ if (width != m_width) {
+ m_width = width;
+ m_widthChanged = true;
+ }
+}
+
+void RenderTableCell::layout()
+{
+ layoutBlock(m_widthChanged);
+ m_widthChanged = false;
+}
+
+IntRect RenderTableCell::absoluteClippedOverflowRect()
+{
+ // If the table grid is dirty, we cannot get reliable information about adjoining cells,
+ // so we ignore outside borders. This should not be a problem because it means that
+ // the table is going to recalculate the grid, relayout and repaint its current rect, which
+ // includes any outside borders of this cell.
+ if (!table()->collapseBorders() || table()->needsSectionRecalc())
+ return RenderBlock::absoluteClippedOverflowRect();
+
+ bool rtl = table()->style()->direction() == RTL;
+ int outlineSize = style()->outlineSize();
+ int left = max(borderHalfLeft(true), outlineSize);
+ int right = max(borderHalfRight(true), outlineSize);
+ int top = max(borderHalfTop(true), outlineSize);
+ int bottom = max(borderHalfBottom(true), outlineSize);
+ if (left && !rtl || right && rtl) {
+ if (RenderTableCell* before = table()->cellBefore(this)) {
+ top = max(top, before->borderHalfTop(true));
+ bottom = max(bottom, before->borderHalfBottom(true));
+ }
+ }
+ if (left && rtl || right && !rtl) {
+ if (RenderTableCell* after = table()->cellAfter(this)) {
+ top = max(top, after->borderHalfTop(true));
+ bottom = max(bottom, after->borderHalfBottom(true));
+ }
+ }
+ if (top) {
+ if (RenderTableCell* above = table()->cellAbove(this)) {
+ left = max(left, above->borderHalfLeft(true));
+ right = max(right, above->borderHalfRight(true));
+ }
+ }
+ if (bottom) {
+ if (RenderTableCell* below = table()->cellBelow(this)) {
+ left = max(left, below->borderHalfLeft(true));
+ right = max(right, below->borderHalfRight(true));
+ }
+ }
+ left = max(left, -overflowLeft(false));
+ top = max(top, -overflowTop(false) - borderTopExtra());
+ IntRect r(-left, -borderTopExtra() - top, left + max(width() + right, overflowWidth(false)), borderTopExtra() + top + max(height() + bottom + borderBottomExtra(), overflowHeight(false)));
+
+ if (RenderView* v = view())
+ r.move(v->layoutDelta());
+
+ computeAbsoluteRepaintRect(r);
+ return r;
+}
+
+void RenderTableCell::computeAbsoluteRepaintRect(IntRect& r, bool fixed)
+{
+ r.setY(r.y() + m_topExtra);
+ RenderView* v = view();
+ if ((!v || !v->layoutState()) && parent())
+ r.move(-parent()->xPos(), -parent()->yPos()); // Rows are in the same coordinate space, so don't add their offset in.
+ RenderBlock::computeAbsoluteRepaintRect(r, fixed);
+}
+
+FloatPoint RenderTableCell::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const
+{
+ RenderView* v = view();
+ if ((!v || !v->layoutState()) && parent()) {
+ // Rows are in the same coordinate space, so don't add their offset in.
+ localPoint.move(-parent()->xPos(), -parent()->yPos());
+ }
+ return RenderBlock::localToAbsolute(localPoint, fixed, useTransforms);
+}
+
+FloatPoint RenderTableCell::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const
+{
+ FloatPoint localPoint = RenderBlock::absoluteToLocal(containerPoint, fixed, useTransforms);
+ if (parent()) {
+ // Rows are in the same coordinate space, so add their offset back in.
+ localPoint.move(parent()->xPos(), parent()->yPos());
+ }
+ return localPoint;
+}
+
+FloatQuad RenderTableCell::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const
+{
+ FloatQuad quad = localQuad;
+ if (parent()) {
+ // Rows are in the same coordinate space, so don't add their offset in.
+ quad.move(-parent()->xPos(), -parent()->yPos());
+ }
+ return RenderBlock::localToAbsoluteQuad(quad, fixed);
+}
+
+int RenderTableCell::baselinePosition(bool /*firstLine*/, bool /*isRootLineBox*/) const
+{
+ // <http://www.w3.org/TR/2007/CR-CSS21-20070719/tables.html#height-layout>: The baseline of a cell is the baseline of
+ // the first in-flow line box in the cell, or the first in-flow table-row in the cell, whichever comes first. If there
+ // is no such line box or table-row, the baseline is the bottom of content edge of the cell box.
+
+ int firstLineBaseline = getBaselineOfFirstLineBox();
+ if (firstLineBaseline != -1)
+ return firstLineBaseline;
+
+ return paddingTop() + borderTop() + contentHeight();
+}
+
+void RenderTableCell::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
+{
+ if (parent() && section() && style() && style()->height() != newStyle->height())
+ section()->setNeedsCellRecalc();
+
+ ASSERT(newStyle->display() == TABLE_CELL);
+
+ RenderBlock::styleWillChange(diff, newStyle);
+}
+
+void RenderTableCell::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+ setHasBoxDecorations(true);
+}
+
+bool RenderTableCell::requiresLayer()
+{
+ return isPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection();
+}
+
+// The following rules apply for resolving conflicts and figuring out which border
+// to use.
+// (1) Borders with the 'border-style' of 'hidden' take precedence over all other conflicting
+// borders. Any border with this value suppresses all borders at this location.
+// (2) Borders with a style of 'none' have the lowest priority. Only if the border properties of all
+// the elements meeting at this edge are 'none' will the border be omitted (but note that 'none' is
+// the default value for the border style.)
+// (3) If none of the styles are 'hidden' and at least one of them is not 'none', then narrow borders
+// are discarded in favor of wider ones. If several have the same 'border-width' then styles are preferred
+// in this order: 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove', and the lowest: 'inset'.
+// (4) If border styles differ only in color, then a style set on a cell wins over one on a row,
+// which wins over a row group, column, column group and, lastly, table. It is undefined which color
+// is used when two elements of the same type disagree.
+static CollapsedBorderValue compareBorders(const CollapsedBorderValue& border1, const CollapsedBorderValue& border2)
+{
+ // Sanity check the values passed in. If either is null, return the other.
+ if (!border2.exists())
+ return border1;
+ if (!border1.exists())
+ return border2;
+
+ // Rule #1 above.
+ if (border1.style() == BHIDDEN || border2.style() == BHIDDEN)
+ return CollapsedBorderValue(); // No border should exist at this location.
+
+ // Rule #2 above. A style of 'none' has lowest priority and always loses to any other border.
+ if (border2.style() == BNONE)
+ return border1;
+ if (border1.style() == BNONE)
+ return border2;
+
+ // The first part of rule #3 above. Wider borders win.
+ if (border1.width() != border2.width())
+ return border1.width() > border2.width() ? border1 : border2;
+
+ // The borders have equal width. Sort by border style.
+ if (border1.style() != border2.style())
+ return border1.style() > border2.style() ? border1 : border2;
+
+ // The border have the same width and style. Rely on precedence (cell over row over row group, etc.)
+ return border1.precedence >= border2.precedence ? border1 : border2;
+}
+
+CollapsedBorderValue RenderTableCell::collapsedLeftBorder(bool rtl) const
+{
+ RenderTable* tableElt = table();
+ bool leftmostColumn;
+ if (!rtl)
+ leftmostColumn = col() == 0;
+ else {
+ int effCol = tableElt->colToEffCol(col() + colSpan() - 1);
+ leftmostColumn = effCol == tableElt->numEffCols() - 1;
+ }
+
+ // For border left, we need to check, in order of precedence:
+ // (1) Our left border.
+ CollapsedBorderValue result(&style()->borderLeft(), BCELL);
+
+ // (2) The right border of the cell to the left.
+ RenderTableCell* prevCell = rtl ? tableElt->cellAfter(this) : tableElt->cellBefore(this);
+ if (prevCell) {
+ result = rtl ? compareBorders(result, CollapsedBorderValue(&prevCell->style()->borderRight(), BCELL)) : compareBorders(CollapsedBorderValue(&prevCell->style()->borderRight(), BCELL), result);
+ if (!result.exists())
+ return result;
+ } else if (leftmostColumn) {
+ // (3) Our row's left border.
+ result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderLeft(), BROW));
+ if (!result.exists())
+ return result;
+
+ // (4) Our row group's left border.
+ result = compareBorders(result, CollapsedBorderValue(&section()->style()->borderLeft(), BROWGROUP));
+ if (!result.exists())
+ return result;
+ }
+
+ // (5) Our column and column group's left borders.
+ bool startColEdge;
+ bool endColEdge;
+ RenderTableCol* colElt = tableElt->colElement(col() + (rtl ? colSpan() - 1 : 0), &startColEdge, &endColEdge);
+ if (colElt && (!rtl ? startColEdge : endColEdge)) {
+ result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderLeft(), BCOL));
+ if (!result.exists())
+ return result;
+ if (colElt->parent()->isTableCol() && (!rtl ? !colElt->previousSibling() : !colElt->nextSibling())) {
+ result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderLeft(), BCOLGROUP));
+ if (!result.exists())
+ return result;
+ }
+ }
+
+ // (6) The right border of the column to the left.
+ if (!leftmostColumn) {
+ colElt = tableElt->colElement(col() + (rtl ? colSpan() : -1), &startColEdge, &endColEdge);
+ if (colElt && (!rtl ? endColEdge : startColEdge)) {
+ result = rtl ? compareBorders(result, CollapsedBorderValue(&colElt->style()->borderRight(), BCOL)) : compareBorders(CollapsedBorderValue(&colElt->style()->borderRight(), BCOL), result);
+ if (!result.exists())
+ return result;
+ }
+ } else {
+ // (7) The table's left border.
+ result = compareBorders(result, CollapsedBorderValue(&tableElt->style()->borderLeft(), BTABLE));
+ if (!result.exists())
+ return result;
+ }
+
+ return result;
+}
+
+CollapsedBorderValue RenderTableCell::collapsedRightBorder(bool rtl) const
+{
+ RenderTable* tableElt = table();
+ bool rightmostColumn;
+ if (rtl)
+ rightmostColumn = col() == 0;
+ else {
+ int effCol = tableElt->colToEffCol(col() + colSpan() - 1);
+ rightmostColumn = effCol == tableElt->numEffCols() - 1;
+ }
+
+ // For border right, we need to check, in order of precedence:
+ // (1) Our right border.
+ CollapsedBorderValue result = CollapsedBorderValue(&style()->borderRight(), BCELL);
+
+ // (2) The left border of the cell to the right.
+ if (!rightmostColumn) {
+ RenderTableCell* nextCell = rtl ? tableElt->cellBefore(this) : tableElt->cellAfter(this);
+ if (nextCell && nextCell->style()) {
+ result = rtl ? compareBorders(CollapsedBorderValue(&nextCell->style()->borderLeft(), BCELL), result) : compareBorders(result, CollapsedBorderValue(&nextCell->style()->borderLeft(), BCELL));
+ if (!result.exists())
+ return result;
+ }
+ } else {
+ // (3) Our row's right border.
+ result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderRight(), BROW));
+ if (!result.exists())
+ return result;
+
+ // (4) Our row group's right border.
+ result = compareBorders(result, CollapsedBorderValue(&section()->style()->borderRight(), BROWGROUP));
+ if (!result.exists())
+ return result;
+ }
+
+ // (5) Our column and column group's right borders.
+ bool startColEdge;
+ bool endColEdge;
+ RenderTableCol* colElt = tableElt->colElement(col() + (rtl ? 0 : colSpan() - 1), &startColEdge, &endColEdge);
+ if (colElt && (!rtl ? endColEdge : startColEdge)) {
+ result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderRight(), BCOL));
+ if (!result.exists())
+ return result;
+ if (colElt->parent()->isTableCol() && (!rtl ? !colElt->nextSibling() : !colElt->previousSibling())) {
+ result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderRight(), BCOLGROUP));
+ if (!result.exists())
+ return result;
+ }
+ }
+
+ // (6) The left border of the column to the right.
+ if (!rightmostColumn) {
+ colElt = tableElt->colElement(col() + (rtl ? -1 : colSpan()), &startColEdge, &endColEdge);
+ if (colElt && (!rtl ? startColEdge : endColEdge)) {
+ result = rtl ? compareBorders(CollapsedBorderValue(&colElt->style()->borderLeft(), BCOL), result) : compareBorders(result, CollapsedBorderValue(&colElt->style()->borderLeft(), BCOL));
+ if (!result.exists())
+ return result;
+ }
+ } else {
+ // (7) The table's right border.
+ result = compareBorders(result, CollapsedBorderValue(&tableElt->style()->borderRight(), BTABLE));
+ if (!result.exists())
+ return result;
+ }
+
+ return result;
+}
+
+CollapsedBorderValue RenderTableCell::collapsedTopBorder() const
+{
+ // For border top, we need to check, in order of precedence:
+ // (1) Our top border.
+ CollapsedBorderValue result = CollapsedBorderValue(&style()->borderTop(), BCELL);
+
+ RenderTableCell* prevCell = table()->cellAbove(this);
+ if (prevCell) {
+ // (2) A previous cell's bottom border.
+ result = compareBorders(CollapsedBorderValue(&prevCell->style()->borderBottom(), BCELL), result);
+ if (!result.exists())
+ return result;
+ }
+
+ // (3) Our row's top border.
+ result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderTop(), BROW));
+ if (!result.exists())
+ return result;
+
+ // (4) The previous row's bottom border.
+ if (prevCell) {
+ RenderObject* prevRow = 0;
+ if (prevCell->section() == section())
+ prevRow = parent()->previousSibling();
+ else
+ prevRow = prevCell->section()->lastChild();
+
+ if (prevRow) {
+ result = compareBorders(CollapsedBorderValue(&prevRow->style()->borderBottom(), BROW), result);
+ if (!result.exists())
+ return result;
+ }
+ }
+
+ // Now check row groups.
+ RenderTableSection* currSection = section();
+ if (!row()) {
+ // (5) Our row group's top border.
+ result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderTop(), BROWGROUP));
+ if (!result.exists())
+ return result;
+
+ // (6) Previous row group's bottom border.
+ currSection = table()->sectionAbove(currSection);
+ if (currSection) {
+ result = compareBorders(CollapsedBorderValue(&currSection->style()->borderBottom(), BROWGROUP), result);
+ if (!result.exists())
+ return result;
+ }
+ }
+
+ if (!currSection) {
+ // (8) Our column and column group's top borders.
+ RenderTableCol* colElt = table()->colElement(col());
+ if (colElt) {
+ result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderTop(), BCOL));
+ if (!result.exists())
+ return result;
+ if (colElt->parent()->isTableCol()) {
+ result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderTop(), BCOLGROUP));
+ if (!result.exists())
+ return result;
+ }
+ }
+
+ // (9) The table's top border.
+ result = compareBorders(result, CollapsedBorderValue(&table()->style()->borderTop(), BTABLE));
+ if (!result.exists())
+ return result;
+ }
+
+ return result;
+}
+
+CollapsedBorderValue RenderTableCell::collapsedBottomBorder() const
+{
+ // For border top, we need to check, in order of precedence:
+ // (1) Our bottom border.
+ CollapsedBorderValue result = CollapsedBorderValue(&style()->borderBottom(), BCELL);
+
+ RenderTableCell* nextCell = table()->cellBelow(this);
+ if (nextCell) {
+ // (2) A following cell's top border.
+ result = compareBorders(result, CollapsedBorderValue(&nextCell->style()->borderTop(), BCELL));
+ if (!result.exists())
+ return result;
+ }
+
+ // (3) Our row's bottom border. (FIXME: Deal with rowspan!)
+ result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderBottom(), BROW));
+ if (!result.exists())
+ return result;
+
+ // (4) The next row's top border.
+ if (nextCell) {
+ result = compareBorders(result, CollapsedBorderValue(&nextCell->parent()->style()->borderTop(), BROW));
+ if (!result.exists())
+ return result;
+ }
+
+ // Now check row groups.
+ RenderTableSection* currSection = section();
+ if (row() + rowSpan() >= static_cast<RenderTableSection*>(currSection)->numRows()) {
+ // (5) Our row group's bottom border.
+ result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderBottom(), BROWGROUP));
+ if (!result.exists())
+ return result;
+
+ // (6) Following row group's top border.
+ currSection = table()->sectionBelow(currSection);
+ if (currSection) {
+ result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderTop(), BROWGROUP));
+ if (!result.exists())
+ return result;
+ }
+ }
+
+ if (!currSection) {
+ // (8) Our column and column group's bottom borders.
+ RenderTableCol* colElt = table()->colElement(col());
+ if (colElt) {
+ result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderBottom(), BCOL));
+ if (!result.exists()) return result;
+ if (colElt->parent()->isTableCol()) {
+ result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderBottom(), BCOLGROUP));
+ if (!result.exists())
+ return result;
+ }
+ }
+
+ // (9) The table's bottom border.
+ result = compareBorders(result, CollapsedBorderValue(&table()->style()->borderBottom(), BTABLE));
+ if (!result.exists())
+ return result;
+ }
+
+ return result;
+}
+
+int RenderTableCell::borderLeft() const
+{
+ return table()->collapseBorders() ? borderHalfLeft(false) : RenderBlock::borderLeft();
+}
+
+int RenderTableCell::borderRight() const
+{
+ return table()->collapseBorders() ? borderHalfRight(false) : RenderBlock::borderRight();
+}
+
+int RenderTableCell::borderTop() const
+{
+ return table()->collapseBorders() ? borderHalfTop(false) : RenderBlock::borderTop();
+}
+
+int RenderTableCell::borderBottom() const
+{
+ return table()->collapseBorders() ? borderHalfBottom(false) : RenderBlock::borderBottom();
+}
+
+int RenderTableCell::borderHalfLeft(bool outer) const
+{
+ CollapsedBorderValue border = collapsedLeftBorder(table()->style()->direction() == RTL);
+ if (border.exists())
+ return (border.width() + (outer ? 0 : 1)) / 2; // Give the extra pixel to top and left.
+ return 0;
+}
+
+int RenderTableCell::borderHalfRight(bool outer) const
+{
+ CollapsedBorderValue border = collapsedRightBorder(table()->style()->direction() == RTL);
+ if (border.exists())
+ return (border.width() + (outer ? 1 : 0)) / 2;
+ return 0;
+}
+
+int RenderTableCell::borderHalfTop(bool outer) const
+{
+ CollapsedBorderValue border = collapsedTopBorder();
+ if (border.exists())
+ return (border.width() + (outer ? 0 : 1)) / 2; // Give the extra pixel to top and left.
+ return 0;
+}
+
+int RenderTableCell::borderHalfBottom(bool outer) const
+{
+ CollapsedBorderValue border = collapsedBottomBorder();
+ if (border.exists())
+ return (border.width() + (outer ? 1 : 0)) / 2;
+ return 0;
+}
+
+void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ tx += m_x;
+ ty += m_y;
+
+ // check if we need to do anything at all...
+ int os = 2 * maximalOutlineSize(paintInfo.phase);
+
+ if (paintInfo.phase == PaintPhaseCollapsedTableBorders && style()->visibility() == VISIBLE) {
+ if (ty - table()->outerBorderTop() >= paintInfo.rect.bottom() + os ||
+ ty + m_topExtra + m_height + m_bottomExtra + table()->outerBorderBottom() <= paintInfo.rect.y() - os)
+ return;
+ int w = width();
+ int h = height() + borderTopExtra() + borderBottomExtra();
+ paintCollapsedBorder(paintInfo.context, tx, ty, w, h);
+ } else {
+ if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + m_topExtra + overflowHeight(false) + m_bottomExtra <= paintInfo.rect.y() - os)
+ return;
+ RenderBlock::paintObject(paintInfo, tx, ty + m_topExtra);
+ }
+}
+
+static EBorderStyle collapsedBorderStyle(EBorderStyle style)
+{
+ if (style == OUTSET)
+ return GROOVE;
+ if (style == INSET)
+ return RIDGE;
+ return style;
+}
+
+struct CollapsedBorder {
+ CollapsedBorderValue borderValue;
+ RenderObject::BorderSide side;
+ bool shouldPaint;
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+ EBorderStyle style;
+};
+
+class CollapsedBorders {
+public:
+ CollapsedBorders()
+ : m_count(0)
+ {
+ }
+
+ void addBorder(const CollapsedBorderValue& borderValue, RenderObject::BorderSide borderSide, bool shouldPaint,
+ int x1, int y1, int x2, int y2, EBorderStyle borderStyle)
+ {
+ if (borderValue.exists() && shouldPaint) {
+ m_borders[m_count].borderValue = borderValue;
+ m_borders[m_count].side = borderSide;
+ m_borders[m_count].shouldPaint = shouldPaint;
+ m_borders[m_count].x1 = x1;
+ m_borders[m_count].x2 = x2;
+ m_borders[m_count].y1 = y1;
+ m_borders[m_count].y2 = y2;
+ m_borders[m_count].style = borderStyle;
+ m_count++;
+ }
+ }
+
+ CollapsedBorder* nextBorder()
+ {
+ for (int i = 0; i < m_count; i++) {
+ if (m_borders[i].borderValue.exists() && m_borders[i].shouldPaint) {
+ m_borders[i].shouldPaint = false;
+ return &m_borders[i];
+ }
+ }
+
+ return 0;
+ }
+
+ CollapsedBorder m_borders[4];
+ int m_count;
+};
+
+static void addBorderStyle(RenderTableCell::CollapsedBorderStyles& borderStyles, CollapsedBorderValue borderValue)
+{
+ if (!borderValue.exists())
+ return;
+ size_t count = borderStyles.size();
+ for (size_t i = 0; i < count; ++i)
+ if (borderStyles[i] == borderValue)
+ return;
+ borderStyles.append(borderValue);
+}
+
+void RenderTableCell::collectBorderStyles(CollapsedBorderStyles& borderStyles) const
+{
+ bool rtl = table()->style()->direction() == RTL;
+ addBorderStyle(borderStyles, collapsedLeftBorder(rtl));
+ addBorderStyle(borderStyles, collapsedRightBorder(rtl));
+ addBorderStyle(borderStyles, collapsedTopBorder());
+ addBorderStyle(borderStyles, collapsedBottomBorder());
+}
+
+static int compareBorderStylesForQSort(const void* pa, const void* pb)
+{
+ const CollapsedBorderValue* a = static_cast<const CollapsedBorderValue*>(pa);
+ const CollapsedBorderValue* b = static_cast<const CollapsedBorderValue*>(pb);
+ if (*a == *b)
+ return 0;
+ CollapsedBorderValue borderWithHigherPrecedence = compareBorders(*a, *b);
+ if (*a == borderWithHigherPrecedence)
+ return 1;
+ return -1;
+}
+
+void RenderTableCell::sortBorderStyles(CollapsedBorderStyles& borderStyles)
+{
+ qsort(borderStyles.data(), borderStyles.size(), sizeof(CollapsedBorderValue),
+ compareBorderStylesForQSort);
+}
+
+void RenderTableCell::paintCollapsedBorder(GraphicsContext* graphicsContext, int tx, int ty, int w, int h)
+{
+ if (!table()->currentBorderStyle())
+ return;
+
+ bool rtl = table()->style()->direction() == RTL;
+ CollapsedBorderValue leftVal = collapsedLeftBorder(rtl);
+ CollapsedBorderValue rightVal = collapsedRightBorder(rtl);
+ CollapsedBorderValue topVal = collapsedTopBorder();
+ CollapsedBorderValue bottomVal = collapsedBottomBorder();
+
+ // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location.
+ int topWidth = topVal.width();
+ int bottomWidth = bottomVal.width();
+ int leftWidth = leftVal.width();
+ int rightWidth = rightVal.width();
+
+ tx -= leftWidth / 2;
+ ty -= topWidth / 2;
+ w += leftWidth / 2 + (rightWidth + 1) / 2;
+ h += topWidth / 2 + (bottomWidth + 1) / 2;
+
+ EBorderStyle topStyle = collapsedBorderStyle(topVal.style());
+ EBorderStyle bottomStyle = collapsedBorderStyle(bottomVal.style());
+ EBorderStyle leftStyle = collapsedBorderStyle(leftVal.style());
+ EBorderStyle rightStyle = collapsedBorderStyle(rightVal.style());
+
+ bool renderTop = topStyle > BHIDDEN && !topVal.isTransparent();
+ bool renderBottom = bottomStyle > BHIDDEN && !bottomVal.isTransparent();
+ bool renderLeft = leftStyle > BHIDDEN && !leftVal.isTransparent();
+ bool renderRight = rightStyle > BHIDDEN && !rightVal.isTransparent();
+
+ // We never paint diagonals at the joins. We simply let the border with the highest
+ // precedence paint on top of borders with lower precedence.
+ CollapsedBorders borders;
+ borders.addBorder(topVal, BSTop, renderTop, tx, ty, tx + w, ty + topWidth, topStyle);
+ borders.addBorder(bottomVal, BSBottom, renderBottom, tx, ty + h - bottomWidth, tx + w, ty + h, bottomStyle);
+ borders.addBorder(leftVal, BSLeft, renderLeft, tx, ty, tx + leftWidth, ty + h, leftStyle);
+ borders.addBorder(rightVal, BSRight, renderRight, tx + w - rightWidth, ty, tx + w, ty + h, rightStyle);
+
+ for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) {
+ if (border->borderValue == *table()->currentBorderStyle())
+ drawBorder(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side,
+ border->borderValue.color(), style()->color(), border->style, 0, 0);
+ }
+}
+
+void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, int ty, RenderObject* backgroundObject)
+{
+ if (!backgroundObject)
+ return;
+
+ if (style()->visibility() != VISIBLE)
+ return;
+
+ RenderTable* tableElt = table();
+ if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
+ return;
+
+ if (backgroundObject != this) {
+ tx += m_x;
+ ty += m_y + m_topExtra;
+ }
+
+ int w = width();
+ int h = height() + borderTopExtra() + borderBottomExtra();
+ ty -= borderTopExtra();
+
+ int my = max(ty, paintInfo.rect.y());
+ int end = min(paintInfo.rect.bottom(), ty + h);
+ int mh = end - my;
+
+ Color c = backgroundObject->style()->backgroundColor();
+ const FillLayer* bgLayer = backgroundObject->style()->backgroundLayers();
+
+ if (bgLayer->hasImage() || c.isValid()) {
+ // We have to clip here because the background would paint
+ // on top of the borders otherwise. This only matters for cells and rows.
+ bool shouldClip = backgroundObject->hasLayer() && (backgroundObject == this || backgroundObject == parent()) && tableElt->collapseBorders();
+ if (shouldClip) {
+ IntRect clipRect(tx + borderLeft(), ty + borderTop(),
+ w - borderLeft() - borderRight(), h - borderTop() - borderBottom());
+ paintInfo.context->save();
+ paintInfo.context->clip(clipRect);
+ }
+ paintFillLayers(paintInfo, c, bgLayer, my, mh, tx, ty, w, h);
+ if (shouldClip)
+ paintInfo.context->restore();
+ }
+}
+
+void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
+{
+ RenderTable* tableElt = table();
+ if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
+ return;
+
+ int w = width();
+ int h = height() + borderTopExtra() + borderBottomExtra();
+
+ if (style()->boxShadow())
+ paintBoxShadow(paintInfo.context, tx, ty - borderTopExtra(), w, h, style());
+
+ // Paint our cell background.
+ paintBackgroundsBehindCell(paintInfo, tx, ty, this);
+
+ if (!style()->hasBorder() || tableElt->collapseBorders())
+ return;
+
+ ty -= borderTopExtra();
+ paintBorder(paintInfo.context, tx, ty, w, h, style());
+}
+
+void RenderTableCell::paintMask(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
+ return;
+
+ RenderTable* tableElt = table();
+ if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
+ return;
+
+ int w = width();
+ int h = height() + borderTopExtra() + borderBottomExtra();
+
+ int my = max(ty, paintInfo.rect.y());
+ int end = min(paintInfo.rect.bottom(), ty + h);
+ int mh = end - my;
+
+ paintMaskImages(paintInfo, my, mh, tx, ty, w, h);
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h
new file mode 100644
index 0000000..20b7da7
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableCell.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ * (C) 1997 Torben Weis (weis@kde.org)
+ * (C) 1998 Waldo Bastian (bastian@kde.org)
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 RenderTableCell_h
+#define RenderTableCell_h
+
+#include "RenderTableSection.h"
+
+namespace WebCore {
+
+class RenderTableCell : public RenderBlock {
+public:
+ RenderTableCell(Node*);
+
+ virtual const char* renderName() const { return isAnonymous() ? "RenderTableCell (anonymous)" : "RenderTableCell"; }
+
+ virtual bool isTableCell() const { return true; }
+
+ virtual void destroy();
+
+ // FIXME: need to implement cellIndex
+ int cellIndex() const { return 0; }
+ void setCellIndex(int) { }
+
+ int colSpan() const { return m_columnSpan; }
+ void setColSpan(int c) { m_columnSpan = c; }
+
+ int rowSpan() const { return m_rowSpan; }
+ void setRowSpan(int r) { m_rowSpan = r; }
+
+ int col() const { return m_column; }
+ void setCol(int col) { m_column = col; }
+ int row() const { return m_row; }
+ void setRow(int row) { m_row = row; }
+
+ RenderTableSection* section() const { return static_cast<RenderTableSection*>(parent()->parent()); }
+ RenderTable* table() const { return static_cast<RenderTable*>(parent()->parent()->parent()); }
+
+ Length styleOrColWidth() const;
+
+ virtual bool requiresLayer();
+
+ virtual void calcPrefWidths();
+ virtual void calcWidth();
+ virtual void setWidth(int);
+
+ virtual bool expandsToEncloseOverhangingFloats() const { return true; }
+
+ int borderLeft() const;
+ int borderRight() const;
+ int borderTop() const;
+ int borderBottom() const;
+
+ int borderHalfLeft(bool outer) const;
+ int borderHalfRight(bool outer) const;
+ int borderHalfTop(bool outer) const;
+ int borderHalfBottom(bool outer) const;
+
+ CollapsedBorderValue collapsedLeftBorder(bool rtl) const;
+ CollapsedBorderValue collapsedRightBorder(bool rtl) const;
+ CollapsedBorderValue collapsedTopBorder() const;
+ CollapsedBorderValue collapsedBottomBorder() const;
+
+ typedef Vector<CollapsedBorderValue, 100> CollapsedBorderStyles;
+ void collectBorderStyles(CollapsedBorderStyles&) const;
+ static void sortBorderStyles(CollapsedBorderStyles&);
+
+ virtual void updateFromElement();
+
+ virtual void layout();
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void paintBoxDecorations(PaintInfo&, int tx, int ty);
+ virtual void paintMask(PaintInfo& paintInfo, int tx, int ty);
+ void paintCollapsedBorder(GraphicsContext*, int x, int y, int w, int h);
+ void paintBackgroundsBehindCell(PaintInfo&, int tx, int ty, RenderObject* backgroundObject);
+
+ // Lie about position to outside observers.
+ virtual int yPos() const { return m_y + m_topExtra; }
+
+ virtual IntRect absoluteClippedOverflowRect();
+ virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false);
+ virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const;
+ virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const;
+ virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const;
+
+ virtual int baselinePosition(bool firstLine = false, bool isRootLineBox = false) const;
+
+ void setCellTopExtra(int p) { m_topExtra = p; }
+ void setCellBottomExtra(int p) { m_bottomExtra = p; }
+
+ virtual int borderTopExtra() const { return m_topExtra; }
+ virtual int borderBottomExtra() const { return m_bottomExtra; }
+
+protected:
+ virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle);
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+private:
+ int m_row;
+ int m_column;
+ int m_rowSpan;
+ int m_columnSpan;
+ int m_topExtra : 31;
+ int m_bottomExtra : 31;
+ bool m_widthChanged : 1;
+ int m_percentageHeight;
+};
+
+} // namespace WebCore
+
+#endif // RenderTableCell_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.cpp
new file mode 100644
index 0000000..5c2a049
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.cpp
@@ -0,0 +1,92 @@
+/**
+ * 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)
+ * (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) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "RenderTableCol.h"
+
+#include "CachedImage.h"
+#include "HTMLNames.h"
+#include "HTMLTableColElement.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderTableCol::RenderTableCol(Node* node)
+ : RenderContainer(node), m_span(1)
+{
+ // init RenderObject attributes
+ setInline(true); // our object is not Inline
+ updateFromElement();
+}
+
+void RenderTableCol::updateFromElement()
+{
+ int oldSpan = m_span;
+ Node* node = element();
+ if (node && (node->hasTagName(colTag) || node->hasTagName(colgroupTag))) {
+ HTMLTableColElement* tc = static_cast<HTMLTableColElement*>(node);
+ m_span = tc->span();
+ } else
+ m_span = !(style() && style()->display() == TABLE_COLUMN_GROUP);
+ if (m_span != oldSpan && style() && parent())
+ setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+bool RenderTableCol::isChildAllowed(RenderObject* child, RenderStyle* style) const
+{
+ return !child->isText() && style && (style->display() == TABLE_COLUMN);
+}
+
+bool RenderTableCol::canHaveChildren() const
+{
+ // Cols cannot have children. This is actually necessary to fix a bug
+ // with libraries.uc.edu, which makes a <p> be a table-column.
+ return style()->display() == TABLE_COLUMN_GROUP;
+}
+
+IntRect RenderTableCol::absoluteClippedOverflowRect()
+{
+ // For now, just repaint the whole table.
+ // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we
+ // might have propagated a background color or borders into.
+ RenderObject* table = parent();
+ if (table && !table->isTable())
+ table = table->parent();
+ if (table && table->isTable())
+ return table->absoluteClippedOverflowRect();
+
+ return IntRect();
+}
+
+void RenderTableCol::imageChanged(WrappedImagePtr, const IntRect*)
+{
+ // FIXME: Repaint only the rect the image paints in.
+ repaint();
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.h b/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.h
new file mode 100644
index 0000000..6752bd8
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableCol.h
@@ -0,0 +1,61 @@
+/*
+ * 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)
+ * (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) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef RenderTableCol_h
+#define RenderTableCol_h
+
+#include "RenderContainer.h"
+
+namespace WebCore {
+
+class RenderTableCol : public RenderContainer
+{
+public:
+ RenderTableCol(Node*);
+
+ virtual const char* renderName() const { return "RenderTableCol"; }
+ virtual bool isTableCol() const { return true; }
+ virtual int lineHeight(bool) const { return 0; }
+ virtual void updateFromElement();
+
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
+ virtual bool canHaveChildren() const;
+ virtual bool requiresLayer() { return false; }
+
+ virtual IntRect absoluteClippedOverflowRect();
+ virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+
+ int span() const { return m_span; }
+ void setSpan(int s) { m_span = s; }
+
+private:
+ int m_span;
+};
+
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp
new file mode 100644
index 0000000..21ba91a
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.cpp
@@ -0,0 +1,219 @@
+/**
+ * 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)
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 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
+ * 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 "RenderTableRow.h"
+
+#include "CachedImage.h"
+#include "Document.h"
+#include "HTMLNames.h"
+#include "RenderTableCell.h"
+#include "RenderView.h"
+
+#if ENABLE(WML)
+#include "WMLNames.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderTableRow::RenderTableRow(Node* node)
+ : RenderContainer(node)
+{
+ // init RenderObject attributes
+ setInline(false); // our object is not Inline
+}
+
+void RenderTableRow::destroy()
+{
+ RenderTableSection* recalcSection = section();
+
+ RenderContainer::destroy();
+
+ if (recalcSection)
+ recalcSection->setNeedsCellRecalc();
+}
+
+void RenderTableRow::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
+{
+ if (section() && style() && style()->height() != newStyle->height())
+ section()->setNeedsCellRecalc();
+
+ ASSERT(newStyle->display() == TABLE_ROW);
+
+ RenderContainer::styleWillChange(diff, newStyle);
+}
+
+void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild)
+{
+ // Make sure we don't append things after :after-generated content if we have it.
+ if (!beforeChild && isAfterContent(lastChild()))
+ beforeChild = lastChild();
+
+ bool isTableRow = element() && element()->hasTagName(trTag);
+
+#if ENABLE(WML)
+ if (!isTableRow && element() && element()->isWMLElement())
+ isTableRow = element()->hasTagName(WMLNames::trTag);
+#endif
+
+ if (!child->isTableCell()) {
+ if (isTableRow && child->element() && child->element()->hasTagName(formTag) && document()->isHTMLDocument()) {
+ RenderContainer::addChild(child, beforeChild);
+ return;
+ }
+
+ RenderObject* last = beforeChild;
+ if (!last)
+ last = lastChild();
+ if (last && last->isAnonymous() && last->isTableCell()) {
+ last->addChild(child);
+ return;
+ }
+
+ // If beforeChild is inside an anonymous cell, insert into the cell.
+ if (last && !last->isTableCell() && last->parent() && last->parent()->isAnonymous()) {
+ last->parent()->addChild(child, beforeChild);
+ return;
+ }
+
+ RenderTableCell* cell = new (renderArena()) RenderTableCell(document() /* anonymous object */);
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(style());
+ newStyle->setDisplay(TABLE_CELL);
+ cell->setStyle(newStyle.release());
+ addChild(cell, beforeChild);
+ cell->addChild(child);
+ return;
+ }
+
+ // If the next renderer is actually wrapped in an anonymous table cell, we need to go up and find that.
+ while (beforeChild && beforeChild->parent() != this)
+ beforeChild = beforeChild->parent();
+
+ RenderTableCell* cell = static_cast<RenderTableCell*>(child);
+
+ // Generated content can result in us having a null section so make sure to null check our parent.
+ if (parent())
+ section()->addCell(cell, this);
+
+ ASSERT(!beforeChild || beforeChild->isTableCell() || isTableRow && beforeChild->element() && beforeChild->element()->hasTagName(formTag) && document()->isHTMLDocument());
+ RenderContainer::addChild(cell, beforeChild);
+
+ if (beforeChild || nextSibling())
+ section()->setNeedsCellRecalc();
+}
+
+void RenderTableRow::layout()
+{
+ ASSERT(needsLayout());
+
+ // Table rows do not add translation.
+ LayoutStateMaintainer statePusher(view(), this, IntSize());
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isTableCell()) {
+ RenderTableCell* cell = static_cast<RenderTableCell*>(child);
+ if (child->needsLayout()) {
+ cell->calcVerticalMargins();
+ cell->layout();
+ }
+ }
+ }
+
+ // We only ever need to repaint if our cells didn't, which menas that they didn't need
+ // layout, so we know that our bounds didn't change. This code is just making up for
+ // the fact that we did not repaint in setStyle() because we had a layout hint.
+ // We cannot call repaint() because our absoluteClippedOverflowRect() is taken from the
+ // parent table, and being mid-layout, that is invalid. Instead, we repaint our cells.
+ if (selfNeedsLayout() && checkForRepaintDuringLayout()) {
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isTableCell())
+ child->repaint();
+ }
+ }
+
+ statePusher.pop();
+ setNeedsLayout(false);
+}
+
+IntRect RenderTableRow::absoluteClippedOverflowRect()
+{
+ // For now, just repaint the whole table.
+ // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we
+ // might have propagated a background color into.
+ if (RenderTable* parentTable = table())
+ return parentTable->absoluteClippedOverflowRect();
+
+ return IntRect();
+}
+
+// Hit Testing
+bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action)
+{
+ // Table rows cannot ever be hit tested. Effectively they do not exist.
+ // Just forward to our children always.
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
+ // FIXME: We have to skip over inline flows, since they can show up inside table rows
+ // at the moment (a demoted inline <form> for example). If we ever implement a
+ // table-specific hit-test method (which we should do for performance reasons anyway),
+ // then we can remove this check.
+ if (!child->hasLayer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) {
+ updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void RenderTableRow::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ ASSERT(m_layer);
+ if (!m_layer)
+ return;
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isTableCell()) {
+ // Paint the row background behind the cell.
+ if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground) {
+ RenderTableCell* cell = static_cast<RenderTableCell*>(child);
+ cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this);
+ }
+ if (!child->hasLayer())
+ child->paint(paintInfo, tx, ty);
+ }
+ }
+}
+
+void RenderTableRow::imageChanged(WrappedImagePtr, const IntRect*)
+{
+ // FIXME: Examine cells and repaint only the rect the image paints in.
+ repaint();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.h b/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.h
new file mode 100644
index 0000000..a65d0e9
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableRow.h
@@ -0,0 +1,67 @@
+/*
+ * 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)
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 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
+ * 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 RenderTableRow_h
+#define RenderTableRow_h
+
+#include "RenderTableSection.h"
+
+namespace WebCore {
+
+class RenderTableRow : public RenderContainer {
+public:
+ RenderTableRow(Node*);
+
+ RenderTableSection* section() const { return static_cast<RenderTableSection*>(parent()); }
+ RenderTable* table() const { return static_cast<RenderTable*>(parent()->parent()); }
+
+private:
+ virtual const char* renderName() const { return isAnonymous() ? "RenderTableRow (anonymous)" : "RenderTableRow"; }
+
+ virtual bool isTableRow() const { return true; }
+
+ virtual void destroy();
+
+ virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
+ virtual int lineHeight(bool, bool) const { return 0; }
+ virtual void position(InlineBox*) { }
+ virtual void layout();
+ virtual IntRect absoluteClippedOverflowRect();
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+ // The only time rows get a layer is when they have transparency.
+ virtual bool requiresLayer() { return isTransparent() || hasOverflowClip(); }
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+
+ virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle);
+
+};
+
+} // namespace WebCore
+
+#endif // RenderTableRow_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp
new file mode 100644
index 0000000..be43ab8
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.cpp
@@ -0,0 +1,1080 @@
+/*
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ * (C) 1997 Torben Weis (weis@kde.org)
+ * (C) 1998 Waldo Bastian (bastian@kde.org)
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * 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 "RenderTableSection.h"
+
+#include "CachedImage.h"
+#include "Document.h"
+#include "HTMLNames.h"
+#include "RenderTableCell.h"
+#include "RenderTableCol.h"
+#include "RenderTableRow.h"
+#include "RenderView.h"
+#include <limits>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderTableSection::RenderTableSection(Node* node)
+ : RenderContainer(node)
+ , m_gridRows(0)
+ , m_cCol(0)
+ , m_cRow(-1)
+ , m_needsCellRecalc(false)
+ , m_outerBorderLeft(0)
+ , m_outerBorderRight(0)
+ , m_outerBorderTop(0)
+ , m_outerBorderBottom(0)
+ , m_overflowLeft(0)
+ , m_overflowWidth(0)
+ , m_overflowTop(0)
+ , m_overflowHeight(0)
+ , m_hasOverflowingCell(false)
+{
+ // init RenderObject attributes
+ setInline(false); // our object is not Inline
+}
+
+RenderTableSection::~RenderTableSection()
+{
+ clearGrid();
+}
+
+void RenderTableSection::destroy()
+{
+ RenderTable* recalcTable = table();
+
+ RenderContainer::destroy();
+
+ // recalc cell info because RenderTable has unguarded pointers
+ // stored that point to this RenderTableSection.
+ if (recalcTable)
+ recalcTable->setNeedsSectionRecalc();
+}
+
+void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild)
+{
+ // Make sure we don't append things after :after-generated content if we have it.
+ if (!beforeChild && isAfterContent(lastChild()))
+ beforeChild = lastChild();
+
+ bool isTableSection = element() && (element()->hasTagName(theadTag) || element()->hasTagName(tbodyTag) || element()->hasTagName(tfootTag));
+
+ if (!child->isTableRow()) {
+ if (isTableSection && child->element() && child->element()->hasTagName(formTag) && document()->isHTMLDocument()) {
+ RenderContainer::addChild(child, beforeChild);
+ return;
+ }
+
+ RenderObject* last = beforeChild;
+ if (!last)
+ last = lastChild();
+ if (last && last->isAnonymous()) {
+ last->addChild(child);
+ return;
+ }
+
+ // If beforeChild is inside an anonymous cell/row, insert into the cell or into
+ // the anonymous row containing it, if there is one.
+ RenderObject* lastBox = last;
+ while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableRow())
+ lastBox = lastBox->parent();
+ if (lastBox && lastBox->isAnonymous()) {
+ lastBox->addChild(child, beforeChild);
+ return;
+ }
+
+ RenderObject* row = new (renderArena()) RenderTableRow(document() /* anonymous table */);
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(style());
+ newStyle->setDisplay(TABLE_ROW);
+ row->setStyle(newStyle.release());
+ addChild(row, beforeChild);
+ row->addChild(child);
+ return;
+ }
+
+ if (beforeChild)
+ setNeedsCellRecalc();
+
+ ++m_cRow;
+ m_cCol = 0;
+
+ // make sure we have enough rows
+ if (!ensureRows(m_cRow + 1))
+ return;
+
+ m_grid[m_cRow].rowRenderer = 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 the next renderer is actually wrapped in an anonymous table row, we need to go up and find that.
+ while (beforeChild && beforeChild->parent() != this)
+ beforeChild = beforeChild->parent();
+
+ ASSERT(!beforeChild || beforeChild->isTableRow() || isTableSection && beforeChild->element() && beforeChild->element()->hasTagName(formTag) && document()->isHTMLDocument());
+ RenderContainer::addChild(child, beforeChild);
+}
+
+bool RenderTableSection::ensureRows(int numRows)
+{
+ int nRows = m_gridRows;
+ if (numRows > nRows) {
+ if (numRows > static_cast<int>(m_grid.size())) {
+ size_t maxSize = numeric_limits<size_t>::max() / sizeof(RowStruct);
+ if (static_cast<size_t>(numRows) > maxSize)
+ return false;
+ m_grid.grow(numRows);
+ }
+ m_gridRows = numRows;
+ int nCols = max(1, table()->numEffCols());
+ CellStruct emptyCellStruct;
+ emptyCellStruct.cell = 0;
+ emptyCellStruct.inColSpan = false;
+ for (int r = nRows; r < numRows; r++) {
+ m_grid[r].row = new Row(nCols);
+ m_grid[r].row->fill(emptyCellStruct);
+ m_grid[r].rowRenderer = 0;
+ m_grid[r].baseline = 0;
+ m_grid[r].height = Length();
+ }
+ }
+
+ return true;
+}
+
+void RenderTableSection::addCell(RenderTableCell* cell, RenderObject* row)
+{
+ int rSpan = cell->rowSpan();
+ int cSpan = cell->colSpan();
+ Vector<RenderTable::ColumnStruct>& columns = table()->columns();
+ int nCols = columns.size();
+
+ // ### mozilla still seems to do the old HTML way, even for strict DTD
+ // (see the annotation on table cell layouting in the CSS specs and the testcase below:
+ // <TABLE border>
+ // <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4
+ // <TR><TD colspan="2">5
+ // </TABLE>
+
+ while (m_cCol < nCols && (cellAt(m_cRow, m_cCol).cell || cellAt(m_cRow, m_cCol).inColSpan))
+ m_cCol++;
+
+ if (rSpan == 1) {
+ // we ignore height settings on rowspan cells
+ Length height = cell->style()->height();
+ if (height.isPositive() || (height.isRelative() && height.value() >= 0)) {
+ Length cRowHeight = m_grid[m_cRow].height;
+ switch (height.type()) {
+ case Percent:
+ if (!(cRowHeight.isPercent()) ||
+ (cRowHeight.isPercent() && cRowHeight.rawValue() < height.rawValue()))
+ m_grid[m_cRow].height = height;
+ break;
+ case Fixed:
+ if (cRowHeight.type() < Percent ||
+ (cRowHeight.isFixed() && cRowHeight.value() < height.value()))
+ m_grid[m_cRow].height = height;
+ break;
+ case Relative:
+ default:
+ break;
+ }
+ }
+ }
+
+ // make sure we have enough rows
+ if (!ensureRows(m_cRow + rSpan))
+ return;
+
+ m_grid[m_cRow].rowRenderer = row;
+
+ int col = m_cCol;
+ // tell the cell where it is
+ CellStruct currentCell;
+ currentCell.cell = cell;
+ currentCell.inColSpan = false;
+ while (cSpan) {
+ int currentSpan;
+ if (m_cCol >= nCols) {
+ table()->appendColumn(cSpan);
+ currentSpan = cSpan;
+ } else {
+ if (cSpan < columns[m_cCol].span)
+ table()->splitColumn(m_cCol, cSpan);
+ currentSpan = columns[m_cCol].span;
+ }
+
+ for (int r = 0; r < rSpan; r++) {
+ CellStruct& c = cellAt(m_cRow + r, m_cCol);
+ if (currentCell.cell && !c.cell)
+ c.cell = currentCell.cell;
+ if (currentCell.inColSpan)
+ c.inColSpan = true;
+ }
+ m_cCol++;
+ cSpan -= currentSpan;
+ currentCell.cell = 0;
+ currentCell.inColSpan = true;
+ }
+ if (cell) {
+ cell->setRow(m_cRow);
+ cell->setCol(table()->effColToCol(col));
+ }
+}
+
+void RenderTableSection::setCellWidths()
+{
+ Vector<int>& columnPos = table()->columnPositions();
+
+ LayoutStateMaintainer statePusher(view());
+
+ for (int i = 0; i < m_gridRows; i++) {
+ Row& row = *m_grid[i].row;
+ int cols = row.size();
+ for (int j = 0; j < cols; j++) {
+ CellStruct current = row[j];
+ RenderTableCell* cell = current.cell;
+
+ if (!cell)
+ continue;
+ int endCol = j;
+ int cspan = cell->colSpan();
+ while (cspan && endCol < cols) {
+ cspan -= table()->columns()[endCol].span;
+ endCol++;
+ }
+ int w = columnPos[endCol] - columnPos[j] - table()->hBorderSpacing();
+ int oldWidth = cell->width();
+ if (w != oldWidth) {
+ cell->setNeedsLayout(true);
+ if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout()) {
+ if (!statePusher.didPush()) {
+ // Technically, we should also push state for the row, but since
+ // rows don't push a coordinate transform, that's not necessary.
+ statePusher.push(this, IntSize(m_x, m_y));
+ }
+ cell->repaint();
+ }
+ cell->setWidth(w);
+ }
+ }
+ }
+
+ statePusher.pop(); // only pops if we pushed
+}
+
+int RenderTableSection::calcRowHeight()
+{
+ RenderTableCell* cell;
+
+ int spacing = table()->vBorderSpacing();
+
+ LayoutStateMaintainer statePusher(view());
+
+ m_rowPos.resize(m_gridRows + 1);
+ m_rowPos[0] = spacing;
+
+ for (int r = 0; r < m_gridRows; r++) {
+ m_rowPos[r + 1] = 0;
+ m_grid[r].baseline = 0;
+ int baseline = 0;
+ int bdesc = 0;
+ int ch = m_grid[r].height.calcMinValue(0);
+ int pos = m_rowPos[r] + ch + (m_grid[r].rowRenderer ? spacing : 0);
+
+ m_rowPos[r + 1] = max(m_rowPos[r + 1], pos);
+
+ Row* row = m_grid[r].row;
+ int totalCols = row->size();
+
+ for (int c = 0; c < totalCols; c++) {
+ CellStruct current = cellAt(r, c);
+ cell = current.cell;
+ if (!cell || current.inColSpan)
+ continue;
+ if (r < m_gridRows - 1 && cellAt(r + 1, c).cell == cell)
+ continue;
+
+ int indx = max(r - cell->rowSpan() + 1, 0);
+
+ if (cell->overrideSize() != -1) {
+ if (!statePusher.didPush()) {
+ // Technically, we should also push state for the row, but since
+ // rows don't push a coordinate transform, that's not necessary.
+ statePusher.push(this, IntSize(m_x, m_y));
+ }
+ cell->setOverrideSize(-1);
+ cell->setChildNeedsLayout(true, false);
+ cell->layoutIfNeeded();
+ }
+
+ // Explicit heights use the border box in quirks mode. In strict mode do the right
+ // thing and actually add in the border and padding.
+ ch = cell->style()->height().calcValue(0) +
+ (cell->style()->htmlHacks() ? 0 : (cell->paddingTop() + cell->paddingBottom() +
+ cell->borderTop() + cell->borderBottom()));
+ ch = max(ch, cell->height());
+
+ pos = m_rowPos[indx] + ch + (m_grid[r].rowRenderer ? spacing : 0);
+
+ m_rowPos[r + 1] = max(m_rowPos[r + 1], pos);
+
+ // find out the baseline
+ EVerticalAlign va = cell->style()->verticalAlign();
+ if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) {
+ int b = cell->baselinePosition();
+ if (b > cell->borderTop() + cell->paddingTop()) {
+ baseline = max(baseline, b);
+ bdesc = max(bdesc, m_rowPos[indx] + ch - b);
+ }
+ }
+ }
+
+ //do we have baseline aligned elements?
+ if (baseline) {
+ // increase rowheight if baseline requires
+ m_rowPos[r + 1] = max(m_rowPos[r + 1], baseline + bdesc + (m_grid[r].rowRenderer ? spacing : 0));
+ m_grid[r].baseline = baseline;
+ }
+
+ m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r]);
+ }
+
+ statePusher.pop();
+
+ return m_rowPos[m_gridRows];
+}
+
+int RenderTableSection::layoutRows(int toAdd)
+{
+ int rHeight;
+ int rindx;
+ int totalRows = m_gridRows;
+
+ // Set the width of our section now. The rows will also be this width.
+ m_width = table()->contentWidth();
+ m_overflowLeft = 0;
+ m_overflowWidth = m_width;
+ m_overflowTop = 0;
+ m_overflowHeight = 0;
+ m_hasOverflowingCell = false;
+
+ if (toAdd && totalRows && (m_rowPos[totalRows] || !nextSibling())) {
+ int totalHeight = m_rowPos[totalRows] + toAdd;
+
+ int dh = toAdd;
+ int totalPercent = 0;
+ int numAuto = 0;
+ for (int r = 0; r < totalRows; r++) {
+ if (m_grid[r].height.isAuto())
+ numAuto++;
+ else if (m_grid[r].height.isPercent())
+ totalPercent += m_grid[r].height.rawValue();
+ }
+ if (totalPercent) {
+ // try to satisfy percent
+ int add = 0;
+ totalPercent = min(totalPercent, 100 * percentScaleFactor);
+ int rh = m_rowPos[1] - m_rowPos[0];
+ for (int r = 0; r < totalRows; r++) {
+ if (totalPercent > 0 && m_grid[r].height.isPercent()) {
+ int toAdd = min(dh, (totalHeight * m_grid[r].height.rawValue() / (100 * percentScaleFactor)) - rh);
+ // If toAdd is negative, then we don't want to shrink the row (this bug
+ // affected Outlook Web Access).
+ toAdd = max(0, toAdd);
+ add += toAdd;
+ dh -= toAdd;
+ totalPercent -= m_grid[r].height.rawValue();
+ }
+ if (r < totalRows - 1)
+ rh = m_rowPos[r + 2] - m_rowPos[r + 1];
+ m_rowPos[r + 1] += add;
+ }
+ }
+ if (numAuto) {
+ // distribute over variable cols
+ int add = 0;
+ for (int r = 0; r < totalRows; r++) {
+ if (numAuto > 0 && m_grid[r].height.isAuto()) {
+ int toAdd = dh / numAuto;
+ add += toAdd;
+ dh -= toAdd;
+ numAuto--;
+ }
+ m_rowPos[r + 1] += add;
+ }
+ }
+ if (dh > 0 && m_rowPos[totalRows]) {
+ // if some left overs, distribute equally.
+ int tot = m_rowPos[totalRows];
+ int add = 0;
+ int prev = m_rowPos[0];
+ for (int r = 0; r < totalRows; r++) {
+ //weight with the original height
+ add += dh * (m_rowPos[r + 1] - prev) / tot;
+ prev = m_rowPos[r + 1];
+ m_rowPos[r + 1] += add;
+ }
+ }
+ }
+
+ int hspacing = table()->hBorderSpacing();
+ int vspacing = table()->vBorderSpacing();
+ int nEffCols = table()->numEffCols();
+
+ LayoutStateMaintainer statePusher(view(), this, IntSize(m_x, m_y));
+
+ for (int r = 0; r < totalRows; r++) {
+ // Set the row's x/y position and width/height.
+ if (RenderObject* rowRenderer = m_grid[r].rowRenderer) {
+ rowRenderer->setPos(0, m_rowPos[r]);
+ rowRenderer->setWidth(m_width);
+ rowRenderer->setHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing);
+ }
+
+ 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;
+
+ rindx = max(0, r - cell->rowSpan() + 1);
+
+ rHeight = m_rowPos[r + 1] - m_rowPos[rindx] - vspacing;
+
+ // Force percent height children to lay themselves out again.
+ // This will cause these children to grow to fill the cell.
+ // FIXME: There is still more work to do here to fully match WinIE (should
+ // it become necessary to do so). In quirks mode, WinIE behaves like we
+ // do, but it will clip the cells that spill out of the table section. In
+ // strict mode, Mozilla and WinIE both regrow the table to accommodate the
+ // new height of the cell (thus letting the percentages cause growth one
+ // time only). We may also not be handling row-spanning cells correctly.
+ //
+ // Note also the oddity where replaced elements always flex, and yet blocks/tables do
+ // not necessarily flex. WinIE is crazy and inconsistent, and we can't hope to
+ // match the behavior perfectly, but we'll continue to refine it as we discover new
+ // bugs. :)
+ bool cellChildrenFlex = false;
+ bool flexAllChildren = cell->style()->height().isFixed() ||
+ (!table()->style()->height().isAuto() && rHeight != cell->height());
+
+ for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) {
+ if (!o->isText() && o->style()->height().isPercent() && (o->isReplaced() || o->scrollsOverflow() || flexAllChildren)) {
+ // Tables with no sections do not flex.
+ if (!o->isTable() || static_cast<RenderTable*>(o)->hasSections()) {
+ o->setNeedsLayout(true, false);
+ cell->setChildNeedsLayout(true, false);
+ cellChildrenFlex = true;
+ }
+ }
+ }
+ if (cellChildrenFlex) {
+ // Alignment within a cell is based off the calculated
+ // height, which becomes irrelevant once the cell has
+ // been resized based off its percentage. -dwh
+ cell->setOverrideSize(max(0,
+ rHeight - cell->borderTop() - cell->paddingTop() -
+ cell->borderBottom() - cell->paddingBottom()));
+ cell->layoutIfNeeded();
+
+ // If the baseline moved, we may have to update the data for our row. Find out the new baseline.
+ EVerticalAlign va = cell->style()->verticalAlign();
+ if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) {
+ int b = cell->baselinePosition();
+ if (b > cell->borderTop() + cell->paddingTop())
+ m_grid[r].baseline = max(m_grid[r].baseline, b);
+ }
+ }
+
+ int te = 0;
+ switch (cell->style()->verticalAlign()) {
+ case SUB:
+ case SUPER:
+ case TEXT_TOP:
+ case TEXT_BOTTOM:
+ case BASELINE:
+ te = getBaseline(r) - cell->baselinePosition();
+ break;
+ case TOP:
+ te = 0;
+ break;
+ case MIDDLE:
+ te = (rHeight - cell->height()) / 2;
+ break;
+ case BOTTOM:
+ te = rHeight - cell->height();
+ break;
+ default:
+ break;
+ }
+
+ int oldTe = cell->borderTopExtra();
+ int oldBe = cell->borderBottomExtra();
+
+ int be = rHeight - cell->height() - te;
+ cell->setCellTopExtra(te);
+ cell->setCellBottomExtra(be);
+ if ((te != oldTe || be > oldBe) && !table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
+ cell->repaint();
+
+ IntRect oldCellRect(cell->xPos(), cell->yPos() - cell->borderTopExtra() , cell->width(), cell->height());
+
+ if (style()->direction() == RTL) {
+ cell->setPos(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]);
+ } else
+ cell->setPos(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]);
+
+ m_overflowLeft = min(m_overflowLeft, cell->xPos() + cell->overflowLeft(false));
+ m_overflowWidth = max(m_overflowWidth, cell->xPos() + cell->overflowWidth(false));
+ m_overflowTop = min(m_overflowTop, cell->yPos() + cell->overflowTop(false));
+ m_overflowHeight = max(m_overflowHeight, cell->yPos() + 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.
+ if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
+ cell->repaintDuringLayoutIfMoved(oldCellRect);
+ }
+ }
+
+ statePusher.pop();
+
+ m_height = m_rowPos[totalRows];
+ m_overflowHeight = max(m_overflowHeight, m_height);
+ return m_height;
+}
+
+int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int bottom = RenderContainer::lowestPosition(includeOverflowInterior, includeSelf);
+ if (!includeOverflowInterior && hasOverflowClip())
+ return bottom;
+
+ for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
+ for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
+ if (cell->isTableCell())
+ bottom = max(bottom, cell->yPos() + cell->lowestPosition(false));
+ }
+ }
+
+ return bottom;
+}
+
+int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int right = RenderContainer::rightmostPosition(includeOverflowInterior, includeSelf);
+ if (!includeOverflowInterior && hasOverflowClip())
+ return right;
+
+ for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
+ for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
+ if (cell->isTableCell())
+ right = max(right, cell->xPos() + cell->rightmostPosition(false));
+ }
+ }
+
+ return right;
+}
+
+int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int left = RenderContainer::leftmostPosition(includeOverflowInterior, includeSelf);
+ if (!includeOverflowInterior && hasOverflowClip())
+ return left;
+
+ for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
+ for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
+ if (cell->isTableCell())
+ left = min(left, cell->xPos() + cell->leftmostPosition(false));
+ }
+ }
+
+ return left;
+}
+
+int RenderTableSection::calcOuterBorderTop() const
+{
+ int totalCols = table()->numEffCols();
+ if (!m_gridRows || !totalCols)
+ return 0;
+
+ unsigned borderWidth = 0;
+
+ const BorderValue& sb = style()->borderTop();
+ if (sb.style() == BHIDDEN)
+ return -1;
+ if (sb.style() > BHIDDEN)
+ borderWidth = sb.width;
+
+ const BorderValue& rb = firstChild()->style()->borderTop();
+ if (rb.style() == BHIDDEN)
+ return -1;
+ if (rb.style() > BHIDDEN && rb.width > borderWidth)
+ borderWidth = rb.width;
+
+ bool allHidden = true;
+ for (int c = 0; c < totalCols; c++) {
+ const CellStruct& current = cellAt(0, c);
+ if (current.inColSpan || !current.cell)
+ continue;
+ const BorderValue& cb = current.cell->style()->borderTop();
+ // FIXME: Don't repeat for the same col group
+ RenderTableCol* colGroup = table()->colElement(c);
+ if (colGroup) {
+ const BorderValue& gb = colGroup->style()->borderTop();
+ if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
+ continue;
+ else
+ allHidden = false;
+ if (gb.style() > BHIDDEN && gb.width > borderWidth)
+ borderWidth = gb.width;
+ if (cb.style() > BHIDDEN && cb.width > borderWidth)
+ borderWidth = cb.width;
+ } else {
+ if (cb.style() == BHIDDEN)
+ continue;
+ else
+ allHidden = false;
+ if (cb.style() > BHIDDEN && cb.width > borderWidth)
+ borderWidth = cb.width;
+ }
+ }
+ if (allHidden)
+ return -1;
+
+ return borderWidth / 2;
+}
+
+int RenderTableSection::calcOuterBorderBottom() const
+{
+ int totalCols = table()->numEffCols();
+ if (!m_gridRows || !totalCols)
+ return 0;
+
+ unsigned borderWidth = 0;
+
+ const BorderValue& sb = style()->borderBottom();
+ if (sb.style() == BHIDDEN)
+ return -1;
+ if (sb.style() > BHIDDEN)
+ borderWidth = sb.width;
+
+ const BorderValue& rb = lastChild()->style()->borderBottom();
+ if (rb.style() == BHIDDEN)
+ return -1;
+ if (rb.style() > BHIDDEN && rb.width > borderWidth)
+ borderWidth = rb.width;
+
+ bool allHidden = true;
+ for (int c = 0; c < totalCols; c++) {
+ const CellStruct& current = cellAt(m_gridRows - 1, c);
+ if (current.inColSpan || !current.cell)
+ continue;
+ const BorderValue& cb = current.cell->style()->borderBottom();
+ // FIXME: Don't repeat for the same col group
+ RenderTableCol* colGroup = table()->colElement(c);
+ if (colGroup) {
+ const BorderValue& gb = colGroup->style()->borderBottom();
+ if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
+ continue;
+ else
+ allHidden = false;
+ if (gb.style() > BHIDDEN && gb.width > borderWidth)
+ borderWidth = gb.width;
+ if (cb.style() > BHIDDEN && cb.width > borderWidth)
+ borderWidth = cb.width;
+ } else {
+ if (cb.style() == BHIDDEN)
+ continue;
+ else
+ allHidden = false;
+ if (cb.style() > BHIDDEN && cb.width > borderWidth)
+ borderWidth = cb.width;
+ }
+ }
+ if (allHidden)
+ return -1;
+
+ return (borderWidth + 1) / 2;
+}
+
+int RenderTableSection::calcOuterBorderLeft(bool rtl) const
+{
+ int totalCols = table()->numEffCols();
+ if (!m_gridRows || !totalCols)
+ return 0;
+
+ unsigned borderWidth = 0;
+
+ const BorderValue& sb = style()->borderLeft();
+ if (sb.style() == BHIDDEN)
+ return -1;
+ if (sb.style() > BHIDDEN)
+ borderWidth = sb.width;
+
+ int leftmostColumn = rtl ? totalCols - 1 : 0;
+ RenderTableCol* colGroup = table()->colElement(leftmostColumn);
+ if (colGroup) {
+ const BorderValue& gb = colGroup->style()->borderLeft();
+ if (gb.style() == BHIDDEN)
+ return -1;
+ if (gb.style() > BHIDDEN && gb.width > borderWidth)
+ borderWidth = gb.width;
+ }
+
+ bool allHidden = true;
+ for (int r = 0; r < m_gridRows; r++) {
+ const CellStruct& current = cellAt(r, leftmostColumn);
+ if (!current.cell)
+ continue;
+ // FIXME: Don't repeat for the same cell
+ const BorderValue& cb = current.cell->style()->borderLeft();
+ const BorderValue& rb = current.cell->parent()->style()->borderLeft();
+ if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
+ continue;
+ else
+ allHidden = false;
+ if (cb.style() > BHIDDEN && cb.width > borderWidth)
+ borderWidth = cb.width;
+ if (rb.style() > BHIDDEN && rb.width > borderWidth)
+ borderWidth = rb.width;
+ }
+ if (allHidden)
+ return -1;
+
+ return borderWidth / 2;
+}
+
+int RenderTableSection::calcOuterBorderRight(bool rtl) const
+{
+ int totalCols = table()->numEffCols();
+ if (!m_gridRows || !totalCols)
+ return 0;
+
+ unsigned borderWidth = 0;
+
+ const BorderValue& sb = style()->borderRight();
+ if (sb.style() == BHIDDEN)
+ return -1;
+ if (sb.style() > BHIDDEN)
+ borderWidth = sb.width;
+
+ int rightmostColumn = rtl ? 0 : totalCols - 1;
+ RenderTableCol* colGroup = table()->colElement(rightmostColumn);
+ if (colGroup) {
+ const BorderValue& gb = colGroup->style()->borderRight();
+ if (gb.style() == BHIDDEN)
+ return -1;
+ if (gb.style() > BHIDDEN && gb.width > borderWidth)
+ borderWidth = gb.width;
+ }
+
+ bool allHidden = true;
+ for (int r = 0; r < m_gridRows; r++) {
+ const CellStruct& current = cellAt(r, rightmostColumn);
+ if (!current.cell)
+ continue;
+ // FIXME: Don't repeat for the same cell
+ const BorderValue& cb = current.cell->style()->borderRight();
+ const BorderValue& rb = current.cell->parent()->style()->borderRight();
+ if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
+ continue;
+ else
+ allHidden = false;
+ if (cb.style() > BHIDDEN && cb.width > borderWidth)
+ borderWidth = cb.width;
+ if (rb.style() > BHIDDEN && rb.width > borderWidth)
+ borderWidth = rb.width;
+ }
+ if (allHidden)
+ return -1;
+
+ return (borderWidth + 1) / 2;
+}
+
+void RenderTableSection::recalcOuterBorder()
+{
+ bool rtl = table()->style()->direction() == RTL;
+ m_outerBorderTop = calcOuterBorderTop();
+ m_outerBorderBottom = calcOuterBorderBottom();
+ m_outerBorderLeft = calcOuterBorderLeft(rtl);
+ m_outerBorderRight = calcOuterBorderRight(rtl);
+}
+
+int RenderTableSection::getBaselineOfFirstLineBox() const
+{
+ if (!m_gridRows)
+ return -1;
+
+ int firstLineBaseline = m_grid[0].baseline;
+ if (firstLineBaseline)
+ return firstLineBaseline + m_rowPos[0];
+
+ firstLineBaseline = -1;
+ Row* firstRow = m_grid[0].row;
+ for (size_t i = 0; i < firstRow->size(); ++i) {
+ RenderTableCell* cell = firstRow->at(i).cell;
+ if (cell)
+ firstLineBaseline = max(firstLineBaseline, cell->yPos() + cell->paddingTop() + cell->borderTop() + cell->contentHeight());
+ }
+
+ return firstLineBaseline;
+}
+
+void RenderTableSection::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ // put this back in when all layout tests can handle it
+ // ASSERT(!needsLayout());
+ // avoid crashing on bugs that cause us to paint with dirty layout
+ if (needsLayout())
+ return;
+
+ unsigned totalRows = m_gridRows;
+ unsigned totalCols = table()->columns().size();
+
+ if (!totalRows || !totalCols)
+ return;
+
+ tx += m_x;
+ ty += m_y;
+
+ // Check which rows and cols are visible and only paint these.
+ // FIXME: Could use a binary search here.
+ PaintPhase paintPhase = paintInfo.phase;
+ int x = paintInfo.rect.x();
+ int y = paintInfo.rect.y();
+ int w = paintInfo.rect.width();
+ int h = paintInfo.rect.height();
+
+ int os = 2 * maximalOutlineSize(paintPhase);
+ unsigned startrow = 0;
+ unsigned endrow = totalRows;
+
+ // If some cell overflows, just paint all of them.
+ if (!m_hasOverflowingCell) {
+ for (; startrow < totalRows; startrow++) {
+ if (ty + m_rowPos[startrow + 1] >= y - os)
+ break;
+ }
+ if (startrow == totalRows && ty + m_rowPos[totalRows] + table()->outerBorderBottom() >= y - os)
+ startrow--;
+
+ for (; endrow > 0; endrow--) {
+ if (ty + m_rowPos[endrow - 1] <= y + h + os)
+ break;
+ }
+ if (!endrow && ty + m_rowPos[0] - table()->outerBorderTop() <= y + h + os)
+ endrow++;
+ }
+
+ unsigned startcol = 0;
+ unsigned endcol = totalCols;
+ // FIXME: Implement RTL.
+ if (!m_hasOverflowingCell && style()->direction() == LTR) {
+ for (; startcol < totalCols; startcol++) {
+ if (tx + table()->columnPositions()[startcol + 1] >= x - os)
+ break;
+ }
+ if (startcol == totalCols && tx + table()->columnPositions()[totalCols] + table()->outerBorderRight() >= x - os)
+ startcol--;
+
+ for (; endcol > 0; endcol--) {
+ if (tx + table()->columnPositions()[endcol - 1] <= x + w + os)
+ break;
+ }
+ if (!endcol && tx + table()->columnPositions()[0] - table()->outerBorderLeft() <= y + w + os)
+ endcol++;
+ }
+
+ if (startcol < endcol) {
+ // draw the cells
+ for (unsigned r = startrow; r < endrow; r++) {
+ unsigned c = startcol;
+ // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it
+ while (c && cellAt(r, c).inColSpan)
+ c--;
+ for (; c < endcol; c++) {
+ CellStruct current = cellAt(r, c);
+ RenderTableCell* cell = current.cell;
+
+ // Cells must always paint in the order in which they appear taking into account
+ // their upper left originating row/column. For cells with rowspans, avoid repainting
+ // if we've already seen the cell.
+ if (!cell || (r > startrow && (cellAt(r - 1, c).cell == cell)))
+ continue;
+
+ RenderTableRow* row = static_cast<RenderTableRow*>(cell->parent());
+
+ if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) {
+ // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of
+ // the column group, column, row group, row, and then the cell.
+ RenderObject* col = table()->colElement(c);
+ RenderObject* colGroup = 0;
+ if (col && col->parent()->style()->display() == TABLE_COLUMN_GROUP)
+ colGroup = col->parent();
+
+ // Column groups and columns first.
+ // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in
+ // the stack, since we have already opened a transparency layer (potentially) for the table row group.
+ // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the
+ // cell.
+ cell->paintBackgroundsBehindCell(paintInfo, tx, ty, colGroup);
+ cell->paintBackgroundsBehindCell(paintInfo, tx, ty, col);
+
+ // Paint the row group next.
+ cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this);
+
+ // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for
+ // painting the row background for the cell.
+ if (!row->hasLayer())
+ cell->paintBackgroundsBehindCell(paintInfo, tx, ty, row);
+ }
+
+ if ((!cell->hasLayer() && !row->hasLayer()) || paintInfo.phase == PaintPhaseCollapsedTableBorders)
+ cell->paint(paintInfo, tx, ty);
+ }
+ }
+ }
+}
+
+void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*)
+{
+ // FIXME: Examine cells and repaint only the rect the image paints in.
+ repaint();
+}
+
+void RenderTableSection::recalcCells()
+{
+ m_cCol = 0;
+ m_cRow = -1;
+ clearGrid();
+ m_gridRows = 0;
+
+ for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
+ if (row->isTableRow()) {
+ m_cRow++;
+ m_cCol = 0;
+ if (!ensureRows(m_cRow + 1))
+ break;
+ m_grid[m_cRow].rowRenderer = row;
+
+ for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
+ if (cell->isTableCell())
+ addCell(static_cast<RenderTableCell*>(cell), row);
+ }
+ }
+ }
+ m_needsCellRecalc = false;
+ setNeedsLayout(true);
+}
+
+void RenderTableSection::clearGrid()
+{
+ int rows = m_gridRows;
+ while (rows--)
+ delete m_grid[rows].row;
+}
+
+int RenderTableSection::numColumns() const
+{
+ int result = 0;
+
+ for (int r = 0; r < m_gridRows; ++r) {
+ for (int c = result; c < table()->numEffCols(); ++c) {
+ const CellStruct& cell = cellAt(r, c);
+ if (cell.cell || cell.inColSpan)
+ result = c;
+ }
+ }
+
+ return result + 1;
+}
+
+void RenderTableSection::appendColumn(int pos)
+{
+ for (int row = 0; row < m_gridRows; ++row) {
+ m_grid[row].row->resize(pos + 1);
+ CellStruct& c = cellAt(row, pos);
+ c.cell = 0;
+ c.inColSpan = false;
+ }
+}
+
+void RenderTableSection::splitColumn(int pos, int newSize)
+{
+ if (m_cCol > pos)
+ m_cCol++;
+ for (int row = 0; row < m_gridRows; ++row) {
+ m_grid[row].row->resize(newSize);
+ Row& r = *m_grid[row].row;
+ memmove(r.data() + pos + 1, r.data() + pos, (newSize - 1 - pos) * sizeof(CellStruct));
+ r[pos + 1].cell = 0;
+ r[pos + 1].inColSpan = r[pos].inColSpan || r[pos].cell;
+ }
+}
+
+RenderObject* RenderTableSection::removeChildNode(RenderObject* child, bool fullRemove)
+{
+ setNeedsCellRecalc();
+ return RenderContainer::removeChildNode(child, fullRemove);
+}
+
+// Hit Testing
+bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action)
+{
+ // Table sections cannot ever be hit tested. Effectively they do not exist.
+ // Just forward to our children always.
+ tx += m_x;
+ ty += m_y;
+
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
+ // FIXME: We have to skip over inline flows, since they can show up inside table rows
+ // at the moment (a demoted inline <form> for example). If we ever implement a
+ // table-specific hit-test method (which we should do for performance reasons anyway),
+ // then we can remove this check.
+ if (!child->hasLayer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) {
+ updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.h b/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.h
new file mode 100644
index 0000000..8d460cb
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTableSection.h
@@ -0,0 +1,154 @@
+/*
+ * 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)
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 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
+ * 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 RenderTableSection_h
+#define RenderTableSection_h
+
+#include "RenderTable.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class RenderTableCell;
+
+class RenderTableSection : public RenderContainer {
+public:
+ RenderTableSection(Node*);
+ ~RenderTableSection();
+
+ virtual const char* renderName() const { return isAnonymous() ? "RenderTableSection (anonymous)" : "RenderTableSection"; }
+
+ virtual bool isTableSection() const { return true; }
+
+ virtual void destroy();
+
+ virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
+
+ virtual int getBaselineOfFirstLineBox() const;
+
+ void addCell(RenderTableCell*, RenderObject* row);
+
+ void setCellWidths();
+ int calcRowHeight();
+ int layoutRows(int height);
+
+ RenderTable* table() const { return static_cast<RenderTable*>(parent()); }
+
+ struct CellStruct {
+ RenderTableCell* cell;
+ bool inColSpan; // true for columns after the first in a colspan
+ };
+
+ typedef Vector<CellStruct> Row;
+
+ struct RowStruct {
+ Row* row;
+ RenderObject* rowRenderer;
+ int baseline;
+ Length height;
+ };
+
+ CellStruct& cellAt(int row, int col) { return (*m_grid[row].row)[col]; }
+ const CellStruct& cellAt(int row, int col) const { return (*m_grid[row].row)[col]; }
+
+ void appendColumn(int pos);
+ void splitColumn(int pos, int newSize);
+
+ virtual int overflowWidth(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? m_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()) ? m_height : m_overflowHeight; }
+ virtual int overflowTop(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? 0 : m_overflowTop; }
+
+ virtual int lowestPosition(bool includeOverflowInterior, bool includeSelf) const;
+ virtual int rightmostPosition(bool includeOverflowInterior, bool includeSelf) const;
+ virtual int leftmostPosition(bool includeOverflowInterior, bool includeSelf) const;
+
+ int calcOuterBorderTop() const;
+ int calcOuterBorderBottom() const;
+ int calcOuterBorderLeft(bool rtl) const;
+ int calcOuterBorderRight(bool rtl) const;
+ void recalcOuterBorder();
+
+ int outerBorderTop() const { return m_outerBorderTop; }
+ int outerBorderBottom() const { return m_outerBorderBottom; }
+ int outerBorderLeft() const { return m_outerBorderLeft; }
+ int outerBorderRight() const { return m_outerBorderRight; }
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+
+ int numRows() const { return m_gridRows; }
+ int numColumns() const;
+ void recalcCells();
+ void recalcCellsIfNeeded()
+ {
+ if (m_needsCellRecalc)
+ recalcCells();
+ }
+
+ bool needsCellRecalc() const { return m_needsCellRecalc; }
+ void setNeedsCellRecalc()
+ {
+ m_needsCellRecalc = true;
+ table()->setNeedsSectionRecalc();
+ }
+
+ int getBaseline(int row) { return m_grid[row].baseline; }
+
+ virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true);
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+private:
+ virtual int lineHeight(bool, bool) const { return 0; }
+ virtual void position(InlineBox*) { }
+
+ bool ensureRows(int);
+ void clearGrid();
+
+ Vector<RowStruct> m_grid;
+ int m_gridRows;
+ Vector<int> m_rowPos;
+
+ // the current insertion position
+ int m_cCol;
+ int m_cRow;
+ bool m_needsCellRecalc;
+
+ int m_outerBorderLeft;
+ int m_outerBorderRight;
+ int m_outerBorderTop;
+ int m_outerBorderBottom;
+ int m_overflowLeft;
+ int m_overflowWidth;
+ int m_overflowTop;
+ int m_overflowHeight;
+ bool m_hasOverflowingCell;
+};
+
+} // namespace WebCore
+
+#endif // RenderTableSection_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp
new file mode 100644
index 0000000..d7fdbb9
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderText.cpp
@@ -0,0 +1,1216 @@
+/**
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 "RenderText.h"
+
+#include "CharacterNames.h"
+#include "FrameView.h"
+#include "InlineTextBox.h"
+#include "Range.h"
+#include "RenderArena.h"
+#include "RenderBlock.h"
+#include "RenderLayer.h"
+#include "RenderView.h"
+#include "Text.h"
+#include "TextBreakIterator.h"
+#include "break_lines.h"
+#include <wtf/AlwaysInline.h>
+
+using namespace std;
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+// FIXME: Move to StringImpl.h eventually.
+static inline bool charactersAreAllASCII(StringImpl* text)
+{
+ return charactersAreAllASCII(text->characters(), text->length());
+}
+
+RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
+ : RenderObject(node)
+ , m_text(str)
+ , m_firstTextBox(0)
+ , m_lastTextBox(0)
+ , m_minWidth(-1)
+ , m_maxWidth(-1)
+ , m_beginMinWidth(0)
+ , m_endMinWidth(0)
+ , m_selectionState(SelectionNone)
+ , m_hasTab(false)
+ , m_linesDirty(false)
+ , m_containsReversedText(false)
+ , m_isAllASCII(charactersAreAllASCII(m_text.get()))
+{
+ ASSERT(m_text);
+ setRenderText();
+ m_text = m_text->replace('\\', backslashAsCurrencySymbol());
+
+ view()->frameView()->setIsVisuallyNonEmpty();
+}
+
+#ifndef NDEBUG
+
+RenderText::~RenderText()
+{
+ ASSERT(!m_firstTextBox);
+ ASSERT(!m_lastTextBox);
+}
+
+#endif
+
+const char* RenderText::renderName() const
+{
+ return "RenderText";
+}
+
+bool RenderText::isTextFragment() const
+{
+ return false;
+}
+
+bool RenderText::isWordBreak() const
+{
+ return false;
+}
+
+void RenderText::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderObject::styleDidChange(diff, oldStyle);
+
+ ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
+ ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
+
+ if (oldTransform != style()->textTransform() || oldSecurity != style()->textSecurity()
+#if ENABLE(SVG)
+ || isSVGText() /* All SVG text has to be transformed */
+#endif
+ ) {
+ if (RefPtr<StringImpl> textToTransform = originalText())
+ setText(textToTransform.release(), true);
+ }
+}
+
+void RenderText::destroy()
+{
+ if (!documentBeingDestroyed()) {
+ if (firstTextBox()) {
+ if (isBR()) {
+ RootInlineBox* next = firstTextBox()->root()->nextRootBox();
+ if (next)
+ next->markDirty();
+ }
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ box->remove();
+ } else if (parent())
+ parent()->dirtyLinesFromChangedChild(this);
+ }
+ deleteTextBoxes();
+ RenderObject::destroy();
+}
+
+void RenderText::extractTextBox(InlineTextBox* box)
+{
+ checkConsistency();
+
+ m_lastTextBox = box->prevTextBox();
+ if (box == m_firstTextBox)
+ m_firstTextBox = 0;
+ if (box->prevTextBox())
+ box->prevTextBox()->setNextLineBox(0);
+ box->setPreviousLineBox(0);
+ for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox())
+ curr->setExtracted();
+
+ checkConsistency();
+}
+
+void RenderText::attachTextBox(InlineTextBox* box)
+{
+ checkConsistency();
+
+ if (m_lastTextBox) {
+ m_lastTextBox->setNextLineBox(box);
+ box->setPreviousLineBox(m_lastTextBox);
+ } else
+ m_firstTextBox = box;
+ InlineTextBox* last = box;
+ for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
+ curr->setExtracted(false);
+ last = curr;
+ }
+ m_lastTextBox = last;
+
+ checkConsistency();
+}
+
+void RenderText::removeTextBox(InlineTextBox* box)
+{
+ checkConsistency();
+
+ if (box == m_firstTextBox)
+ m_firstTextBox = box->nextTextBox();
+ if (box == m_lastTextBox)
+ m_lastTextBox = box->prevTextBox();
+ if (box->nextTextBox())
+ box->nextTextBox()->setPreviousLineBox(box->prevTextBox());
+ if (box->prevTextBox())
+ box->prevTextBox()->setNextLineBox(box->nextTextBox());
+
+ checkConsistency();
+}
+
+void RenderText::deleteTextBoxes()
+{
+ if (firstTextBox()) {
+ RenderArena* arena = renderArena();
+ InlineTextBox* next;
+ for (InlineTextBox* curr = firstTextBox(); curr; curr = next) {
+ next = curr->nextTextBox();
+ curr->destroy(arena);
+ }
+ m_firstTextBox = m_lastTextBox = 0;
+ }
+}
+
+PassRefPtr<StringImpl> RenderText::originalText() const
+{
+ Node* e = element();
+ return e ? static_cast<Text*>(e)->string() : 0;
+}
+
+void RenderText::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool)
+{
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ rects.append(IntRect(tx + box->xPos(), ty + box->yPos(), box->width(), box->height()));
+}
+
+void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight)
+{
+ // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
+ // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
+ // function to take ints causes various internal mismatches. But selectionRect takes ints, and
+ // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
+ // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
+ ASSERT(end == UINT_MAX || end <= INT_MAX);
+ ASSERT(start <= INT_MAX);
+ start = min(start, static_cast<unsigned>(INT_MAX));
+ end = min(end, static_cast<unsigned>(INT_MAX));
+
+ FloatPoint absPos = localToAbsoluteForContent(FloatPoint());
+
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
+ // Note: box->end() returns the index of the last character, not the index past it
+ if (start <= box->start() && box->end() < end) {
+ IntRect r = IntRect(absPos.x() + box->xPos(), absPos.y() + box->yPos(), box->width(), box->height());
+ if (useSelectionHeight) {
+ IntRect selectionRect = box->selectionRect(absPos.x(), absPos.y(), start, end);
+ r.setHeight(selectionRect.height());
+ r.setY(selectionRect.y());
+ }
+ rects.append(r);
+ } else {
+ unsigned realEnd = min(box->end() + 1, end);
+ IntRect r = box->selectionRect(absPos.x(), absPos.y(), start, realEnd);
+ if (!r.isEmpty()) {
+ if (!useSelectionHeight) {
+ // change the height and y position because selectionRect uses selection-specific values
+ r.setHeight(box->height());
+ r.setY(absPos.y() + box->yPos());
+ }
+ rects.append(r);
+ }
+ }
+ }
+}
+
+void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool)
+{
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ quads.append(localToAbsoluteQuad(FloatRect(box->xPos(), box->yPos(), box->width(), box->height())));
+}
+
+void RenderText::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight)
+{
+ // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
+ // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
+ // function to take ints causes various internal mismatches. But selectionRect takes ints, and
+ // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
+ // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
+ ASSERT(end == UINT_MAX || end <= INT_MAX);
+ ASSERT(start <= INT_MAX);
+ start = min(start, static_cast<unsigned>(INT_MAX));
+ end = min(end, static_cast<unsigned>(INT_MAX));
+
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
+ // Note: box->end() returns the index of the last character, not the index past it
+ if (start <= box->start() && box->end() < end) {
+ IntRect r = IntRect(box->xPos(), box->yPos(), box->width(), box->height());
+ if (useSelectionHeight) {
+ IntRect selectionRect = box->selectionRect(0, 0, start, end);
+ r.setHeight(selectionRect.height());
+ r.setY(selectionRect.y());
+ }
+ quads.append(localToAbsoluteQuad(FloatRect(r)));
+ } else {
+ unsigned realEnd = min(box->end() + 1, end);
+ IntRect r = box->selectionRect(0, 0, start, realEnd);
+ if (!r.isEmpty()) {
+ if (!useSelectionHeight) {
+ // change the height and y position because selectionRect uses selection-specific values
+ r.setHeight(box->height());
+ r.setY(box->yPos());
+ }
+ quads.append(localToAbsoluteQuad(FloatRect(r)));
+ }
+ }
+ }
+}
+
+InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const
+{
+ // The text runs point to parts of the RenderText's m_text
+ // (they don't include '\n')
+ // Find the text run that includes the character at offset
+ // and return pos, which is the position of the char in the run.
+
+ if (!m_firstTextBox)
+ return 0;
+
+ InlineTextBox* s = m_firstTextBox;
+ int off = s->m_len;
+ while (offset > off && s->nextTextBox()) {
+ s = s->nextTextBox();
+ off = s->m_start + s->m_len;
+ }
+ // we are now in the correct text run
+ pos = (offset > off ? s->m_len : s->m_len - (off - offset) );
+ return s;
+}
+
+VisiblePosition RenderText::positionForCoordinates(int x, int y)
+{
+ if (!firstTextBox() || textLength() == 0)
+ return VisiblePosition(element(), 0, DOWNSTREAM);
+
+ // Get the offset for the position, since this will take rtl text into account.
+ int offset;
+
+ // FIXME: We should be able to roll these special cases into the general cases in the loop below.
+ if (firstTextBox() && y < firstTextBox()->root()->bottomOverflow() && 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(x);
+ return VisiblePosition(element(), offset + firstTextBox()->m_start, DOWNSTREAM);
+ }
+ if (lastTextBox() && y >= lastTextBox()->root()->topOverflow() && 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(x);
+ return VisiblePosition(element(), offset + lastTextBox()->m_start, DOWNSTREAM);
+ }
+
+ InlineTextBox* lastBoxAbove = 0;
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
+ if (y >= box->root()->topOverflow()) {
+ int bottom = box->root()->nextRootBox() ? box->root()->nextRootBox()->topOverflow() : box->root()->bottomOverflow();
+ if (y < bottom) {
+ offset = box->offsetForPosition(x);
+
+ if (x == box->m_x)
+ // the x coordinate is equal to the left edge of this box
+ // the affinity must be downstream so the position doesn't jump back to the previous line
+ return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM);
+
+ if (x < box->m_x + box->m_width)
+ // and the x coordinate is to the left of the right edge of this box
+ // check to see if position goes in this box
+ return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
+
+ if (!box->prevOnLine() && x < box->m_x)
+ // box is first on line
+ // and the x coordinate is to the left of the first text box left edge
+ return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM);
+
+ if (!box->nextOnLine())
+ // box is last on line
+ // and the x coordinate is to the right of the last text box right edge
+ // generate VisiblePosition, use UPSTREAM affinity if possible
+ return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
+ }
+ lastBoxAbove = box;
+ }
+ }
+
+ return VisiblePosition(element(), lastBoxAbove ? lastBoxAbove->m_start + lastBoxAbove->m_len : 0, DOWNSTREAM);
+}
+
+IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
+{
+ if (!inlineBox)
+ return IntRect();
+
+ ASSERT(inlineBox->isInlineTextBox());
+ if (!inlineBox->isInlineTextBox())
+ return IntRect();
+
+ InlineTextBox* box = static_cast<InlineTextBox*>(inlineBox);
+
+ int height = box->root()->bottomOverflow() - box->root()->topOverflow();
+ int top = box->root()->topOverflow();
+
+ int left = box->positionForOffset(caretOffset);
+
+ int rootLeft = box->root()->xPos();
+ // FIXME: should we use the width of the root inline box or the
+ // width of the containing block for this?
+ if (extraWidthToEndOfLine)
+ *extraWidthToEndOfLine = (box->root()->width() + rootLeft) - (left + 1);
+
+ RenderBlock* cb = containingBlock();
+ if (style()->autoWrap()) {
+ int availableWidth = cb->lineWidth(top);
+ if (box->direction() == LTR)
+ left = min(left, rootLeft + availableWidth - 1);
+ else
+ left = max(left, rootLeft);
+ }
+
+ const int caretWidth = 1;
+ return IntRect(left, top, caretWidth, height);
+}
+
+ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos) const
+{
+ if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII) {
+ int monospaceCharacterWidth = f.spaceWidth();
+ int tabWidth = allowTabs() ? monospaceCharacterWidth * 8 : 0;
+ int w = 0;
+ bool isSpace;
+ bool previousCharWasSpace = true; // FIXME: Preserves historical behavior, but seems wrong for start > 0.
+ for (int i = start; i < start + len; i++) {
+ char c = (*m_text)[i];
+ if (c <= ' ') {
+ if (c == ' ' || c == '\n') {
+ w += monospaceCharacterWidth;
+ isSpace = true;
+ } else if (c == '\t') {
+ w += tabWidth ? tabWidth - ((xPos + w) % tabWidth) : monospaceCharacterWidth;
+ isSpace = true;
+ } else
+ isSpace = false;
+ } else {
+ w += monospaceCharacterWidth;
+ isSpace = false;
+ }
+ if (isSpace && !previousCharWasSpace)
+ w += f.wordSpacing();
+ previousCharWasSpace = isSpace;
+ }
+ return w;
+ }
+
+ return f.width(TextRun(text()->characters() + start, len, allowTabs(), xPos));
+}
+
+void RenderText::trimmedPrefWidths(int leadWidth,
+ int& beginMinW, bool& beginWS,
+ int& endMinW, bool& endWS,
+ bool& hasBreakableChar, bool& hasBreak,
+ int& beginMaxW, int& endMaxW,
+ int& minW, int& maxW, bool& stripFrontSpaces)
+{
+ bool collapseWhiteSpace = style()->collapseWhiteSpace();
+ if (!collapseWhiteSpace)
+ stripFrontSpaces = false;
+
+ if (m_hasTab || prefWidthsDirty())
+ calcPrefWidths(leadWidth);
+
+ beginWS = !stripFrontSpaces && m_hasBeginWS;
+ endWS = m_hasEndWS;
+
+ int len = textLength();
+
+ if (!len || (stripFrontSpaces && m_text->containsOnlyWhitespace())) {
+ beginMinW = 0;
+ endMinW = 0;
+ beginMaxW = 0;
+ endMaxW = 0;
+ minW = 0;
+ maxW = 0;
+ hasBreak = false;
+ return;
+ }
+
+ minW = m_minWidth;
+ maxW = m_maxWidth;
+
+ beginMinW = m_beginMinWidth;
+ endMinW = m_endMinWidth;
+
+ hasBreakableChar = m_hasBreakableChar;
+ hasBreak = m_hasBreak;
+
+ if ((*m_text)[0] == ' ' || ((*m_text)[0] == '\n' && !style()->preserveNewline()) || (*m_text)[0] == '\t') {
+ const Font& f = style()->font(); // FIXME: This ignores first-line.
+ if (stripFrontSpaces) {
+ const UChar space = ' ';
+ int spaceWidth = f.width(TextRun(&space, 1));
+ maxW -= spaceWidth;
+ } else
+ maxW += f.wordSpacing();
+ }
+
+ stripFrontSpaces = collapseWhiteSpace && m_hasEndWS;
+
+ if (!style()->autoWrap() || minW > maxW)
+ minW = maxW;
+
+ // Compute our max widths by scanning the string for newlines.
+ if (hasBreak) {
+ const Font& f = style()->font(); // FIXME: This ignores first-line.
+ bool firstLine = true;
+ beginMaxW = maxW;
+ endMaxW = maxW;
+ for (int i = 0; i < len; i++) {
+ int linelen = 0;
+ while (i + linelen < len && (*m_text)[i + linelen] != '\n')
+ linelen++;
+
+ if (linelen) {
+ endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW);
+ if (firstLine) {
+ firstLine = false;
+ leadWidth = 0;
+ beginMaxW = endMaxW;
+ }
+ i += linelen;
+ } else if (firstLine) {
+ beginMaxW = 0;
+ firstLine = false;
+ leadWidth = 0;
+ }
+
+ if (i == len - 1)
+ // A <pre> run that ends with a newline, as in, e.g.,
+ // <pre>Some text\n\n<span>More text</pre>
+ endMaxW = 0;
+ }
+ }
+}
+
+static inline bool isSpaceAccordingToStyle(UChar c, RenderStyle* style)
+{
+ return c == ' ' || (c == noBreakSpace && style->nbspMode() == SPACE);
+}
+
+int RenderText::minPrefWidth() const
+{
+ if (prefWidthsDirty())
+ const_cast<RenderText*>(this)->calcPrefWidths(0);
+
+ return m_minWidth;
+}
+
+int RenderText::maxPrefWidth() const
+{
+ if (prefWidthsDirty())
+ const_cast<RenderText*>(this)->calcPrefWidths(0);
+
+ return m_maxWidth;
+}
+
+void RenderText::calcPrefWidths(int leadWidth)
+{
+ ASSERT(m_hasTab || prefWidthsDirty());
+
+ m_minWidth = 0;
+ m_beginMinWidth = 0;
+ m_endMinWidth = 0;
+ m_maxWidth = 0;
+
+ if (isBR())
+ return;
+
+ int currMinWidth = 0;
+ int currMaxWidth = 0;
+ m_hasBreakableChar = false;
+ m_hasBreak = false;
+ m_hasTab = false;
+ m_hasBeginWS = false;
+ m_hasEndWS = false;
+
+ const Font& f = style()->font(); // FIXME: This ignores first-line.
+ int wordSpacing = style()->wordSpacing();
+ int len = textLength();
+ const UChar* txt = characters();
+ bool needsWordSpacing = false;
+ bool ignoringSpaces = false;
+ bool isSpace = false;
+ bool firstWord = true;
+ bool firstLine = true;
+ int nextBreakable = -1;
+ int lastWordBoundary = 0;
+
+ bool breakNBSP = style()->autoWrap() && style()->nbspMode() == SPACE;
+ bool breakAll = (style()->wordBreak() == BreakAllWordBreak || style()->wordBreak() == BreakWordBreak) && style()->autoWrap();
+
+ for (int i = 0; i < len; i++) {
+ UChar c = txt[i];
+
+ bool previousCharacterIsSpace = isSpace;
+
+ bool isNewline = false;
+ if (c == '\n') {
+ if (style()->preserveNewline()) {
+ m_hasBreak = true;
+ isNewline = true;
+ isSpace = false;
+ } else
+ isSpace = true;
+ } else if (c == '\t') {
+ if (!style()->collapseWhiteSpace()) {
+ m_hasTab = true;
+ isSpace = false;
+ } else
+ isSpace = true;
+ } else
+ isSpace = c == ' ';
+
+ if ((isSpace || isNewline) && !i)
+ m_hasBeginWS = true;
+ if ((isSpace || isNewline) && i == len - 1)
+ m_hasEndWS = true;
+
+ if (!ignoringSpaces && style()->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
+ ignoringSpaces = true;
+
+ if (ignoringSpaces && !isSpace)
+ ignoringSpaces = false;
+
+ // Ignore spaces and soft hyphens
+ if (ignoringSpaces) {
+ ASSERT(lastWordBoundary == i);
+ lastWordBoundary++;
+ continue;
+ } else if (c == softHyphen) {
+ currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth);
+ lastWordBoundary = i + 1;
+ continue;
+ }
+
+ bool hasBreak = breakAll || isBreakable(txt, i, len, nextBreakable, breakNBSP);
+ bool betweenWords = true;
+ int j = i;
+ while (c != '\n' && !isSpaceAccordingToStyle(c, style()) && c != '\t' && c != softHyphen) {
+ j++;
+ if (j == len)
+ break;
+ c = txt[j];
+ if (isBreakable(txt, j, len, nextBreakable, breakNBSP))
+ break;
+ if (breakAll) {
+ betweenWords = false;
+ break;
+ }
+ }
+
+ int wordLen = j - i;
+ if (wordLen) {
+ int w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth);
+ currMinWidth += w;
+ if (betweenWords) {
+ if (lastWordBoundary == i)
+ currMaxWidth += w;
+ else
+ currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth);
+ lastWordBoundary = j;
+ }
+
+ bool isSpace = (j < len) && isSpaceAccordingToStyle(c, style());
+ bool isCollapsibleWhiteSpace = (j < len) && style()->isCollapsibleWhiteSpace(c);
+ if (j < len && style()->autoWrap())
+ m_hasBreakableChar = true;
+
+ // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
+ // last word in the run.
+ if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
+ currMaxWidth += wordSpacing;
+
+ if (firstWord) {
+ firstWord = false;
+ // If the first character in the run is breakable, then we consider ourselves to have a beginning
+ // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
+ // being appended to a previous text run when considering the total minimum width of the containing block.
+ if (hasBreak)
+ m_hasBreakableChar = true;
+ m_beginMinWidth = hasBreak ? 0 : w;
+ }
+ m_endMinWidth = w;
+
+ if (currMinWidth > m_minWidth)
+ m_minWidth = currMinWidth;
+ currMinWidth = 0;
+
+ i += wordLen - 1;
+ } else {
+ // Nowrap can never be broken, so don't bother setting the
+ // breakable character boolean. Pre can only be broken if we encounter a newline.
+ if (style()->autoWrap() || isNewline)
+ m_hasBreakableChar = true;
+
+ if (currMinWidth > m_minWidth)
+ m_minWidth = currMinWidth;
+ currMinWidth = 0;
+
+ if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
+ if (firstLine) {
+ firstLine = false;
+ leadWidth = 0;
+ if (!style()->autoWrap())
+ m_beginMinWidth = currMaxWidth;
+ }
+
+ if (currMaxWidth > m_maxWidth)
+ m_maxWidth = currMaxWidth;
+ currMaxWidth = 0;
+ } else {
+ currMaxWidth += f.width(TextRun(txt + i, 1, allowTabs(), leadWidth + currMaxWidth));
+ needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
+ }
+ ASSERT(lastWordBoundary == i);
+ lastWordBoundary++;
+ }
+ }
+
+ if (needsWordSpacing && len > 1 || ignoringSpaces && !firstWord)
+ currMaxWidth += wordSpacing;
+
+ m_minWidth = max(currMinWidth, m_minWidth);
+ m_maxWidth = max(currMaxWidth, m_maxWidth);
+
+ if (!style()->autoWrap())
+ m_minWidth = m_maxWidth;
+
+ if (style()->whiteSpace() == PRE) {
+ if (firstLine)
+ m_beginMinWidth = m_maxWidth;
+ m_endMinWidth = currMaxWidth;
+ }
+
+ setPrefWidthsDirty(false);
+}
+
+bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
+{
+ unsigned currPos;
+ for (currPos = from;
+ currPos < from + len && ((*m_text)[currPos] == '\n' || (*m_text)[currPos] == ' ' || (*m_text)[currPos] == '\t');
+ currPos++) { }
+ return currPos >= (from + len);
+}
+
+int RenderText::minXPos() const
+{
+ if (!m_firstTextBox)
+ return 0;
+
+ // FIXME: we should not use an arbitrary value like this. Perhaps we should use INT_MAX.
+ int minXPos = 6666666;
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ minXPos = min(minXPos, static_cast<int>(box->m_x));
+ return minXPos;
+}
+
+int RenderText::xPos() const
+{
+ return m_firstTextBox ? m_firstTextBox->m_x : 0;
+}
+
+int RenderText::yPos() const
+{
+ return m_firstTextBox ? m_firstTextBox->m_y : 0;
+}
+
+void RenderText::setSelectionState(SelectionState state)
+{
+ InlineTextBox* box;
+
+ m_selectionState = state;
+ if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {
+ int startPos, endPos;
+ selectionStartEnd(startPos, endPos);
+ if (selectionState() == SelectionStart) {
+ endPos = textLength();
+
+ // to handle selection from end of text to end of line
+ if (startPos != 0 && startPos == endPos)
+ startPos = endPos - 1;
+ } else if (selectionState() == SelectionEnd)
+ startPos = 0;
+
+ for (box = firstTextBox(); box; box = box->nextTextBox()) {
+ if (box->isSelected(startPos, endPos)) {
+ RootInlineBox* line = box->root();
+ if (line)
+ line->setHasSelectedChildren(true);
+ }
+ }
+ } else {
+ for (box = firstTextBox(); box; box = box->nextTextBox()) {
+ RootInlineBox* line = box->root();
+ if (line)
+ line->setHasSelectedChildren(state == SelectionInside);
+ }
+ }
+
+ containingBlock()->setSelectionState(state);
+}
+
+void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
+{
+ unsigned oldLen = textLength();
+ unsigned newLen = text->length();
+ int delta = newLen - oldLen;
+ unsigned end = len ? offset + len - 1 : offset;
+
+ RootInlineBox* firstRootBox = 0;
+ RootInlineBox* lastRootBox = 0;
+
+ bool dirtiedLines = false;
+
+ // Dirty all text boxes that include characters in between offset and offset+len.
+ for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
+ // Text run is entirely before the affected range.
+ if (curr->end() < offset)
+ continue;
+
+ // Text run is entirely after the affected range.
+ if (curr->start() > end) {
+ curr->offsetRun(delta);
+ RootInlineBox* root = curr->root();
+ if (!firstRootBox) {
+ firstRootBox = root;
+ if (!dirtiedLines) {
+ // The affected area was in between two runs. Go ahead and mark the root box of
+ // the run after the affected area as dirty.
+ firstRootBox->markDirty();
+ dirtiedLines = true;
+ }
+ }
+ lastRootBox = root;
+ } else if (curr->end() >= offset && curr->end() <= end) {
+ // Text run overlaps with the left end of the affected range.
+ curr->dirtyLineBoxes();
+ dirtiedLines = true;
+ } else if (curr->start() <= offset && curr->end() >= end) {
+ // Text run subsumes the affected range.
+ curr->dirtyLineBoxes();
+ dirtiedLines = true;
+ } else if (curr->start() <= end && curr->end() >= end) {
+ // Text run overlaps with right end of the affected range.
+ curr->dirtyLineBoxes();
+ dirtiedLines = true;
+ }
+ }
+
+ // Now we have to walk all of the clean lines and adjust their cached line break information
+ // to reflect our updated offsets.
+ if (lastRootBox)
+ lastRootBox = lastRootBox->nextRootBox();
+ if (firstRootBox) {
+ RootInlineBox* prev = firstRootBox->prevRootBox();
+ if (prev)
+ firstRootBox = prev;
+ }
+ for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
+ if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
+ curr->setLineBreakPos(curr->lineBreakPos() + delta);
+ }
+
+ // If the text node is empty, dirty the line where new text will be inserted.
+ if (!firstTextBox() && parent()) {
+ parent()->dirtyLinesFromChangedChild(this);
+ dirtiedLines = true;
+ }
+
+ m_linesDirty = dirtiedLines;
+ setText(text, force);
+}
+
+static inline bool isInlineFlowOrEmptyText(RenderObject* o)
+{
+ if (o->isInlineFlow())
+ return true;
+ if (!o->isText())
+ return false;
+ StringImpl* text = static_cast<RenderText*>(o)->text();
+ if (!text)
+ return true;
+ return !text->length();
+}
+
+UChar RenderText::previousCharacter()
+{
+ // find previous text renderer if one exists
+ RenderObject* previousText = this;
+ while ((previousText = previousText->previousInPreOrder()))
+ if (!isInlineFlowOrEmptyText(previousText))
+ break;
+ UChar prev = ' ';
+ if (previousText && previousText->isText())
+ if (StringImpl* previousString = static_cast<RenderText*>(previousText)->text())
+ prev = (*previousString)[previousString->length() - 1];
+ return prev;
+}
+
+void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
+{
+ m_text = text;
+ ASSERT(m_text);
+
+ m_text = m_text->replace('\\', backslashAsCurrencySymbol());
+
+#if ENABLE(SVG)
+ if (isSVGText()) {
+ if (style() && style()->whiteSpace() == PRE) {
+ // Spec: When xml:space="preserve", the SVG user agent will do the following using a
+ // copy of the original character data content. It will convert all newline and tab
+ // characters into space characters. Then, it will draw all space characters, including
+ // leading, trailing and multiple contiguous space characters.
+
+ m_text = m_text->replace('\n', ' ');
+
+ // If xml:space="preserve" is set, white-space is set to "pre", which
+ // preserves leading, trailing & contiguous space character for us.
+ } else {
+ // Spec: When xml:space="default", the SVG user agent will do the following using a
+ // copy of the original character data content. First, it will remove all newline
+ // characters. Then it will convert all tab characters into space characters.
+ // Then, it will strip off all leading and trailing space characters.
+ // Then, all contiguous space characters will be consolidated.
+
+ m_text = m_text->replace('\n', StringImpl::empty());
+
+ // If xml:space="default" is set, white-space is set to "nowrap", which handles
+ // leading, trailing & contiguous space character removal for us.
+ }
+
+ m_text = m_text->replace('\t', ' ');
+ }
+#endif
+
+ if (style()) {
+ switch (style()->textTransform()) {
+ case TTNONE:
+ break;
+ case CAPITALIZE: {
+ m_text = m_text->capitalize(previousCharacter());
+ break;
+ }
+ case UPPERCASE:
+ m_text = m_text->upper();
+ break;
+ case LOWERCASE:
+ m_text = m_text->lower();
+ break;
+ }
+
+ // We use the same characters here as for list markers.
+ // See the listMarkerText function in RenderListMarker.cpp.
+ switch (style()->textSecurity()) {
+ case TSNONE:
+ break;
+ case TSCIRCLE:
+ m_text = m_text->secure(whiteBullet);
+ break;
+ case TSDISC:
+ m_text = m_text->secure(bullet);
+ break;
+ case TSSQUARE:
+ m_text = m_text->secure(blackSquare);
+ }
+ }
+
+ ASSERT(m_text);
+ ASSERT(!isBR() || (textLength() == 1 && (*m_text)[0] == '\n'));
+
+ m_isAllASCII = charactersAreAllASCII(m_text.get());
+}
+
+void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
+{
+ ASSERT(text);
+
+ if (!force && equal(m_text.get(), text.get()))
+ return;
+
+ setTextInternal(text);
+ setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+int RenderText::height() const
+{
+ int retval = 0;
+ if (firstTextBox())
+ retval = lastTextBox()->m_y + lastTextBox()->height() - firstTextBox()->m_y;
+ return retval;
+}
+
+int RenderText::lineHeight(bool firstLine, bool) const
+{
+ // Always use the interior line height of the parent (e.g., if our parent is an inline block).
+ return parent()->lineHeight(firstLine, true);
+}
+
+void RenderText::dirtyLineBoxes(bool fullLayout, bool)
+{
+ if (fullLayout)
+ deleteTextBoxes();
+ else if (!m_linesDirty) {
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ box->dirtyLineBoxes();
+ }
+ m_linesDirty = false;
+}
+
+InlineTextBox* RenderText::createInlineTextBox()
+{
+ return new (renderArena()) InlineTextBox(this);
+}
+
+InlineBox* RenderText::createInlineBox(bool, bool isRootLineBox, bool)
+{
+ ASSERT(!isRootLineBox);
+ InlineTextBox* textBox = createInlineTextBox();
+ if (!m_firstTextBox)
+ m_firstTextBox = m_lastTextBox = textBox;
+ else {
+ m_lastTextBox->setNextLineBox(textBox);
+ textBox->setPreviousLineBox(m_lastTextBox);
+ m_lastTextBox = textBox;
+ }
+ return textBox;
+}
+
+void RenderText::position(InlineBox* box)
+{
+ InlineTextBox* s = static_cast<InlineTextBox*>(box);
+
+ // FIXME: should not be needed!!!
+ if (!s->m_len) {
+ // We want the box to be destroyed.
+ s->remove();
+ s->destroy(renderArena());
+ m_firstTextBox = m_lastTextBox = 0;
+ return;
+ }
+
+ m_containsReversedText |= s->direction() == RTL;
+}
+
+unsigned int RenderText::width(unsigned int from, unsigned int len, int xPos, bool firstLine) const
+{
+ if (from >= textLength())
+ return 0;
+
+ if (from + len > textLength())
+ len = textLength() - from;
+
+ return width(from, len, style(firstLine)->font(), xPos);
+}
+
+unsigned int RenderText::width(unsigned int from, unsigned int len, const Font& f, int xPos) const
+{
+ if (!characters() || from > textLength())
+ return 0;
+
+ if (from + len > textLength())
+ len = textLength() - from;
+
+ int w;
+ if (&f == &style()->font()) {
+ if (!style()->preserveNewline() && !from && len == textLength())
+ w = maxPrefWidth();
+ else
+ w = widthFromCache(f, from, len, xPos);
+ } else
+ w = f.width(TextRun(text()->characters() + from, len, allowTabs(), xPos));
+
+ return w;
+}
+
+int RenderText::width() const
+{
+ // FIXME: we should not use an arbitrary value like this. Perhaps we should use INT_MAX.
+ int minx = 100000000;
+ int maxx = 0;
+ // slooow
+ for (InlineTextBox* s = firstTextBox(); s; s = s->nextTextBox()) {
+ if (s->m_x < minx)
+ minx = s->m_x;
+ if (s->m_x + s->m_width > maxx)
+ maxx = s->m_x + s->m_width;
+ }
+
+ return max(0, maxx - minx);
+}
+
+IntRect RenderText::absoluteClippedOverflowRect()
+{
+ RenderObject* cb = containingBlock();
+ return cb->absoluteClippedOverflowRect();
+}
+
+IntRect RenderText::selectionRect(bool clipToVisibleContent)
+{
+ ASSERT(!needsLayout());
+
+ IntRect rect;
+ if (selectionState() == SelectionNone)
+ return rect;
+ RenderBlock* cb = containingBlock();
+ if (!cb)
+ return rect;
+
+ // Now calculate startPos and endPos for painting selection.
+ // We include a selection while endPos > 0
+ int startPos, endPos;
+ if (selectionState() == SelectionInside) {
+ // We are fully selected.
+ startPos = 0;
+ endPos = textLength();
+ } else {
+ selectionStartEnd(startPos, endPos);
+ if (selectionState() == SelectionStart)
+ endPos = textLength();
+ else if (selectionState() == SelectionEnd)
+ startPos = 0;
+ }
+
+ if (startPos == endPos)
+ return rect;
+
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ rect.unite(box->selectionRect(0, 0, startPos, endPos));
+
+ if (clipToVisibleContent)
+ computeAbsoluteRepaintRect(rect);
+ else {
+ if (cb->hasColumns())
+ cb->adjustRectForColumns(rect);
+ // FIXME: This doesn't work correctly with transforms.
+ FloatPoint absPos = localToAbsolute();
+ rect.move(absPos.x(), absPos.y());
+ }
+
+ return rect;
+}
+
+int RenderText::verticalPositionHint(bool firstLine) const
+{
+ if (parent()->isReplaced())
+ return 0; // Treat inline blocks just like blocks. There can't be any vertical position hint.
+ return parent()->verticalPositionHint(firstLine);
+}
+
+int RenderText::caretMinOffset() const
+{
+ InlineTextBox* box = firstTextBox();
+ if (!box)
+ return 0;
+ int minOffset = box->m_start;
+ for (box = box->nextTextBox(); box; box = box->nextTextBox())
+ minOffset = min(minOffset, box->m_start);
+ return minOffset;
+}
+
+int RenderText::caretMaxOffset() const
+{
+ InlineTextBox* box = lastTextBox();
+ if (!box)
+ return textLength();
+ int maxOffset = box->m_start + box->m_len;
+ for (box = box->prevTextBox(); box; box = box->prevTextBox())
+ maxOffset = max(maxOffset, box->m_start + box->m_len);
+ return maxOffset;
+}
+
+unsigned RenderText::caretMaxRenderedOffset() const
+{
+ int l = 0;
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ l += box->m_len;
+ return l;
+}
+
+int RenderText::previousOffset(int current) const
+{
+ StringImpl* si = m_text.get();
+ TextBreakIterator* iterator = characterBreakIterator(si->characters(), si->length());
+ if (!iterator)
+ return current - 1;
+
+ long result = textBreakPreceding(iterator, current);
+ if (result == TextBreakDone)
+ result = current - 1;
+
+ return result;
+}
+
+int RenderText::nextOffset(int current) const
+{
+ StringImpl* si = m_text.get();
+ TextBreakIterator* iterator = characterBreakIterator(si->characters(), si->length());
+ if (!iterator)
+ return current + 1;
+
+ long result = textBreakFollowing(iterator, current);
+ if (result == TextBreakDone)
+ result = current + 1;
+
+ return result;
+}
+
+#ifndef NDEBUG
+
+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->prevTextBox() == prev);
+ prev = child;
+ }
+ ASSERT(prev == m_lastTextBox);
+#endif
+}
+
+#endif
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderText.h b/src/3rdparty/webkit/WebCore/rendering/RenderText.h
new file mode 100644
index 0000000..4c62638
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderText.h
@@ -0,0 +1,183 @@
+/*
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 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 RenderText_h
+#define RenderText_h
+
+#include "RenderObject.h"
+
+namespace WebCore {
+
+class InlineTextBox;
+class StringImpl;
+
+class RenderText : public RenderObject {
+public:
+ RenderText(Node*, PassRefPtr<StringImpl>);
+#ifndef NDEBUG
+ virtual ~RenderText();
+#endif
+
+ virtual const char* renderName() const;
+
+ virtual bool isTextFragment() const;
+ virtual bool isWordBreak() const;
+
+ virtual PassRefPtr<StringImpl> originalText() const;
+
+ void extractTextBox(InlineTextBox*);
+ void attachTextBox(InlineTextBox*);
+ void removeTextBox(InlineTextBox*);
+
+ virtual void destroy();
+
+ StringImpl* text() const { return m_text.get(); }
+
+ virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false);
+ virtual InlineTextBox* createInlineTextBox();
+ virtual void dirtyLineBoxes(bool fullLayout, bool isRootInlineBox = false);
+
+ virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+ virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+ virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+
+ virtual VisiblePosition positionForCoordinates(int x, int y);
+
+ const UChar* characters() const { return m_text->characters(); }
+ unsigned textLength() const { return m_text->length(); } // non virtual implementation of length()
+ virtual void position(InlineBox*);
+
+ virtual unsigned width(unsigned from, unsigned len, const Font&, int xPos) const;
+ virtual unsigned width(unsigned from, unsigned len, int xPos, bool firstLine = false) const;
+ virtual int width() const;
+ virtual int height() const;
+
+ virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
+
+ virtual int minPrefWidth() const;
+ virtual int maxPrefWidth() const;
+
+ void trimmedPrefWidths(int leadWidth,
+ int& beginMinW, bool& beginWS,
+ int& endMinW, bool& endWS,
+ bool& hasBreakableChar, bool& hasBreak,
+ int& beginMaxW, int& endMaxW,
+ int& minW, int& maxW, bool& stripFrontSpaces);
+
+ // returns the minimum x position of all runs relative to the parent.
+ // defaults to 0.
+ int minXPos() const;
+
+ virtual int xPos() const;
+ virtual int yPos() const;
+
+ virtual int verticalPositionHint(bool firstLine) const;
+
+ void setText(PassRefPtr<StringImpl>, bool force = false);
+ void setTextWithOffset(PassRefPtr<StringImpl>, unsigned offset, unsigned len, bool force = false);
+
+ virtual bool canBeSelectionLeaf() const { return true; }
+ virtual SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState); }
+ virtual void setSelectionState(SelectionState s);
+ virtual IntRect selectionRect(bool clipToVisibleContent = true);
+ virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
+
+ virtual int marginLeft() const { return style()->marginLeft().calcMinValue(0); }
+ virtual int marginRight() const { return style()->marginRight().calcMinValue(0); }
+
+ virtual IntRect absoluteClippedOverflowRect();
+
+ InlineTextBox* firstTextBox() const { return m_firstTextBox; }
+ InlineTextBox* lastTextBox() const { return m_lastTextBox; }
+
+ virtual int caretMinOffset() const;
+ virtual int caretMaxOffset() const;
+ virtual unsigned caretMaxRenderedOffset() const;
+
+ virtual int previousOffset(int current) const;
+ virtual int nextOffset(int current) const;
+
+ bool containsReversedText() const { return m_containsReversedText; }
+
+ InlineTextBox* findNextInlineTextBox(int offset, int& pos) const;
+
+ bool allowTabs() const { return !style()->collapseWhiteSpace(); }
+
+ void checkConsistency() const;
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ virtual void setTextInternal(PassRefPtr<StringImpl>);
+ virtual void calcPrefWidths(int leadWidth);
+ virtual UChar previousCharacter();
+
+private:
+ // Make length() private so that callers that have a RenderText*
+ // will use the more efficient textLength() instead, while
+ // callers with a RenderObject* can continue to use length().
+ virtual unsigned length() const { return textLength(); }
+
+ virtual void paint(PaintInfo&, int, int) { ASSERT_NOT_REACHED(); }
+ virtual void layout() { ASSERT_NOT_REACHED(); }
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) { ASSERT_NOT_REACHED(); return false; }
+
+ void deleteTextBoxes();
+ bool containsOnlyWhitespace(unsigned from, unsigned len) const;
+ int widthFromCache(const Font&, int start, int len, int xPos) const;
+ bool isAllASCII() const { return m_isAllASCII; }
+
+ RefPtr<StringImpl> m_text;
+
+ InlineTextBox* m_firstTextBox;
+ InlineTextBox* m_lastTextBox;
+
+ int m_minWidth;
+ int m_maxWidth;
+ int m_beginMinWidth;
+ int m_endMinWidth;
+
+ unsigned m_selectionState : 3; // enums on Windows are signed, so this needs to be unsigned to prevent it turning negative.
+ bool m_hasBreakableChar : 1; // Whether or not we can be broken into multiple lines.
+ bool m_hasBreak : 1; // Whether or not we have a hard break (e.g., <pre> with '\n').
+ bool m_hasTab : 1; // Whether or not we have a variable width tab character (e.g., <pre> with '\t').
+ bool m_hasBeginWS : 1; // Whether or not we begin with WS (only true if we aren't pre)
+ bool m_hasEndWS : 1; // Whether or not we end with WS (only true if we aren't pre)
+ bool m_linesDirty : 1; // This bit indicates that the text run has already dirtied specific
+ // line boxes, and this hint will enable layoutInlineChildren to avoid
+ // just dirtying everything when character data is modified (e.g., appended/inserted
+ // or removed).
+ bool m_containsReversedText : 1;
+ bool m_isAllASCII : 1;
+};
+
+#ifdef NDEBUG
+inline void RenderText::checkConsistency() const
+{
+}
+#endif
+
+} // namespace WebCore
+
+#endif // RenderText_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp
new file mode 100644
index 0000000..8f853f8
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.cpp
@@ -0,0 +1,591 @@
+/**
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2008 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
+ * 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 "RenderTextControl.h"
+
+#include "CharacterNames.h"
+#include "Editor.h"
+#include "Event.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "HTMLBRElement.h"
+#include "HTMLFormControlElement.h"
+#include "HTMLNames.h"
+#include "HitTestResult.h"
+#include "ScrollbarTheme.h"
+#include "SelectionController.h"
+#include "TextControlInnerElements.h"
+#include "Text.h"
+#include "TextIterator.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// Value chosen by observation. This can be tweaked.
+static const int minColorContrastValue = 1300;
+
+static Color disabledTextColor(const Color& textColor, const Color& backgroundColor)
+{
+ // The explicit check for black is an optimization for the 99% case (black on white).
+ // This also means that black on black will turn into grey on black when disabled.
+ Color disabledColor;
+ if (textColor.rgb() == Color::black || differenceSquared(textColor, Color::white) > differenceSquared(backgroundColor, Color::white))
+ disabledColor = textColor.light();
+ else
+ disabledColor = textColor.dark();
+
+ // If there's not very much contrast between the disabled color and the background color,
+ // just leave the text color alone. We don't want to change a good contrast color scheme so that it has really bad contrast.
+ // If the the contrast was already poor, then it doesn't do any good to change it to a different poor contrast color scheme.
+ if (differenceSquared(disabledColor, backgroundColor) < minColorContrastValue)
+ return textColor;
+
+ return disabledColor;
+}
+
+RenderTextControl::RenderTextControl(Node* node)
+ : RenderBlock(node)
+ , m_edited(false)
+ , m_userEdited(false)
+{
+}
+
+RenderTextControl::~RenderTextControl()
+{
+ // The children renderers have already been destroyed by destroyLeftoverChildren
+ if (m_innerText)
+ m_innerText->detach();
+}
+
+void RenderTextControl::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+
+ if (m_innerText) {
+ RenderBlock* textBlockRenderer = static_cast<RenderBlock*>(m_innerText->renderer());
+ RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(style());
+ // We may have set the width and the height in the old style in layout().
+ // Reset them now to avoid getting a spurious layout hint.
+ textBlockRenderer->style()->setHeight(Length());
+ textBlockRenderer->style()->setWidth(Length());
+ textBlockRenderer->setStyle(textBlockStyle);
+ for (Node* n = m_innerText->firstChild(); n; n = n->traverseNextNode(m_innerText.get())) {
+ if (n->renderer())
+ n->renderer()->setStyle(textBlockStyle);
+ }
+ }
+
+ setHasOverflowClip(false);
+ setReplaced(isInline());
+}
+
+void RenderTextControl::adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle* textBlockStyle) const
+{
+ // The inner block, if present, always has its direction set to LTR,
+ // so we need to inherit the direction from the element.
+ textBlockStyle->setDirection(style()->direction());
+ textBlockStyle->setUserModify((node()->isReadOnlyControl() || !node()->isEnabled()) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);
+
+ if (!node()->isEnabled())
+ textBlockStyle->setColor(disabledTextColor(textBlockStyle->color(), startStyle->backgroundColor()));
+}
+
+void RenderTextControl::createSubtreeIfNeeded(TextControlInnerElement* innerBlock)
+{
+ if (!m_innerText) {
+ // Create the text block element
+ // For non-search fields, there is no intermediate innerBlock as the shadow node.
+ // m_innerText will be the shadow node in that case.
+ RenderStyle* parentStyle = innerBlock ? innerBlock->renderer()->style() : style();
+ m_innerText = new TextControlInnerTextElement(document(), innerBlock ? 0 : node());
+ m_innerText->attachInnerElement(innerBlock ? innerBlock : node(), createInnerTextStyle(parentStyle), renderArena());
+ }
+}
+
+int RenderTextControl::textBlockHeight() const
+{
+ return m_height - paddingTop() - paddingBottom() - borderTop() - borderBottom();
+}
+
+int RenderTextControl::textBlockWidth() const
+{
+ return m_width - paddingLeft() - paddingRight() - borderLeft() - borderRight()
+ - m_innerText->renderer()->paddingLeft() - m_innerText->renderer()->paddingRight();
+}
+
+void RenderTextControl::updateFromElement()
+{
+ m_innerText->renderer()->style()->setUserModify((node()->isReadOnlyControl() || !node()->isEnabled()) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);
+}
+
+void RenderTextControl::setInnerTextValue(const String& innerTextValue)
+{
+ String value;
+
+ if (innerTextValue.isNull())
+ value = "";
+ else {
+ value = innerTextValue;
+ value = value.replace('\\', backslashAsCurrencySymbol());
+ }
+
+ if (value != text() || !m_innerText->hasChildNodes()) {
+ if (value != text()) {
+ if (Frame* frame = document()->frame())
+ frame->editor()->clearUndoRedoOperations();
+ }
+
+ ExceptionCode ec = 0;
+ m_innerText->setInnerText(value, ec);
+ ASSERT(!ec);
+
+ if (value.endsWith("\n") || value.endsWith("\r")) {
+ m_innerText->appendChild(new HTMLBRElement(brTag, document()), ec);
+ ASSERT(!ec);
+ }
+
+ m_edited = false;
+ m_userEdited = false;
+ }
+
+ formControlElement()->setValueMatchesRenderer();
+}
+
+void RenderTextControl::setUserEdited(bool isUserEdited)
+{
+ m_userEdited = isUserEdited;
+ document()->setIgnoreAutofocus(isUserEdited);
+}
+
+int RenderTextControl::selectionStart()
+{
+ Frame* frame = document()->frame();
+ if (!frame)
+ return 0;
+ return indexForVisiblePosition(frame->selection()->start());
+}
+
+int RenderTextControl::selectionEnd()
+{
+ Frame* frame = document()->frame();
+ if (!frame)
+ return 0;
+ return indexForVisiblePosition(frame->selection()->end());
+}
+
+void RenderTextControl::setSelectionStart(int start)
+{
+ setSelectionRange(start, max(start, selectionEnd()));
+}
+
+void RenderTextControl::setSelectionEnd(int end)
+{
+ setSelectionRange(min(end, selectionStart()), end);
+}
+
+void RenderTextControl::select()
+{
+ setSelectionRange(0, text().length());
+}
+
+void RenderTextControl::setSelectionRange(int start, int end)
+{
+ end = max(end, 0);
+ start = min(max(start, 0), end);
+
+ document()->updateLayout();
+
+ if (style()->visibility() == HIDDEN || !m_innerText || !m_innerText->renderer() || !m_innerText->renderer()->height()) {
+ cacheSelection(start, end);
+ return;
+ }
+ VisiblePosition startPosition = visiblePositionForIndex(start);
+ VisiblePosition endPosition;
+ if (start == end)
+ endPosition = startPosition;
+ else
+ endPosition = visiblePositionForIndex(end);
+
+ ASSERT(startPosition.isNotNull() && endPosition.isNotNull());
+ ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node() && endPosition.deepEquivalent().node()->shadowAncestorNode() == node());
+
+ Selection newSelection = Selection(startPosition, endPosition);
+
+ if (Frame* frame = document()->frame())
+ frame->selection()->setSelection(newSelection);
+
+ // FIXME: Granularity is stored separately on the frame, but also in the selection controller.
+ // The granularity in the selection controller should be used, and then this line of code would not be needed.
+ if (Frame* frame = document()->frame())
+ frame->setSelectionGranularity(CharacterGranularity);
+}
+
+Selection RenderTextControl::selection(int start, int end) const
+{
+ return Selection(VisiblePosition(m_innerText.get(), start, VP_DEFAULT_AFFINITY),
+ VisiblePosition(m_innerText.get(), end, VP_DEFAULT_AFFINITY));
+}
+
+VisiblePosition RenderTextControl::visiblePositionForIndex(int index)
+{
+ if (index <= 0)
+ return VisiblePosition(m_innerText.get(), 0, DOWNSTREAM);
+ ExceptionCode ec = 0;
+ RefPtr<Range> range = Range::create(document());
+ range->selectNodeContents(m_innerText.get(), ec);
+ ASSERT(!ec);
+ CharacterIterator it(range.get());
+ it.advance(index - 1);
+ Node* endContainer = it.range()->endContainer(ec);
+ ASSERT(!ec);
+ int endOffset = it.range()->endOffset(ec);
+ ASSERT(!ec);
+ return VisiblePosition(endContainer, endOffset, UPSTREAM);
+}
+
+int RenderTextControl::indexForVisiblePosition(const VisiblePosition& pos)
+{
+ Position indexPosition = pos.deepEquivalent();
+ if (!indexPosition.node() || indexPosition.node()->rootEditableElement() != m_innerText)
+ return 0;
+ ExceptionCode ec = 0;
+ RefPtr<Range> range = Range::create(document());
+ range->setStart(m_innerText.get(), 0, ec);
+ ASSERT(!ec);
+ range->setEnd(indexPosition.node(), indexPosition.offset(), ec);
+ ASSERT(!ec);
+ return TextIterator::rangeLength(range.get());
+}
+
+void RenderTextControl::subtreeHasChanged()
+{
+ m_edited = true;
+ m_userEdited = true;
+}
+
+String RenderTextControl::finishText(Vector<UChar>& result) const
+{
+ // 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')
+ result.shrink(--size);
+
+ // Convert backslash to currency symbol.
+ UChar symbol = backslashAsCurrencySymbol();
+ if (symbol != '\\') {
+ for (size_t i = 0; i < size; ++i) {
+ if (result[i] == '\\')
+ result[i] = symbol;
+ }
+ }
+
+ return String::adopt(result);
+}
+
+String RenderTextControl::text()
+{
+ if (!m_innerText)
+ return "";
+
+ Frame* frame = document()->frame();
+ Text* compositionNode = frame ? frame->editor()->compositionNode() : 0;
+
+ Vector<UChar> result;
+
+ for (Node* n = m_innerText.get(); n; n = n->traverseNextNode(m_innerText.get())) {
+ if (n->hasTagName(brTag))
+ result.append(&newlineCharacter, 1);
+ else if (n->isTextNode()) {
+ Text* text = static_cast<Text*>(n);
+ String data = text->data();
+ unsigned length = data.length();
+ if (text != compositionNode)
+ result.append(data.characters(), length);
+ else {
+ unsigned compositionStart = min(frame->editor()->compositionStart(), length);
+ unsigned compositionEnd = min(max(compositionStart, frame->editor()->compositionEnd()), length);
+ result.append(data.characters(), compositionStart);
+ result.append(data.characters() + compositionEnd, length - compositionEnd);
+ }
+ }
+ }
+
+ return finishText(result);
+}
+
+static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
+{
+ RootInlineBox* next;
+ for (; line; line = next) {
+ next = line->nextRootBox();
+ if (next && !line->endsWithBreak()) {
+ ASSERT(line->lineBreakObj());
+ breakNode = line->lineBreakObj()->node();
+ breakOffset = line->lineBreakPos();
+ line = next;
+ return;
+ }
+ }
+ breakNode = 0;
+}
+
+String RenderTextControl::textWithHardLineBreaks()
+{
+ if (!m_innerText)
+ return "";
+ Node* firstChild = m_innerText->firstChild();
+ if (!firstChild)
+ return "";
+
+ document()->updateLayout();
+
+ RenderObject* renderer = firstChild->renderer();
+ if (!renderer)
+ return "";
+
+ InlineBox* box = renderer->isText() ? static_cast<RenderText*>(renderer)->firstTextBox() : renderer->inlineBoxWrapper();
+ if (!box)
+ return "";
+
+ Frame* frame = document()->frame();
+ Text* compositionNode = frame ? frame->editor()->compositionNode() : 0;
+
+ Node* breakNode;
+ unsigned breakOffset;
+ RootInlineBox* line = box->root();
+ getNextSoftBreak(line, breakNode, breakOffset);
+
+ Vector<UChar> result;
+
+ for (Node* n = firstChild; n; n = n->traverseNextNode(m_innerText.get())) {
+ if (n->hasTagName(brTag))
+ result.append(&newlineCharacter, 1);
+ else if (n->isTextNode()) {
+ Text* text = static_cast<Text*>(n);
+ String data = text->data();
+ unsigned length = data.length();
+ unsigned compositionStart = (text == compositionNode)
+ ? min(frame->editor()->compositionStart(), length) : 0;
+ unsigned compositionEnd = (text == compositionNode)
+ ? min(max(compositionStart, frame->editor()->compositionEnd()), length) : 0;
+ unsigned position = 0;
+ while (breakNode == n && breakOffset < compositionStart) {
+ result.append(data.characters() + position, breakOffset - position);
+ position = breakOffset;
+ result.append(&newlineCharacter, 1);
+ getNextSoftBreak(line, breakNode, breakOffset);
+ }
+ result.append(data.characters() + position, compositionStart - position);
+ position = compositionEnd;
+ while (breakNode == n && breakOffset <= length) {
+ if (breakOffset > position) {
+ result.append(data.characters() + position, breakOffset - position);
+ position = breakOffset;
+ result.append(&newlineCharacter, 1);
+ }
+ getNextSoftBreak(line, breakNode, breakOffset);
+ }
+ result.append(data.characters() + position, length - position);
+ }
+ while (breakNode == n)
+ getNextSoftBreak(line, breakNode, breakOffset);
+ }
+
+ return finishText(result);
+}
+
+int RenderTextControl::scrollbarThickness() const
+{
+ // FIXME: We should get the size of the scrollbar from the RenderTheme instead.
+ return ScrollbarTheme::nativeTheme()->scrollbarThickness();
+}
+
+void RenderTextControl::calcHeight()
+{
+ m_height = m_innerText->renderer()->borderTop() + m_innerText->renderer()->borderBottom() +
+ m_innerText->renderer()->paddingTop() + m_innerText->renderer()->paddingBottom() +
+ m_innerText->renderer()->marginTop() + m_innerText->renderer()->marginBottom();
+
+ adjustControlHeightBasedOnLineHeight(m_innerText->renderer()->lineHeight(true, true));
+ m_height += paddingTop() + paddingBottom() + borderTop() + borderBottom();
+
+ // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap.
+ if (m_innerText->renderer()->style()->overflowX() == OSCROLL || (m_innerText->renderer()->style()->overflowX() == OAUTO && m_innerText->renderer()->style()->wordWrap() == NormalWordWrap))
+ m_height += scrollbarThickness();
+
+ RenderBlock::calcHeight();
+}
+
+void RenderTextControl::hitInnerTextBlock(HitTestResult& result, int x, int y, int tx, int ty)
+{
+ result.setInnerNode(m_innerText.get());
+ result.setLocalPoint(IntPoint(x - tx - m_x - m_innerText->renderer()->xPos(),
+ y - ty - m_y - m_innerText->renderer()->yPos()));
+}
+
+void RenderTextControl::forwardEvent(Event* event)
+{
+ if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)
+ return;
+ m_innerText->defaultEventHandler(event);
+}
+
+IntRect RenderTextControl::controlClipRect(int tx, int ty) const
+{
+ IntRect clipRect = contentBox();
+ clipRect.move(tx, ty);
+ return clipRect;
+}
+
+void RenderTextControl::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = 0;
+
+ if (style()->width().isFixed() && style()->width().value() > 0)
+ m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
+ else {
+ // Figure out how big a text control needs to be for a given number of characters
+ // (using "0" as the nominal character).
+ const UChar ch = '0';
+ float charWidth = style()->font().floatWidth(TextRun(&ch, 1, false, 0, 0, false, false, false));
+ m_maxPrefWidth = preferredContentWidth(charWidth) + m_innerText->renderer()->paddingLeft() + m_innerText->renderer()->paddingRight();
+ }
+
+ if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
+ m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
+ } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
+ m_minPrefWidth = 0;
+ else
+ m_minPrefWidth = m_maxPrefWidth;
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
+ m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
+ }
+
+ int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+
+ m_minPrefWidth += toAdd;
+ m_maxPrefWidth += toAdd;
+
+ setPrefWidthsDirty(false);
+}
+
+void RenderTextControl::selectionChanged(bool userTriggered)
+{
+ cacheSelection(selectionStart(), selectionEnd());
+
+ if (Frame* frame = document()->frame()) {
+ if (frame->selection()->isRange() && userTriggered)
+ static_cast<EventTargetNode*>(node())->dispatchEventForType(eventNames().selectEvent, true, false);
+ }
+}
+
+void RenderTextControl::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
+{
+ graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
+}
+
+void RenderTextControl::autoscroll()
+{
+ RenderLayer* layer = m_innerText->renderer()->layer();
+ if (layer)
+ layer->autoscroll();
+}
+
+int RenderTextControl::scrollWidth() const
+{
+ if (m_innerText)
+ return m_innerText->scrollWidth();
+ return RenderBlock::scrollWidth();
+}
+
+int RenderTextControl::scrollHeight() const
+{
+ if (m_innerText)
+ return m_innerText->scrollHeight();
+ return RenderBlock::scrollHeight();
+}
+
+int RenderTextControl::scrollLeft() const
+{
+ if (m_innerText)
+ return m_innerText->scrollLeft();
+ return RenderBlock::scrollLeft();
+}
+
+int RenderTextControl::scrollTop() const
+{
+ if (m_innerText)
+ return m_innerText->scrollTop();
+ return RenderBlock::scrollTop();
+}
+
+void RenderTextControl::setScrollLeft(int newLeft)
+{
+ if (m_innerText)
+ m_innerText->setScrollLeft(newLeft);
+}
+
+void RenderTextControl::setScrollTop(int newTop)
+{
+ if (m_innerText)
+ m_innerText->setScrollTop(newTop);
+}
+
+bool RenderTextControl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
+{
+ RenderLayer* layer = m_innerText->renderer()->layer();
+ if (layer && layer->scroll(direction, granularity, multiplier))
+ return true;
+ return RenderObject::scroll(direction, granularity, multiplier);
+}
+
+bool RenderTextControl::isScrollable() const
+{
+ if (m_innerText && m_innerText->renderer()->isScrollable())
+ return true;
+ return RenderObject::isScrollable();
+}
+
+HTMLElement* RenderTextControl::innerTextElement() const
+{
+ return m_innerText.get();
+}
+
+FormControlElement* RenderTextControl::formControlElement() const
+{
+ if (node()->isHTMLElement())
+ return static_cast<HTMLFormControlElement*>(node());
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h
new file mode 100644
index 0000000..40f5116
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControl.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2008 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
+ * 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 RenderTextControl_h
+#define RenderTextControl_h
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class FormControlElement;
+class Selection;
+class TextControlInnerElement;
+class TextControlInnerTextElement;
+
+class RenderTextControl : public RenderBlock {
+public:
+ virtual ~RenderTextControl();
+
+ virtual const char* renderName() const { return "RenderTextControl"; }
+ virtual bool hasControlClip() const { return false; }
+ virtual IntRect controlClipRect(int tx, int ty) const;
+ virtual void calcHeight();
+ virtual void calcPrefWidths();
+ virtual void removeLeftoverAnonymousBlock(RenderBlock*) { }
+ virtual void updateFromElement();
+ virtual bool canHaveChildren() const { return false; }
+ virtual bool avoidsFloats() const { return true; }
+
+ virtual bool isEdited() const { return m_edited; }
+ virtual void setEdited(bool isEdited) { m_edited = isEdited; }
+
+ bool isUserEdited() const { return m_userEdited; }
+ void setUserEdited(bool isUserEdited);
+
+ int selectionStart();
+ int selectionEnd();
+ void setSelectionStart(int);
+ void setSelectionEnd(int);
+ void select();
+ void setSelectionRange(int start, int end);
+ Selection selection(int start, int end) const;
+
+ virtual void subtreeHasChanged();
+ String text();
+ String textWithHardLineBreaks();
+ void selectionChanged(bool userTriggered);
+
+ virtual void addFocusRingRects(GraphicsContext*, int tx, int ty);
+
+ virtual bool canBeProgramaticallyScrolled(bool) const { return true; }
+ virtual void autoscroll();
+
+ // Subclassed to forward to our inner div.
+ virtual int scrollLeft() const;
+ virtual int scrollTop() const;
+ virtual int scrollWidth() const;
+ virtual int scrollHeight() const;
+ virtual void setScrollLeft(int);
+ virtual void setScrollTop(int);
+ virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f);
+ virtual bool isScrollable() const;
+
+ VisiblePosition visiblePositionForIndex(int index);
+ int indexForVisiblePosition(const VisiblePosition&);
+
+protected:
+ RenderTextControl(Node*);
+
+ int scrollbarThickness() const;
+ void adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle* textBlockStyle) const;
+ void setInnerTextValue(const String&);
+
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ void createSubtreeIfNeeded(TextControlInnerElement* innerBlock);
+ void hitInnerTextBlock(HitTestResult&, int x, int y, int tx, int ty);
+ void forwardEvent(Event*);
+
+ int textBlockWidth() const;
+ int textBlockHeight() const;
+
+ virtual int preferredContentWidth(float charWidth) const = 0;
+ virtual void adjustControlHeightBasedOnLineHeight(int lineHeight) = 0;
+ virtual void cacheSelection(int start, int end) = 0;
+ virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const = 0;
+
+ friend class TextIterator;
+ HTMLElement* innerTextElement() const;
+
+ FormControlElement* formControlElement() const;
+
+private:
+ String finishText(Vector<UChar>&) const;
+
+ bool m_edited;
+ bool m_userEdited;
+ RefPtr<TextControlInnerTextElement> m_innerText;
+};
+
+} // namespace WebCore
+
+#endif // RenderTextControl_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp
new file mode 100644
index 0000000..f860524
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.cpp
@@ -0,0 +1,157 @@
+/**
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2008 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
+ * 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 "RenderTextControlMultiLine.h"
+
+#include "EventNames.h"
+#include "Frame.h"
+#include "HitTestResult.h"
+#include "HTMLTextAreaElement.h"
+
+namespace WebCore {
+
+RenderTextControlMultiLine::RenderTextControlMultiLine(Node* node)
+ : RenderTextControl(node)
+{
+}
+
+RenderTextControlMultiLine::~RenderTextControlMultiLine()
+{
+ if (node())
+ static_cast<HTMLTextAreaElement*>(node())->rendererWillBeDestroyed();
+}
+
+void RenderTextControlMultiLine::subtreeHasChanged()
+{
+ RenderTextControl::subtreeHasChanged();
+ formControlElement()->setValueMatchesRenderer(false);
+
+ if (!node()->focused())
+ return;
+
+ if (Frame* frame = document()->frame())
+ frame->textDidChangeInTextArea(static_cast<Element*>(node()));
+}
+
+void RenderTextControlMultiLine::layout()
+{
+ int oldHeight = m_height;
+ calcHeight();
+
+ int oldWidth = m_width;
+ calcWidth();
+
+ bool relayoutChildren = oldHeight != m_height || oldWidth != m_width;
+ RenderObject* innerTextRenderer = innerTextElement()->renderer();
+
+ // Set the text block height
+ int desiredHeight = textBlockHeight();
+ if (desiredHeight != innerTextRenderer->height())
+ relayoutChildren = true;
+ innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed));
+
+ // Set the text block width
+ int desiredWidth = textBlockWidth();
+ if (desiredWidth != innerTextRenderer->width())
+ relayoutChildren = true;
+ innerTextRenderer->style()->setWidth(Length(desiredWidth, Fixed));
+
+ RenderBlock::layoutBlock(relayoutChildren);
+}
+
+bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
+{
+ if (!RenderTextControl::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction))
+ return false;
+
+ if (result.innerNode() == element()) {
+ hitInnerTextBlock(result, x, y, tx, ty);
+ return true;
+ }
+
+ return false;
+}
+
+void RenderTextControlMultiLine::forwardEvent(Event* event)
+{
+ RenderTextControl::forwardEvent(event);
+}
+
+int RenderTextControlMultiLine::preferredContentWidth(float charWidth) const
+{
+ int factor = static_cast<HTMLTextAreaElement*>(node())->cols();
+ return static_cast<int>(ceilf(charWidth * factor)) + scrollbarThickness();
+}
+
+void RenderTextControlMultiLine::adjustControlHeightBasedOnLineHeight(int lineHeight)
+{
+ m_height += lineHeight * static_cast<HTMLTextAreaElement*>(node())->rows();
+}
+
+int RenderTextControlMultiLine::baselinePosition(bool, bool) const
+{
+ return height() + marginTop() + marginBottom();
+}
+
+void RenderTextControlMultiLine::updateFromElement()
+{
+ createSubtreeIfNeeded(0);
+ RenderTextControl::updateFromElement();
+
+ setInnerTextValue(static_cast<HTMLTextAreaElement*>(node())->value());
+}
+
+void RenderTextControlMultiLine::cacheSelection(int start, int end)
+{
+ static_cast<HTMLTextAreaElement*>(node())->cacheSelection(start, end);
+}
+
+PassRefPtr<RenderStyle> RenderTextControlMultiLine::createInnerTextStyle(const RenderStyle* startStyle) const
+{
+ RefPtr<RenderStyle> textBlockStyle = RenderStyle::create();
+ textBlockStyle->inheritFrom(startStyle);
+
+ adjustInnerTextStyle(startStyle, textBlockStyle.get());
+
+ // Forward overflow properties.
+ textBlockStyle->setOverflowX(startStyle->overflowX() == OVISIBLE ? OAUTO : startStyle->overflowX());
+ textBlockStyle->setOverflowY(startStyle->overflowY() == OVISIBLE ? OAUTO : startStyle->overflowY());
+
+ // Set word wrap property based on wrap attribute.
+ if (static_cast<HTMLTextAreaElement*>(node())->shouldWrapText()) {
+ textBlockStyle->setWhiteSpace(PRE_WRAP);
+ textBlockStyle->setWordWrap(BreakWordWrap);
+ } else {
+ textBlockStyle->setWhiteSpace(PRE);
+ textBlockStyle->setWordWrap(NormalWordWrap);
+ }
+
+ textBlockStyle->setDisplay(BLOCK);
+
+ // We're adding three extra pixels of padding to line textareas up with text fields.
+ textBlockStyle->setPaddingLeft(Length(3, Fixed));
+ textBlockStyle->setPaddingRight(Length(3, Fixed));
+
+ return textBlockStyle.release();
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h
new file mode 100644
index 0000000..591a65d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlMultiLine.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 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
+ * 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 RenderTextControlMultiLine_h
+#define RenderTextControlMultiLine_h
+
+#include "RenderTextControl.h"
+
+namespace WebCore {
+
+class RenderTextControlMultiLine : public RenderTextControl {
+public:
+ RenderTextControlMultiLine(Node*);
+ virtual ~RenderTextControlMultiLine();
+
+ virtual bool isTextArea() const { return true; }
+
+ virtual void subtreeHasChanged();
+ virtual void layout();
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+ void forwardEvent(Event*);
+
+private:
+ virtual int preferredContentWidth(float charWidth) const;
+ virtual void adjustControlHeightBasedOnLineHeight(int lineHeight);
+ virtual int baselinePosition(bool firstLine, bool isRootLineBox) const;
+
+ virtual void updateFromElement();
+ virtual void cacheSelection(int start, int end);
+
+ virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const;
+};
+
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp
new file mode 100644
index 0000000..4f52527
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.cpp
@@ -0,0 +1,759 @@
+/**
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2008 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
+ * 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 "RenderTextControlSingleLine.h"
+
+#include "CSSStyleSelector.h"
+#include "Event.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "HitTestResult.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "LocalizedStrings.h"
+#include "MouseEvent.h"
+#include "PlatformKeyboardEvent.h"
+#include "RenderScrollbar.h"
+#include "RenderTheme.h"
+#include "SearchPopupMenu.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "TextControlInnerElements.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderTextControlSingleLine::RenderTextControlSingleLine(Node* node)
+ : RenderTextControl(node)
+ , m_placeholderVisible(false)
+ , m_searchPopupIsVisible(false)
+ , m_shouldDrawCapsLockIndicator(false)
+ , m_searchEventTimer(this, &RenderTextControlSingleLine::searchEventTimerFired)
+ , m_searchPopup(0)
+{
+}
+
+RenderTextControlSingleLine::~RenderTextControlSingleLine()
+{
+ if (m_searchPopup) {
+ m_searchPopup->disconnectClient();
+ m_searchPopup = 0;
+ }
+
+ if (m_innerBlock)
+ m_innerBlock->detach();
+}
+
+bool RenderTextControlSingleLine::placeholderShouldBeVisible() const
+{
+ return static_cast<HTMLInputElement*>(node())->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();
+}
+
+void RenderTextControlSingleLine::addSearchResult()
+{
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ if (input->maxResults() <= 0)
+ return;
+
+ String value = input->value();
+ if (value.isEmpty())
+ return;
+
+ Settings* settings = document()->settings();
+ if (!settings || settings->privateBrowsingEnabled())
+ return;
+
+ int size = static_cast<int>(m_recentSearches.size());
+ for (int i = size - 1; i >= 0; --i) {
+ if (m_recentSearches[i] == value)
+ m_recentSearches.remove(i);
+ }
+
+ m_recentSearches.insert(0, value);
+ while (static_cast<int>(m_recentSearches.size()) > input->maxResults())
+ m_recentSearches.removeLast();
+
+ const AtomicString& name = autosaveName();
+ if (!m_searchPopup)
+ m_searchPopup = SearchPopupMenu::create(this);
+
+ m_searchPopup->saveRecentSearches(name, m_recentSearches);
+}
+
+void RenderTextControlSingleLine::stopSearchEventTimer()
+{
+ m_searchEventTimer.stop();
+}
+
+void RenderTextControlSingleLine::showPopup()
+{
+ if (m_searchPopupIsVisible)
+ return;
+
+ if (!m_searchPopup)
+ m_searchPopup = SearchPopupMenu::create(this);
+
+ if (!m_searchPopup->enabled())
+ return;
+
+ m_searchPopupIsVisible = true;
+
+ const AtomicString& name = autosaveName();
+ m_searchPopup->loadRecentSearches(name, m_recentSearches);
+
+ // Trim the recent searches list if the maximum size has changed since we last saved.
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ if (static_cast<int>(m_recentSearches.size()) > input->maxResults()) {
+ do {
+ m_recentSearches.removeLast();
+ } while (static_cast<int>(m_recentSearches.size()) > input->maxResults());
+
+ m_searchPopup->saveRecentSearches(name, m_recentSearches);
+ }
+
+ m_searchPopup->show(absoluteBoundingBoxRect(true), document()->view(), -1);
+}
+
+void RenderTextControlSingleLine::hidePopup()
+{
+ if (m_searchPopup)
+ m_searchPopup->hide();
+
+ m_searchPopupIsVisible = false;
+}
+
+void RenderTextControlSingleLine::subtreeHasChanged()
+{
+ bool wasEdited = isEdited();
+ RenderTextControl::subtreeHasChanged();
+
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ input->setValueFromRenderer(input->constrainValue(text()));
+
+ if (RenderObject* cancelButtonRenderer = m_cancelButton ? m_cancelButton->renderer() : 0)
+ updateCancelButtonVisibility(cancelButtonRenderer->style());
+
+ // If the incremental attribute is set, then dispatch the search event
+ if (!input->getAttribute(incrementalAttr).isNull())
+ startSearchEventTimer();
+
+ if (!wasEdited && input->focused()) {
+ if (Frame* frame = document()->frame())
+ frame->textFieldDidBeginEditing(input);
+ }
+
+ if (input->focused()) {
+ if (Frame* frame = document()->frame())
+ frame->textDidChangeInTextField(input);
+ }
+}
+
+void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ RenderTextControl::paint(paintInfo, tx, ty);
+
+ if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) {
+ IntRect contentsRect = contentBox();
+
+ // Convert the rect into the coords used for painting the content
+ contentsRect.move(tx + xPos(), ty + yPos());
+ theme()->paintCapsLockIndicator(this, paintInfo, contentsRect);
+ }
+}
+
+void RenderTextControlSingleLine::layout()
+{
+ int oldHeight = m_height;
+ calcHeight();
+
+ int oldWidth = m_width;
+ calcWidth();
+
+ bool relayoutChildren = oldHeight != m_height || oldWidth != m_width;
+
+ RenderObject* innerTextRenderer = innerTextElement()->renderer();
+ RenderObject* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderer() : 0;
+
+ // Set the text block height
+ int desiredHeight = textBlockHeight();
+ int currentHeight = innerTextRenderer->height();
+
+ if (m_innerBlock || currentHeight > m_height) {
+ if (desiredHeight != currentHeight)
+ relayoutChildren = true;
+ innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed));
+ }
+
+ if (m_innerBlock) {
+ ASSERT(innerBlockRenderer);
+ if (desiredHeight != innerBlockRenderer->height())
+ relayoutChildren = true;
+ innerBlockRenderer->style()->setHeight(Length(desiredHeight, Fixed));
+ }
+
+ // Set the text block width
+ int desiredWidth = textBlockWidth();
+ if (desiredWidth != innerTextRenderer->width())
+ relayoutChildren = true;
+ innerTextRenderer->style()->setWidth(Length(desiredWidth, Fixed));
+
+ if (m_innerBlock) {
+ int innerBlockWidth = m_width - paddingLeft() - paddingRight() - borderLeft() - borderRight();
+ if (innerBlockWidth != innerBlockRenderer->width())
+ relayoutChildren = true;
+ innerBlockRenderer->style()->setWidth(Length(innerBlockWidth, Fixed));
+ }
+
+ RenderBlock::layoutBlock(relayoutChildren);
+
+ // For text fields, center the inner text vertically
+ // Don't do this for search fields, since we don't honor height for them
+ if (!m_innerBlock) {
+ currentHeight = innerTextRenderer->height();
+ if (currentHeight < m_height)
+ innerTextRenderer->setPos(innerTextRenderer->xPos(), (m_height - currentHeight) / 2);
+ }
+}
+
+bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
+{
+ // If we're within the text control, we want to act as if we've hit the inner text block element, in case the point
+ // was on the control but not on the inner element (see Radar 4617841).
+
+ // In a search field, we want to act as if we've hit the results block if we're to the left of the inner text block,
+ // and act as if we've hit the close block if we're to the right of the inner text block.
+
+ if (!RenderTextControl::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction))
+ return false;
+
+ if (result.innerNode() != element() && result.innerNode() != m_innerBlock.get())
+ return false;
+
+ hitInnerTextBlock(result, x, y, tx, ty);
+
+ if (!m_innerBlock)
+ return true;
+
+ Node* innerNode = 0;
+ RenderObject* innerBlockRenderer = m_innerBlock->renderer();
+ RenderObject* innerTextRenderer = innerTextElement()->renderer();
+
+ IntPoint localPoint = result.localPoint();
+ localPoint.move(-innerBlockRenderer->xPos(), -innerBlockRenderer->yPos());
+
+ int textLeft = tx + m_x + innerBlockRenderer->xPos() + innerTextRenderer->xPos();
+ if (m_resultsButton && m_resultsButton->renderer() && x < textLeft)
+ innerNode = m_resultsButton.get();
+
+ if (!innerNode) {
+ int textRight = textLeft + innerTextRenderer->width();
+ if (m_cancelButton && m_cancelButton->renderer() && x > textRight)
+ innerNode = m_cancelButton.get();
+ }
+
+ if (innerNode) {
+ result.setInnerNode(innerNode);
+ localPoint.move(-innerNode->renderer()->xPos(), -innerNode->renderer()->yPos());
+ }
+
+ result.setLocalPoint(localPoint);
+ return true;
+}
+
+void RenderTextControlSingleLine::forwardEvent(Event* event)
+{
+ RenderObject* innerTextRenderer = innerTextElement()->renderer();
+
+ if (event->type() == eventNames().blurEvent) {
+ if (innerTextRenderer) {
+ if (RenderLayer* innerLayer = innerTextRenderer->layer())
+ innerLayer->scrollToOffset(style()->direction() == RTL ? innerLayer->scrollWidth() : 0, 0);
+ }
+
+ capsLockStateMayHaveChanged();
+ } else if (event->type() == eventNames().focusEvent)
+ capsLockStateMayHaveChanged();
+
+ if (!event->isMouseEvent()) {
+ RenderTextControl::forwardEvent(event);
+ return;
+ }
+
+ FloatPoint localPoint = innerTextRenderer->absoluteToLocal(FloatPoint(static_cast<MouseEvent*>(event)->pageX(), static_cast<MouseEvent*>(event)->pageY()), false, true);
+ if (m_resultsButton && localPoint.x() < innerTextRenderer->borderBox().x())
+ m_resultsButton->defaultEventHandler(event);
+ else if (m_cancelButton && localPoint.x() > innerTextRenderer->borderBox().right())
+ m_cancelButton->defaultEventHandler(event);
+ else
+ RenderTextControl::forwardEvent(event);
+}
+
+void RenderTextControlSingleLine::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderTextControl::styleDidChange(diff, oldStyle);
+
+ if (RenderObject* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderer() : 0) {
+ // We may have set the width and the height in the old style in layout().
+ // Reset them now to avoid getting a spurious layout hint.
+ innerBlockRenderer->style()->setHeight(Length());
+ innerBlockRenderer->style()->setWidth(Length());
+ innerBlockRenderer->setStyle(createInnerBlockStyle(style()));
+ }
+
+ if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0)
+ resultsRenderer->setStyle(createResultsButtonStyle(style()));
+
+ if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0)
+ cancelRenderer->setStyle(createCancelButtonStyle(style()));
+}
+
+void RenderTextControlSingleLine::capsLockStateMayHaveChanged()
+{
+ if (!node() || !document())
+ return;
+
+ // Only draw the caps lock indicator if these things are true:
+ // 1) The field is a password field
+ // 2) The frame is active
+ // 3) The element is focused
+ // 4) The caps lock is on
+ bool shouldDrawCapsLockIndicator = false;
+
+ if (Frame* frame = document()->frame())
+ shouldDrawCapsLockIndicator = static_cast<HTMLInputElement*>(node())->inputType() == HTMLInputElement::PASSWORD
+ && frame->selection()->isFocusedAndActive()
+ && document()->focusedNode() == node()
+ && PlatformKeyboardEvent::currentCapsLockState();
+
+ if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) {
+ m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator;
+ repaint();
+ }
+}
+
+int RenderTextControlSingleLine::textBlockWidth() const
+{
+ int width = RenderTextControl::textBlockWidth();
+
+ if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0) {
+ resultsRenderer->calcWidth();
+ width -= resultsRenderer->width();
+ }
+
+ if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) {
+ cancelRenderer->calcWidth();
+ width -= cancelRenderer->width();
+ }
+
+ return width;
+}
+
+int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const
+{
+ int factor = static_cast<HTMLInputElement*>(node())->size();
+ if (factor <= 0)
+ factor = 20;
+
+ int result = static_cast<int>(ceilf(charWidth * factor));
+
+ if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0)
+ result += resultsRenderer->borderLeft() + resultsRenderer->borderRight() +
+ resultsRenderer->paddingLeft() + resultsRenderer->paddingRight();
+
+ if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0)
+ result += cancelRenderer->borderLeft() + cancelRenderer->borderRight() +
+ cancelRenderer->paddingLeft() + cancelRenderer->paddingRight();
+
+ return result;
+}
+
+void RenderTextControlSingleLine::adjustControlHeightBasedOnLineHeight(int lineHeight)
+{
+ if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0) {
+ static_cast<RenderBlock*>(resultsRenderer)->calcHeight();
+ m_height = max(m_height,
+ resultsRenderer->borderTop() + resultsRenderer->borderBottom() +
+ resultsRenderer->paddingTop() + resultsRenderer->paddingBottom() +
+ resultsRenderer->marginTop() + resultsRenderer->marginBottom());
+ lineHeight = max(lineHeight, resultsRenderer->height());
+ }
+
+ if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) {
+ static_cast<RenderBlock*>(cancelRenderer)->calcHeight();
+ m_height = max(m_height,
+ cancelRenderer->borderTop() + cancelRenderer->borderBottom() +
+ cancelRenderer->paddingTop() + cancelRenderer->paddingBottom() +
+ cancelRenderer->marginTop() + cancelRenderer->marginBottom());
+ lineHeight = max(lineHeight, cancelRenderer->height());
+ }
+
+ m_height += lineHeight;
+}
+
+void RenderTextControlSingleLine::createSubtreeIfNeeded()
+{
+ if (!static_cast<HTMLInputElement*>(node())->isSearchField()) {
+ RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get());
+ return;
+ }
+
+ if (!m_innerBlock) {
+ // Create the inner block element
+ m_innerBlock = new TextControlInnerElement(document(), node());
+ m_innerBlock->attachInnerElement(node(), createInnerBlockStyle(style()), renderArena());
+ }
+
+ if (!m_resultsButton) {
+ // Create the search results button element
+ m_resultsButton = new SearchFieldResultsButtonElement(document());
+ m_resultsButton->attachInnerElement(m_innerBlock.get(), createResultsButtonStyle(m_innerBlock->renderer()->style()), renderArena());
+ }
+
+ // Create innerText element before adding the cancel button
+ RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get());
+
+ if (!m_cancelButton) {
+ // Create the cancel button element
+ m_cancelButton = new SearchFieldCancelButtonElement(document());
+ m_cancelButton->attachInnerElement(m_innerBlock.get(), createCancelButtonStyle(m_innerBlock->renderer()->style()), renderArena());
+ }
+}
+
+void RenderTextControlSingleLine::updateFromElement()
+{
+ createSubtreeIfNeeded();
+ RenderTextControl::updateFromElement();
+
+ bool placeholderVisibilityShouldChange = m_placeholderVisible != placeholderShouldBeVisible();
+ m_placeholderVisible = placeholderShouldBeVisible();
+
+ if (RenderObject* cancelButtonRenderer = m_cancelButton ? m_cancelButton->renderer() : 0)
+ updateCancelButtonVisibility(cancelButtonRenderer->style());
+
+ HTMLInputElement* element = static_cast<HTMLInputElement*>(node());
+
+ if (m_placeholderVisible) {
+ ExceptionCode ec = 0;
+ innerTextElement()->setInnerText(element->getAttribute(placeholderAttr), ec);
+ ASSERT(ec == 0);
+ } else if (!formControlElement()->valueMatchesRenderer() || placeholderVisibilityShouldChange)
+ setInnerTextValue(element->value());
+
+ if (m_searchPopupIsVisible)
+ m_searchPopup->updateFromElement();
+}
+
+void RenderTextControlSingleLine::cacheSelection(int start, int end)
+{
+ static_cast<HTMLInputElement*>(node())->cacheSelection(start, end);
+}
+
+PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const
+{
+ RefPtr<RenderStyle> textBlockStyle;
+ if (placeholderShouldBeVisible()) {
+ RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::INPUT_PLACEHOLDER);
+ textBlockStyle = RenderStyle::clone(pseudoStyle);
+ } else {
+ textBlockStyle = RenderStyle::create();
+ textBlockStyle->inheritFrom(startStyle);
+ }
+
+ adjustInnerTextStyle(startStyle, textBlockStyle.get());
+
+ textBlockStyle->setWhiteSpace(PRE);
+ textBlockStyle->setWordWrap(NormalWordWrap);
+ textBlockStyle->setOverflowX(OHIDDEN);
+ textBlockStyle->setOverflowY(OHIDDEN);
+
+ // Do not allow line-height to be smaller than our default.
+ if (textBlockStyle->font().lineSpacing() > lineHeight(true, true))
+ textBlockStyle->setLineHeight(Length(-100.0f, Percent));
+
+ textBlockStyle->setDisplay(m_innerBlock ? INLINE_BLOCK : BLOCK);
+
+ // We're adding one extra pixel of padding to match WinIE.
+ textBlockStyle->setPaddingLeft(Length(1, Fixed));
+ textBlockStyle->setPaddingRight(Length(1, Fixed));
+
+ // When the placeholder is going to be displayed, temporarily override the text security to be "none".
+ // 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())
+ textBlockStyle->setTextSecurity(TSNONE);
+
+ return textBlockStyle.release();
+}
+
+PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const RenderStyle* startStyle) const
+{
+ RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create();
+ innerBlockStyle->inheritFrom(startStyle);
+
+ innerBlockStyle->setDisplay(BLOCK);
+ innerBlockStyle->setDirection(LTR);
+
+ // We don't want the shadow dom to be editable, so we set this block to read-only in case the input itself is editable.
+ innerBlockStyle->setUserModify(READ_ONLY);
+
+ return innerBlockStyle.release();
+}
+
+PassRefPtr<RenderStyle> RenderTextControlSingleLine::createResultsButtonStyle(const RenderStyle* startStyle) const
+{
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+
+ RefPtr<RenderStyle> resultsBlockStyle;
+ if (input->maxResults() < 0)
+ resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_DECORATION);
+ else if (!input->maxResults())
+ resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_RESULTS_DECORATION);
+ else
+ resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_RESULTS_BUTTON);
+
+ if (!resultsBlockStyle)
+ resultsBlockStyle = RenderStyle::create();
+
+ if (startStyle)
+ resultsBlockStyle->inheritFrom(startStyle);
+
+ return resultsBlockStyle.release();
+}
+
+PassRefPtr<RenderStyle> RenderTextControlSingleLine::createCancelButtonStyle(const RenderStyle* startStyle) const
+{
+ RefPtr<RenderStyle> cancelBlockStyle;
+
+ if (RefPtr<RenderStyle> pseudoStyle = getCachedPseudoStyle(RenderStyle::SEARCH_CANCEL_BUTTON))
+ // We may be sharing style with another search field, but we must not share the cancel button style.
+ cancelBlockStyle = RenderStyle::clone(pseudoStyle.get());
+ else
+ cancelBlockStyle = RenderStyle::create();
+
+ if (startStyle)
+ cancelBlockStyle->inheritFrom(startStyle);
+
+ updateCancelButtonVisibility(cancelBlockStyle.get());
+ return cancelBlockStyle.release();
+}
+
+void RenderTextControlSingleLine::updateCancelButtonVisibility(RenderStyle* style) const
+{
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ style->setVisibility(input->value().isEmpty() ? HIDDEN : VISIBLE);
+}
+
+const AtomicString& RenderTextControlSingleLine::autosaveName() const
+{
+ return static_cast<Element*>(node())->getAttribute(autosaveAttr);
+}
+
+void RenderTextControlSingleLine::startSearchEventTimer()
+{
+ unsigned length = text().length();
+
+ // If there's no text, fire the event right away.
+ if (!length) {
+ stopSearchEventTimer();
+ static_cast<HTMLInputElement*>(node())->onSearch();
+ return;
+ }
+
+ // After typing the first key, we wait 0.5 seconds.
+ // After the second key, 0.4 seconds, then 0.3, then 0.2 from then on.
+ m_searchEventTimer.startOneShot(max(0.2, 0.6 - 0.1 * length));
+}
+
+void RenderTextControlSingleLine::searchEventTimerFired(Timer<RenderTextControlSingleLine>*)
+{
+ static_cast<HTMLInputElement*>(node())->onSearch();
+}
+
+// PopupMenuClient methods
+void RenderTextControlSingleLine::valueChanged(unsigned listIndex, bool fireEvents)
+{
+ ASSERT(static_cast<int>(listIndex) < listSize());
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
+ if (static_cast<int>(listIndex) == (listSize() - 1)) {
+ if (fireEvents) {
+ m_recentSearches.clear();
+ const AtomicString& name = autosaveName();
+ if (!name.isEmpty()) {
+ if (!m_searchPopup)
+ m_searchPopup = SearchPopupMenu::create(this);
+ m_searchPopup->saveRecentSearches(name, m_recentSearches);
+ }
+ }
+ } else {
+ input->setValue(itemText(listIndex));
+ if (fireEvents)
+ input->onSearch();
+ input->select();
+ }
+}
+
+String RenderTextControlSingleLine::itemText(unsigned listIndex) const
+{
+ int size = listSize();
+ if (size == 1) {
+ ASSERT(!listIndex);
+ return searchMenuNoRecentSearchesText();
+ }
+ if (!listIndex)
+ return searchMenuRecentSearchesText();
+ if (itemIsSeparator(listIndex))
+ return String();
+ if (static_cast<int>(listIndex) == (size - 1))
+ return searchMenuClearRecentSearchesText();
+ return m_recentSearches[listIndex - 1];
+}
+
+bool RenderTextControlSingleLine::itemIsEnabled(unsigned listIndex) const
+{
+ if (!listIndex || itemIsSeparator(listIndex))
+ return false;
+ return true;
+}
+
+PopupMenuStyle RenderTextControlSingleLine::itemStyle(unsigned) const
+{
+ return menuStyle();
+}
+
+PopupMenuStyle RenderTextControlSingleLine::menuStyle() const
+{
+ return PopupMenuStyle(style()->color(), style()->backgroundColor(), style()->font(), style()->visibility() == VISIBLE);
+}
+
+int RenderTextControlSingleLine::clientInsetLeft() const
+{
+ // Inset the menu by the radius of the cap on the left so that
+ // it only runs along the straight part of the bezel.
+ return height() / 2;
+}
+
+int RenderTextControlSingleLine::clientInsetRight() const
+{
+ // Inset the menu by the radius of the cap on the right so that
+ // it only runs along the straight part of the bezel (unless it needs
+ // to be wider).
+ return height() / 2;
+}
+
+int RenderTextControlSingleLine::clientPaddingLeft() const
+{
+ int padding = clientPaddingLeft();
+
+ if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0)
+ padding += resultsRenderer->width();
+
+ return padding;
+}
+
+int RenderTextControlSingleLine::clientPaddingRight() const
+{
+ int padding = clientPaddingRight();
+
+ if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0)
+ padding += cancelRenderer->width();
+
+ return padding;
+}
+
+int RenderTextControlSingleLine::listSize() const
+{
+ // If there are no recent searches, then our menu will have 1 "No recent searches" item.
+ if (!m_recentSearches.size())
+ return 1;
+ // Otherwise, leave room in the menu for a header, a separator, and the "Clear recent searches" item.
+ return m_recentSearches.size() + 3;
+}
+
+int RenderTextControlSingleLine::selectedIndex() const
+{
+ return -1;
+}
+
+bool RenderTextControlSingleLine::itemIsSeparator(unsigned listIndex) const
+{
+ // The separator will be the second to last item in our list.
+ return static_cast<int>(listIndex) == (listSize() - 2);
+}
+
+bool RenderTextControlSingleLine::itemIsLabel(unsigned listIndex) const
+{
+ return listIndex == 0;
+}
+
+bool RenderTextControlSingleLine::itemIsSelected(unsigned) const
+{
+ return false;
+}
+
+void RenderTextControlSingleLine::setTextFromItem(unsigned listIndex)
+{
+ static_cast<HTMLInputElement*>(node())->setValue(itemText(listIndex));
+}
+
+FontSelector* RenderTextControlSingleLine::fontSelector() const
+{
+ return document()->styleSelector()->fontSelector();
+}
+
+HostWindow* RenderTextControlSingleLine::hostWindow() const
+{
+ return document()->view()->hostWindow();
+}
+
+PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
+{
+ RefPtr<Scrollbar> widget;
+ bool hasCustomScrollbarStyle = style()->hasPseudoStyle(RenderStyle::SCROLLBAR);
+ if (hasCustomScrollbarStyle)
+ widget = RenderScrollbar::createCustomScrollbar(client, orientation, this);
+ else
+ widget = Scrollbar::createNativeScrollbar(client, orientation, controlSize);
+ return widget.release();
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h
new file mode 100644
index 0000000..a0d8d68
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextControlSingleLine.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2008 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
+ * 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 RenderTextControlSingleLine_h
+#define RenderTextControlSingleLine_h
+
+#include "PopupMenuClient.h"
+#include "RenderTextControl.h"
+#include "Timer.h"
+
+namespace WebCore {
+
+class SearchFieldCancelButtonElement;
+class SearchFieldResultsButtonElement;
+class SearchPopupMenu;
+class TextControlInnerElement;
+
+class RenderTextControlSingleLine : public RenderTextControl, private PopupMenuClient {
+public:
+ RenderTextControlSingleLine(Node*);
+ virtual ~RenderTextControlSingleLine();
+
+ virtual bool hasControlClip() const { return m_cancelButton; }
+ virtual bool isTextField() const { return true; }
+
+ 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
+
+ virtual void subtreeHasChanged();
+ virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void layout();
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+ void forwardEvent(Event*);
+
+private:
+ virtual void capsLockStateMayHaveChanged();
+
+ int textBlockWidth() const;
+ virtual int preferredContentWidth(float charWidth) const;
+ virtual void adjustControlHeightBasedOnLineHeight(int lineHeight);
+
+ void createSubtreeIfNeeded();
+ virtual void updateFromElement();
+ virtual void cacheSelection(int start, int end);
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+ virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const;
+ PassRefPtr<RenderStyle> createInnerBlockStyle(const RenderStyle* startStyle) const;
+ PassRefPtr<RenderStyle> createResultsButtonStyle(const RenderStyle* startStyle) const;
+ PassRefPtr<RenderStyle> createCancelButtonStyle(const RenderStyle* startStyle) const;
+
+ void updateCancelButtonVisibility(RenderStyle*) const;
+ const AtomicString& autosaveName() const;
+
+ void startSearchEventTimer();
+ void searchEventTimerFired(Timer<RenderTextControlSingleLine>*);
+
+private:
+ // PopupMenuClient methods
+ virtual void valueChanged(unsigned listIndex, bool fireEvents = true);
+ virtual String itemText(unsigned listIndex) const;
+ virtual bool itemIsEnabled(unsigned listIndex) const;
+ virtual PopupMenuStyle itemStyle(unsigned listIndex) const;
+ virtual PopupMenuStyle menuStyle() const;
+ virtual int clientInsetLeft() const;
+ virtual int clientInsetRight() const;
+ virtual int clientPaddingLeft() const;
+ virtual int clientPaddingRight() const;
+ virtual int listSize() const;
+ virtual int selectedIndex() const;
+ virtual bool itemIsSeparator(unsigned listIndex) const;
+ virtual bool itemIsLabel(unsigned listIndex) const;
+ virtual bool itemIsSelected(unsigned listIndex) const;
+ virtual bool shouldPopOver() const { return false; }
+ virtual bool valueShouldChangeOnHotTrack() const { return false; }
+ virtual void setTextFromItem(unsigned listIndex);
+ virtual FontSelector* fontSelector() const;
+ virtual HostWindow* hostWindow() const;
+ virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize);
+
+private:
+ bool m_placeholderVisible;
+ bool m_searchPopupIsVisible;
+ bool m_shouldDrawCapsLockIndicator;
+
+ RefPtr<TextControlInnerElement> m_innerBlock;
+ RefPtr<SearchFieldResultsButtonElement> m_resultsButton;
+ RefPtr<SearchFieldCancelButtonElement> m_cancelButton;
+
+ Timer<RenderTextControlSingleLine> m_searchEventTimer;
+ RefPtr<SearchPopupMenu> m_searchPopup;
+ Vector<String> m_recentSearches;
+};
+
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp
new file mode 100644
index 0000000..c8beba0
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.cpp
@@ -0,0 +1,87 @@
+/*
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 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 "RenderTextFragment.h"
+
+#include "Text.h"
+
+namespace WebCore {
+
+RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str, int startOffset, int length)
+ : RenderText(node, str ? str->substring(startOffset, length) : 0)
+ , m_start(startOffset)
+ , m_end(length)
+ , m_firstLetter(0)
+{
+}
+
+RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str)
+ : RenderText(node, str)
+ , m_start(0)
+ , m_end(str ? str->length() : 0)
+ , m_contentString(str)
+ , m_firstLetter(0)
+{
+}
+
+PassRefPtr<StringImpl> RenderTextFragment::originalText() const
+{
+ Node* e = element();
+ RefPtr<StringImpl> result = (e ? static_cast<Text*>(e)->string() : contentString());
+ if (result && (start() > 0 || start() < result->length()))
+ result = result->substring(start(), end());
+ return result.release();
+}
+
+void RenderTextFragment::destroy()
+{
+ if (m_firstLetter)
+ m_firstLetter->destroy();
+ RenderText::destroy();
+}
+
+void RenderTextFragment::setTextInternal(PassRefPtr<StringImpl> text)
+{
+ RenderText::setTextInternal(text);
+ if (m_firstLetter) {
+ ASSERT(!m_contentString);
+ m_firstLetter->destroy();
+ m_firstLetter = 0;
+ m_start = 0;
+ m_end = textLength();
+ }
+}
+
+UChar RenderTextFragment::previousCharacter()
+{
+ if (start()) {
+ Node* e = element();
+ StringImpl* original = (e ? static_cast<Text*>(e)->string() : contentString());
+ if (original)
+ return (*original)[start() - 1];
+ }
+
+ return RenderText::previousCharacter();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.h b/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.h
new file mode 100644
index 0000000..1fa509a
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTextFragment.h
@@ -0,0 +1,64 @@
+/*
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 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 RenderTextFragment_h
+#define RenderTextFragment_h
+
+#include "RenderText.h"
+
+namespace WebCore {
+
+// Used to represent a text substring of an element, e.g., for text runs that are split because of
+// first letter and that must therefore have different styles (and positions in the render tree).
+// We cache offsets so that text transformations can be applied in such a way that we can recover
+// the original unaltered string from our corresponding DOM node.
+class RenderTextFragment : public RenderText {
+public:
+ RenderTextFragment(Node*, StringImpl*, int startOffset, int length);
+ RenderTextFragment(Node*, StringImpl*);
+
+ virtual bool isTextFragment() const { return true; }
+
+ virtual void destroy();
+
+ unsigned start() const { return m_start; }
+ unsigned end() const { return m_end; }
+
+ RenderObject* firstLetter() const { return m_firstLetter; }
+ void setFirstLetter(RenderObject* firstLetter) { m_firstLetter = firstLetter; }
+
+ StringImpl* contentString() const { return m_contentString.get(); }
+ virtual PassRefPtr<StringImpl> originalText() const;
+
+private:
+ virtual void setTextInternal(PassRefPtr<StringImpl>);
+ virtual UChar previousCharacter();
+
+ unsigned m_start;
+ unsigned m_end;
+ RefPtr<StringImpl> m_contentString;
+ RenderObject* m_firstLetter;
+};
+
+} // namespace WebCore
+
+#endif // RenderTextFragment_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp
new file mode 100644
index 0000000..aa18407
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.cpp
@@ -0,0 +1,776 @@
+/**
+ * This file is part of the theme implementation for form controls in WebCore.
+ *
+ * Copyright (C) 2005, 2006, 2007, 2008 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
+ * 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 "RenderTheme.h"
+
+#include "CSSValueKeywords.h"
+#include "Document.h"
+#include "FocusController.h"
+#include "FontSelector.h"
+#include "Frame.h"
+#include "GraphicsContext.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "Page.h"
+#include "RenderStyle.h"
+#include "RenderView.h"
+#include "SelectionController.h"
+#include "Settings.h"
+
+// The methods in this file are shared by all themes on every platform.
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderTheme::RenderTheme()
+#if USE(NEW_THEME)
+ : m_theme(platformTheme())
+#endif
+{
+}
+
+void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e,
+ bool UAHasAppearance, const BorderData& border, const FillLayer& background, const Color& backgroundColor)
+{
+ // Force inline and table display styles to be inline-block (except for table- which is block)
+ ControlPart part = style->appearance();
+ if (style->display() == INLINE || style->display() == INLINE_TABLE || style->display() == TABLE_ROW_GROUP ||
+ style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_FOOTER_GROUP ||
+ style->display() == TABLE_ROW || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_COLUMN ||
+ style->display() == TABLE_CELL || style->display() == TABLE_CAPTION)
+ style->setDisplay(INLINE_BLOCK);
+ else if (style->display() == COMPACT || style->display() == RUN_IN || style->display() == LIST_ITEM || style->display() == TABLE)
+ style->setDisplay(BLOCK);
+
+ if (UAHasAppearance && theme()->isControlStyled(style, border, background, backgroundColor)) {
+ if (part == MenulistPart) {
+ style->setAppearance(MenulistButtonPart);
+ part = MenulistButtonPart;
+ } else
+ style->setAppearance(NoControlPart);
+ }
+
+ if (!style->hasAppearance())
+ return;
+
+ // Never support box-shadow on native controls.
+ style->setBoxShadow(0);
+
+#if USE(NEW_THEME)
+ switch (part) {
+ case CheckboxPart:
+ case RadioPart:
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart: {
+ // Border
+ LengthBox borderBox(style->borderTopWidth(), style->borderRightWidth(), style->borderBottomWidth(), style->borderLeftWidth());
+ borderBox = m_theme->controlBorder(part, style->font(), borderBox, style->effectiveZoom());
+ if (borderBox.top().value() != style->borderTopWidth()) {
+ if (borderBox.top().value())
+ style->setBorderTopWidth(borderBox.top().value());
+ else
+ style->resetBorderTop();
+ }
+ if (borderBox.right().value() != style->borderRightWidth()) {
+ if (borderBox.right().value())
+ style->setBorderRightWidth(borderBox.right().value());
+ else
+ style->resetBorderRight();
+ }
+ if (borderBox.bottom().value() != style->borderBottomWidth()) {
+ style->setBorderBottomWidth(borderBox.bottom().value());
+ if (borderBox.bottom().value())
+ style->setBorderBottomWidth(borderBox.bottom().value());
+ else
+ style->resetBorderBottom();
+ }
+ if (borderBox.left().value() != style->borderLeftWidth()) {
+ style->setBorderLeftWidth(borderBox.left().value());
+ if (borderBox.left().value())
+ style->setBorderLeftWidth(borderBox.left().value());
+ else
+ style->resetBorderLeft();
+ }
+
+ // Padding
+ LengthBox paddingBox = m_theme->controlPadding(part, style->font(), style->paddingBox(), style->effectiveZoom());
+ if (paddingBox != style->paddingBox())
+ style->setPaddingBox(paddingBox);
+
+ // Whitespace
+ if (m_theme->controlRequiresPreWhiteSpace(part))
+ style->setWhiteSpace(PRE);
+
+ // Width / Height
+ // The width and height here are affected by the zoom.
+ // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
+ LengthSize controlSize = m_theme->controlSize(part, style->font(), LengthSize(style->width(), style->height()), style->effectiveZoom());
+ if (controlSize.width() != style->width())
+ style->setWidth(controlSize.width());
+ if (controlSize.height() != style->height())
+ style->setHeight(controlSize.height());
+
+ // Min-Width / Min-Height
+ LengthSize minControlSize = m_theme->minimumControlSize(part, style->font(), style->effectiveZoom());
+ if (minControlSize.width() != style->minWidth())
+ style->setMinWidth(minControlSize.width());
+ if (minControlSize.height() != style->minHeight())
+ style->setMinHeight(minControlSize.height());
+
+ // Font
+ FontDescription controlFont = m_theme->controlFont(part, style->font(), style->effectiveZoom());
+ if (controlFont != style->font().fontDescription()) {
+ // Reset our line-height
+ style->setLineHeight(RenderStyle::initialLineHeight());
+
+ // Now update our font.
+ if (style->setFontDescription(controlFont))
+ style->font().update(0);
+ }
+ }
+ default:
+ break;
+ }
+#endif
+
+ // Call the appropriate style adjustment method based off the appearance value.
+ switch (style->appearance()) {
+#if !USE(NEW_THEME)
+ case CheckboxPart:
+ return adjustCheckboxStyle(selector, style, e);
+ case RadioPart:
+ return adjustRadioStyle(selector, style, e);
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ return adjustButtonStyle(selector, style, e);
+#endif
+ case TextFieldPart:
+ return adjustTextFieldStyle(selector, style, e);
+ case TextAreaPart:
+ return adjustTextAreaStyle(selector, style, e);
+ case MenulistPart:
+ return adjustMenuListStyle(selector, style, e);
+ case MenulistButtonPart:
+ return adjustMenuListButtonStyle(selector, style, e);
+ case MediaSliderPart:
+ case SliderHorizontalPart:
+ case SliderVerticalPart:
+ return adjustSliderTrackStyle(selector, style, e);
+ case SliderThumbHorizontalPart:
+ case SliderThumbVerticalPart:
+ return adjustSliderThumbStyle(selector, style, e);
+ case SearchFieldPart:
+ return adjustSearchFieldStyle(selector, style, e);
+ case SearchFieldCancelButtonPart:
+ return adjustSearchFieldCancelButtonStyle(selector, style, e);
+ case SearchFieldDecorationPart:
+ return adjustSearchFieldDecorationStyle(selector, style, e);
+ case SearchFieldResultsDecorationPart:
+ return adjustSearchFieldResultsDecorationStyle(selector, style, e);
+ case SearchFieldResultsButtonPart:
+ return adjustSearchFieldResultsButtonStyle(selector, style, e);
+ default:
+ break;
+ }
+}
+
+bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ // If painting is disabled, but we aren't updating control tints, then just bail.
+ // If we are updating control tints, just schedule a repaint if the theme supports tinting
+ // for that control.
+ if (paintInfo.context->updatingControlTints()) {
+ if (controlSupportsTints(o))
+ o->repaint();
+ return false;
+ }
+ if (paintInfo.context->paintingDisabled())
+ return false;
+
+ ControlPart part = o->style()->appearance();
+
+#if USE(NEW_THEME)
+ switch (part) {
+ case CheckboxPart:
+ case RadioPart:
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ m_theme->paint(part, controlStatesForRenderer(o), const_cast<GraphicsContext*>(paintInfo.context), r, o->style()->effectiveZoom(), o->view()->frameView());
+ return false;
+ default:
+ break;
+ }
+#endif
+
+ // Call the appropriate paint method based off the appearance value.
+ switch (part) {
+#if !USE(NEW_THEME)
+ case CheckboxPart:
+ return paintCheckbox(o, paintInfo, r);
+ case RadioPart:
+ return paintRadio(o, paintInfo, r);
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ return paintButton(o, paintInfo, r);
+#endif
+ case MenulistPart:
+ return paintMenuList(o, paintInfo, r);
+ case SliderHorizontalPart:
+ case SliderVerticalPart:
+ return paintSliderTrack(o, paintInfo, r);
+ case SliderThumbHorizontalPart:
+ case SliderThumbVerticalPart:
+ if (o->parent()->isSlider())
+ return paintSliderThumb(o, paintInfo, r);
+ // We don't support drawing a slider thumb without a parent slider
+ break;
+ case MediaFullscreenButtonPart:
+ return paintMediaFullscreenButton(o, paintInfo, r);
+ case MediaPlayButtonPart:
+ return paintMediaPlayButton(o, paintInfo, r);
+ case MediaMuteButtonPart:
+ return paintMediaMuteButton(o, paintInfo, r);
+ case MediaSeekBackButtonPart:
+ return paintMediaSeekBackButton(o, paintInfo, r);
+ case MediaSeekForwardButtonPart:
+ return paintMediaSeekForwardButton(o, paintInfo, r);
+ case MediaSliderPart:
+ return paintMediaSliderTrack(o, paintInfo, r);
+ case MediaSliderThumbPart:
+ if (o->parent()->isSlider())
+ return paintMediaSliderThumb(o, paintInfo, r);
+ break;
+ case MenulistButtonPart:
+ case TextFieldPart:
+ case TextAreaPart:
+ case ListboxPart:
+ return true;
+ case SearchFieldPart:
+ return paintSearchField(o, paintInfo, r);
+ case SearchFieldCancelButtonPart:
+ return paintSearchFieldCancelButton(o, paintInfo, r);
+ case SearchFieldDecorationPart:
+ return paintSearchFieldDecoration(o, paintInfo, r);
+ case SearchFieldResultsDecorationPart:
+ return paintSearchFieldResultsDecoration(o, paintInfo, r);
+ case SearchFieldResultsButtonPart:
+ return paintSearchFieldResultsButton(o, paintInfo, r);
+ default:
+ break;
+ }
+
+ return true; // We don't support the appearance, so let the normal background/border paint.
+}
+
+bool RenderTheme::paintBorderOnly(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ if (paintInfo.context->paintingDisabled())
+ return false;
+
+ // Call the appropriate paint method based off the appearance value.
+ switch (o->style()->appearance()) {
+ case TextFieldPart:
+ return paintTextField(o, paintInfo, r);
+ case ListboxPart:
+ case TextAreaPart:
+ return paintTextArea(o, paintInfo, r);
+ case MenulistButtonPart:
+ return true;
+ case CheckboxPart:
+ case RadioPart:
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ case MenulistPart:
+ case SliderHorizontalPart:
+ case SliderVerticalPart:
+ case SliderThumbHorizontalPart:
+ case SliderThumbVerticalPart:
+ case SearchFieldPart:
+ case SearchFieldCancelButtonPart:
+ case SearchFieldDecorationPart:
+ case SearchFieldResultsDecorationPart:
+ case SearchFieldResultsButtonPart:
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool RenderTheme::paintDecorations(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ if (paintInfo.context->paintingDisabled())
+ return false;
+
+ // Call the appropriate paint method based off the appearance value.
+ switch (o->style()->appearance()) {
+ case MenulistButtonPart:
+ return paintMenuListButton(o, paintInfo, r);
+ case TextFieldPart:
+ case TextAreaPart:
+ case ListboxPart:
+ case CheckboxPart:
+ case RadioPart:
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ case MenulistPart:
+ case SliderHorizontalPart:
+ case SliderVerticalPart:
+ case SliderThumbHorizontalPart:
+ case SliderThumbVerticalPart:
+ case SearchFieldPart:
+ case SearchFieldCancelButtonPart:
+ case SearchFieldDecorationPart:
+ case SearchFieldResultsDecorationPart:
+ case SearchFieldResultsButtonPart:
+ default:
+ break;
+ }
+
+ return false;
+}
+
+#if ENABLE(VIDEO)
+bool RenderTheme::hitTestMediaControlPart(RenderObject* o, const IntPoint& absPoint)
+{
+ FloatPoint localPoint = o->absoluteToLocal(absPoint, false, true); // respect transforms
+
+ return o->borderBox().contains(roundedIntPoint(localPoint));
+}
+#endif
+
+Color RenderTheme::activeSelectionBackgroundColor() const
+{
+ if (!m_activeSelectionColor.isValid())
+ m_activeSelectionColor = platformActiveSelectionBackgroundColor().blendWithWhite();
+ return m_activeSelectionColor;
+}
+
+Color RenderTheme::inactiveSelectionBackgroundColor() const
+{
+ if (!m_inactiveSelectionColor.isValid())
+ m_inactiveSelectionColor = platformInactiveSelectionBackgroundColor().blendWithWhite();
+ return m_inactiveSelectionColor;
+}
+
+Color RenderTheme::platformActiveSelectionBackgroundColor() const
+{
+ // Use a blue color by default if the platform theme doesn't define anything.
+ return Color(0, 0, 255);
+}
+
+Color RenderTheme::platformInactiveSelectionBackgroundColor() const
+{
+ // Use a grey color by default if the platform theme doesn't define anything.
+ return Color(128, 128, 128);
+}
+
+Color RenderTheme::platformActiveSelectionForegroundColor() const
+{
+ return Color();
+}
+
+Color RenderTheme::platformInactiveSelectionForegroundColor() const
+{
+ return Color();
+}
+
+Color RenderTheme::activeListBoxSelectionBackgroundColor() const
+{
+ return activeSelectionBackgroundColor();
+}
+
+Color RenderTheme::activeListBoxSelectionForegroundColor() const
+{
+ // Use a white color by default if the platform theme doesn't define anything.
+ return Color(255, 255, 255);
+}
+
+Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const
+{
+ return inactiveSelectionBackgroundColor();
+}
+
+Color RenderTheme::inactiveListBoxSelectionForegroundColor() const
+{
+ // Use a black color by default if the platform theme doesn't define anything.
+ return Color(0, 0, 0);
+}
+
+int RenderTheme::baselinePosition(const RenderObject* o) const
+{
+#if USE(NEW_THEME)
+ return o->height() + o->marginTop() + m_theme->baselinePositionAdjustment(o->style()->appearance()) * o->style()->effectiveZoom();
+#else
+ return o->height() + o->marginTop();
+#endif
+}
+
+bool RenderTheme::isControlContainer(ControlPart appearance) const
+{
+ // There are more leaves than this, but we'll patch this function as we add support for
+ // more controls.
+ return appearance != CheckboxPart && appearance != RadioPart;
+}
+
+bool RenderTheme::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& background,
+ const Color& backgroundColor) const
+{
+ switch (style->appearance()) {
+ case PushButtonPart:
+ case SquareButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart:
+ case ListboxPart:
+ case MenulistPart:
+ // FIXME: Uncomment this when making search fields style-able.
+ // case SearchFieldPart:
+ case TextFieldPart:
+ case TextAreaPart:
+ // Test the style to see if the UA border and background match.
+ return (style->border() != border ||
+ *style->backgroundLayers() != background ||
+ style->backgroundColor() != backgroundColor);
+ default:
+ return false;
+ }
+}
+
+void RenderTheme::adjustRepaintRect(const RenderObject* o, IntRect& r)
+{
+#if USE(NEW_THEME)
+ m_theme->inflateControlPaintRect(o->style()->appearance(), controlStatesForRenderer(o), r, o->style()->effectiveZoom());
+#endif
+}
+
+bool RenderTheme::supportsFocusRing(const RenderStyle* style) const
+{
+ return (style->hasAppearance() && style->appearance() != TextFieldPart && style->appearance() != TextAreaPart && style->appearance() != MenulistButtonPart && style->appearance() != ListboxPart);
+}
+
+bool RenderTheme::stateChanged(RenderObject* o, ControlState state) const
+{
+ // Default implementation assumes the controls dont respond to changes in :hover state
+ if (state == HoverState && !supportsHover(o->style()))
+ return false;
+
+ // Assume pressed state is only responded to if the control is enabled.
+ if (state == PressedState && !isEnabled(o))
+ return false;
+
+ // Repaint the control.
+ o->repaint();
+ return true;
+}
+
+ControlStates RenderTheme::controlStatesForRenderer(const RenderObject* o) const
+{
+ ControlStates result = 0;
+ if (isHovered(o))
+ result |= HoverState;
+ if (isPressed(o))
+ result |= PressedState;
+ if (isFocused(o) && o->style()->outlineStyleIsAuto())
+ result |= FocusState;
+ if (isEnabled(o))
+ result |= EnabledState;
+ if (isChecked(o))
+ result |= CheckedState;
+ if (isReadOnlyControl(o))
+ result |= ReadOnlyState;
+ if (isDefault(o))
+ result |= DefaultState;
+ if (!isActive(o))
+ result |= WindowInactiveState;
+ if (isIndeterminate(o))
+ result |= IndeterminateState;
+ return result;
+}
+
+bool RenderTheme::isActive(const RenderObject* o) const
+{
+ Node* node = o->element();
+ if (!node)
+ return false;
+
+ Frame* frame = node->document()->frame();
+ if (!frame)
+ return false;
+
+ Page* page = frame->page();
+ if (!page)
+ return false;
+
+ return page->focusController()->isActive();
+}
+
+bool RenderTheme::isChecked(const RenderObject* o) const
+{
+ if (!o->element())
+ return false;
+ return o->element()->isChecked();
+}
+
+bool RenderTheme::isIndeterminate(const RenderObject* o) const
+{
+ if (!o->element())
+ return false;
+ return o->element()->isIndeterminate();
+}
+
+bool RenderTheme::isEnabled(const RenderObject* o) const
+{
+ if (!o->element())
+ return true;
+ return o->element()->isEnabled();
+}
+
+bool RenderTheme::isFocused(const RenderObject* o) const
+{
+ Node* node = o->element();
+ if (!node)
+ return false;
+ Document* document = node->document();
+ Frame* frame = document->frame();
+ return node == document->focusedNode() && frame && frame->selection()->isFocusedAndActive();
+}
+
+bool RenderTheme::isPressed(const RenderObject* o) const
+{
+ if (!o->element())
+ return false;
+ return o->element()->active();
+}
+
+bool RenderTheme::isReadOnlyControl(const RenderObject* o) const
+{
+ if (!o->element())
+ return false;
+ return o->element()->isReadOnlyControl();
+}
+
+bool RenderTheme::isHovered(const RenderObject* o) const
+{
+ if (!o->element())
+ return false;
+ return o->element()->hovered();
+}
+
+bool RenderTheme::isDefault(const RenderObject* o) const
+{
+ if (!o->document())
+ return false;
+
+ Settings* settings = o->document()->settings();
+ if (!settings || !settings->inApplicationChromeMode())
+ return false;
+
+ return o->style()->appearance() == DefaultButtonPart;
+}
+
+#if !USE(NEW_THEME)
+
+void RenderTheme::adjustCheckboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
+{
+ // A summary of the rules for checkbox designed to match WinIE:
+ // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
+ // font-size - not honored (control has no text), but we use it to decide which control size to use.
+ setCheckboxSize(style);
+
+ // padding - not honored by WinIE, needs to be removed.
+ style->resetPadding();
+
+ // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
+ // for now, we will not honor it.
+ style->resetBorder();
+
+ style->setBoxShadow(0);
+}
+
+void RenderTheme::adjustRadioStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
+{
+ // A summary of the rules for checkbox designed to match WinIE:
+ // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.)
+ // font-size - not honored (control has no text), but we use it to decide which control size to use.
+ setRadioSize(style);
+
+ // padding - not honored by WinIE, needs to be removed.
+ style->resetPadding();
+
+ // border - honored by WinIE, but looks terrible (just paints in the control box and turns off the Windows XP theme)
+ // for now, we will not honor it.
+ style->resetBorder();
+
+ style->setBoxShadow(0);
+}
+
+void RenderTheme::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
+{
+ // Most platforms will completely honor all CSS, and so we have no need to adjust the style
+ // at all by default. We will still allow the theme a crack at setting up a desired vertical size.
+ setButtonSize(style);
+}
+
+#endif
+
+void RenderTheme::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustButtonInnerStyle(RenderStyle*) const
+{
+}
+
+void RenderTheme::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustSliderThumbSize(RenderObject*) const
+{
+}
+
+void RenderTheme::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+void RenderTheme::platformColorsDidChange()
+{
+ m_activeSelectionColor = Color();
+ m_inactiveSelectionColor = Color();
+}
+
+Color RenderTheme::systemColor(int cssValueId) const
+{
+ switch (cssValueId) {
+ case CSSValueActiveborder:
+ return 0xFFFFFFFF;
+ case CSSValueActivecaption:
+ return 0xFFCCCCCC;
+ case CSSValueAppworkspace:
+ return 0xFFFFFFFF;
+ case CSSValueBackground:
+ return 0xFF6363CE;
+ case CSSValueButtonface:
+ return 0xFFC0C0C0;
+ case CSSValueButtonhighlight:
+ return 0xFFDDDDDD;
+ case CSSValueButtonshadow:
+ return 0xFF888888;
+ case CSSValueButtontext:
+ return 0xFF000000;
+ case CSSValueCaptiontext:
+ return 0xFF000000;
+ case CSSValueGraytext:
+ return 0xFF808080;
+ case CSSValueHighlight:
+ return 0xFFB5D5FF;
+ case CSSValueHighlighttext:
+ return 0xFF000000;
+ case CSSValueInactiveborder:
+ return 0xFFFFFFFF;
+ case CSSValueInactivecaption:
+ return 0xFFFFFFFF;
+ case CSSValueInactivecaptiontext:
+ return 0xFF7F7F7F;
+ case CSSValueInfobackground:
+ return 0xFFFBFCC5;
+ case CSSValueInfotext:
+ return 0xFF000000;
+ case CSSValueMenu:
+ return 0xFFC0C0C0;
+ case CSSValueMenutext:
+ return 0xFF000000;
+ case CSSValueScrollbar:
+ return 0xFFFFFFFF;
+ case CSSValueText:
+ return 0xFF000000;
+ case CSSValueThreeddarkshadow:
+ return 0xFF666666;
+ case CSSValueThreedface:
+ return 0xFFC0C0C0;
+ case CSSValueThreedhighlight:
+ return 0xFFDDDDDD;
+ case CSSValueThreedlightshadow:
+ return 0xFFC0C0C0;
+ case CSSValueThreedshadow:
+ return 0xFF888888;
+ case CSSValueWindow:
+ return 0xFFFFFFFF;
+ case CSSValueWindowframe:
+ return 0xFFCCCCCC;
+ case CSSValueWindowtext:
+ return 0xFF000000;
+ }
+ return Color();
+}
+
+Color RenderTheme::platformTextSearchHighlightColor() const
+{
+ return Color(255, 255, 0);
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h
new file mode 100644
index 0000000..f948936
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTheme.h
@@ -0,0 +1,234 @@
+/*
+ * This file is part of the theme implementation for form controls in WebCore.
+ *
+ * Copyright (C) 2005, 2006, 2007, 2008 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
+ * 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 RenderTheme_h
+#define RenderTheme_h
+
+#include "RenderObject.h"
+#if USE(NEW_THEME)
+#include "Theme.h"
+#else
+#include "ThemeTypes.h"
+#endif
+
+namespace WebCore {
+
+class Element;
+class PopupMenu;
+class RenderMenuList;
+class CSSStyleSheet;
+
+class RenderTheme {
+public:
+ RenderTheme();
+ virtual ~RenderTheme() { }
+
+ // This method is called whenever style has been computed for an element and the appearance
+ // property has been set to a value other than "none". The theme should map in all of the appropriate
+ // metrics and defaults given the contents of the style. This includes sophisticated operations like
+ // selection of control size based off the font, the disabling of appearance when certain other properties like
+ // "border" are set, or if the appearance is not supported by the theme.
+ void adjustStyle(CSSStyleSelector*, RenderStyle*, Element*, bool UAHasAppearance,
+ const BorderData&, const FillLayer&, const Color& backgroundColor);
+
+ // This method is called to paint the widget as a background of the RenderObject. A widget's foreground, e.g., the
+ // text of a button, is always rendered by the engine itself. The boolean return value indicates
+ // whether the CSS border/background should also be painted.
+ bool paint(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ bool paintBorderOnly(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ bool paintDecorations(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ // The remaining methods should be implemented by the platform-specific portion of the theme, e.g.,
+ // RenderThemeMac.cpp for Mac OS X.
+
+ // These methods return the theme's extra style sheets rules, to let each platform
+ // adjust the default CSS rules in html4.css, quirks.css, or mediaControls.css
+ virtual String extraDefaultStyleSheet() { return String(); }
+ virtual String extraQuirksStyleSheet() { return String(); }
+#if ENABLE(VIDEO)
+ virtual String extraMediaControlsStyleSheet() { return String(); };
+#endif
+
+ // 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;
+
+ // A method for asking if a control is a container or not. Leaf controls have to have some special behavior (like
+ // the baseline position API above).
+ bool isControlContainer(ControlPart) const;
+
+ // A method asking if the control changes its tint when the window has focus or not.
+ virtual bool controlSupportsTints(const RenderObject*) const { return false; }
+
+ // Whether or not the control has been styled enough by the author to disable the native appearance.
+ virtual bool isControlStyled(const RenderStyle*, const BorderData&, const FillLayer&, const Color& backgroundColor) const;
+
+ // A general method asking if any control tinting is supported at all.
+ virtual bool supportsControlTints() const { return false; }
+
+ // Some controls may spill out of their containers (e.g., the check on an OS X checkbox). When these controls repaint,
+ // the theme needs to communicate this inflated rect to the engine so that it can invalidate the whole control.
+ virtual void adjustRepaintRect(const RenderObject*, IntRect&);
+
+ // This method is called whenever a relevant state changes on a particular themed object, e.g., the mouse becomes pressed
+ // or a control becomes disabled.
+ virtual bool stateChanged(RenderObject*, ControlState) const;
+
+ // This method is called whenever the theme changes on the system in order to flush cached resources from the
+ // old theme.
+ virtual void themeChanged() { }
+
+ // A method asking if the theme is able to draw the focus ring.
+ virtual bool supportsFocusRing(const RenderStyle*) const;
+
+ // A method asking if the theme's controls actually care about redrawing when hovered.
+ virtual bool supportsHover(const RenderStyle*) const { return false; }
+
+ // The selection color.
+ Color activeSelectionBackgroundColor() const;
+ Color inactiveSelectionBackgroundColor() const;
+
+ virtual Color platformTextSearchHighlightColor() const;
+
+ // The platform selection color.
+ virtual Color platformActiveSelectionBackgroundColor() const;
+ virtual Color platformInactiveSelectionBackgroundColor() const;
+ virtual Color platformActiveSelectionForegroundColor() const;
+ virtual Color platformInactiveSelectionForegroundColor() const;
+
+ // List Box selection color
+ virtual Color activeListBoxSelectionBackgroundColor() const;
+ virtual Color activeListBoxSelectionForegroundColor() const;
+ virtual Color inactiveListBoxSelectionBackgroundColor() const;
+ virtual Color inactiveListBoxSelectionForegroundColor() const;
+
+ virtual void platformColorsDidChange();
+
+ virtual double caretBlinkInterval() const { return 0.5; }
+
+ // System fonts and colors for CSS.
+ virtual void systemFont(int cssValueId, FontDescription&) const = 0;
+ virtual Color systemColor(int cssValueId) const;
+
+ virtual int minimumMenuListSize(RenderStyle*) const { return 0; }
+
+ virtual void adjustButtonInnerStyle(RenderStyle*) const;
+ virtual void adjustSliderThumbSize(RenderObject*) const;
+
+ virtual int popupInternalPaddingLeft(RenderStyle*) const { return 0; }
+ virtual int popupInternalPaddingRight(RenderStyle*) const { return 0; }
+ virtual int popupInternalPaddingTop(RenderStyle*) const { return 0; }
+ virtual int popupInternalPaddingBottom(RenderStyle*) const { return 0; }
+
+ // Method for painting the caps lock indicator
+ virtual bool paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return 0; };
+
+#if ENABLE(VIDEO)
+ virtual bool hitTestMediaControlPart(RenderObject*, const IntPoint& absPoint);
+#endif
+
+protected:
+#if !USE(NEW_THEME)
+ // Methods for each appearance value.
+ virtual void adjustCheckboxStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual void setCheckboxSize(RenderStyle*) const { }
+
+ virtual void adjustRadioStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual void setRadioSize(RenderStyle*) const { }
+
+ virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual void setButtonSize(RenderStyle*) const { }
+#endif
+
+ virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual void adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldResultsDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+
+ virtual bool paintMediaFullscreenButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual bool paintMediaMuteButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ virtual bool paintMediaSeekBackButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; }
+ 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; }
+
+public:
+ // Methods for state querying
+ ControlStates controlStatesForRenderer(const RenderObject* o) const;
+ bool isActive(const RenderObject*) const;
+ bool isChecked(const RenderObject*) const;
+ bool isIndeterminate(const RenderObject*) const;
+ bool isEnabled(const RenderObject*) const;
+ bool isFocused(const RenderObject*) const;
+ bool isPressed(const RenderObject*) const;
+ bool isHovered(const RenderObject*) const;
+ bool isReadOnlyControl(const RenderObject*) const;
+ bool isDefault(const RenderObject*) const;
+
+private:
+ mutable Color m_activeSelectionColor;
+ mutable Color m_inactiveSelectionColor;
+#if USE(NEW_THEME)
+ Theme* m_theme; // The platform-specific theme.
+#endif
+};
+
+// Function to obtain the theme. This is implemented in your platform-specific theme implementation to hand
+// back the appropriate platform theme.
+RenderTheme* theme();
+
+} // namespace WebCore
+
+#endif // RenderTheme_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h
new file mode 100644
index 0000000..a1da7ff
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeMac.h
@@ -0,0 +1,177 @@
+/*
+ * This file is part of the theme implementation for form controls in WebCore.
+ *
+ * Copyright (C) 2005 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
+ * 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 RenderThemeMac_h
+#define RenderThemeMac_h
+
+#import "RenderTheme.h"
+#import <wtf/HashMap.h>
+#import <wtf/RetainPtr.h>
+
+#ifdef __OBJC__
+@class WebCoreRenderThemeNotificationObserver;
+#else
+class WebCoreRenderThemeNotificationObserver;
+#endif
+
+namespace WebCore {
+
+class RenderStyle;
+
+class RenderThemeMac : public RenderTheme {
+public:
+ RenderThemeMac();
+ virtual ~RenderThemeMac();
+
+ // 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 activeListBoxSelectionBackgroundColor() const;
+
+ 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&);
+
+ virtual Color systemColor(int cssValueId) const;
+
+protected:
+ 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:
+ 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;
+
+ // 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
+
+ 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;
+
+ bool m_isSliderThumbHorizontalPressed;
+ bool m_isSliderThumbVerticalPressed;
+
+ mutable HashMap<int, RGBA32> m_systemColorCache;
+
+ RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver;
+};
+
+} // namespace WebCore
+
+#endif // RenderThemeMac_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp
new file mode 100644
index 0000000..31315bc
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.cpp
@@ -0,0 +1,1235 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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
+ * 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 "RenderThemeSafari.h"
+#include "RenderThemeWin.h"
+#include "Settings.h"
+
+#if USE(SAFARI_THEME)
+
+#include "CSSValueKeywords.h"
+#include "Document.h"
+#include "Element.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLInputElement.h"
+#include "HTMLMediaElement.h"
+#include "HTMLNames.h"
+#include "RenderSlider.h"
+#include "RenderView.h"
+#include "RetainPtr.h"
+#include "SoftLinking.h"
+#include "cssstyleselector.h"
+#include <CoreGraphics/CoreGraphics.h>
+
+using std::min;
+
+// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeMac.
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace SafariTheme;
+
+enum {
+ topMargin,
+ rightMargin,
+ bottomMargin,
+ leftMargin
+};
+
+enum {
+ topPadding,
+ rightPadding,
+ bottomPadding,
+ leftPadding
+};
+
+RenderTheme* theme()
+{
+ static RenderThemeSafari safariTheme;
+ static RenderThemeWin windowsTheme;
+ if (Settings::shouldPaintNativeControls())
+ return &windowsTheme;
+ return &safariTheme;
+}
+
+#if !defined(NDEBUG) && defined(USE_DEBUG_SAFARI_THEME)
+SOFT_LINK_DEBUG_LIBRARY(SafariTheme)
+#else
+SOFT_LINK_LIBRARY(SafariTheme)
+#endif
+
+SOFT_LINK(SafariTheme, paintThemePart, void, __stdcall, (ThemePart part, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state), (part, context, rect, size, state))
+#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
+SOFT_LINK(SafariTheme, STPaintProgressIndicator, void, APIENTRY, (ProgressIndicatorType type, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state, float value), (type, context, rect, size, state, value))
+#endif
+
+ThemeControlState RenderThemeSafari::determineState(RenderObject* o) const
+{
+ ThemeControlState result = 0;
+ if (isActive(o))
+ result |= SafariTheme::ActiveState;
+ if (isEnabled(o) && !isReadOnlyControl(o))
+ result |= SafariTheme::EnabledState;
+ if (isPressed(o))
+ result |= SafariTheme::PressedState;
+ if (isChecked(o))
+ result |= SafariTheme::CheckedState;
+ if (isIndeterminate(o))
+ result |= SafariTheme::IndeterminateCheckedState;
+ if (isFocused(o))
+ result |= SafariTheme::FocusedState;
+ if (isDefault(o))
+ result |= SafariTheme::DefaultState;
+ return result;
+}
+
+static NSControlSize controlSizeFromRect(const IntRect& rect, const IntSize sizes[])
+{
+ if (sizes[NSRegularControlSize].height() == rect.height())
+ return NSRegularControlSize;
+ else if (sizes[NSMiniControlSize].height() == rect.height())
+ return NSMiniControlSize;
+
+ return NSSmallControlSize;
+}
+
+RenderThemeSafari::RenderThemeSafari()
+{
+}
+
+RenderThemeSafari::~RenderThemeSafari()
+{
+}
+
+Color RenderThemeSafari::platformActiveSelectionBackgroundColor() const
+{
+ return Color(181, 213, 255);
+}
+
+Color RenderThemeSafari::platformInactiveSelectionBackgroundColor() const
+{
+ return Color(212, 212, 212);
+}
+
+Color RenderThemeSafari::activeListBoxSelectionBackgroundColor() const
+{
+ // FIXME: This should probably just be a darker version of the platformActiveSelectionBackgroundColor
+ return Color(56, 117, 215);
+}
+
+static float systemFontSizeForControlSize(NSControlSize controlSize)
+{
+ static float sizes[] = { 13.0f, 11.0f, 9.0f };
+
+ return sizes[controlSize];
+}
+
+void RenderThemeSafari::systemFont(int propId, FontDescription& fontDescription) const
+{
+ static FontDescription systemFont;
+ static FontDescription smallSystemFont;
+ static FontDescription menuFont;
+ static FontDescription labelFont;
+ static FontDescription miniControlFont;
+ static FontDescription smallControlFont;
+ static FontDescription controlFont;
+
+ FontDescription* cachedDesc;
+ float fontSize = 0;
+ switch (propId) {
+ case CSSValueSmallCaption:
+ cachedDesc = &smallSystemFont;
+ if (!smallSystemFont.isAbsoluteSize())
+ fontSize = systemFontSizeForControlSize(NSSmallControlSize);
+ break;
+ case CSSValueMenu:
+ cachedDesc = &menuFont;
+ if (!menuFont.isAbsoluteSize())
+ fontSize = systemFontSizeForControlSize(NSRegularControlSize);
+ break;
+ case CSSValueStatusBar:
+ cachedDesc = &labelFont;
+ if (!labelFont.isAbsoluteSize())
+ fontSize = 10.0f;
+ break;
+ case CSSValueWebkitMiniControl:
+ cachedDesc = &miniControlFont;
+ if (!miniControlFont.isAbsoluteSize())
+ fontSize = systemFontSizeForControlSize(NSMiniControlSize);
+ break;
+ case CSSValueWebkitSmallControl:
+ cachedDesc = &smallControlFont;
+ if (!smallControlFont.isAbsoluteSize())
+ fontSize = systemFontSizeForControlSize(NSSmallControlSize);
+ break;
+ case CSSValueWebkitControl:
+ cachedDesc = &controlFont;
+ if (!controlFont.isAbsoluteSize())
+ fontSize = systemFontSizeForControlSize(NSRegularControlSize);
+ break;
+ default:
+ cachedDesc = &systemFont;
+ if (!systemFont.isAbsoluteSize())
+ fontSize = 13.0f;
+ }
+
+ if (fontSize) {
+ cachedDesc->setIsAbsoluteSize(true);
+ cachedDesc->setGenericFamily(FontDescription::NoFamily);
+ cachedDesc->firstFamily().setFamily("Lucida Grande");
+ cachedDesc->setSpecifiedSize(fontSize);
+ cachedDesc->setWeight(FontWeightNormal);
+ cachedDesc->setItalic(false);
+ }
+ fontDescription = *cachedDesc;
+}
+
+bool RenderThemeSafari::isControlStyled(const RenderStyle* style, const BorderData& border,
+ const FillLayer& background, const Color& backgroundColor) const
+{
+ // If we didn't find SafariTheme.dll we won't be able to paint any themed controls.
+ if (!SafariThemeLibrary())
+ return true;
+
+ if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart)
+ return style->border() != border;
+ return RenderTheme::isControlStyled(style, border, background, backgroundColor);
+}
+
+void RenderThemeSafari::adjustRepaintRect(const RenderObject* o, IntRect& r)
+{
+ NSControlSize controlSize = controlSizeForFont(o->style());
+
+ switch (o->style()->appearance()) {
+ case CheckboxPart: {
+ // 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.
+ r = inflateRect(r, checkboxSizes()[controlSize], checkboxMargins(controlSize));
+ break;
+ }
+ case RadioPart: {
+ // 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.
+ r = inflateRect(r, radioSizes()[controlSize], radioMargins(controlSize));
+ break;
+ }
+ case PushButtonPart:
+ case DefaultButtonPart:
+ case ButtonPart: {
+ // 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 (r.height() <= buttonSizes()[NSRegularControlSize].height())
+ r = inflateRect(r, buttonSizes()[controlSize], buttonMargins(controlSize));
+ break;
+ }
+ case MenulistPart: {
+ r = inflateRect(r, popupButtonSizes()[controlSize], popupButtonMargins(controlSize));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+IntRect RenderThemeSafari::inflateRect(const IntRect& r, const IntSize& size, const int* margins) const
+{
+ // 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] + margins[rightMargin]);
+ int heightDelta = r.height() - (size.height() + margins[topMargin] + margins[bottomMargin]);
+ IntRect result(r);
+ if (widthDelta < 0) {
+ result.setX(result.x() - margins[leftMargin]);
+ result.setWidth(result.width() - widthDelta);
+ }
+ if (heightDelta < 0) {
+ result.setY(result.y() - margins[topMargin]);
+ result.setHeight(result.height() - heightDelta);
+ }
+ return result;
+}
+
+int RenderThemeSafari::baselinePosition(const RenderObject* o) const
+{
+ if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart)
+ return o->marginTop() + o->height() - 2; // The baseline is 2px up from the bottom of the checkbox/radio in AppKit.
+ return RenderTheme::baselinePosition(o);
+}
+
+bool RenderThemeSafari::controlSupportsTints(const RenderObject* o) const
+{
+ if (!isEnabled(o))
+ return false;
+
+ // Checkboxes only have tint when checked.
+ if (o->style()->appearance() == CheckboxPart)
+ return isChecked(o);
+
+ // For now assume other controls have tint if enabled.
+ return true;
+}
+
+NSControlSize RenderThemeSafari::controlSizeForFont(RenderStyle* style) const
+{
+ int fontSize = style->fontSize();
+ if (fontSize >= 16)
+ return NSRegularControlSize;
+ if (fontSize >= 11)
+ return NSSmallControlSize;
+ return NSMiniControlSize;
+}
+/*
+void RenderThemeSafari::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize)
+{
+ NSControlSize size;
+ if (minSize.width() >= sizes[NSRegularControlSize].width() &&
+ minSize.height() >= sizes[NSRegularControlSize].height())
+ size = NSRegularControlSize;
+ else if (minSize.width() >= sizes[NSSmallControlSize].width() &&
+ minSize.height() >= sizes[NSSmallControlSize].height())
+ size = NSSmallControlSize;
+ else
+ size = NSMiniControlSize;
+ if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same.
+ [cell setControlSize:size];
+}
+*/
+IntSize RenderThemeSafari::sizeForFont(RenderStyle* style, const IntSize* sizes) const
+{
+ return sizes[controlSizeForFont(style)];
+}
+
+IntSize RenderThemeSafari::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const
+{
+ return sizes[controlSizeForSystemFont(style)];
+}
+
+void RenderThemeSafari::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const
+{
+ // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
+ IntSize size = sizeForFont(style, sizes);
+ if (style->width().isIntrinsicOrAuto() && size.width() > 0)
+ style->setWidth(Length(size.width(), Fixed));
+ if (style->height().isAuto() && size.height() > 0)
+ style->setHeight(Length(size.height(), Fixed));
+}
+
+void RenderThemeSafari::setFontFromControlSize(CSSStyleSelector* selector, RenderStyle* style, NSControlSize controlSize) const
+{
+ FontDescription fontDescription;
+ fontDescription.setIsAbsoluteSize(true);
+ fontDescription.setGenericFamily(FontDescription::SerifFamily);
+
+ float fontSize = systemFontSizeForControlSize(controlSize);
+ fontDescription.firstFamily().setFamily("Lucida Grande");
+ fontDescription.setComputedSize(fontSize);
+ fontDescription.setSpecifiedSize(fontSize);
+
+ // Reset line height
+ style->setLineHeight(RenderStyle::initialLineHeight());
+
+ if (style->setFontDescription(fontDescription))
+ style->font().update(selector->fontSelector());
+}
+
+NSControlSize RenderThemeSafari::controlSizeForSystemFont(RenderStyle* style) const
+{
+ int fontSize = style->fontSize();
+ if (fontSize >= 13)
+ return NSRegularControlSize;
+ if (fontSize >= 11)
+ return NSSmallControlSize;
+ return NSMiniControlSize;
+}
+
+bool RenderThemeSafari::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ ASSERT(SafariThemeLibrary());
+
+ NSControlSize controlSize = controlSizeForFont(o->style());
+
+ IntRect inflatedRect = inflateRect(r, checkboxSizes()[controlSize], checkboxMargins(controlSize));
+ paintThemePart(SafariTheme::CheckboxPart, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
+
+ return false;
+}
+
+const IntSize* RenderThemeSafari::checkboxSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) };
+ return sizes;
+}
+
+const int* RenderThemeSafari::checkboxMargins(NSControlSize controlSize) const
+{
+ static const int margins[3][4] =
+ {
+ { 2, 2, 2, 2 },
+ { 2, 2, 2, 1 },
+ { 1, 0, 0, 0 },
+ };
+ return margins[controlSize];
+}
+
+void RenderThemeSafari::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());
+}
+
+bool RenderThemeSafari::paintRadio(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ ASSERT(SafariThemeLibrary());
+
+ NSControlSize controlSize = controlSizeForFont(o->style());
+
+ IntRect inflatedRect = inflateRect(r, radioSizes()[controlSize], radioMargins(controlSize));
+ paintThemePart(RadioButtonPart, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
+
+ return false;
+}
+
+const IntSize* RenderThemeSafari::radioSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) };
+ return sizes;
+}
+
+const int* RenderThemeSafari::radioMargins(NSControlSize controlSize) const
+{
+ static const int margins[3][4] =
+ {
+ { 1, 2, 2, 2 },
+ { 0, 1, 2, 1 },
+ { 0, 0, 1, 0 },
+ };
+ return margins[controlSize];
+}
+
+void RenderThemeSafari::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());
+}
+
+void RenderThemeSafari::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->setPaddingLeft(Length(padding, Fixed));
+ style->setPaddingRight(Length(padding, Fixed));
+ style->setPaddingTop(Length(0, Fixed));
+ style->setPaddingBottom(Length(0, Fixed));
+}
+
+void RenderThemeSafari::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(15, Fixed));
+
+ // Reset the top and bottom borders.
+ style->resetBorderTop();
+ style->resetBorderBottom();
+ }
+}
+
+const IntSize* RenderThemeSafari::buttonSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
+ return sizes;
+}
+
+const int* RenderThemeSafari::buttonMargins(NSControlSize controlSize) const
+{
+ static const int margins[3][4] =
+ {
+ { 4, 6, 7, 6 },
+ { 4, 5, 6, 5 },
+ { 0, 1, 1, 1 },
+ };
+ return margins[controlSize];
+}
+
+void RenderThemeSafari::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());
+}
+
+bool RenderThemeSafari::paintButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ ASSERT(SafariThemeLibrary());
+
+ // 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.
+
+ NSControlSize controlSize = controlSizeFromRect(r, buttonSizes());
+ IntRect inflatedRect = r;
+
+ ThemePart part;
+ if (r.height() <= buttonSizes()[NSRegularControlSize].height()) {
+ // Push button
+ part = SafariTheme::PushButtonPart;
+
+ IntSize size = buttonSizes()[controlSize];
+ size.setWidth(r.width());
+
+ // 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(controlSize));
+ } else
+ part = SafariTheme::SquareButtonPart;
+
+ paintThemePart(part, paintInfo.context->platformContext(), inflatedRect, controlSize, determineState(o));
+ return false;
+}
+
+bool RenderThemeSafari::paintTextField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ ASSERT(SafariThemeLibrary());
+
+ paintThemePart(SafariTheme::TextFieldPart, paintInfo.context->platformContext(), r, (NSControlSize)0, determineState(o) & ~FocusedState);
+ return false;
+}
+
+void RenderThemeSafari::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+bool RenderThemeSafari::paintCapsLockIndicator(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 1
+ ASSERT(SafariThemeLibrary());
+
+ if (paintInfo.context->paintingDisabled())
+ return true;
+
+ paintThemePart(CapsLockPart, paintInfo.context->platformContext(), r, (NSControlSize)0, (ThemeControlState)0);
+
+ return false;
+#else
+ return true;
+#endif
+}
+
+bool RenderThemeSafari::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ ASSERT(SafariThemeLibrary());
+
+ paintThemePart(SafariTheme::TextAreaPart, paintInfo.context->platformContext(), r, (NSControlSize)0, determineState(o) & ~FocusedState);
+ return false;
+}
+
+void RenderThemeSafari::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const
+{
+}
+
+const int* RenderThemeSafari::popupButtonMargins(NSControlSize size) const
+{
+ static const int margins[3][4] =
+ {
+ { 2, 3, 3, 3 },
+ { 1, 3, 3, 3 },
+ { 0, 1, 0, 1 }
+ };
+ return margins[size];
+}
+
+const IntSize* RenderThemeSafari::popupButtonSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) };
+ return sizes;
+}
+
+const int* RenderThemeSafari::popupButtonPadding(NSControlSize size) const
+{
+ static const int padding[3][4] =
+ {
+ { 2, 26, 3, 8 },
+ { 2, 23, 3, 8 },
+ { 2, 22, 3, 10 }
+ };
+ return padding[size];
+}
+
+bool RenderThemeSafari::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& info, const IntRect& r)
+{
+ ASSERT(SafariThemeLibrary());
+
+ NSControlSize controlSize = controlSizeFromRect(r, popupButtonSizes());
+ IntRect inflatedRect = r;
+ IntSize size = popupButtonSizes()[controlSize];
+ size.setWidth(r.width());
+
+ // Now inflate it to account for the shadow.
+ if (r.width() >= minimumMenuListSize(o->style()))
+ inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(controlSize));
+
+ paintThemePart(DropDownButtonPart, info.context->platformContext(), inflatedRect, controlSize, determineState(o));
+
+ return false;
+}
+
+const float baseFontSize = 11.0f;
+const float baseArrowHeight = 5.0f;
+const float baseArrowWidth = 7.0f;
+const int arrowPaddingLeft = 5;
+const int arrowPaddingRight = 5;
+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 float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f };
+ static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f };
+ float a = inData[0];
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ outData[i] = (1.0f - a) * dark[i] + a * light[i];
+}
+
+static void BottomGradientInterpolate(void* info, 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 };
+ float a = inData[0];
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ outData[i] = (1.0f - a) * dark[i] + a * light[i];
+}
+
+static void MainGradientInterpolate(void* info, 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 };
+ float a = inData[0];
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ outData[i] = (1.0f - a) * dark[i] + a * light[i];
+}
+
+static void TrackGradientInterpolate(void* info, 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 };
+ float a = inData[0];
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ outData[i] = (1.0f - a) * dark[i] + a * light[i];
+}
+
+void RenderThemeSafari::paintMenuListButtonGradients(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ CGContextRef context = paintInfo.context->platformContext();
+
+ paintInfo.context->save();
+
+ int radius = o->style()->borderTopLeftRadius().width();
+
+ RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
+
+ FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f);
+ struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL };
+ RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks));
+ RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.bottom()), topFunction.get(), false, false));
+
+ FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f);
+ struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL };
+ RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks));
+ RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.bottom()), bottomFunction.get(), false, false));
+
+ struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL };
+ RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
+ RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.bottom()), mainFunction.get(), false, false));
+
+ RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false));
+
+ 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());
+ 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());
+ 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();
+
+ paintInfo.context->save();
+ CGContextClipToRect(context, r);
+ paintInfo.context->addRoundedRectClip(r,
+ o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(),
+ o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius());
+ CGContextDrawShading(context, leftShading.get());
+ CGContextDrawShading(context, rightShading.get());
+ paintInfo.context->restore();
+
+ paintInfo.context->restore();
+}
+
+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(),
+ r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth());
+ // Draw the gradients to give the styled popup menu a button appearance
+ paintMenuListButtonGradients(o, paintInfo, bounds);
+
+ // Since we actually know the size of the control here, we restrict the font scale to make sure the arrow will fit vertically in the bounds
+ float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / baseArrowHeight);
+ float centerY = bounds.y() + bounds.height() / 2.0f;
+ float arrowHeight = baseArrowHeight * fontScale;
+ float arrowWidth = baseArrowWidth * fontScale;
+ float leftEdge = bounds.right() - arrowPaddingRight - arrowWidth;
+
+ if (bounds.width() < arrowWidth + arrowPaddingLeft)
+ return false;
+
+ paintInfo.context->setFillColor(o->style()->color());
+ paintInfo.context->setStrokeColor(NoStroke);
+
+ FloatPoint arrow[3];
+ arrow[0] = FloatPoint(leftEdge, centerY - arrowHeight / 2.0f);
+ arrow[1] = FloatPoint(leftEdge + arrowWidth, centerY - arrowHeight / 2.0f);
+ arrow[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + arrowHeight / 2.0f);
+
+ // Draw the arrow
+ paintInfo.context->drawConvexPolygon(3, arrow, true);
+
+ Color leftSeparatorColor(0, 0, 0, 40);
+ Color rightSeparatorColor(255, 255, 255, 40);
+
+ // FIXME: Should the separator thickness and space be scaled up by fontScale?
+ int separatorSpace = 2;
+ int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft); // FIXME: Round?
+
+ // Draw the separator to the left of the arrows
+ paintInfo.context->setStrokeThickness(1.0f);
+ paintInfo.context->setStrokeStyle(SolidStroke);
+ paintInfo.context->setStrokeColor(leftSeparatorColor);
+ paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()),
+ IntPoint(leftEdgeOfSeparator, bounds.bottom()));
+
+ paintInfo.context->setStrokeColor(rightSeparatorColor);
+ paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()),
+ IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom()));
+
+ paintInfo.context->restore();
+ return false;
+}
+
+void RenderThemeSafari::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ NSControlSize controlSize = controlSizeForFont(style);
+
+ style->resetBorder();
+ style->resetPadding();
+
+ // Height is locked to auto.
+ style->setHeight(Length(Auto));
+
+ // White-space is locked to pre
+ style->setWhiteSpace(PRE);
+
+ // Set the foreground color to black or gray when we have the aqua look.
+ // Cast to RGB32 is to work around a compiler bug.
+ style->setColor(e->isEnabled() ? static_cast<RGBA32>(Color::black) : Color::darkGray);
+
+ // Set the button's vertical size.
+ setButtonSize(style);
+
+ // 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);
+}
+
+int RenderThemeSafari::popupInternalPaddingLeft(RenderStyle* style) const
+{
+ if (style->appearance() == MenulistPart)
+ return popupButtonPadding(controlSizeForFont(style))[leftPadding];
+ if (style->appearance() == MenulistButtonPart)
+ return styledPopupPaddingLeft;
+ return 0;
+}
+
+int RenderThemeSafari::popupInternalPaddingRight(RenderStyle* style) const
+{
+ if (style->appearance() == MenulistPart)
+ return popupButtonPadding(controlSizeForFont(style))[rightPadding];
+ if (style->appearance() == MenulistButtonPart) {
+ float fontScale = style->fontSize() / baseFontSize;
+ float arrowWidth = baseArrowWidth * fontScale;
+ return static_cast<int>(ceilf(arrowWidth + arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator));
+ }
+ return 0;
+}
+
+int RenderThemeSafari::popupInternalPaddingTop(RenderStyle* style) const
+{
+ if (style->appearance() == MenulistPart)
+ return popupButtonPadding(controlSizeForFont(style))[topPadding];
+ if (style->appearance() == MenulistButtonPart)
+ return styledPopupPaddingTop;
+ return 0;
+}
+
+int RenderThemeSafari::popupInternalPaddingBottom(RenderStyle* style) const
+{
+ if (style->appearance() == MenulistPart)
+ return popupButtonPadding(controlSizeForFont(style))[bottomPadding];
+ if (style->appearance() == MenulistButtonPart)
+ return styledPopupPaddingBottom;
+ return 0;
+}
+
+void RenderThemeSafari::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ float fontScale = style->fontSize() / baseFontSize;
+
+ style->resetPadding();
+ style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up?
+
+ const int minHeight = 15;
+ style->setMinHeight(Length(minHeight, Fixed));
+
+ style->setLineHeight(RenderStyle::initialLineHeight());
+}
+
+const IntSize* RenderThemeSafari::menuListSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) };
+ return sizes;
+}
+
+int RenderThemeSafari::minimumMenuListSize(RenderStyle* style) const
+{
+ return sizeForSystemFont(style, menuListSizes()).width();
+}
+
+const int trackWidth = 5;
+const int trackRadius = 2;
+
+bool RenderThemeSafari::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ IntRect bounds = r;
+
+ if (o->style()->appearance() == SliderHorizontalPart ||
+ o->style()->appearance() == MediaSliderPart) {
+ bounds.setHeight(trackWidth);
+ bounds.setY(r.y() + r.height() / 2 - trackWidth / 2);
+ } else if (o->style()->appearance() == SliderVerticalPart) {
+ bounds.setWidth(trackWidth);
+ bounds.setX(r.x() + r.width() / 2 - trackWidth / 2);
+ }
+
+ CGContextRef context = paintInfo.context->platformContext();
+ RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB());
+
+ paintInfo.context->save();
+ CGContextClipToRect(context, bounds);
+
+ struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL };
+ RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks));
+ RetainPtr<CGShadingRef> mainShading;
+ if (o->style()->appearance() == SliderVerticalPart)
+ mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.bottom()), CGPointMake(bounds.right(), bounds.bottom()), mainFunction.get(), false, false));
+ else
+ mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.bottom()), mainFunction.get(), false, false));
+
+ IntSize radius(trackRadius, trackRadius);
+ paintInfo.context->addRoundedRectClip(bounds,
+ radius, radius,
+ radius, radius);
+ CGContextDrawShading(context, mainShading.get());
+ paintInfo.context->restore();
+
+ return false;
+}
+
+void RenderThemeSafari::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ style->setBoxShadow(0);
+}
+
+const float verticalSliderHeightPadding = 0.1f;
+
+bool RenderThemeSafari::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ ASSERT(SafariThemeLibrary());
+
+ ASSERT(o->parent()->isSlider());
+
+ bool pressed = static_cast<RenderSlider*>(o->parent())->inDragMode();
+ ThemeControlState state = determineState(o->parent());
+ state &= ~SafariTheme::PressedState;
+ if (pressed)
+ state |= SafariTheme::PressedState;
+
+ paintThemePart(SliderThumbPart, paintInfo.context->platformContext(), r, NSSmallControlSize, state);
+ return false;
+}
+
+const int sliderThumbWidth = 15;
+const int sliderThumbHeight = 15;
+const int mediaSliderThumbWidth = 13;
+const int mediaSliderThumbHeight = 14;
+
+void RenderThemeSafari::adjustSliderThumbSize(RenderObject* o) const
+{
+ if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) {
+ o->style()->setWidth(Length(sliderThumbWidth, Fixed));
+ o->style()->setHeight(Length(sliderThumbHeight, Fixed));
+ } else if (o->style()->appearance() == MediaSliderThumbPart) {
+ o->style()->setWidth(Length(mediaSliderThumbWidth, Fixed));
+ o->style()->setHeight(Length(mediaSliderThumbHeight, Fixed));
+ }
+
+}
+
+bool RenderThemeSafari::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ ASSERT(SafariThemeLibrary());
+
+ paintThemePart(SafariTheme::SearchFieldPart, paintInfo.context->platformContext(), r, controlSizeFromRect(r, searchFieldSizes()), determineState(o));
+ return false;
+}
+
+const IntSize* RenderThemeSafari::searchFieldSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 15) };
+ return sizes;
+}
+
+void RenderThemeSafari::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 RenderThemeSafari::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ // Override border.
+ style->resetBorder();
+ const short borderWidth = 2;
+ style->setBorderLeftWidth(borderWidth);
+ style->setBorderLeftStyle(INSET);
+ style->setBorderRightWidth(borderWidth);
+ style->setBorderRightStyle(INSET);
+ style->setBorderBottomWidth(borderWidth);
+ style->setBorderBottomStyle(INSET);
+ style->setBorderTopWidth(borderWidth);
+ style->setBorderTopStyle(INSET);
+
+ // Override height.
+ style->setHeight(Length(Auto));
+ setSearchFieldSize(style);
+
+ // Override padding size to match AppKit text positioning.
+ const int padding = 1;
+ 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);
+}
+
+bool RenderThemeSafari::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect&)
+{
+ ASSERT(SafariThemeLibrary());
+
+ Node* input = o->node()->shadowAncestorNode();
+ ASSERT(input);
+ RenderObject* renderer = input->renderer();
+ ASSERT(renderer);
+
+ IntRect searchRect = renderer->absoluteBoundingBoxRect();
+
+ paintThemePart(SafariTheme::SearchFieldCancelButtonPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
+ return false;
+}
+
+const IntSize* RenderThemeSafari::cancelButtonSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) };
+ return sizes;
+}
+
+void RenderThemeSafari::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ IntSize size = sizeForSystemFont(style, cancelButtonSizes());
+ style->setWidth(Length(size.width(), Fixed));
+ style->setHeight(Length(size.height(), Fixed));
+}
+
+const IntSize* RenderThemeSafari::resultsButtonSizes() const
+{
+ static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) };
+ return sizes;
+}
+
+const int emptyResultsOffset = 9;
+void RenderThemeSafari::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ IntSize size = sizeForSystemFont(style, resultsButtonSizes());
+ style->setWidth(Length(size.width() - emptyResultsOffset, Fixed));
+ style->setHeight(Length(size.height(), Fixed));
+}
+
+bool RenderThemeSafari::paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&)
+{
+ return false;
+}
+
+void RenderThemeSafari::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ IntSize size = sizeForSystemFont(style, resultsButtonSizes());
+ style->setWidth(Length(size.width(), Fixed));
+ style->setHeight(Length(size.height(), Fixed));
+}
+
+bool RenderThemeSafari::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect&)
+{
+ ASSERT(SafariThemeLibrary());
+
+ Node* input = o->node()->shadowAncestorNode();
+ ASSERT(input);
+ RenderObject* renderer = input->renderer();
+ ASSERT(renderer);
+
+ IntRect searchRect = renderer->absoluteBoundingBoxRect();
+
+ paintThemePart(SafariTheme::SearchFieldResultsDecorationPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
+ return false;
+}
+
+const int resultsArrowWidth = 5;
+void RenderThemeSafari::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ IntSize size = sizeForSystemFont(style, resultsButtonSizes());
+ style->setWidth(Length(size.width() + resultsArrowWidth, Fixed));
+ style->setHeight(Length(size.height(), Fixed));
+}
+
+bool RenderThemeSafari::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect&)
+{
+ ASSERT(SafariThemeLibrary());
+
+ Node* input = o->node()->shadowAncestorNode();
+ ASSERT(input);
+ RenderObject* renderer = input->renderer();
+ ASSERT(renderer);
+
+ IntRect searchRect = renderer->absoluteBoundingBoxRect();
+
+ paintThemePart(SafariTheme::SearchFieldResultsButtonPart, paintInfo.context->platformContext(), searchRect, controlSizeFromRect(searchRect, searchFieldSizes()), determineState(o));
+ return false;
+}
+#if ENABLE(VIDEO)
+bool RenderThemeSafari::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
+ ASSERT(SafariThemeLibrary());
+ paintThemePart(SafariTheme::MediaFullscreenButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+#endif
+
+ return false;
+}
+
+bool RenderThemeSafari::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ Node* node = o->element();
+ 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;
+
+#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
+ ASSERT(SafariThemeLibrary());
+ paintThemePart(mediaElement->muted() ? SafariTheme::MediaUnMuteButtonPart : SafariTheme::MediaMuteButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+#endif
+
+ return false;
+}
+
+bool RenderThemeSafari::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ Node* node = o->element();
+ 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;
+
+#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
+ ASSERT(SafariThemeLibrary());
+ paintThemePart(mediaElement->canPlay() ? SafariTheme::MediaPlayButtonPart : SafariTheme::MediaPauseButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+#endif
+
+ return false;
+}
+
+bool RenderThemeSafari::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
+ ASSERT(SafariThemeLibrary());
+ paintThemePart(SafariTheme::MediaSeekBackButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+#endif
+
+ return false;
+}
+
+bool RenderThemeSafari::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
+ ASSERT(SafariThemeLibrary());
+ paintThemePart(SafariTheme::MediaSeekForwardButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+#endif
+
+ return false;
+}
+
+bool RenderThemeSafari::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ Node* node = o->element();
+ 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 percentLoaded = 0;
+ if (MediaPlayer* player = mediaElement->player())
+ if (player->duration())
+ percentLoaded = player->maxTimeBuffered() / player->duration();
+
+#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
+ ASSERT(SafariThemeLibrary());
+ STPaintProgressIndicator(SafariTheme::MediaType, paintInfo.context->platformContext(), r, NSRegularControlSize, 0, percentLoaded);
+#endif
+ return false;
+}
+
+bool RenderThemeSafari::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ ASSERT(SafariThemeLibrary());
+
+#if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2
+ paintThemePart(SafariTheme::MediaSliderThumbPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+#endif
+
+ return false;
+}
+#endif
+
+} // namespace WebCore
+
+#endif // #if USE(SAFARI_THEME)
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.h
new file mode 100644
index 0000000..8ac5acf
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeSafari.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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
+ * 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 RenderThemeSafari_h
+#define RenderThemeSafari_h
+
+#if USE(SAFARI_THEME)
+
+#include "RenderTheme.h"
+
+// If you have an empty placeholder SafariThemeConstants.h, then include SafariTheme.h
+// This is a workaround until a version of WebKitSupportLibrary is released with an updated SafariThemeConstants.h
+#include <SafariTheme/SafariThemeConstants.h>
+#ifndef SafariThemeConstants_h
+#include <SafariTheme/SafariTheme.h>
+#endif
+
+#if PLATFORM(WIN)
+typedef void* HANDLE;
+typedef struct HINSTANCE__* HINSTANCE;
+typedef HINSTANCE HMODULE;
+#endif
+
+namespace WebCore {
+
+using namespace SafariTheme;
+
+class RenderStyle;
+
+class RenderThemeSafari : public RenderTheme {
+public:
+ RenderThemeSafari();
+ virtual ~RenderThemeSafari();
+
+ // 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;
+
+ // 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 activeListBoxSelectionBackgroundColor() const;
+
+ // System fonts.
+ virtual void systemFont(int propId, FontDescription&) const;
+
+ virtual int minimumMenuListSize(RenderStyle*) const;
+
+ virtual void adjustSliderThumbSize(RenderObject*) const;
+ virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+
+ virtual int popupInternalPaddingLeft(RenderStyle*) const;
+ virtual int popupInternalPaddingRight(RenderStyle*) const;
+ virtual int popupInternalPaddingTop(RenderStyle*) const;
+ virtual int popupInternalPaddingBottom(RenderStyle*) const;
+
+protected:
+ // 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 bool paintSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ 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 paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+#if ENABLE(VIDEO)
+ 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&);
+#endif
+
+private:
+ IntRect inflateRect(const IntRect&, const IntSize&, const int* margins) 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);
+ 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;
+
+ // Helpers for adjusting appearance and for painting
+ const IntSize* checkboxSizes() const;
+ const int* checkboxMargins(NSControlSize) const;
+
+ const IntSize* radioSizes() const;
+ const int* radioMargins(NSControlSize) const;
+
+ void setButtonPaddingFromControlSize(RenderStyle*, NSControlSize) const;
+ const IntSize* buttonSizes() const;
+ const int* buttonMargins(NSControlSize) const;
+
+ const IntSize* popupButtonSizes() const;
+ const int* popupButtonMargins(NSControlSize) 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 setSearchFieldSize(RenderStyle*) const;
+
+ ThemeControlState determineState(RenderObject*) const;
+};
+
+} // namespace WebCore
+
+#endif // #if USE(SAFARI_THEME)
+
+#endif // RenderThemeSafari_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp
new file mode 100644
index 0000000..fd07b54
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.cpp
@@ -0,0 +1,852 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderThemeWin.h"
+
+#include "CSSStyleSheet.h"
+#include "CSSValueKeywords.h"
+#include "Document.h"
+#include "GraphicsContext.h"
+#include "HTMLElement.h"
+#include "HTMLSelectElement.h"
+#include "Icon.h"
+#include "RenderSlider.h"
+#include "SoftLinking.h"
+#include "UserAgentStyleSheets.h"
+
+#include <tchar.h>
+
+/*
+ * The following constants are used to determine how a widget is drawn using
+ * Windows' Theme API. For more information on theme parts and states see
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp
+ */
+
+// Generic state constants
+#define TS_NORMAL 1
+#define TS_HOVER 2
+#define TS_ACTIVE 3
+#define TS_DISABLED 4
+#define TS_FOCUSED 5
+
+// Button constants
+#define BP_BUTTON 1
+#define BP_RADIO 2
+#define BP_CHECKBOX 3
+
+// Textfield constants
+#define TFP_TEXTFIELD 1
+#define TFS_READONLY 6
+
+// ComboBox constants (from tmschema.h)
+#define CP_DROPDOWNBUTTON 1
+
+// TrackBar (slider) parts
+#define TKP_TRACK 1
+#define TKP_TRACKVERT 2
+
+// TrackBar (slider) thumb parts
+#define TKP_THUMBBOTTOM 4
+#define TKP_THUMBTOP 5
+#define TKP_THUMBLEFT 7
+#define TKP_THUMBRIGHT 8
+
+// Trackbar (slider) thumb states
+#define TUS_NORMAL 1
+#define TUS_HOT 2
+#define TUS_PRESSED 3
+#define TUS_FOCUSED 4
+#define TUS_DISABLED 5
+
+// button states
+#define PBS_NORMAL 1
+#define PBS_HOT 2
+#define PBS_PRESSED 3
+#define PBS_DISABLED 4
+#define PBS_DEFAULTED 5
+
+// This is the fixed width IE and Firefox use for buttons on dropdown menus
+static const int dropDownButtonWidth = 17;
+
+static const int shell32MagnifierIconIndex = 22;
+
+// Default font size to match Firefox.
+static const float defaultControlFontPixelSize = 13;
+
+SOFT_LINK_LIBRARY(uxtheme)
+SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
+SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
+SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, pClipRect))
+SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ())
+SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId))
+
+static bool haveTheme;
+
+namespace WebCore {
+
+static bool gWebKitIsBeingUnloaded;
+
+void RenderThemeWin::setWebKitIsBeingUnloaded()
+{
+ gWebKitIsBeingUnloaded = true;
+}
+
+#if !USE(SAFARI_THEME)
+RenderTheme* theme()
+{
+ static RenderThemeWin winTheme;
+ return &winTheme;
+}
+#endif
+
+RenderThemeWin::RenderThemeWin()
+ : m_buttonTheme(0)
+ , m_textFieldTheme(0)
+ , m_menuListTheme(0)
+ , m_sliderTheme(0)
+{
+ haveTheme = uxthemeLibrary() && IsThemeActive();
+}
+
+RenderThemeWin::~RenderThemeWin()
+{
+ // If WebKit is being unloaded, then uxtheme.dll is no longer available.
+ if (gWebKitIsBeingUnloaded || !uxthemeLibrary())
+ return;
+ close();
+}
+
+HANDLE RenderThemeWin::buttonTheme() const
+{
+ if (haveTheme && !m_buttonTheme)
+ m_buttonTheme = OpenThemeData(0, L"Button");
+ return m_buttonTheme;
+}
+
+HANDLE RenderThemeWin::textFieldTheme() const
+{
+ if (haveTheme && !m_textFieldTheme)
+ m_textFieldTheme = OpenThemeData(0, L"Edit");
+ return m_textFieldTheme;
+}
+
+HANDLE RenderThemeWin::menuListTheme() const
+{
+ if (haveTheme && !m_menuListTheme)
+ m_menuListTheme = OpenThemeData(0, L"ComboBox");
+ return m_menuListTheme;
+}
+
+HANDLE RenderThemeWin::sliderTheme() const
+{
+ if (haveTheme && !m_sliderTheme)
+ m_sliderTheme = OpenThemeData(0, L"TrackBar");
+ return m_sliderTheme;
+}
+
+void RenderThemeWin::close()
+{
+ // This method will need to be called when the OS theme changes to flush our cached themes.
+ if (m_buttonTheme)
+ CloseThemeData(m_buttonTheme);
+ if (m_textFieldTheme)
+ CloseThemeData(m_textFieldTheme);
+ if (m_menuListTheme)
+ CloseThemeData(m_menuListTheme);
+ if (m_sliderTheme)
+ CloseThemeData(m_sliderTheme);
+ m_buttonTheme = m_textFieldTheme = m_menuListTheme = m_sliderTheme = 0;
+
+ haveTheme = uxthemeLibrary() && IsThemeActive();
+}
+
+void RenderThemeWin::themeChanged()
+{
+ close();
+}
+
+String RenderThemeWin::extraDefaultStyleSheet()
+{
+ return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet));
+}
+
+String RenderThemeWin::extraQuirksStyleSheet()
+{
+ return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
+}
+
+bool RenderThemeWin::supportsHover(const RenderStyle*) const
+{
+ // The Classic/2k look has no hover effects.
+ return haveTheme;
+}
+
+Color RenderThemeWin::platformActiveSelectionBackgroundColor() const
+{
+ COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
+ return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
+}
+
+Color RenderThemeWin::platformInactiveSelectionBackgroundColor() const
+{
+ COLORREF color = GetSysColor(COLOR_GRAYTEXT);
+ return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
+}
+
+Color RenderThemeWin::platformActiveSelectionForegroundColor() const
+{
+ COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
+}
+
+Color RenderThemeWin::platformInactiveSelectionForegroundColor() const
+{
+ return Color::white;
+}
+
+static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont, float fontSize)
+{
+ fontDescription.setIsAbsoluteSize(true);
+ fontDescription.setGenericFamily(FontDescription::NoFamily);
+ fontDescription.firstFamily().setFamily(String(logFont.lfFaceName));
+ fontDescription.setSpecifiedSize(fontSize);
+ fontDescription.setWeight(logFont.lfWeight >= 700 ? FontWeightBold : FontWeightNormal); // FIXME: Use real weight.
+ fontDescription.setItalic(logFont.lfItalic);
+}
+
+static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont)
+{
+ fillFontDescription(fontDescription, logFont, abs(logFont.lfHeight));
+}
+
+void RenderThemeWin::systemFont(int propId, FontDescription& fontDescription) const
+{
+ static FontDescription captionFont;
+ static FontDescription controlFont;
+ static FontDescription smallCaptionFont;
+ static FontDescription menuFont;
+ static FontDescription iconFont;
+ static FontDescription messageBoxFont;
+ static FontDescription statusBarFont;
+ static FontDescription systemFont;
+
+ static bool initialized;
+ static NONCLIENTMETRICS ncm;
+
+ if (!initialized) {
+ initialized = true;
+ ncm.cbSize = sizeof(NONCLIENTMETRICS);
+ ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
+ }
+
+ switch (propId) {
+ case CSSValueIcon: {
+ if (!iconFont.isAbsoluteSize()) {
+ LOGFONT logFont;
+ ::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0);
+ fillFontDescription(iconFont, logFont);
+ }
+ fontDescription = iconFont;
+ break;
+ }
+ case CSSValueMenu:
+ if (!menuFont.isAbsoluteSize())
+ fillFontDescription(menuFont, ncm.lfMenuFont);
+ fontDescription = menuFont;
+ break;
+ case CSSValueMessageBox:
+ if (!messageBoxFont.isAbsoluteSize())
+ fillFontDescription(messageBoxFont, ncm.lfMessageFont);
+ fontDescription = messageBoxFont;
+ break;
+ case CSSValueStatusBar:
+ if (!statusBarFont.isAbsoluteSize())
+ fillFontDescription(statusBarFont, ncm.lfStatusFont);
+ fontDescription = statusBarFont;
+ break;
+ case CSSValueCaption:
+ if (!captionFont.isAbsoluteSize())
+ fillFontDescription(captionFont, ncm.lfCaptionFont);
+ fontDescription = captionFont;
+ break;
+ case CSSValueSmallCaption:
+ if (!smallCaptionFont.isAbsoluteSize())
+ fillFontDescription(smallCaptionFont, ncm.lfSmCaptionFont);
+ fontDescription = smallCaptionFont;
+ break;
+ case CSSValueWebkitSmallControl:
+ case CSSValueWebkitMiniControl: // Just map to small.
+ case CSSValueWebkitControl: // Just map to small.
+ if (!controlFont.isAbsoluteSize()) {
+ HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
+ if (hGDI) {
+ LOGFONT logFont;
+ if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
+ fillFontDescription(controlFont, logFont, defaultControlFontPixelSize);
+ }
+ }
+ fontDescription = controlFont;
+ break;
+ default: { // Everything else uses the stock GUI font.
+ if (!systemFont.isAbsoluteSize()) {
+ HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
+ if (hGDI) {
+ LOGFONT logFont;
+ if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
+ fillFontDescription(systemFont, logFont);
+ }
+ }
+ fontDescription = systemFont;
+ }
+ }
+}
+
+bool RenderThemeWin::supportsFocus(ControlPart appearance)
+{
+ switch (appearance) {
+ case PushButtonPart:
+ case ButtonPart:
+ case DefaultButtonPart:
+ case TextFieldPart:
+ case TextAreaPart:
+ return true;
+ case MenulistPart:
+ return false;
+ default:
+ return false;
+ }
+}
+
+unsigned RenderThemeWin::determineClassicState(RenderObject* o)
+{
+ unsigned state = 0;
+ switch (o->style()->appearance()) {
+ case PushButtonPart:
+ case ButtonPart:
+ case DefaultButtonPart:
+ state = DFCS_BUTTONPUSH;
+ if (!isEnabled(o))
+ state |= DFCS_INACTIVE;
+ else if (isPressed(o))
+ state |= DFCS_PUSHED;
+ break;
+ case RadioPart:
+ case CheckboxPart:
+ state = (o->style()->appearance() == RadioPart) ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK;
+ if (isChecked(o))
+ state |= DFCS_CHECKED;
+ if (!isEnabled(o))
+ state |= DFCS_INACTIVE;
+ else if (isPressed(o))
+ state |= DFCS_PUSHED;
+ break;
+ case MenulistPart:
+ state = DFCS_SCROLLCOMBOBOX;
+ if (!isEnabled(o))
+ state |= DFCS_INACTIVE;
+ else if (isPressed(o))
+ state |= DFCS_PUSHED;
+ default:
+ break;
+ }
+ return state;
+}
+
+unsigned RenderThemeWin::determineState(RenderObject* o)
+{
+ unsigned result = TS_NORMAL;
+ ControlPart appearance = o->style()->appearance();
+ if (!isEnabled(o))
+ result = TS_DISABLED;
+ else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance))
+ result = TFS_READONLY; // Readonly is supported on textfields.
+ else if (isPressed(o)) // Active overrides hover and focused.
+ result = TS_ACTIVE;
+ else if (supportsFocus(appearance) && isFocused(o))
+ result = TS_FOCUSED;
+ else if (isHovered(o))
+ result = TS_HOVER;
+ if (isChecked(o))
+ result += 4; // 4 unchecked states, 4 checked states.
+ return result;
+}
+
+unsigned RenderThemeWin::determineSliderThumbState(RenderObject* o)
+{
+ unsigned result = TUS_NORMAL;
+ if (!isEnabled(o->parent()))
+ result = TUS_DISABLED;
+ else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent()))
+ result = TUS_FOCUSED;
+ else if (static_cast<RenderSlider*>(o->parent())->inDragMode())
+ result = TUS_PRESSED;
+ else if (isHovered(o))
+ result = TUS_HOT;
+ return result;
+}
+
+unsigned RenderThemeWin::determineButtonState(RenderObject* o)
+{
+ unsigned result = PBS_NORMAL;
+ if (!isEnabled(o))
+ result = PBS_DISABLED;
+ else if (isPressed(o))
+ result = PBS_PRESSED;
+ else if (supportsFocus(o->style()->appearance()) && isFocused(o))
+ result = PBS_DEFAULTED;
+ else if (isHovered(o))
+ result = PBS_HOT;
+ else if (isDefault(o))
+ result = PBS_DEFAULTED;
+ return result;
+}
+
+ThemeData RenderThemeWin::getClassicThemeData(RenderObject* o)
+{
+ ThemeData result;
+ switch (o->style()->appearance()) {
+ case PushButtonPart:
+ case ButtonPart:
+ case DefaultButtonPart:
+ case CheckboxPart:
+ case RadioPart:
+ result.m_part = DFC_BUTTON;
+ result.m_state = determineClassicState(o);
+ break;
+ case MenulistPart:
+ result.m_part = DFC_SCROLL;
+ result.m_state = determineClassicState(o);
+ break;
+ case TextFieldPart:
+ case TextAreaPart:
+ result.m_part = TFP_TEXTFIELD;
+ result.m_state = determineState(o);
+ break;
+ case SliderHorizontalPart:
+ result.m_part = TKP_TRACK;
+ result.m_state = TS_NORMAL;
+ break;
+ case SliderVerticalPart:
+ result.m_part = TKP_TRACKVERT;
+ result.m_state = TS_NORMAL;
+ break;
+ case SliderThumbHorizontalPart:
+ result.m_part = TKP_THUMBBOTTOM;
+ result.m_state = determineSliderThumbState(o);
+ break;
+ case SliderThumbVerticalPart:
+ result.m_part = TKP_THUMBRIGHT;
+ result.m_state = determineSliderThumbState(o);
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+ThemeData RenderThemeWin::getThemeData(RenderObject* o)
+{
+ if (!haveTheme)
+ return getClassicThemeData(o);
+
+ ThemeData result;
+ switch (o->style()->appearance()) {
+ case PushButtonPart:
+ case ButtonPart:
+ case DefaultButtonPart:
+ result.m_part = BP_BUTTON;
+ result.m_state = determineButtonState(o);
+ break;
+ case CheckboxPart:
+ result.m_part = BP_CHECKBOX;
+ result.m_state = determineState(o);
+ break;
+ case MenulistPart:
+ case MenulistButtonPart:
+ result.m_part = CP_DROPDOWNBUTTON;
+ result.m_state = determineState(o);
+ break;
+ case RadioPart:
+ result.m_part = BP_RADIO;
+ result.m_state = determineState(o);
+ break;
+ case TextFieldPart:
+ case TextAreaPart:
+ result.m_part = TFP_TEXTFIELD;
+ result.m_state = determineState(o);
+ break;
+ case SliderHorizontalPart:
+ result.m_part = TKP_TRACK;
+ result.m_state = TS_NORMAL;
+ break;
+ case SliderVerticalPart:
+ result.m_part = TKP_TRACKVERT;
+ result.m_state = TS_NORMAL;
+ break;
+ case SliderThumbHorizontalPart:
+ result.m_part = TKP_THUMBBOTTOM;
+ result.m_state = determineSliderThumbState(o);
+ break;
+ case SliderThumbVerticalPart:
+ result.m_part = TKP_THUMBRIGHT;
+ result.m_state = determineSliderThumbState(o);
+ break;
+ }
+
+ return result;
+}
+
+static void drawControl(GraphicsContext* context, RenderObject* o, HANDLE theme, const ThemeData& themeData, const IntRect& r)
+{
+ bool alphaBlend = false;
+ if (theme)
+ alphaBlend = IsThemeBackgroundPartiallyTransparent(theme, themeData.m_part, themeData.m_state);
+ HDC hdc = context->getWindowsContext(r, alphaBlend);
+ RECT widgetRect = r;
+ if (theme)
+ DrawThemeBackground(theme, hdc, themeData.m_part, themeData.m_state, &widgetRect, NULL);
+ else {
+ if (themeData.m_part == TFP_TEXTFIELD) {
+ ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+ if (themeData.m_state == TS_DISABLED || themeData.m_state == TFS_READONLY)
+ ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_BTNFACE+1));
+ else
+ ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_WINDOW+1));
+ } else if (themeData.m_part == TKP_TRACK || themeData.m_part == TKP_TRACKVERT) {
+ ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+ ::FillRect(hdc, &widgetRect, (HBRUSH)GetStockObject(GRAY_BRUSH));
+ } else if ((o->style()->appearance() == SliderThumbHorizontalPart ||
+ o->style()->appearance() == SliderThumbVerticalPart) &&
+ (themeData.m_part == TKP_THUMBBOTTOM || themeData.m_part == TKP_THUMBTOP ||
+ themeData.m_part == TKP_THUMBLEFT || themeData.m_part == TKP_THUMBRIGHT)) {
+ ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
+ if (themeData.m_state == TUS_DISABLED) {
+ static WORD patternBits[8] = {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55};
+ HBITMAP patternBmp = ::CreateBitmap(8, 8, 1, 1, patternBits);
+ if (patternBmp) {
+ HBRUSH brush = (HBRUSH) ::CreatePatternBrush(patternBmp);
+ COLORREF oldForeColor = ::SetTextColor(hdc, ::GetSysColor(COLOR_3DFACE));
+ COLORREF oldBackColor = ::SetBkColor(hdc, ::GetSysColor(COLOR_3DHILIGHT));
+ POINT p;
+ ::GetViewportOrgEx(hdc, &p);
+ ::SetBrushOrgEx(hdc, p.x + widgetRect.left, p.y + widgetRect.top, NULL);
+ HBRUSH oldBrush = (HBRUSH) ::SelectObject(hdc, brush);
+ ::FillRect(hdc, &widgetRect, brush);
+ ::SetTextColor(hdc, oldForeColor);
+ ::SetBkColor(hdc, oldBackColor);
+ ::SelectObject(hdc, oldBrush);
+ ::DeleteObject(brush);
+ } else
+ ::FillRect(hdc, &widgetRect, (HBRUSH)COLOR_3DHILIGHT);
+ ::DeleteObject(patternBmp);
+ }
+ } else {
+ // Push buttons, buttons, checkboxes and radios, and the dropdown arrow in menulists.
+ if (o->style()->appearance() == DefaultButtonPart) {
+ HBRUSH brush = ::GetSysColorBrush(COLOR_3DDKSHADOW);
+ ::FrameRect(hdc, &widgetRect, brush);
+ ::InflateRect(&widgetRect, -1, -1);
+ ::DrawEdge(hdc, &widgetRect, BDR_RAISEDOUTER, BF_RECT | BF_MIDDLE);
+ }
+ ::DrawFrameControl(hdc, &widgetRect, themeData.m_part, themeData.m_state);
+ }
+ }
+ context->releaseWindowsContext(hdc, r, alphaBlend);
+}
+
+bool RenderThemeWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ drawControl(i.context, o, buttonTheme(), getThemeData(o), r);
+ return false;
+}
+
+void RenderThemeWin::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;
+
+ // FIXME: A hard-coded size of 13 is used. This is wrong but necessary for now. It matches Firefox.
+ // At different DPI settings on Windows, 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.
+ if (style->width().isIntrinsicOrAuto())
+ style->setWidth(Length(13, Fixed));
+ if (style->height().isAuto())
+ style->setHeight(Length(13, Fixed));
+}
+
+bool RenderThemeWin::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ drawControl(i.context, o, textFieldTheme(), getThemeData(o), r);
+ return false;
+}
+
+bool RenderThemeWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ // The outer box of a menu list is just a text field. Paint it first.
+ drawControl(i.context, o, textFieldTheme(), ThemeData(TFP_TEXTFIELD, determineState(o)), r);
+
+ return paintMenuListButton(o, i, r);
+}
+
+void RenderThemeWin::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ style->resetBorder();
+ adjustMenuListButtonStyle(selector, style, e);
+}
+
+void RenderThemeWin::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ // These are the paddings needed to place the text correctly in the <select> box
+ const int dropDownBoxPaddingTop = 2;
+ const int dropDownBoxPaddingRight = style->direction() == LTR ? 4 + dropDownButtonWidth : 4;
+ const int dropDownBoxPaddingBottom = 2;
+ const int dropDownBoxPaddingLeft = style->direction() == LTR ? 4 : 4 + dropDownButtonWidth;
+ // The <select> box must be at least 12px high for the button to render nicely on Windows
+ const int dropDownBoxMinHeight = 12;
+
+ // Position the text correctly within the select box and make the box wide enough to fit the dropdown button
+ style->setPaddingTop(Length(dropDownBoxPaddingTop, Fixed));
+ style->setPaddingRight(Length(dropDownBoxPaddingRight, Fixed));
+ style->setPaddingBottom(Length(dropDownBoxPaddingBottom, Fixed));
+ style->setPaddingLeft(Length(dropDownBoxPaddingLeft, Fixed));
+
+ // Height is locked to auto
+ style->setHeight(Length(Auto));
+
+ // Calculate our min-height
+ int minHeight = style->font().height();
+ minHeight = max(minHeight, dropDownBoxMinHeight);
+
+ style->setMinHeight(Length(minHeight, Fixed));
+
+ // White-space is locked to pre
+ style->setWhiteSpace(PRE);
+}
+
+bool RenderThemeWin::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ // FIXME: Don't make hardcoded assumptions about the thickness of the textfield border.
+ int borderThickness = haveTheme ? 1 : 2;
+
+ // Paint the dropdown button on the inner edge of the text field,
+ // leaving space for the text field's 1px border
+ IntRect buttonRect(r);
+ buttonRect.inflate(-borderThickness);
+ if (o->style()->direction() == LTR)
+ buttonRect.setX(buttonRect.right() - dropDownButtonWidth);
+ buttonRect.setWidth(dropDownButtonWidth);
+
+ drawControl(i.context, o, menuListTheme(), getThemeData(o), buttonRect);
+
+ return false;
+}
+
+const int trackWidth = 4;
+
+bool RenderThemeWin::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ IntRect bounds = r;
+
+ if (o->style()->appearance() == SliderHorizontalPart) {
+ bounds.setHeight(trackWidth);
+ bounds.setY(r.y() + r.height() / 2 - trackWidth / 2);
+ } else if (o->style()->appearance() == SliderVerticalPart) {
+ bounds.setWidth(trackWidth);
+ bounds.setX(r.x() + r.width() / 2 - trackWidth / 2);
+ }
+
+ drawControl(i.context, o, sliderTheme(), getThemeData(o), bounds);
+ return false;
+}
+
+bool RenderThemeWin::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ drawControl(i.context, o, sliderTheme(), getThemeData(o), r);
+ return false;
+}
+
+const int sliderThumbWidth = 7;
+const int sliderThumbHeight = 15;
+
+void RenderThemeWin::adjustSliderThumbSize(RenderObject* o) const
+{
+ if (o->style()->appearance() == SliderThumbVerticalPart) {
+ o->style()->setWidth(Length(sliderThumbHeight, Fixed));
+ o->style()->setHeight(Length(sliderThumbWidth, Fixed));
+ } else if (o->style()->appearance() == SliderThumbHorizontalPart) {
+ o->style()->setWidth(Length(sliderThumbWidth, Fixed));
+ o->style()->setHeight(Length(sliderThumbHeight, Fixed));
+ }
+}
+
+void RenderThemeWin::adjustButtonInnerStyle(RenderStyle* style) const
+{
+ // This inner padding matches Firefox.
+ style->setPaddingTop(Length(1, Fixed));
+ style->setPaddingRight(Length(3, Fixed));
+ style->setPaddingBottom(Length(1, Fixed));
+ style->setPaddingLeft(Length(3, Fixed));
+}
+
+bool RenderThemeWin::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ return paintTextField(o, i, r);
+}
+
+void RenderThemeWin::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ // Override padding size to match AppKit text positioning.
+ const int padding = 1;
+ style->setPaddingLeft(Length(padding, Fixed));
+ style->setPaddingRight(Length(padding, Fixed));
+ style->setPaddingTop(Length(padding, Fixed));
+ style->setPaddingBottom(Length(padding, Fixed));
+}
+
+bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ Color buttonColor = (o->element() && o->element()->active()) ? Color(138, 138, 138) : Color(186, 186, 186);
+
+ IntSize cancelSize(10, 10);
+ IntSize cancelRadius(cancelSize.width() / 2, cancelSize.height() / 2);
+ int x = r.x() + (r.width() - cancelSize.width()) / 2;
+ int y = r.y() + (r.height() - cancelSize.height()) / 2 + 1;
+ IntRect cancelBounds(IntPoint(x, y), cancelSize);
+ paintInfo.context->save();
+ paintInfo.context->addRoundedRectClip(cancelBounds, cancelRadius, cancelRadius, cancelRadius, cancelRadius);
+ paintInfo.context->fillRect(cancelBounds, buttonColor);
+
+ // Draw the 'x'
+ IntSize xSize(3, 3);
+ IntRect xBounds(cancelBounds.location() + IntSize(3, 3), xSize);
+ paintInfo.context->setStrokeColor(Color::white);
+ paintInfo.context->drawLine(xBounds.location(), xBounds.location() + xBounds.size());
+ paintInfo.context->drawLine(IntPoint(xBounds.right(), xBounds.y()), IntPoint(xBounds.x(), xBounds.bottom()));
+
+ paintInfo.context->restore();
+ return false;
+}
+
+void RenderThemeWin::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ IntSize cancelSize(13, 11);
+ style->setWidth(Length(cancelSize.width(), Fixed));
+ style->setHeight(Length(cancelSize.height(), Fixed));
+}
+
+void RenderThemeWin::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ IntSize emptySize(1, 11);
+ style->setWidth(Length(emptySize.width(), Fixed));
+ style->setHeight(Length(emptySize.height(), Fixed));
+}
+
+void RenderThemeWin::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ IntSize magnifierSize(15, 11);
+ style->setWidth(Length(magnifierSize.width(), Fixed));
+ style->setHeight(Length(magnifierSize.height(), Fixed));
+}
+
+bool RenderThemeWin::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ IntRect bounds = r;
+ bounds.setWidth(bounds.height());
+
+ TCHAR buffer[MAX_PATH];
+ UINT length = ::GetSystemDirectory(buffer, ARRAYSIZE(buffer));
+ if (!length)
+ return 0;
+
+ if (_tcscat_s(buffer, TEXT("\\shell32.dll")))
+ return 0;
+
+ HICON hIcon;
+ if (!::ExtractIconEx(buffer, shell32MagnifierIconIndex, 0, &hIcon, 1))
+ return 0;
+
+ RefPtr<Icon> icon = Icon::create(hIcon);
+ icon->paint(paintInfo.context, bounds);
+ return false;
+}
+
+void RenderThemeWin::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ IntSize magnifierSize(15, 11);
+ style->setWidth(Length(magnifierSize.width(), Fixed));
+ style->setHeight(Length(magnifierSize.height(), Fixed));
+}
+
+bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ paintSearchFieldResultsDecoration(o, paintInfo, r);
+ return false;
+}
+
+// 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 RenderThemeWin::systemColor(int cssValueId) const
+{
+ int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
+ if (sysColorIndex == -1)
+ return RenderTheme::systemColor(cssValueId);
+
+ COLORREF color = GetSysColor(sysColorIndex);
+ return Color(GetRValue(color), GetGValue(color), GetBValue(color));
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h
new file mode 100644
index 0000000..8562b22
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderThemeWin.h
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006, 2008 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
+ * 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 RenderThemeWin_h
+#define RenderThemeWin_h
+
+#include "RenderTheme.h"
+
+#if WIN32
+typedef void* HANDLE;
+typedef struct HINSTANCE__* HINSTANCE;
+typedef HINSTANCE HMODULE;
+#endif
+
+namespace WebCore {
+
+struct ThemeData {
+ ThemeData() :m_part(0), m_state(0), m_classicState(0) {}
+ ThemeData(int part, int state)
+ : m_part(part)
+ , m_state(state)
+ , m_classicState(0)
+ { }
+
+ unsigned m_part;
+ unsigned m_state;
+ unsigned m_classicState;
+};
+
+class RenderThemeWin : public RenderTheme {
+public:
+ RenderThemeWin();
+ ~RenderThemeWin();
+
+ virtual String extraDefaultStyleSheet();
+ virtual String extraQuirksStyleSheet();
+
+ // A method asking if the theme's controls actually care about redrawing when hovered.
+ virtual bool supportsHover(const RenderStyle*) const;
+
+ virtual Color platformActiveSelectionBackgroundColor() const;
+ virtual Color platformInactiveSelectionBackgroundColor() const;
+ virtual Color platformActiveSelectionForegroundColor() const;
+ virtual Color platformInactiveSelectionForegroundColor() const;
+
+ // System fonts.
+ virtual void systemFont(int propId, FontDescription&) const;
+ virtual Color systemColor(int cssValueId) const;
+
+ virtual bool paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+ { return paintButton(o, i, r); }
+ virtual void setCheckboxSize(RenderStyle*) const;
+
+ virtual bool paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+ { return paintButton(o, i, r); }
+ virtual void setRadioSize(RenderStyle* style) const
+ { return setCheckboxSize(style); }
+
+ virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ virtual bool paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+ { return paintTextField(o, i, r); }
+
+ virtual void adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const;
+ virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+ virtual void adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const;
+
+ virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ virtual bool paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+ virtual bool paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+ virtual void adjustSliderThumbSize(RenderObject*) const;
+
+ virtual void adjustButtonInnerStyle(RenderStyle*) const;
+
+ virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+ 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&) { return false; }
+
+ 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 void themeChanged();
+
+ virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {}
+ virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {}
+ virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {}
+
+ static void setWebKitIsBeingUnloaded();
+
+private:
+ void addIntrinsicMargins(RenderStyle*) const;
+ void close();
+
+ unsigned determineState(RenderObject*);
+ unsigned determineClassicState(RenderObject*);
+ unsigned determineSliderThumbState(RenderObject*);
+ unsigned determineButtonState(RenderObject*);
+
+ bool supportsFocus(ControlPart);
+
+ ThemeData getThemeData(RenderObject*);
+ ThemeData getClassicThemeData(RenderObject* o);
+
+ HANDLE buttonTheme() const;
+ HANDLE textFieldTheme() const;
+ HANDLE menuListTheme() const;
+ HANDLE sliderTheme() const;
+
+ mutable HANDLE m_buttonTheme;
+ mutable HANDLE m_textFieldTheme;
+ mutable HANDLE m_menuListTheme;
+ mutable HANDLE m_sliderTheme;
+};
+
+};
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp
new file mode 100644
index 0000000..f46ff20
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.cpp
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RenderTreeAsText.h"
+
+#include "CharacterNames.h"
+#include "Document.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "HTMLElement.h"
+#include "HTMLNames.h"
+#include "InlineTextBox.h"
+#include "RenderBR.h"
+#include "RenderListMarker.h"
+#include "RenderTableCell.h"
+#include "RenderView.h"
+#include "RenderWidget.h"
+#include "SelectionController.h"
+#include "TextStream.h"
+#include <wtf/Vector.h>
+
+#if ENABLE(SVG)
+#include "RenderSVGRoot.h"
+#include "RenderSVGContainer.h"
+#include "RenderSVGInlineText.h"
+#include "RenderSVGText.h"
+#include "SVGRenderTreeAsText.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const IntRect& paintDirtyRect, int indent = 0);
+
+#if !ENABLE(SVG)
+static TextStream &operator<<(TextStream& ts, const IntRect& r)
+{
+ return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height();
+}
+#endif
+
+static void writeIndent(TextStream& ts, int indent)
+{
+ for (int i = 0; i != indent; ++i)
+ ts << " ";
+}
+
+static void printBorderStyle(TextStream& ts, const RenderObject& o, const EBorderStyle borderStyle)
+{
+ switch (borderStyle) {
+ case BNONE:
+ ts << "none";
+ break;
+ case BHIDDEN:
+ ts << "hidden";
+ break;
+ case INSET:
+ ts << "inset";
+ break;
+ case GROOVE:
+ ts << "groove";
+ break;
+ case RIDGE:
+ ts << "ridge";
+ break;
+ case OUTSET:
+ ts << "outset";
+ break;
+ case DOTTED:
+ ts << "dotted";
+ break;
+ case DASHED:
+ ts << "dashed";
+ break;
+ case SOLID:
+ ts << "solid";
+ break;
+ case DOUBLE:
+ ts << "double";
+ break;
+ }
+
+ ts << " ";
+}
+
+static String getTagName(Node* n)
+{
+ if (n->isDocumentNode())
+ return "";
+ if (n->isCommentNode())
+ return "COMMENT";
+ return n->nodeName();
+}
+
+static bool isEmptyOrUnstyledAppleStyleSpan(const Node* node)
+{
+ if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag))
+ return false;
+
+ const HTMLElement* elem = static_cast<const HTMLElement*>(node);
+ if (elem->getAttribute(classAttr) != "Apple-style-span")
+ return false;
+
+ if (!node->hasChildNodes())
+ return true;
+
+ CSSMutableStyleDeclaration* inlineStyleDecl = elem->inlineStyleDecl();
+ return (!inlineStyleDecl || inlineStyleDecl->length() == 0);
+}
+
+String quoteAndEscapeNonPrintables(const String& s)
+{
+ Vector<UChar> result;
+ result.append('"');
+ for (unsigned i = 0; i != s.length(); ++i) {
+ UChar c = s[i];
+ if (c == '\\') {
+ result.append('\\');
+ result.append('\\');
+ } else if (c == '"') {
+ result.append('\\');
+ result.append('"');
+ } else if (c == '\n' || c == noBreakSpace)
+ result.append(' ');
+ else {
+ if (c >= 0x20 && c < 0x7F)
+ result.append(c);
+ else {
+ unsigned u = c;
+ String hex = String::format("\\x{%X}", u);
+ unsigned len = hex.length();
+ for (unsigned i = 0; i < len; ++i)
+ result.append(hex[i]);
+ }
+ }
+ }
+ result.append('"');
+ return String::adopt(result);
+}
+
+static TextStream &operator<<(TextStream& ts, const RenderObject& o)
+{
+ ts << o.renderName();
+
+ if (o.style() && o.style()->zIndex())
+ ts << " zI: " << o.style()->zIndex();
+
+ if (o.element()) {
+ String tagName = getTagName(o.element());
+ if (!tagName.isEmpty()) {
+ ts << " {" << tagName << "}";
+ // flag empty or unstyled AppleStyleSpan because we never
+ // want to leave them in the DOM
+ if (isEmptyOrUnstyledAppleStyleSpan(o.element()))
+ ts << " *empty or unstyled AppleStyleSpan*";
+ }
+ }
+
+ IntRect r(o.xPos(), o.yPos(), o.width(), o.height());
+ ts << " " << r;
+
+ if (!(o.isText() && !o.isBR())) {
+ if (o.parent() && (o.parent()->style()->color() != o.style()->color()))
+ ts << " [color=" << o.style()->color().name() << "]";
+
+ if (o.parent() && (o.parent()->style()->backgroundColor() != o.style()->backgroundColor()) &&
+ o.style()->backgroundColor().isValid() && o.style()->backgroundColor().rgb())
+ // Do not dump invalid or transparent backgrounds, since that is the default.
+ ts << " [bgcolor=" << o.style()->backgroundColor().name() << "]";
+
+ if (o.parent() && (o.parent()->style()->textFillColor() != o.style()->textFillColor()) &&
+ o.style()->textFillColor().isValid() && o.style()->textFillColor() != o.style()->color() &&
+ o.style()->textFillColor().rgb())
+ ts << " [textFillColor=" << o.style()->textFillColor().name() << "]";
+
+ if (o.parent() && (o.parent()->style()->textStrokeColor() != o.style()->textStrokeColor()) &&
+ o.style()->textStrokeColor().isValid() && o.style()->textStrokeColor() != o.style()->color() &&
+ o.style()->textStrokeColor().rgb())
+ ts << " [textStrokeColor=" << o.style()->textStrokeColor().name() << "]";
+
+ if (o.parent() && (o.parent()->style()->textStrokeWidth() != o.style()->textStrokeWidth()) &&
+ o.style()->textStrokeWidth() > 0)
+ ts << " [textStrokeWidth=" << o.style()->textStrokeWidth() << "]";
+
+ if (o.borderTop() || o.borderRight() || o.borderBottom() || o.borderLeft()) {
+ ts << " [border:";
+
+ BorderValue prevBorder;
+ if (o.style()->borderTop() != prevBorder) {
+ prevBorder = o.style()->borderTop();
+ if (!o.borderTop())
+ ts << " none";
+ else {
+ ts << " (" << o.borderTop() << "px ";
+ printBorderStyle(ts, o, o.style()->borderTopStyle());
+ Color col = o.style()->borderTopColor();
+ if (!col.isValid())
+ col = o.style()->color();
+ ts << col.name() << ")";
+ }
+ }
+
+ if (o.style()->borderRight() != prevBorder) {
+ prevBorder = o.style()->borderRight();
+ if (!o.borderRight())
+ ts << " none";
+ else {
+ ts << " (" << o.borderRight() << "px ";
+ printBorderStyle(ts, o, o.style()->borderRightStyle());
+ Color col = o.style()->borderRightColor();
+ if (!col.isValid())
+ col = o.style()->color();
+ ts << col.name() << ")";
+ }
+ }
+
+ if (o.style()->borderBottom() != prevBorder) {
+ prevBorder = o.style()->borderBottom();
+ if (!o.borderBottom())
+ ts << " none";
+ else {
+ ts << " (" << o.borderBottom() << "px ";
+ printBorderStyle(ts, o, o.style()->borderBottomStyle());
+ Color col = o.style()->borderBottomColor();
+ if (!col.isValid())
+ col = o.style()->color();
+ ts << col.name() << ")";
+ }
+ }
+
+ if (o.style()->borderLeft() != prevBorder) {
+ prevBorder = o.style()->borderLeft();
+ if (!o.borderLeft())
+ ts << " none";
+ else {
+ ts << " (" << o.borderLeft() << "px ";
+ printBorderStyle(ts, o, o.style()->borderLeftStyle());
+ Color col = o.style()->borderLeftColor();
+ if (!col.isValid())
+ col = o.style()->color();
+ ts << col.name() << ")";
+ }
+ }
+
+ ts << "]";
+ }
+ }
+
+ if (o.isTableCell()) {
+ const RenderTableCell& c = static_cast<const RenderTableCell&>(o);
+ ts << " [r=" << c.row() << " c=" << c.col() << " rs=" << c.rowSpan() << " cs=" << c.colSpan() << "]";
+ }
+
+ if (o.isListMarker()) {
+ String text = static_cast<const RenderListMarker&>(o).text();
+ if (!text.isEmpty()) {
+ if (text.length() != 1)
+ text = quoteAndEscapeNonPrintables(text);
+ else {
+ switch (text[0]) {
+ case bullet:
+ text = "bullet";
+ break;
+ case blackSquare:
+ text = "black square";
+ break;
+ case whiteBullet:
+ text = "white bullet";
+ break;
+ default:
+ text = quoteAndEscapeNonPrintables(text);
+ }
+ }
+ ts << ": " << text;
+ }
+ }
+
+ return ts;
+}
+
+static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBox& run)
+{
+ ts << "text run at (" << run.m_x << "," << run.m_y << ") width " << run.m_width;
+ if (run.direction() == RTL || run.m_dirOverride) {
+ ts << (run.direction() == RTL ? " RTL" : " LTR");
+ if (run.m_dirOverride)
+ ts << " override";
+ }
+ ts << ": "
+ << quoteAndEscapeNonPrintables(String(o.text()).substring(run.m_start, run.m_len))
+ << "\n";
+}
+
+void write(TextStream& ts, const RenderObject& o, int indent)
+{
+#if ENABLE(SVG)
+ if (o.isRenderPath()) {
+ write(ts, static_cast<const RenderPath&>(o), indent);
+ return;
+ }
+ if (o.isSVGContainer()) {
+ write(ts, static_cast<const RenderSVGContainer&>(o), indent);
+ return;
+ }
+ if (o.isSVGRoot()) {
+ write(ts, static_cast<const RenderSVGRoot&>(o), indent);
+ return;
+ }
+ if (o.isSVGText()) {
+ if (!o.isText())
+ write(ts, static_cast<const RenderSVGText&>(o), indent);
+ else
+ write(ts, static_cast<const RenderSVGInlineText&>(o), indent);
+ return;
+ }
+#endif
+
+ writeIndent(ts, indent);
+
+ ts << o << "\n";
+
+ if (o.isText() && !o.isBR()) {
+ const RenderText& text = static_cast<const RenderText&>(o);
+ for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) {
+ writeIndent(ts, indent + 1);
+ writeTextRun(ts, text, *box);
+ }
+ }
+
+ for (RenderObject* child = o.firstChild(); child; child = child->nextSibling()) {
+ if (child->hasLayer())
+ continue;
+ write(ts, *child, indent + 1);
+ }
+
+ if (o.isWidget()) {
+ Widget* widget = static_cast<const RenderWidget&>(o).widget();
+ if (widget && widget->isFrameView()) {
+ FrameView* view = static_cast<FrameView*>(widget);
+ RenderObject* root = view->frame()->contentRenderer();
+ if (root) {
+ view->layout();
+ RenderLayer* l = root->layer();
+ if (l)
+ writeLayers(ts, l, l, IntRect(l->xPos(), l->yPos(), l->width(), l->height()), indent + 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)
+{
+ writeIndent(ts, indent);
+
+ ts << "layer " << layerBounds;
+
+ if (!layerBounds.isEmpty()) {
+ if (!backgroundClipRect.contains(layerBounds))
+ ts << " backgroundClip " << backgroundClipRect;
+ if (!clipRect.contains(layerBounds))
+ ts << " clip " << clipRect;
+ if (!outlineClipRect.contains(layerBounds))
+ ts << " outlineClip " << outlineClipRect;
+ }
+
+ if (l.renderer()->hasOverflowClip()) {
+ if (l.scrollXOffset())
+ ts << " scrollX " << l.scrollXOffset();
+ if (l.scrollYOffset())
+ ts << " scrollY " << l.scrollYOffset();
+ if (l.renderer()->clientWidth() != l.scrollWidth())
+ ts << " scrollWidth " << l.scrollWidth();
+ if (l.renderer()->clientHeight() != l.scrollHeight())
+ ts << " scrollHeight " << l.scrollHeight();
+ }
+
+ if (layerType == -1)
+ ts << " layerType: background only";
+ else if (layerType == 1)
+ ts << " layerType: foreground only";
+
+ ts << "\n";
+
+ if (layerType != -1)
+ write(ts, *l.renderer(), indent + 1);
+}
+
+static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLayer* l,
+ const IntRect& paintDirtyRect, int indent)
+{
+ // Calculate the clip rects we should use.
+ IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
+ l->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, true);
+
+ // Ensure our lists are up-to-date.
+ l->updateZOrderLists();
+ l->updateOverflowList();
+
+ bool shouldPaint = 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);
+
+ if (negList) {
+ for (unsigned i = 0; i != negList->size(); ++i)
+ writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, indent);
+ }
+
+ if (shouldPaint)
+ write(ts, *l, layerBounds, damageRect, clipRectToApply, outlineRect, negList && negList->size() > 0, indent);
+
+ Vector<RenderLayer*>* overflowList = l->overflowList();
+ if (overflowList) {
+ for (unsigned i = 0; i != overflowList->size(); ++i)
+ writeLayers(ts, rootLayer, overflowList->at(i), paintDirtyRect, indent);
+ }
+
+ Vector<RenderLayer*>* posList = l->posZOrderList();
+ if (posList) {
+ for (unsigned i = 0; i != posList->size(); ++i)
+ writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, indent);
+ }
+}
+
+static String nodePosition(Node* node)
+{
+ String result;
+
+ Node* parent;
+ for (Node* n = node; n; n = parent) {
+ parent = n->parentNode();
+ if (!parent)
+ parent = n->shadowParentNode();
+ if (n != node)
+ result += " of ";
+ if (parent)
+ result += "child " + String::number(n->nodeIndex()) + " {" + getTagName(n) + "}";
+ else
+ result += "document";
+ }
+
+ return result;
+}
+
+static void writeSelection(TextStream& ts, const RenderObject* o)
+{
+ Node* n = o->element();
+ if (!n || !n->isDocumentNode())
+ return;
+
+ Document* doc = static_cast<Document*>(n);
+ Frame* frame = doc->frame();
+ if (!frame)
+ return;
+
+ Selection selection = frame->selection()->selection();
+ if (selection.isCaret()) {
+ ts << "caret: position " << selection.start().offset() << " of " << nodePosition(selection.start().node());
+ if (selection.affinity() == UPSTREAM)
+ ts << " (upstream affinity)";
+ ts << "\n";
+ } else if (selection.isRange())
+ ts << "selection start: position " << selection.start().offset() << " of " << nodePosition(selection.start().node()) << "\n"
+ << "selection end: position " << selection.end().offset() << " of " << nodePosition(selection.end().node()) << "\n";
+}
+
+String externalRepresentation(RenderObject* o)
+{
+ if (!o)
+ return String();
+
+ TextStream ts;
+#if ENABLE(SVG)
+ writeRenderResources(ts, o->document());
+#endif
+ if (o->view()->frameView())
+ o->view()->frameView()->layout();
+ RenderLayer* l = o->layer();
+ if (l) {
+ writeLayers(ts, l, l, IntRect(l->xPos(), l->yPos(), l->width(), l->height()));
+ writeSelection(ts, o);
+ }
+ return ts.release();
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.h b/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.h
new file mode 100644
index 0000000..daca253
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderTreeAsText.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderTreeAsText_h
+#define RenderTreeAsText_h
+
+namespace WebCore {
+
+ class RenderObject;
+ class String;
+ class TextStream;
+
+ String externalRepresentation(RenderObject*);
+ void write(TextStream&, const RenderObject&, int indent = 0);
+
+ // Helper function shared with SVGRenderTreeAsText
+ String quoteAndEscapeNonPrintables(const String&);
+
+} // namespace WebCore
+
+#endif // RenderTreeAsText_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp
new file mode 100644
index 0000000..3d9cb3d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO)
+#include "RenderVideo.h"
+
+#include "Document.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLVideoElement.h"
+#include "MediaPlayer.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+RenderVideo::RenderVideo(HTMLMediaElement* video)
+ : RenderMedia(video, video->player() ? video->player()->naturalSize() : IntSize(300, 150))
+{
+}
+
+RenderVideo::~RenderVideo()
+{
+ if (MediaPlayer* p = player()) {
+ p->setVisible(false);
+ p->setFrameView(0);
+ }
+}
+
+void RenderVideo::videoSizeChanged()
+{
+ if (!player())
+ return;
+ IntSize size = player()->naturalSize();
+ if (!size.isEmpty() && size != intrinsicSize()) {
+ setIntrinsicSize(size);
+ setPrefWidthsDirty(true);
+ setNeedsLayout(true);
+ }
+}
+
+IntRect RenderVideo::videoBox() const
+{
+ IntRect contentRect = contentBox();
+
+ if (intrinsicSize().isEmpty() || contentRect.isEmpty())
+ return IntRect();
+
+ IntRect resultRect = contentRect;
+ int ratio = contentRect.width() * intrinsicSize().height() - contentRect.height() * intrinsicSize().width();
+ if (ratio > 0) {
+ int newWidth = contentRect.height() * intrinsicSize().width() / intrinsicSize().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);
+ } 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);
+ }
+ return resultRect;
+}
+
+void RenderVideo::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
+{
+ MediaPlayer* mediaPlayer = player();
+ if (!mediaPlayer)
+ return;
+ updatePlayer();
+ IntRect rect = videoBox();
+ if (rect.isEmpty())
+ return;
+ rect.move(tx, ty);
+ mediaPlayer->paint(paintInfo.context, rect);
+}
+
+void RenderVideo::layout()
+{
+ RenderMedia::layout();
+ updatePlayer();
+}
+
+void RenderVideo::updateFromElement()
+{
+ RenderMedia::updateFromElement();
+ updatePlayer();
+}
+
+void RenderVideo::updatePlayer()
+{
+ MediaPlayer* mediaPlayer = player();
+ if (!mediaPlayer)
+ return;
+ if (!mediaElement()->inActiveDocument()) {
+ mediaPlayer->setVisible(false);
+ return;
+ }
+
+ // FIXME: This doesn't work correctly with transforms.
+ FloatPoint absPos = localToAbsolute();
+ IntRect videoBounds = videoBox();
+ videoBounds.move(absPos.x(), absPos.y());
+ mediaPlayer->setFrameView(document()->view());
+ mediaPlayer->setRect(videoBounds);
+ 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;
+ if (isWidthSpecified())
+ width = calcReplacedWidthUsing(style()->width());
+ else
+ width = calcAspectRatioWidth() * style()->effectiveZoom();
+
+ int minW = calcReplacedWidthUsing(style()->minWidth());
+ int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth());
+
+ return max(minW, min(width, maxW));
+}
+
+int RenderVideo::calcReplacedHeight() const
+{
+ int height;
+ if (isHeightSpecified())
+ height = calcReplacedHeightUsing(style()->height());
+ else
+ height = calcAspectRatioHeight() * style()->effectiveZoom();
+
+ int minH = calcReplacedHeightUsing(style()->minHeight());
+ int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight());
+
+ return max(minH, min(height, maxH));
+}
+
+int RenderVideo::calcAspectRatioWidth() const
+{
+ int intrinsicWidth = intrinsicSize().width();
+ int intrinsicHeight = intrinsicSize().height();
+ if (!intrinsicHeight)
+ return 0;
+ return RenderBox::calcReplacedHeight() * intrinsicWidth / intrinsicHeight;
+}
+
+int RenderVideo::calcAspectRatioHeight() const
+{
+ int intrinsicWidth = intrinsicSize().width();
+ int intrinsicHeight = intrinsicSize().height();
+ if (!intrinsicWidth)
+ return 0;
+ return RenderBox::calcReplacedWidth() * intrinsicHeight / intrinsicWidth;
+}
+
+void RenderVideo::calcPrefWidths()
+{
+ 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);
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h
new file mode 100644
index 0000000..43c1e7b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderVideo.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderVideo_h
+#define RenderVideo_h
+
+#if ENABLE(VIDEO)
+
+#include "RenderMedia.h"
+
+namespace WebCore {
+
+class HTMLMediaElement;
+
+class RenderVideo : public RenderMedia {
+public:
+ RenderVideo(HTMLMediaElement*);
+ virtual ~RenderVideo();
+
+ virtual const char* renderName() const { return "RenderVideo"; }
+
+ virtual void paintReplaced(PaintInfo& paintInfo, int tx, int ty);
+
+ virtual void layout();
+
+ virtual int calcReplacedWidth(bool includeMaxWidth = true) const;
+ virtual int calcReplacedHeight() const;
+
+ virtual void calcPrefWidths();
+
+ void videoSizeChanged();
+
+ void updateFromElement();
+
+protected:
+ virtual void intrinsicSizeChanged() { videoSizeChanged(); }
+
+private:
+ int calcAspectRatioWidth() const;
+ int calcAspectRatioHeight() const;
+
+ bool isWidthSpecified() const;
+ bool isHeightSpecified() const;
+
+ IntRect videoBox() const;
+
+ void updatePlayer();
+};
+
+} // namespace WebCore
+
+#endif
+#endif // RenderVideo_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp
new file mode 100644
index 0000000..1715509
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderView.cpp
@@ -0,0 +1,611 @@
+/**
+ * This file is part of the HTML widget for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004, 2005, 2006 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
+ * 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 "RenderView.h"
+
+#include "Document.h"
+#include "Element.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "RenderLayer.h"
+
+namespace WebCore {
+
+RenderView::RenderView(Node* node, FrameView* view)
+ : RenderBlock(node)
+ , m_frameView(view)
+ , m_selectionStart(0)
+ , m_selectionEnd(0)
+ , m_selectionStartPos(-1)
+ , m_selectionEndPos(-1)
+ , m_printImages(true)
+ , m_maximalOutlineSize(0)
+ , m_layoutState(0)
+ , m_layoutStateDisableCount(0)
+{
+ // Clear our anonymous bit, set because RenderObject assumes
+ // any renderer with document as the node is anonymous.
+ setIsAnonymous(false);
+
+ // init RenderObject attributes
+ setInline(false);
+
+ // try to contrain the width to the views width
+ m_width = 0;
+ m_height = 0;
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = 0;
+
+ setPrefWidthsDirty(true, false);
+
+ setPositioned(true); // to 0,0 :)
+
+ // Create a new root layer for our layer hierarchy.
+ m_layer = new (node->document()->renderArena()) RenderLayer(this);
+ setHasLayer(true);
+}
+
+RenderView::~RenderView()
+{
+}
+
+void RenderView::calcHeight()
+{
+ if (!printing() && m_frameView)
+ m_height = viewHeight();
+}
+
+void RenderView::calcWidth()
+{
+ if (!printing() && m_frameView)
+ m_width = viewWidth();
+ m_marginLeft = 0;
+ m_marginRight = 0;
+}
+
+void RenderView::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ RenderBlock::calcPrefWidths();
+
+ m_maxPrefWidth = m_minPrefWidth;
+}
+
+void RenderView::layout()
+{
+ if (printing())
+ m_minPrefWidth = m_maxPrefWidth = m_width;
+
+ // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account.
+ bool relayoutChildren = !printing() && (!m_frameView || m_width != viewWidth() || m_height != viewHeight());
+ if (relayoutChildren) {
+ setChildNeedsLayout(true, false);
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent())
+ child->setChildNeedsLayout(true, false);
+ }
+ }
+
+ ASSERT(!m_layoutState);
+ LayoutState state;
+ // FIXME: May be better to push a clip and avoid issuing offscreen repaints.
+ state.m_clipped = false;
+ m_layoutState = &state;
+
+ if (needsLayout())
+ RenderBlock::layout();
+
+ // Ensure that docWidth() >= width() and docHeight() >= height().
+ setOverflowWidth(m_width);
+ setOverflowHeight(m_height);
+
+ setOverflowWidth(docWidth());
+ setOverflowHeight(docHeight());
+
+ ASSERT(layoutDelta() == IntSize());
+ ASSERT(m_layoutStateDisableCount == 0);
+ ASSERT(m_layoutState == &state);
+ m_layoutState = 0;
+ setNeedsLayout(false);
+}
+
+FloatPoint RenderView::localToAbsolute(FloatPoint localPoint, bool fixed, bool) const
+{
+ if (fixed && m_frameView)
+ localPoint += m_frameView->scrollOffset();
+
+ return localPoint;
+}
+
+FloatPoint RenderView::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool) const
+{
+ if (fixed && m_frameView)
+ containerPoint -= m_frameView->scrollOffset();
+
+ return containerPoint;
+}
+
+FloatQuad RenderView::localToAbsoluteQuad(const FloatQuad& localQuad, bool fixed) const
+{
+ FloatQuad quad = localQuad;
+ if (fixed && m_frameView)
+ quad += m_frameView->scrollOffset();
+
+ return quad;
+}
+
+void RenderView::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ // If we ever require layout but receive a paint anyway, something has gone horribly wrong.
+ ASSERT(!needsLayout());
+
+ // Cache the print rect because the dirty rect could get changed during painting.
+ if (printing())
+ setPrintRect(paintInfo.rect);
+ else
+ setPrintRect(IntRect());
+ paintObject(paintInfo, tx, ty);
+}
+
+static inline bool rendererObscuresBackground(RenderObject* object)
+{
+ return object && object->style()->visibility() == VISIBLE && object->style()->opacity() == 1 && !object->style()->hasTransform();
+}
+
+void RenderView::paintBoxDecorations(PaintInfo& paintInfo, int, int)
+{
+ // Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit
+ // when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers,
+ // layers with reflections, or transformed layers.
+ // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being inside
+ // a transform, transparency layer, etc.
+ Element* elt;
+ for (elt = document()->ownerElement(); view() && elt && elt->renderer(); elt = elt->document()->ownerElement()) {
+ RenderLayer* layer = elt->renderer()->enclosingLayer();
+ if (layer->requiresSlowRepaints()) {
+ frameView()->setUseSlowRepaints();
+ break;
+ }
+ }
+
+ // If painting will entirely fill the view, no need to fill the background.
+ if (elt || rendererObscuresBackground(firstChild()) || !view())
+ return;
+
+ // This code typically only executes if the root element's visibility has been set to hidden,
+ // or there is a transform on the <html>.
+ // Only fill with the base background color (typically white) if we're the root document,
+ // since iframes/frames with no background in the child document should show the parent's background.
+ if (view()->isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent.
+ frameView()->setUseSlowRepaints(); // The parent must show behind the child.
+ else {
+ Color baseColor = frameView()->baseBackgroundColor();
+ if (baseColor.alpha() > 0) {
+ paintInfo.context->save();
+ paintInfo.context->setCompositeOperation(CompositeCopy);
+ paintInfo.context->fillRect(paintInfo.rect, baseColor);
+ paintInfo.context->restore();
+ } else
+ paintInfo.context->clearRect(paintInfo.rect);
+ }
+}
+
+void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate)
+{
+ if (printing() || ur.width() == 0 || ur.height() == 0)
+ return;
+
+ if (!m_frameView)
+ return;
+
+ // We always just invalidate the root view, since we could be an iframe that is clipped out
+ // or even invisible.
+ Element* elt = document()->ownerElement();
+ if (!elt)
+ m_frameView->repaintContentRectangle(ur, immediate);
+ else if (RenderObject* obj = elt->renderer()) {
+ IntRect vr = viewRect();
+ IntRect r = intersection(ur, vr);
+
+ // Subtract out the contentsX and contentsY offsets to get our coords within the viewing
+ // rectangle.
+ r.move(-vr.x(), -vr.y());
+
+ // FIXME: Hardcoded offsets here are not good.
+ r.move(obj->borderLeft() + obj->paddingLeft(),
+ obj->borderTop() + obj->paddingTop());
+ obj->repaintRectangle(r, immediate);
+ }
+}
+
+void RenderView::computeAbsoluteRepaintRect(IntRect& rect, bool fixed)
+{
+ if (printing())
+ return;
+
+ if (fixed && m_frameView)
+ rect.move(m_frameView->scrollX(), m_frameView->scrollY());
+
+ // Apply our transform if we have one (because of full page zooming).
+ if (m_layer && m_layer->transform())
+ rect = m_layer->transform()->mapRect(rect);
+}
+
+void RenderView::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool)
+{
+ rects.append(IntRect(tx, ty, m_layer->width(), m_layer->height()));
+}
+
+void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool)
+{
+ quads.append(FloatRect(0, 0, m_layer->width(), m_layer->height()));
+}
+
+RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset)
+{
+ if (!object)
+ return 0;
+
+ RenderObject* child = object->childAt(offset);
+ return child ? child : object->nextInPreOrderAfterChildren();
+}
+
+IntRect RenderView::selectionRect(bool clipToVisibleContent)
+{
+ // The virtual selectionRect() should never be called on the RenderView.
+ // We assert because there used to be ambiguity between
+ // RenderView::selectionRect(bool) and
+ // virtual RenderObject::selectionRect(bool) const
+ ASSERT_NOT_REACHED();
+ return RenderBlock::selectionRect(clipToVisibleContent);
+}
+
+IntRect RenderView::selectionBounds(bool clipToVisibleContent) const
+{
+ document()->updateRendering();
+
+ typedef HashMap<RenderObject*, SelectionInfo*> SelectionMap;
+ SelectionMap selectedObjects;
+
+ RenderObject* os = m_selectionStart;
+ RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos);
+ while (os && os != stop) {
+ if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) {
+ // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
+ selectedObjects.set(os, new SelectionInfo(os, clipToVisibleContent));
+ RenderBlock* cb = os->containingBlock();
+ while (cb && !cb->isRenderView()) {
+ SelectionInfo* blockInfo = selectedObjects.get(cb);
+ if (blockInfo)
+ break;
+ selectedObjects.set(cb, new SelectionInfo(cb, clipToVisibleContent));
+ cb = cb->containingBlock();
+ }
+ }
+
+ os = os->nextInPreOrder();
+ }
+
+ // Now create a single bounding box rect that encloses the whole selection.
+ IntRect selRect;
+ SelectionMap::iterator end = selectedObjects.end();
+ for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) {
+ SelectionInfo* info = i->second;
+ selRect.unite(info->rect());
+ delete info;
+ }
+ return selRect;
+}
+
+void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos)
+{
+ // Make sure both our start and end objects are defined.
+ // Check www.msnbc.com and try clicking around to find the case where this happened.
+ if ((start && !end) || (end && !start))
+ return;
+
+ // Just return if the selection hasn't changed.
+ if (m_selectionStart == start && m_selectionStartPos == startPos &&
+ m_selectionEnd == end && m_selectionEndPos == endPos)
+ return;
+
+ // Record the old selected objects. These will be used later
+ // when we compare against the new selected objects.
+ int oldStartPos = m_selectionStartPos;
+ int oldEndPos = m_selectionEndPos;
+
+ // Objects each have a single selection rect to examine.
+ typedef HashMap<RenderObject*, SelectionInfo*> SelectedObjectMap;
+ SelectedObjectMap oldSelectedObjects;
+ SelectedObjectMap newSelectedObjects;
+
+ // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks.
+ // In order to get the repaint rect right, we have to examine left, middle, and right rects individually, since otherwise
+ // the union of those rects might remain the same even when changes have occurred.
+ typedef HashMap<RenderBlock*, BlockSelectionInfo*> SelectedBlockMap;
+ SelectedBlockMap oldSelectedBlocks;
+ SelectedBlockMap newSelectedBlocks;
+
+ RenderObject* os = m_selectionStart;
+ RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos);
+ while (os && os != stop) {
+ if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) {
+ // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
+ oldSelectedObjects.set(os, new SelectionInfo(os, true));
+ RenderBlock* cb = os->containingBlock();
+ while (cb && !cb->isRenderView()) {
+ BlockSelectionInfo* blockInfo = oldSelectedBlocks.get(cb);
+ if (blockInfo)
+ break;
+ oldSelectedBlocks.set(cb, new BlockSelectionInfo(cb));
+ cb = cb->containingBlock();
+ }
+ }
+
+ os = os->nextInPreOrder();
+ }
+
+ // Now clear the selection.
+ SelectedObjectMap::iterator oldObjectsEnd = oldSelectedObjects.end();
+ for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i)
+ i->first->setSelectionState(SelectionNone);
+
+ // set selection start and end
+ m_selectionStart = start;
+ m_selectionStartPos = startPos;
+ m_selectionEnd = end;
+ m_selectionEndPos = endPos;
+
+ // Update the selection status of all objects between m_selectionStart and m_selectionEnd
+ if (start && start == end)
+ start->setSelectionState(SelectionBoth);
+ else {
+ if (start)
+ start->setSelectionState(SelectionStart);
+ if (end)
+ end->setSelectionState(SelectionEnd);
+ }
+
+ RenderObject* o = start;
+ stop = rendererAfterPosition(end, endPos);
+
+ while (o && o != stop) {
+ if (o != start && o != end && o->canBeSelectionLeaf())
+ o->setSelectionState(SelectionInside);
+ o = o->nextInPreOrder();
+ }
+
+ // Now that the selection state has been updated for the new objects, walk them again and
+ // put them in the new objects list.
+ o = start;
+ while (o && o != stop) {
+ if ((o->canBeSelectionLeaf() || o == start || o == end) && o->selectionState() != SelectionNone) {
+ newSelectedObjects.set(o, new SelectionInfo(o, true));
+ RenderBlock* cb = o->containingBlock();
+ while (cb && !cb->isRenderView()) {
+ BlockSelectionInfo* blockInfo = newSelectedBlocks.get(cb);
+ if (blockInfo)
+ break;
+ newSelectedBlocks.set(cb, new BlockSelectionInfo(cb));
+ cb = cb->containingBlock();
+ }
+ }
+
+ o = o->nextInPreOrder();
+ }
+
+ if (!m_frameView) {
+ // We built the maps, but we aren't going to use them.
+ // We need to delete the values, otherwise they'll all leak!
+ deleteAllValues(oldSelectedObjects);
+ deleteAllValues(newSelectedObjects);
+ deleteAllValues(oldSelectedBlocks);
+ deleteAllValues(newSelectedBlocks);
+ return;
+ }
+
+ // 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;
+ SelectionInfo* newInfo = newSelectedObjects.get(obj);
+ SelectionInfo* oldInfo = i->second;
+ if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() ||
+ (m_selectionStart == obj && oldStartPos != m_selectionStartPos) ||
+ (m_selectionEnd == obj && oldEndPos != m_selectionEndPos)) {
+ repaintViewRectangle(oldInfo->rect());
+ if (newInfo) {
+ repaintViewRectangle(newInfo->rect());
+ newSelectedObjects.remove(obj);
+ delete newInfo;
+ }
+ }
+ delete oldInfo;
+ }
+
+ // Any new objects that remain were not found in the old objects dict, and so they need to be updated.
+ SelectedObjectMap::iterator newObjectsEnd = newSelectedObjects.end();
+ for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i) {
+ SelectionInfo* newInfo = i->second;
+ repaintViewRectangle(newInfo->rect());
+ delete newInfo;
+ }
+
+ // Have any of the old blocks changed?
+ SelectedBlockMap::iterator oldBlocksEnd = oldSelectedBlocks.end();
+ for (SelectedBlockMap::iterator i = oldSelectedBlocks.begin(); i != oldBlocksEnd; ++i) {
+ RenderBlock* block = i->first;
+ BlockSelectionInfo* newInfo = newSelectedBlocks.get(block);
+ BlockSelectionInfo* oldInfo = i->second;
+ if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) {
+ repaintViewRectangle(oldInfo->rects());
+ if (newInfo) {
+ repaintViewRectangle(newInfo->rects());
+ newSelectedBlocks.remove(block);
+ delete newInfo;
+ }
+ }
+ delete oldInfo;
+ }
+
+ // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated.
+ SelectedBlockMap::iterator newBlocksEnd = newSelectedBlocks.end();
+ for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i) {
+ BlockSelectionInfo* newInfo = i->second;
+ repaintViewRectangle(newInfo->rects());
+ delete newInfo;
+ }
+}
+
+void RenderView::clearSelection()
+{
+ setSelection(0, -1, 0, -1);
+}
+
+void RenderView::selectionStartEnd(int& startPos, int& endPos) const
+{
+ startPos = m_selectionStartPos;
+ endPos = m_selectionEndPos;
+}
+
+bool RenderView::printing() const
+{
+ return document()->printing();
+}
+
+void RenderView::updateWidgetPositions()
+{
+ RenderObjectSet::iterator end = m_widgets.end();
+ for (RenderObjectSet::iterator it = m_widgets.begin(); it != end; ++it)
+ (*it)->updateWidgetPosition();
+}
+
+void RenderView::addWidget(RenderObject* o)
+{
+ m_widgets.add(o);
+}
+
+void RenderView::removeWidget(RenderObject* o)
+{
+ m_widgets.remove(o);
+}
+
+IntRect RenderView::viewRect() const
+{
+ if (printing())
+ return IntRect(0, 0, m_width, m_height);
+ if (m_frameView)
+ return m_frameView->visibleContentRect();
+ return IntRect();
+}
+
+int RenderView::docHeight() const
+{
+ int h = m_height;
+ int lowestPos = lowestPosition();
+ if (lowestPos > h)
+ h = lowestPos;
+
+ // FIXME: This doesn't do any margin collapsing.
+ // Instead of this dh computation we should keep the result
+ // when we call RenderBlock::layout.
+ int dh = 0;
+ for (RenderObject* c = firstChild(); c; c = c->nextSibling())
+ dh += c->height() + c->marginTop() + c->marginBottom();
+
+ if (dh > h)
+ h = dh;
+
+ return h;
+}
+
+int RenderView::docWidth() const
+{
+ int w = m_width;
+ int rightmostPos = rightmostPosition();
+ if (rightmostPos > w)
+ w = rightmostPos;
+
+ for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
+ int dw = c->width() + c->marginLeft() + c->marginRight();
+ if (dw > w)
+ w = dw;
+ }
+
+ return w;
+}
+
+int RenderView::viewHeight() const
+{
+ int height = 0;
+ if (!printing() && m_frameView) {
+ height = m_frameView->layoutHeight();
+ height = m_frameView->useFixedLayout() ? ceilf(style()->effectiveZoom() * float(height)) : height;
+ }
+ return height;
+}
+
+int RenderView::viewWidth() const
+{
+ int width = 0;
+ if (!printing() && m_frameView) {
+ width = m_frameView->layoutWidth();
+ width = m_frameView->useFixedLayout() ? ceilf(style()->effectiveZoom() * float(width)) : width;
+ }
+ return width;
+}
+
+// The idea here is to take into account what object is moving the pagination point, and
+// thus choose the best place to chop it.
+void RenderView::setBestTruncatedAt(int y, RenderObject* forRenderer, bool forcedBreak)
+{
+ // Nobody else can set a page break once we have a forced break.
+ if (m_forcedPageBreak)
+ return;
+
+ // Forced breaks always win over unforced breaks.
+ if (forcedBreak) {
+ m_forcedPageBreak = true;
+ m_bestTruncatedAt = y;
+ return;
+ }
+
+ // prefer the widest object who tries to move the pagination point
+ int width = forRenderer->width();
+ if (width > m_truncatorWidth) {
+ m_truncatorWidth = width;
+ m_bestTruncatedAt = y;
+ }
+}
+
+void RenderView::pushLayoutState(RenderObject* root)
+{
+ ASSERT(!m_frameView->needsFullRepaint());
+ ASSERT(m_layoutStateDisableCount == 0);
+ ASSERT(m_layoutState == 0);
+
+ m_layoutState = new (renderArena()) LayoutState(root);
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderView.h b/src/3rdparty/webkit/WebCore/rendering/RenderView.h
new file mode 100644
index 0000000..96597de
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderView.h
@@ -0,0 +1,226 @@
+/*
+ * This file is part of the HTML widget for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2006 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
+ * 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 RenderView_h
+#define RenderView_h
+
+#include "FrameView.h"
+#include "Frame.h"
+#include "LayoutState.h"
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+class RenderView : public RenderBlock {
+public:
+ RenderView(Node*, FrameView*);
+ virtual ~RenderView();
+
+ virtual const char* renderName() const { return "RenderView"; }
+
+ virtual bool isRenderView() const { return true; }
+
+ virtual void layout();
+ virtual void calcWidth();
+ virtual void calcHeight();
+ virtual void calcPrefWidths();
+ virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const;
+ virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const;
+ virtual FloatQuad localToAbsoluteQuad(const FloatQuad&, bool fixed = false) const;
+
+ int docHeight() const;
+ int docWidth() const;
+
+ // The same as the FrameView's layoutHeight/layoutWidth but with null check guards.
+ int viewHeight() const;
+ int viewWidth() const;
+
+ float zoomFactor() const { return m_frameView->frame() && m_frameView->frame()->shouldApplyPageZoom() ? m_frameView->frame()->zoomFactor() : 1.0f; }
+
+ FrameView* frameView() const { return m_frameView; }
+
+ virtual bool hasOverhangingFloats() { return false; }
+
+ virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false);
+ virtual void repaintViewRectangle(const IntRect&, bool immediate = false);
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void paintBoxDecorations(PaintInfo&, int tx, int ty);
+
+ void setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos);
+ void clearSelection();
+ virtual RenderObject* selectionStart() const { return m_selectionStart; }
+ virtual RenderObject* selectionEnd() const { return m_selectionEnd; }
+
+ 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 setBestTruncatedAt(int y, RenderObject *forRenderer, bool forcedBreak = false);
+ int bestTruncatedAt() const { return m_bestTruncatedAt; }
+
+ int truncatedAt() const { return m_truncatedAt; }
+
+ virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true);
+ virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true);
+
+ IntRect selectionBounds(bool clipToVisibleContent = true) const;
+
+ void setMaximalOutlineSize(int o) { m_maximalOutlineSize = o; }
+ int maximalOutlineSize() const { return m_maximalOutlineSize; }
+
+ virtual IntRect viewRect() const;
+
+ virtual void selectionStartEnd(int& startPos, int& endPos) const;
+
+ IntRect printRect() const { return m_printRect; }
+ void setPrintRect(const IntRect& r) { m_printRect = r; }
+
+ void updateWidgetPositions();
+ void addWidget(RenderObject*);
+ void removeWidget(RenderObject*);
+
+ // layoutDelta is used transiently during layout to store how far an object has moved from its
+ // last layout location, in order to repaint correctly
+ const IntSize& layoutDelta() const { return m_layoutDelta; }
+ void addLayoutDelta(const IntSize& delta) { m_layoutDelta += delta; }
+
+ void pushLayoutState(RenderBox* renderer, const IntSize& offset)
+ {
+ if (m_layoutStateDisableCount || m_frameView->needsFullRepaint())
+ return;
+ m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset);
+ }
+
+ void pushLayoutState(RenderObject*);
+
+ void popLayoutState()
+ {
+ if (m_layoutStateDisableCount || m_frameView->needsFullRepaint())
+ return;
+ LayoutState* state = m_layoutState;
+ m_layoutState = state->m_next;
+ state->destroy(renderArena());
+ }
+
+ LayoutState* layoutState() const { return m_layoutStateDisableCount ? 0 : m_layoutState; }
+
+ // Suspends the LayoutState optimization. Used under transforms that cannot be represented by
+ // LayoutState (common in SVG) and when manipulating the render tree during layout in ways
+ // that can trigger repaint of a non-child (e.g. when a list item moves its list marker around).
+ void disableLayoutState() { m_layoutStateDisableCount++; }
+ void enableLayoutState() { ASSERT(m_layoutStateDisableCount > 0); m_layoutStateDisableCount--; }
+
+private:
+ // selectionRect should never be called on a RenderView
+ virtual IntRect selectionRect(bool);
+
+protected:
+ FrameView* m_frameView;
+
+ RenderObject* m_selectionStart;
+ RenderObject* m_selectionEnd;
+ int m_selectionStartPos;
+ int m_selectionEndPos;
+
+ // used to ignore viewport width when printing to the printer
+ bool m_printImages;
+ int m_truncatedAt;
+
+ int m_maximalOutlineSize; // Used to apply a fudge factor to dirty-rect checks on blocks/tables.
+ IntRect m_printRect; // Used when printing.
+
+ typedef HashSet<RenderObject*> RenderObjectSet;
+
+ RenderObjectSet m_widgets;
+
+private:
+ int m_bestTruncatedAt;
+ int m_truncatorWidth;
+ bool m_forcedPageBreak;
+ IntSize m_layoutDelta;
+ LayoutState* m_layoutState;
+ unsigned m_layoutStateDisableCount;
+};
+
+// Stack-based class to assist with LayoutState push/pop
+class LayoutStateMaintainer : Noncopyable {
+public:
+ // ctor to push now
+ LayoutStateMaintainer(RenderView* view, RenderBox* root, IntSize offset, bool shouldPush = true)
+ : m_view(view)
+ , m_shouldPushPop(shouldPush)
+ , m_didStart(false)
+ , m_didEnd(false)
+ {
+ push(root, offset);
+ }
+
+ // ctor to maybe push later
+ LayoutStateMaintainer(RenderView* view)
+ : m_view(view)
+ , m_shouldPushPop(true)
+ , m_didStart(false)
+ , m_didEnd(false)
+ {
+ }
+
+ ~LayoutStateMaintainer()
+ {
+ ASSERT(m_didStart == m_didEnd); // if this fires, it means that someone did a push(), but forgot to pop().
+ }
+
+ void pop()
+ {
+ if (m_didStart) {
+ ASSERT(!m_didEnd);
+ if (m_shouldPushPop)
+ m_view->popLayoutState();
+ else
+ m_view->enableLayoutState();
+ m_didEnd = true;
+ }
+ }
+
+ void push(RenderBox* root, IntSize offset)
+ {
+ ASSERT(!m_didStart);
+ if (m_shouldPushPop)
+ m_view->pushLayoutState(root, offset);
+ else
+ m_view->disableLayoutState();
+ m_didStart = true;
+ }
+
+ bool didPush() const { return m_didStart; }
+
+private:
+ RenderView* m_view;
+ bool m_shouldPushPop : 1; // true if we should push/pop, rather than disable/enable
+ bool m_didStart : 1; // true if we did a push or disable
+ bool m_didEnd : 1; // true if we popped or re-enabled
+};
+
+} // namespace WebCore
+
+#endif // RenderView_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp
new file mode 100644
index 0000000..1a9744a
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.cpp
@@ -0,0 +1,278 @@
+/**
+ * This file is part of the HTML widget for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006 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
+ * 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 "RenderWidget.h"
+
+#include "AnimationController.h"
+#include "AXObjectCache.h"
+#include "Document.h"
+#include "Element.h"
+#include "Event.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HitTestResult.h"
+#include "RenderLayer.h"
+#include "RenderView.h"
+
+using namespace std;
+
+namespace WebCore {
+
+static HashMap<const Widget*, RenderWidget*>& widgetRendererMap()
+{
+ static HashMap<const Widget*, RenderWidget*>* staticWidgetRendererMap = new HashMap<const Widget*, RenderWidget*>;
+ return *staticWidgetRendererMap;
+}
+
+RenderWidget::RenderWidget(Node* node)
+ : RenderReplaced(node)
+ , m_widget(0)
+ , m_refCount(0)
+{
+ // a replaced element doesn't support being anonymous
+ ASSERT(node);
+ m_view = node->document()->view();
+
+ 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();
+}
+
+void RenderWidget::destroy()
+{
+ // We can't call the base class's destroy because we don't
+ // want to unconditionally delete ourselves (we're ref-counted).
+ // 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())
+ v->removeWidget(this);
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->remove(this);
+
+ remove();
+
+ if (m_widget) {
+ if (m_view)
+ m_view->removeChild(m_widget);
+ widgetRendererMap().remove(m_widget);
+ }
+
+ // removes from override size map
+ if (hasOverrideSize())
+ setOverrideSize(-1);
+
+ RenderLayer* layer = m_layer;
+ RenderArena* arena = renderArena();
+
+ if (layer)
+ layer->clearClipRects();
+
+ if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent()))
+ RenderBlock::removePercentHeightDescendant(this);
+
+ setNode(0);
+ deref(arena);
+
+ if (layer)
+ layer->destroy(arena);
+}
+
+RenderWidget::~RenderWidget()
+{
+ ASSERT(m_refCount <= 0);
+ deleteWidget();
+}
+
+void RenderWidget::setWidgetGeometry(const IntRect& frame)
+{
+ if (element() && m_widget->frameRect() != frame) {
+ RenderArena* arena = ref();
+ RefPtr<Node> protectedElement(element());
+ m_widget->setFrameRect(frame);
+ deref(arena);
+ }
+}
+
+void RenderWidget::setWidget(Widget* widget)
+{
+ if (widget != m_widget) {
+ if (m_widget) {
+ m_widget->removeFromParent();
+ widgetRendererMap().remove(m_widget);
+ deleteWidget();
+ }
+ m_widget = widget;
+ if (m_widget) {
+ widgetRendererMap().add(m_widget, 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_view->addChild(m_widget);
+ }
+ }
+}
+
+void RenderWidget::layout()
+{
+ ASSERT(needsLayout());
+
+ setNeedsLayout(false);
+}
+
+void RenderWidget::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
+{
+ RenderReplaced::styleDidChange(diff, oldStyle);
+ if (m_widget) {
+ if (style()->visibility() != VISIBLE)
+ m_widget->hide();
+ else
+ m_widget->show();
+ }
+}
+
+void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (!shouldPaint(paintInfo, tx, ty))
+ return;
+
+ tx += m_x;
+ ty += m_y;
+
+ if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
+ paintBoxDecorations(paintInfo, tx, ty);
+
+ if (paintInfo.phase == PaintPhaseMask) {
+ paintMask(paintInfo, tx, ty);
+ return;
+ }
+
+ if (!m_view || paintInfo.phase != PaintPhaseForeground || style()->visibility() != VISIBLE)
+ return;
+
+#if PLATFORM(MAC)
+ if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
+ paintCustomHighlight(tx - m_x, ty - m_y, style()->highlight(), true);
+#endif
+
+ 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);
+ }
+
+ // Paint a partially transparent wash over selected widgets.
+ if (isSelected() && !document()->printing())
+ paintInfo.context->fillRect(selectionRect(), selectionBackgroundColor());
+}
+
+void RenderWidget::deref(RenderArena *arena)
+{
+ if (--m_refCount <= 0)
+ arenaDelete(arena, this);
+}
+
+void RenderWidget::updateWidgetPosition()
+{
+ if (!m_widget)
+ return;
+
+ // FIXME: This doesn't work correctly with transforms.
+ FloatPoint absPos = localToAbsolute();
+ absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
+
+ int width = m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight();
+ int height = m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom();
+
+ IntRect newBounds(absPos.x(), absPos.y(), width, height);
+ IntRect oldBounds(m_widget->frameRect());
+ if (newBounds != oldBounds) {
+ // The widget changed positions. Update the frame geometry.
+ if (checkForRepaintDuringLayout()) {
+ RenderView* v = view();
+ if (!v->printing()) {
+ v->repaintViewRectangle(oldBounds);
+ v->repaintViewRectangle(newBounds);
+ }
+ }
+
+ RenderArena* arena = ref();
+ element()->ref();
+ m_widget->setFrameRect(newBounds);
+ element()->deref();
+ deref(arena);
+ }
+}
+
+void RenderWidget::setSelectionState(SelectionState state)
+{
+ if (selectionState() != state) {
+ RenderReplaced::setSelectionState(state);
+ if (m_widget)
+ m_widget->setIsSelected(isSelected());
+ }
+}
+
+void RenderWidget::deleteWidget()
+{
+ delete m_widget;
+}
+
+RenderWidget* RenderWidget::find(const Widget* widget)
+{
+ return widgetRendererMap().get(widget);
+}
+
+bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action)
+{
+ bool hadResult = result.innerNode();
+ bool inside = RenderReplaced::nodeAtPoint(request, result, x, y, tx, ty, action);
+
+ // Check to see if we are really over the widget itself (and not just in the border/padding area).
+ if (inside && !hadResult && result.innerNode() == element())
+ result.setIsOverWidget(contentBox().contains(result.localPoint()));
+ return inside;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h
new file mode 100644
index 0000000..a64bb54
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderWidget.h
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the HTML widget for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004, 2005, 2006 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
+ * 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 RenderWidget_h
+#define RenderWidget_h
+
+#include "RenderReplaced.h"
+
+namespace WebCore {
+
+class Widget;
+
+class RenderWidget : public RenderReplaced {
+public:
+ RenderWidget(Node*);
+ virtual ~RenderWidget();
+
+ virtual bool isWidget() const { return true; }
+
+ virtual void paint(PaintInfo&, int tx, int ty);
+
+ virtual void destroy();
+ virtual void layout();
+
+ Widget* widget() const { return m_widget; }
+ static RenderWidget* find(const Widget*);
+
+ RenderArena* ref() { ++m_refCount; return renderArena(); }
+ void deref(RenderArena*);
+
+ virtual void setSelectionState(SelectionState);
+
+ virtual void updateWidgetPosition();
+
+ virtual void setWidget(Widget*);
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+
+protected:
+ virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
+
+private:
+ void setWidgetGeometry(const IntRect&);
+
+ virtual void deleteWidget();
+
+protected:
+ Widget* m_widget;
+ FrameView* m_view;
+
+private:
+ int m_refCount;
+};
+
+} // namespace WebCore
+
+#endif // RenderWidget_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderWordBreak.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderWordBreak.cpp
new file mode 100644
index 0000000..a620560
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderWordBreak.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "RenderWordBreak.h"
+
+#include "HTMLElement.h"
+
+namespace WebCore {
+
+RenderWordBreak::RenderWordBreak(HTMLElement* element)
+ : RenderText(element, StringImpl::empty())
+{
+}
+
+const char* RenderWordBreak::renderName() const
+{
+ return "RenderWordBreak";
+}
+
+bool RenderWordBreak::isWordBreak() const
+{
+ return true;
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderWordBreak.h b/src/3rdparty/webkit/WebCore/rendering/RenderWordBreak.h
new file mode 100644
index 0000000..acd8179
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RenderWordBreak.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef RenderWordBreak_h
+#define RenderWordBreak_h
+
+#include "RenderText.h"
+
+namespace WebCore {
+
+class HTMLElement;
+
+class RenderWordBreak : public RenderText {
+public:
+ RenderWordBreak(HTMLElement*);
+
+ virtual const char* renderName() const;
+ virtual bool isWordBreak() const;
+};
+
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp
new file mode 100644
index 0000000..bb88f24
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.cpp
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2003, 2006, 2008 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 "RootInlineBox.h"
+
+#include "BidiResolver.h"
+#include "ChromeClient.h"
+#include "Document.h"
+#include "EllipsisBox.h"
+#include "Frame.h"
+#include "GraphicsContext.h"
+#include "HitTestResult.h"
+#include "Page.h"
+#include "RenderArena.h"
+#include "RenderBlock.h"
+
+using namespace std;
+
+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);
+}
+
+void RootInlineBox::detachEllipsisBox(RenderArena* arena)
+{
+ if (m_hasEllipsisBox) {
+ EllipsisBox* box = gEllipsisBoxMap->take(this);
+ box->setParent(0);
+ box->destroy(arena);
+ m_hasEllipsisBox = false;
+ }
+}
+
+void RootInlineBox::clearTruncation()
+{
+ if (m_hasEllipsisBox) {
+ detachEllipsisBox(m_object->renderArena());
+ InlineFlowBox::clearTruncation();
+ }
+}
+
+bool RootInlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth)
+{
+ // First sanity-check the unoverflowed width of the whole line to see if there is sufficient room.
+ int delta = ltr ? lineBoxEdge - blockEdge : blockEdge - lineBoxEdge;
+ if (width() - delta < ellipsisWidth)
+ return false;
+
+ // Next iterate over all the line boxes on the line. If we find a replaced element that intersects
+ // then we refuse to accommodate the ellipsis. Otherwise we're ok.
+ return InlineFlowBox::canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth);
+}
+
+void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth,
+ InlineBox* markupBox)
+{
+ // Create an ellipsis box.
+ EllipsisBox* ellipsisBox = new (m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this,
+ ellipsisWidth - (markupBox ? markupBox->width() : 0),
+ yPos(), height(), baseline(), !prevRootBox(),
+ markupBox);
+
+ if (!gEllipsisBoxMap)
+ gEllipsisBoxMap = new EllipsisBoxMap();
+ gEllipsisBoxMap->add(this, ellipsisBox);
+ m_hasEllipsisBox = true;
+
+ if (ltr && (xPos() + width() + ellipsisWidth) <= blockEdge) {
+ ellipsisBox->m_x = xPos() + width();
+ return;
+ }
+
+ // Now attempt to find the nearest glyph horizontally and place just to the right (or left in RTL)
+ // of that glyph. Mark all of the objects that intersect the ellipsis box as not painting (as being
+ // truncated).
+ bool foundBox = false;
+ ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
+}
+
+int RootInlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox)
+{
+ int result = InlineFlowBox::placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
+ if (result == -1)
+ result = ltr ? blockEdge - ellipsisWidth : blockEdge;
+ return result;
+}
+
+void RootInlineBox::paintEllipsisBox(RenderObject::PaintInfo& paintInfo, int tx, int ty) const
+{
+ if (m_hasEllipsisBox && object()->shouldPaintWithinRoot(paintInfo) && object()->style()->visibility() == VISIBLE &&
+ paintInfo.phase == PaintPhaseForeground)
+ ellipsisBox()->paint(paintInfo, tx, ty);
+}
+
+#if PLATFORM(MAC)
+
+void RootInlineBox::addHighlightOverflow()
+{
+ Frame* frame = object()->document()->frame();
+ if (!frame)
+ return;
+ Page* page = frame->page();
+ if (!page)
+ return;
+
+ // Highlight acts as a selection inflation.
+ FloatRect rootRect(0, selectionTop(), width(), selectionHeight());
+ IntRect inflatedRect = enclosingIntRect(page->chrome()->client()->customHighlightRect(object()->node(), object()->style()->highlight(), rootRect));
+ setHorizontalOverflowPositions(min(leftOverflow(), inflatedRect.x()), max(rightOverflow(), inflatedRect.right()));
+ setVerticalOverflowPositions(min(topOverflow(), inflatedRect.y()), max(bottomOverflow(), inflatedRect.bottom()));
+}
+
+void RootInlineBox::paintCustomHighlight(RenderObject::PaintInfo& paintInfo, int tx, int ty, const AtomicString& highlightType)
+{
+ if (!object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground)
+ return;
+
+ Frame* frame = object()->document()->frame();
+ if (!frame)
+ return;
+ Page* page = frame->page();
+ if (!page)
+ return;
+
+ // Get the inflated rect so that we can properly hit test.
+ FloatRect rootRect(tx + xPos(), ty + selectionTop(), width(), selectionHeight());
+ FloatRect inflatedRect = page->chrome()->client()->customHighlightRect(object()->node(), highlightType, rootRect);
+ if (inflatedRect.intersects(paintInfo.rect))
+ page->chrome()->client()->paintCustomHighlight(object()->node(), highlightType, rootRect, rootRect, false, true);
+}
+
+#endif
+
+void RootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
+{
+ InlineFlowBox::paint(paintInfo, tx, ty);
+ paintEllipsisBox(paintInfo, tx, ty);
+#if PLATFORM(MAC)
+ RenderStyle* styleToUse = object()->style(m_firstLine);
+ if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
+ paintCustomHighlight(paintInfo, tx, ty, styleToUse->highlight());
+#endif
+}
+
+bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
+{
+ if (m_hasEllipsisBox && visibleToHitTesting()) {
+ if (ellipsisBox()->nodeAtPoint(request, result, x, y, tx, ty)) {
+ object()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+ }
+ return InlineFlowBox::nodeAtPoint(request, result, x, y, tx, ty);
+}
+
+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_blockHeight += dy;
+}
+
+void RootInlineBox::childRemoved(InlineBox* box)
+{
+ if (box->object() == m_lineBreakObj)
+ setLineBreakInfo(0, 0, BidiStatus());
+
+ for (RootInlineBox* prev = prevRootBox(); prev && prev->lineBreakObj() == box->object(); prev = prev->prevRootBox()) {
+ prev->setLineBreakInfo(0, 0, BidiStatus());
+ prev->markDirty();
+ }
+}
+
+GapRects RootInlineBox::fillLineSelectionGap(int selTop, int selHeight, RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
+ const RenderObject::PaintInfo* paintInfo)
+{
+ RenderObject::SelectionState lineState = selectionState();
+
+ bool leftGap, rightGap;
+ block()->getHorizontalSelectionGapInfo(lineState, leftGap, rightGap);
+
+ GapRects result;
+
+ InlineBox* firstBox = firstSelectedBox();
+ InlineBox* lastBox = lastSelectedBox();
+ if (leftGap)
+ result.uniteLeft(block()->fillLeftSelectionGap(firstBox->parent()->object(),
+ firstBox->xPos(), selTop, selHeight,
+ rootBlock, blockX, blockY, tx, ty, paintInfo));
+ if (rightGap)
+ result.uniteRight(block()->fillRightSelectionGap(lastBox->parent()->object(),
+ lastBox->xPos() + lastBox->width(), selTop, selHeight,
+ rootBlock, blockX, blockY, tx, ty, paintInfo));
+
+ if (firstBox && firstBox != lastBox) {
+ // Now fill in any gaps on the line that occurred between two selected elements.
+ int lastX = firstBox->xPos() + firstBox->width();
+ for (InlineBox* box = firstBox->nextLeafChild(); box; box = box->nextLeafChild()) {
+ if (box->selectionState() != RenderObject::SelectionNone) {
+ result.uniteCenter(block()->fillHorizontalSelectionGap(box->parent()->object(),
+ lastX + tx, selTop + ty,
+ box->xPos() - lastX, selHeight, paintInfo));
+ lastX = box->xPos() + box->width();
+ }
+ if (box == lastBox)
+ break;
+ }
+ }
+
+ return result;
+}
+
+void RootInlineBox::setHasSelectedChildren(bool b)
+{
+ if (m_hasSelectedChildren == b)
+ return;
+ m_hasSelectedChildren = b;
+}
+
+RenderObject::SelectionState RootInlineBox::selectionState()
+{
+ // Walk over all of the selected boxes.
+ RenderObject::SelectionState state = RenderObject::SelectionNone;
+ for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) {
+ RenderObject::SelectionState boxState = box->selectionState();
+ if ((boxState == RenderObject::SelectionStart && state == RenderObject::SelectionEnd) ||
+ (boxState == RenderObject::SelectionEnd && state == RenderObject::SelectionStart))
+ state = RenderObject::SelectionBoth;
+ else if (state == RenderObject::SelectionNone ||
+ ((boxState == RenderObject::SelectionStart || boxState == RenderObject::SelectionEnd) &&
+ (state == RenderObject::SelectionNone || state == RenderObject::SelectionInside)))
+ state = boxState;
+ if (state == RenderObject::SelectionBoth)
+ break;
+ }
+
+ return state;
+}
+
+InlineBox* RootInlineBox::firstSelectedBox()
+{
+ for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) {
+ if (box->selectionState() != RenderObject::SelectionNone)
+ return box;
+ }
+
+ return 0;
+}
+
+InlineBox* RootInlineBox::lastSelectedBox()
+{
+ for (InlineBox* box = lastLeafChild(); box; box = box->prevLeafChild()) {
+ if (box->selectionState() != RenderObject::SelectionNone)
+ return box;
+ }
+
+ return 0;
+}
+
+int RootInlineBox::selectionTop()
+{
+ int selectionTop = m_overflow ? m_overflow->m_selectionTop : m_y;
+ if (!prevRootBox())
+ return selectionTop;
+
+ int prevBottom = prevRootBox()->selectionBottom();
+ if (prevBottom < selectionTop && block()->containsFloats()) {
+ // This line has actually been moved further down, probably from a large line-height, but possibly because the
+ // line was forced to clear floats. If so, let's check the offsets, and only be willing to use the previous
+ // line's bottom overflow if the offsets are greater on both sides.
+ int prevLeft = block()->leftOffset(prevBottom);
+ int prevRight = block()->rightOffset(prevBottom);
+ int newLeft = block()->leftOffset(selectionTop);
+ int newRight = block()->rightOffset(selectionTop);
+ if (prevLeft > newLeft || prevRight < newRight)
+ return selectionTop;
+ }
+
+ return prevBottom;
+}
+
+RenderBlock* RootInlineBox::block() const
+{
+ return static_cast<RenderBlock*>(m_object);
+}
+
+bool isEditableLeaf(InlineBox* leaf)
+{
+ return leaf && leaf->object() && leaf->object()->element() && leaf->object()->element()->isContentEditable();
+}
+
+InlineBox* RootInlineBox::closestLeafChildForXPos(int x, bool onlyEditableLeaves)
+{
+ InlineBox* firstLeaf = firstLeafChildAfterBox();
+ InlineBox* lastLeaf = lastLeafChildBeforeBox();
+ if (firstLeaf == lastLeaf && (!onlyEditableLeaves || isEditableLeaf(firstLeaf)))
+ return firstLeaf;
+
+ // Avoid returning a list marker when possible.
+ if (x <= firstLeaf->m_x && !firstLeaf->object()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(firstLeaf)))
+ // The x coordinate is less or equal to left edge of the firstLeaf.
+ // Return it.
+ return firstLeaf;
+
+ if (x >= lastLeaf->m_x + lastLeaf->m_width && !lastLeaf->object()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(lastLeaf)))
+ // The x coordinate is greater or equal to right edge of the lastLeaf.
+ // Return it.
+ return lastLeaf;
+
+ InlineBox* closestLeaf = 0;
+ for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChild()) {
+ if (!leaf->object()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(leaf))) {
+ closestLeaf = leaf;
+ if (x < leaf->m_x + leaf->m_width)
+ // The x coordinate is less than the right edge of the box.
+ // Return it.
+ return leaf;
+ }
+ }
+
+ return closestLeaf ? closestLeaf : lastLeaf;
+}
+
+BidiStatus RootInlineBox::lineBreakBidiStatus() const
+{
+ return BidiStatus(m_lineBreakBidiStatusEor, m_lineBreakBidiStatusLastStrong, m_lineBreakBidiStatusLast, m_lineBreakContext);
+}
+
+void RootInlineBox::setLineBreakInfo(RenderObject* obj, unsigned breakPos, const BidiStatus& status)
+{
+ m_lineBreakObj = obj;
+ m_lineBreakPos = breakPos;
+ m_lineBreakBidiStatusEor = status.eor;
+ m_lineBreakBidiStatusLastStrong = status.lastStrong;
+ m_lineBreakBidiStatusLast = status.last;
+ m_lineBreakContext = status.context;
+}
+
+EllipsisBox* RootInlineBox::ellipsisBox() const
+{
+ if (!m_hasEllipsisBox)
+ return false;
+ return gEllipsisBoxMap->get(this);
+}
+
+void RootInlineBox::setVerticalOverflowPositions(int top, int bottom)
+{
+ if (!m_overflow) {
+ if (top == m_y && bottom == m_y + m_height)
+ return;
+ m_overflow = new (m_object->renderArena()) Overflow(this);
+ }
+ m_overflow->m_topOverflow = top;
+ m_overflow->m_bottomOverflow = bottom;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h
new file mode 100644
index 0000000..4724110
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/RootInlineBox.h
@@ -0,0 +1,206 @@
+/*
+ * 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
+ * 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 RootInlineBox_h
+#define RootInlineBox_h
+
+#include "BidiContext.h"
+#include "InlineFlowBox.h"
+
+namespace WebCore {
+
+class BidiStatus;
+class EllipsisBox;
+class HitTestResult;
+struct GapRects;
+
+class RootInlineBox : public InlineFlowBox {
+public:
+ RootInlineBox(RenderObject* obj)
+ : InlineFlowBox(obj)
+ , m_overflow(0)
+ , m_lineBreakObj(0)
+ , m_lineBreakPos(0)
+ {
+ }
+
+ virtual bool isRootInlineBox() { 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); }
+
+ virtual void adjustPosition(int dx, int dy);
+
+ virtual int topOverflow() { return m_overflow ? m_overflow->m_topOverflow : m_y; }
+ virtual int bottomOverflow() { return m_overflow ? m_overflow->m_bottomOverflow : m_y + m_height; }
+ virtual int leftOverflow() { return m_overflow ? m_overflow->m_leftOverflow : m_x; }
+ virtual int rightOverflow() { return m_overflow ? m_overflow->m_rightOverflow : m_x + m_width; }
+
+ virtual void setVerticalOverflowPositions(int top, int bottom);
+ void setHorizontalOverflowPositions(int left, int right);
+
+ virtual void setVerticalSelectionPositions(int top, int bottom);
+
+#if ENABLE(SVG)
+ virtual void computePerCharacterLayoutInformation() { }
+#endif
+
+ RenderObject* lineBreakObj() const { return m_lineBreakObj; }
+ BidiStatus lineBreakBidiStatus() const;
+ void setLineBreakInfo(RenderObject*, unsigned breakPos, const BidiStatus&);
+
+ unsigned lineBreakPos() const { return m_lineBreakPos; }
+ void setLineBreakPos(unsigned p) { m_lineBreakPos = p; }
+
+ int blockHeight() const { return m_blockHeight; }
+ void setBlockHeight(int h) { m_blockHeight = h; }
+
+ bool endsWithBreak() const { return m_endsWithBreak; }
+ void setEndsWithBreak(bool b) { m_endsWithBreak = b; }
+
+ void childRemoved(InlineBox* box);
+
+ bool canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth);
+ void placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth, InlineBox* markupBox = 0);
+ virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox);
+
+ EllipsisBox* ellipsisBox() const;
+
+ void paintEllipsisBox(RenderObject::PaintInfo&, int tx, int ty) const;
+ bool hitTestEllipsisBox(HitTestResult&, int x, int y, int tx, int ty, HitTestAction, bool);
+
+ virtual void clearTruncation();
+
+#if PLATFORM(MAC)
+ void addHighlightOverflow();
+ void paintCustomHighlight(RenderObject::PaintInfo&, int tx, int ty, const AtomicString& highlightType);
+#endif
+
+ virtual void paint(RenderObject::PaintInfo&, int tx, int ty);
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int);
+
+ bool hasSelectedChildren() const { return m_hasSelectedChildren; }
+ void setHasSelectedChildren(bool);
+
+ virtual RenderObject::SelectionState selectionState();
+ InlineBox* firstSelectedBox();
+ InlineBox* lastSelectedBox();
+
+ GapRects fillLineSelectionGap(int selTop, int selHeight, RenderBlock* rootBlock, int blockX, int blockY,
+ int tx, int ty, const RenderObject::PaintInfo*);
+
+ RenderBlock* block() const;
+
+ int selectionTop();
+ int selectionBottom() { return m_overflow ? m_overflow->m_selectionBottom : m_y + m_height; }
+ int selectionHeight() { return max(0, selectionBottom() - selectionTop()); }
+
+ InlineBox* closestLeafChildForXPos(int x, bool onlyEditableLeaves = false);
+
+ Vector<RenderObject*>& floats()
+ {
+ ASSERT(!isDirty());
+ if (!m_overflow)
+ m_overflow = new (m_object->renderArena()) Overflow(this);
+ return m_overflow->floats;
+ }
+
+ Vector<RenderObject*>* floatsPtr() { ASSERT(!isDirty()); return m_overflow ? &m_overflow->floats : 0; }
+
+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->m_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->m_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<RenderObject*> 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;
+
+ // The height of the block at the end of this line. This is where the next line starts.
+ int m_blockHeight;
+
+ WTF::Unicode::Direction m_lineBreakBidiStatusEor : 5;
+ WTF::Unicode::Direction m_lineBreakBidiStatusLastStrong : 5;
+ 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_object->renderArena()) Overflow(this);
+ }
+ m_overflow->m_leftOverflow = left;
+ m_overflow->m_rightOverflow = right;
+}
+
+inline void RootInlineBox::setVerticalSelectionPositions(int top, int bottom)
+{
+ if (!m_overflow) {
+ if (top == m_y && bottom == m_y + m_height)
+ return;
+ m_overflow = new (m_object->renderArena()) Overflow(this);
+ }
+ m_overflow->m_selectionTop = top;
+ m_overflow->m_selectionBottom = bottom;
+}
+
+} // namespace WebCore
+
+#endif // RootInlineBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp
new file mode 100644
index 0000000..89bab2d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.cpp
@@ -0,0 +1,535 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGCharacterLayoutInfo.h"
+
+#include "InlineFlowBox.h"
+#include "InlineTextBox.h"
+#include "SVGLengthList.h"
+#include "SVGNumberList.h"
+#include "SVGTextPositioningElement.h"
+#include "RenderSVGTextPath.h"
+
+#include <float.h>
+
+namespace WebCore {
+
+// Helper function
+static float calculateBaselineShift(RenderObject* item)
+{
+ const Font& font = item->style()->font();
+ const SVGRenderStyle* svgStyle = item->style()->svgStyle();
+
+ float baselineShift = 0.0f;
+ if (svgStyle->baselineShift() == BS_LENGTH) {
+ CSSPrimitiveValue* primitive = static_cast<CSSPrimitiveValue*>(svgStyle->baselineShiftValue());
+ baselineShift = primitive->getFloatValue();
+
+ if (primitive->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
+ baselineShift = baselineShift / 100.0f * font.pixelSize();
+ } else {
+ float baselineAscent = font.ascent() + font.descent();
+
+ switch (svgStyle->baselineShift()) {
+ case BS_BASELINE:
+ break;
+ case BS_SUB:
+ baselineShift = -baselineAscent / 2.0f;
+ break;
+ case BS_SUPER:
+ baselineShift = baselineAscent / 2.0f;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ return baselineShift;
+}
+
+SVGCharacterLayoutInfo::SVGCharacterLayoutInfo(Vector<SVGChar>& chars)
+ : curx(0.0f)
+ , cury(0.0f)
+ , angle(0.0f)
+ , dx(0.0f)
+ , dy(0.0f)
+ , shiftx(0.0f)
+ , shifty(0.0f)
+ , pathExtraAdvance(0.0f)
+ , pathTextLength(0.0f)
+ , pathChunkLength(0.0f)
+ , svgChars(chars)
+ , nextDrawnSeperated(false)
+ , xStackChanged(false)
+ , yStackChanged(false)
+ , dxStackChanged(false)
+ , dyStackChanged(false)
+ , angleStackChanged(false)
+ , baselineShiftStackChanged(false)
+ , pathLayout(false)
+ , currentOffset(0.0f)
+ , startOffset(0.0f)
+ , layoutPathLength(0.0f)
+{
+}
+
+bool SVGCharacterLayoutInfo::xValueAvailable() const
+{
+ return xStack.isEmpty() ? false : xStack.last().position() < xStack.last().size();
+}
+
+bool SVGCharacterLayoutInfo::yValueAvailable() const
+{
+ return yStack.isEmpty() ? false : yStack.last().position() < yStack.last().size();
+}
+
+bool SVGCharacterLayoutInfo::dxValueAvailable() const
+{
+ return dxStack.isEmpty() ? false : dxStack.last().position() < dxStack.last().size();
+}
+
+bool SVGCharacterLayoutInfo::dyValueAvailable() const
+{
+ return dyStack.isEmpty() ? false : dyStack.last().position() < dyStack.last().size();
+}
+
+bool SVGCharacterLayoutInfo::angleValueAvailable() const
+{
+ return angleStack.isEmpty() ? false : angleStack.last().position() < angleStack.last().size();
+}
+
+bool SVGCharacterLayoutInfo::baselineShiftValueAvailable() const
+{
+ return !baselineShiftStack.isEmpty();
+}
+
+float SVGCharacterLayoutInfo::xValueNext() const
+{
+ ASSERT(!xStack.isEmpty());
+ return xStack.last().valueAtCurrentPosition();
+}
+
+float SVGCharacterLayoutInfo::yValueNext() const
+{
+ ASSERT(!yStack.isEmpty());
+ return yStack.last().valueAtCurrentPosition();
+}
+
+float SVGCharacterLayoutInfo::dxValueNext() const
+{
+ ASSERT(!dxStack.isEmpty());
+ return dxStack.last().valueAtCurrentPosition();
+}
+
+float SVGCharacterLayoutInfo::dyValueNext() const
+{
+ ASSERT(!dyStack.isEmpty());
+ return dyStack.last().valueAtCurrentPosition();
+}
+
+float SVGCharacterLayoutInfo::angleValueNext() const
+{
+ ASSERT(!angleStack.isEmpty());
+ return angleStack.last().valueAtCurrentPosition();
+}
+
+float SVGCharacterLayoutInfo::baselineShiftValueNext() const
+{
+ ASSERT(!baselineShiftStack.isEmpty());
+ return baselineShiftStack.last();
+}
+
+void SVGCharacterLayoutInfo::processedSingleCharacter()
+{
+ xStackWalk();
+ yStackWalk();
+ dxStackWalk();
+ dyStackWalk();
+ angleStackWalk();
+ baselineShiftStackWalk();
+}
+
+void SVGCharacterLayoutInfo::processedChunk(float savedShiftX, float savedShiftY)
+{
+ // baseline-shift doesn't span across ancestors, unlike dx/dy.
+ curx += savedShiftX - shiftx;
+ cury += savedShiftY - shifty;
+
+ if (inPathLayout()) {
+ shiftx = savedShiftX;
+ shifty = savedShiftY;
+ }
+
+ // rotation also doesn't span
+ angle = 0.0f;
+
+ if (xStackChanged) {
+ ASSERT(!xStack.isEmpty());
+ xStack.removeLast();
+ xStackChanged = false;
+ }
+
+ if (yStackChanged) {
+ ASSERT(!yStack.isEmpty());
+ yStack.removeLast();
+ yStackChanged = false;
+ }
+
+ if (dxStackChanged) {
+ ASSERT(!dxStack.isEmpty());
+ dxStack.removeLast();
+ dxStackChanged = false;
+ }
+
+ if (dyStackChanged) {
+ ASSERT(!dyStack.isEmpty());
+ dyStack.removeLast();
+ dyStackChanged = false;
+ }
+
+ if (angleStackChanged) {
+ ASSERT(!angleStack.isEmpty());
+ angleStack.removeLast();
+ angleStackChanged = false;
+ }
+
+ if (baselineShiftStackChanged) {
+ ASSERT(!baselineShiftStack.isEmpty());
+ baselineShiftStack.removeLast();
+ baselineShiftStackChanged = false;
+ }
+}
+
+bool SVGCharacterLayoutInfo::nextPathLayoutPointAndAngle(float glyphAdvance, float extraAdvance, float newOffset)
+{
+ if (layoutPathLength <= 0.0f)
+ return false;
+
+ if (newOffset != FLT_MIN)
+ currentOffset = startOffset + newOffset;
+
+ // Respect translation along path (extraAdvance is orthogonal to the path)
+ currentOffset += extraAdvance;
+
+ float offset = currentOffset + glyphAdvance / 2.0f;
+ currentOffset += glyphAdvance + pathExtraAdvance;
+
+ if (offset < 0.0f || offset > layoutPathLength)
+ return false;
+
+ bool ok = false;
+ FloatPoint point = layoutPath.pointAtLength(offset, ok);
+ ASSERT(ok);
+
+ curx = point.x();
+ cury = point.y();
+
+ angle = layoutPath.normalAngleAtLength(offset, ok);
+ ASSERT(ok);
+
+ // fprintf(stderr, "t: %f, x: %f, y: %f, angle: %f, glyphAdvance: %f\n", currentOffset, x, y, angle, glyphAdvance);
+ return true;
+}
+
+bool SVGCharacterLayoutInfo::inPathLayout() const
+{
+ return pathLayout;
+}
+
+void SVGCharacterLayoutInfo::setInPathLayout(bool value)
+{
+ pathLayout = value;
+
+ pathExtraAdvance = 0.0f;
+ pathTextLength = 0.0f;
+ pathChunkLength = 0.0f;
+}
+
+void SVGCharacterLayoutInfo::addLayoutInformation(InlineFlowBox* flowBox, float textAnchorStartOffset)
+{
+ bool isInitialLayout = xStack.isEmpty() && yStack.isEmpty() &&
+ dxStack.isEmpty() && dyStack.isEmpty() &&
+ angleStack.isEmpty() && baselineShiftStack.isEmpty() &&
+ curx == 0.0f && cury == 0.0f;
+
+ RenderSVGTextPath* textPath = static_cast<RenderSVGTextPath*>(flowBox->object());
+ Path path = textPath->layoutPath();
+
+ float baselineShift = calculateBaselineShift(textPath);
+
+ layoutPath = path;
+ layoutPathLength = path.length();
+
+ if (layoutPathLength <= 0.0f)
+ return;
+
+ startOffset = textPath->startOffset();
+
+ if (textPath->startOffset() >= 0.0f && textPath->startOffset() <= 1.0f)
+ startOffset *= layoutPathLength;
+
+ startOffset += textAnchorStartOffset;
+ currentOffset = startOffset;
+
+ // Only baseline-shift is handled through the normal layout system
+ addStackContent(BaselineShiftStack, baselineShift);
+
+ if (isInitialLayout) {
+ xStackChanged = false;
+ yStackChanged = false;
+ dxStackChanged = false;
+ dyStackChanged = false;
+ angleStackChanged = false;
+ baselineShiftStackChanged = false;
+ }
+}
+
+void SVGCharacterLayoutInfo::addLayoutInformation(SVGTextPositioningElement* element)
+{
+ bool isInitialLayout = xStack.isEmpty() && yStack.isEmpty() &&
+ dxStack.isEmpty() && dyStack.isEmpty() &&
+ angleStack.isEmpty() && baselineShiftStack.isEmpty() &&
+ curx == 0.0f && cury == 0.0f;
+
+ float baselineShift = calculateBaselineShift(element->renderer());
+
+ addStackContent(XStack, element->x(), element);
+ addStackContent(YStack, element->y(), element);
+ addStackContent(DxStack, element->dx(), element);
+ addStackContent(DyStack, element->dy(), element);
+ addStackContent(AngleStack, element->rotate());
+ addStackContent(BaselineShiftStack, baselineShift);
+
+ if (isInitialLayout) {
+ xStackChanged = false;
+ yStackChanged = false;
+ dxStackChanged = false;
+ dyStackChanged = false;
+ angleStackChanged = false;
+ baselineShiftStackChanged = false;
+ }
+}
+
+void SVGCharacterLayoutInfo::addStackContent(StackType type, SVGNumberList* list)
+{
+ unsigned length = list->numberOfItems();
+ if (!length)
+ return;
+
+ PositionedFloatVector newLayoutInfo;
+
+ // TODO: Convert more efficiently!
+ ExceptionCode ec = 0;
+ for (unsigned i = 0; i < length; ++i) {
+ float value = list->getItem(i, ec);
+ ASSERT(ec == 0);
+
+ newLayoutInfo.append(value);
+ }
+
+ addStackContent(type, newLayoutInfo);
+}
+
+void SVGCharacterLayoutInfo::addStackContent(StackType type, SVGLengthList* list, const SVGElement* context)
+{
+ unsigned length = list->numberOfItems();
+ if (!length)
+ return;
+
+ PositionedFloatVector newLayoutInfo;
+
+ ExceptionCode ec = 0;
+ for (unsigned i = 0; i < length; ++i) {
+ float value = list->getItem(i, ec).value(context);
+ ASSERT(ec == 0);
+
+ newLayoutInfo.append(value);
+ }
+
+ addStackContent(type, newLayoutInfo);
+}
+
+void SVGCharacterLayoutInfo::addStackContent(StackType type, const PositionedFloatVector& list)
+{
+ switch (type) {
+ case XStack:
+ xStackChanged = true;
+ xStack.append(list);
+ break;
+ case YStack:
+ yStackChanged = true;
+ yStack.append(list);
+ break;
+ case DxStack:
+ dxStackChanged = true;
+ dxStack.append(list);
+ break;
+ case DyStack:
+ dyStackChanged = true;
+ dyStack.append(list);
+ break;
+ case AngleStack:
+ angleStackChanged = true;
+ angleStack.append(list);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void SVGCharacterLayoutInfo::addStackContent(StackType type, float value)
+{
+ if (value == 0.0f)
+ return;
+
+ switch (type) {
+ case BaselineShiftStack:
+ baselineShiftStackChanged = true;
+ baselineShiftStack.append(value);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void SVGCharacterLayoutInfo::xStackWalk()
+{
+ unsigned i = 1;
+
+ while (!xStack.isEmpty()) {
+ PositionedFloatVector& cur = xStack.last();
+ if (i + cur.position() < cur.size()) {
+ cur.advance(i);
+ break;
+ }
+
+ i += cur.position();
+ xStack.removeLast();
+ xStackChanged = false;
+ }
+}
+
+void SVGCharacterLayoutInfo::yStackWalk()
+{
+ unsigned i = 1;
+
+ while (!yStack.isEmpty()) {
+ PositionedFloatVector& cur = yStack.last();
+ if (i + cur.position() < cur.size()) {
+ cur.advance(i);
+ break;
+ }
+
+ i += cur.position();
+ yStack.removeLast();
+ yStackChanged = false;
+ }
+}
+
+void SVGCharacterLayoutInfo::dxStackWalk()
+{
+ unsigned i = 1;
+
+ while (!dxStack.isEmpty()) {
+ PositionedFloatVector& cur = dxStack.last();
+ if (i + cur.position() < cur.size()) {
+ cur.advance(i);
+ break;
+ }
+
+ i += cur.position();
+ dxStack.removeLast();
+ dxStackChanged = false;
+ }
+}
+
+void SVGCharacterLayoutInfo::dyStackWalk()
+{
+ unsigned i = 1;
+
+ while (!dyStack.isEmpty()) {
+ PositionedFloatVector& cur = dyStack.last();
+ if (i + cur.position() < cur.size()) {
+ cur.advance(i);
+ break;
+ }
+
+ i += cur.position();
+ dyStack.removeLast();
+ dyStackChanged = false;
+ }
+}
+
+void SVGCharacterLayoutInfo::angleStackWalk()
+{
+ unsigned i = 1;
+
+ while (!angleStack.isEmpty()) {
+ PositionedFloatVector& cur = angleStack.last();
+ if (i + cur.position() < cur.size()) {
+ cur.advance(i);
+ break;
+ }
+
+ i += cur.position();
+ angleStack.removeLast();
+ angleStackChanged = false;
+ }
+}
+
+void SVGCharacterLayoutInfo::baselineShiftStackWalk()
+{
+ if (!baselineShiftStack.isEmpty()) {
+ baselineShiftStack.removeLast();
+ baselineShiftStackChanged = false;
+ }
+}
+
+bool SVGChar::isHidden() const
+{
+ return pathData && pathData->hidden;
+}
+
+TransformationMatrix SVGChar::characterTransform() const
+{
+ TransformationMatrix ctm;
+
+ // Rotate character around angle, and possibly scale.
+ ctm.translate(x, y);
+ ctm.rotate(angle);
+
+ if (pathData) {
+ ctm.scale(pathData->xScale, pathData->yScale);
+ ctm.translate(pathData->xShift, pathData->yShift);
+ ctm.rotate(pathData->orientationAngle);
+ }
+
+ ctm.translate(orientationShiftX - x, orientationShiftY - y);
+ return ctm;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.h b/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.h
new file mode 100644
index 0000000..0188b9d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGCharacterLayoutInfo.h
@@ -0,0 +1,416 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SVGCharacterLayoutInfo_h
+#define SVGCharacterLayoutInfo_h
+
+#if ENABLE(SVG)
+#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"
+
+namespace WebCore {
+
+class InlineBox;
+class InlineFlowBox;
+class SVGInlineTextBox;
+class SVGLengthList;
+class SVGNumberList;
+class SVGTextPositioningElement;
+
+template<class Type>
+class PositionedVector : public Vector<Type>
+{
+public:
+ PositionedVector<Type>()
+ : m_position(0)
+ {
+ }
+
+ unsigned position() const
+ {
+ return m_position;
+ }
+
+ void advance(unsigned position)
+ {
+ m_position += position;
+ ASSERT(m_position < Vector<Type>::size());
+ }
+
+ Type valueAtCurrentPosition() const
+ {
+ ASSERT(m_position < Vector<Type>::size());
+ return Vector<Type>::at(m_position);
+ }
+
+private:
+ unsigned m_position;
+};
+
+class PositionedFloatVector : public PositionedVector<float> { };
+struct SVGChar;
+
+struct SVGCharacterLayoutInfo {
+ SVGCharacterLayoutInfo(Vector<SVGChar>&);
+
+ enum StackType { XStack, YStack, DxStack, DyStack, AngleStack, BaselineShiftStack };
+
+ bool xValueAvailable() const;
+ bool yValueAvailable() const;
+ bool dxValueAvailable() const;
+ bool dyValueAvailable() const;
+ bool angleValueAvailable() const;
+ bool baselineShiftValueAvailable() const;
+
+ float xValueNext() const;
+ float yValueNext() const;
+ float dxValueNext() const;
+ float dyValueNext() const;
+ float angleValueNext() const;
+ float baselineShiftValueNext() const;
+
+ void processedChunk(float savedShiftX, float savedShiftY);
+ void processedSingleCharacter();
+
+ bool nextPathLayoutPointAndAngle(float glyphAdvance, float extraAdvance, float newOffset);
+
+ // Used for text-on-path.
+ void addLayoutInformation(InlineFlowBox*, float textAnchorOffset = 0.0f);
+
+ bool inPathLayout() const;
+ void setInPathLayout(bool value);
+
+ // Used for anything else.
+ void addLayoutInformation(SVGTextPositioningElement*);
+
+ // Global position
+ float curx;
+ float cury;
+
+ // Global rotation
+ float angle;
+
+ // Accumulated dx/dy values
+ float dx;
+ float dy;
+
+ // Accumulated baseline-shift values
+ float shiftx;
+ float shifty;
+
+ // Path specific advance values to handle lengthAdjust
+ float pathExtraAdvance;
+ float pathTextLength;
+ float pathChunkLength;
+
+ // Result vector
+ Vector<SVGChar>& svgChars;
+ bool nextDrawnSeperated : 1;
+
+private:
+ // Used for baseline-shift.
+ void addStackContent(StackType, float);
+
+ // Used for angle.
+ void addStackContent(StackType, SVGNumberList*);
+
+ // Used for x/y/dx/dy.
+ void addStackContent(StackType, SVGLengthList*, const SVGElement*);
+
+ void addStackContent(StackType, const PositionedFloatVector&);
+
+ void xStackWalk();
+ void yStackWalk();
+ void dxStackWalk();
+ void dyStackWalk();
+ void angleStackWalk();
+ void baselineShiftStackWalk();
+
+private:
+ bool xStackChanged : 1;
+ bool yStackChanged : 1;
+ bool dxStackChanged : 1;
+ bool dyStackChanged : 1;
+ bool angleStackChanged : 1;
+ bool baselineShiftStackChanged : 1;
+
+ // text on path layout
+ bool pathLayout : 1;
+ float currentOffset;
+ float startOffset;
+ float layoutPathLength;
+ Path layoutPath;
+
+ Vector<PositionedFloatVector> xStack;
+ Vector<PositionedFloatVector> yStack;
+ Vector<PositionedFloatVector> dxStack;
+ Vector<PositionedFloatVector> dyStack;
+ Vector<PositionedFloatVector> angleStack;
+ Vector<float> baselineShiftStack;
+};
+
+// Holds extra data, when the character is laid out on a path
+struct SVGCharOnPath : RefCounted<SVGCharOnPath> {
+ static PassRefPtr<SVGCharOnPath> create() { return adoptRef(new SVGCharOnPath); }
+
+ float xScale;
+ float yScale;
+
+ float xShift;
+ float yShift;
+
+ float orientationAngle;
+
+ bool hidden : 1;
+
+private:
+ SVGCharOnPath()
+ : xScale(1.0f)
+ , yScale(1.0f)
+ , xShift(0.0f)
+ , yShift(0.0f)
+ , orientationAngle(0.0f)
+ , hidden(false)
+ {
+ }
+};
+
+struct SVGChar {
+ SVGChar()
+ : x(0.0f)
+ , y(0.0f)
+ , angle(0.0f)
+ , orientationShiftX(0.0f)
+ , orientationShiftY(0.0f)
+ , pathData()
+ , drawnSeperated(false)
+ , newTextChunk(false)
+ {
+ }
+
+ ~SVGChar()
+ {
+ }
+
+ float x;
+ float y;
+ float angle;
+
+ float orientationShiftX;
+ float orientationShiftY;
+
+ RefPtr<SVGCharOnPath> pathData;
+
+ // Determines wheter this char needs to be drawn seperated
+ bool drawnSeperated : 1;
+
+ // Determines wheter this char starts a new chunk
+ bool newTextChunk : 1;
+
+ // Helper methods
+ bool isHidden() const;
+ TransformationMatrix characterTransform() const;
+};
+
+struct SVGInlineBoxCharacterRange {
+ SVGInlineBoxCharacterRange()
+ : startOffset(INT_MIN)
+ , endOffset(INT_MIN)
+ , box(0)
+ {
+ }
+
+ bool isOpen() const { return (startOffset == endOffset) && (endOffset == INT_MIN); }
+ bool isClosed() const { return startOffset != INT_MIN && endOffset != INT_MIN; }
+
+ int startOffset;
+ int endOffset;
+
+ InlineBox* box;
+};
+
+// Convenience typedef
+typedef SVGTextContentElement::SVGLengthAdjustType ELengthAdjust;
+
+struct SVGTextChunk {
+ SVGTextChunk()
+ : anchor(TA_START)
+ , textLength(0.0f)
+ , lengthAdjust(SVGTextContentElement::LENGTHADJUST_SPACING)
+ , ctm()
+ , isVerticalText(false)
+ , isTextPath(false)
+ , start(0)
+ , end(0)
+ { }
+
+ // text-anchor support
+ ETextAnchor anchor;
+
+ // textLength & lengthAdjust support
+ float textLength;
+ ELengthAdjust lengthAdjust;
+ TransformationMatrix ctm;
+
+ // status flags
+ bool isVerticalText : 1;
+ bool isTextPath : 1;
+
+ // main chunk data
+ Vector<SVGChar>::iterator start;
+ Vector<SVGChar>::iterator end;
+
+ Vector<SVGInlineBoxCharacterRange> boxes;
+};
+
+struct SVGTextChunkWalkerBase {
+ virtual ~SVGTextChunkWalkerBase() { }
+
+ virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& 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 setupFill(InlineBox*) = 0;
+ virtual bool setupStroke(InlineBox*) = 0;
+};
+
+template<typename CallbackClass>
+struct SVGTextChunkWalker : public SVGTextChunkWalkerBase {
+public:
+ typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox,
+ int startOffset,
+ const TransformationMatrix& chunkCtm,
+ const Vector<SVGChar>::iterator& start,
+ const Vector<SVGChar>::iterator& end);
+
+ // These callbacks are only used for painting!
+ typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox* box);
+ typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox* box);
+
+ typedef bool (CallbackClass::*SVGTextChunkSetupFillCallback)(InlineBox* box);
+ typedef bool (CallbackClass::*SVGTextChunkSetupStrokeCallback)(InlineBox* box);
+
+ SVGTextChunkWalker(CallbackClass* object,
+ SVGTextChunkWalkerCallback walker,
+ SVGTextChunkStartCallback start = 0,
+ SVGTextChunkEndCallback end = 0,
+ SVGTextChunkSetupFillCallback fill = 0,
+ SVGTextChunkSetupStrokeCallback stroke = 0)
+ : m_object(object)
+ , m_walkerCallback(walker)
+ , m_startCallback(start)
+ , m_endCallback(end)
+ , m_setupFillCallback(fill)
+ , m_setupStrokeCallback(stroke)
+ {
+ ASSERT(object);
+ ASSERT(walker);
+ }
+
+ virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
+ const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
+ {
+ (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end);
+ }
+
+ // Followings methods are only used for painting text chunks
+ virtual void start(InlineBox* box)
+ {
+ if (m_startCallback)
+ (*m_object.*m_startCallback)(box);
+ else
+ ASSERT_NOT_REACHED();
+ }
+
+ virtual void end(InlineBox* box)
+ {
+ if (m_endCallback)
+ (*m_object.*m_endCallback)(box);
+ else
+ ASSERT_NOT_REACHED();
+ }
+
+ virtual bool setupFill(InlineBox* box)
+ {
+ if (m_setupFillCallback)
+ return (*m_object.*m_setupFillCallback)(box);
+
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ virtual bool setupStroke(InlineBox* box)
+ {
+ if (m_setupStrokeCallback)
+ return (*m_object.*m_setupStrokeCallback)(box);
+
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+private:
+ CallbackClass* m_object;
+ SVGTextChunkWalkerCallback m_walkerCallback;
+ SVGTextChunkStartCallback m_startCallback;
+ SVGTextChunkEndCallback m_endCallback;
+ SVGTextChunkSetupFillCallback m_setupFillCallback;
+ SVGTextChunkSetupStrokeCallback m_setupStrokeCallback;
+};
+
+struct SVGTextChunkLayoutInfo {
+ SVGTextChunkLayoutInfo(Vector<SVGTextChunk>& textChunks)
+ : assignChunkProperties(true)
+ , handlingTextPath(false)
+ , svgTextChunks(textChunks)
+ , it(0)
+ {
+ }
+
+ bool assignChunkProperties : 1;
+ bool handlingTextPath : 1;
+
+ Vector<SVGTextChunk>& svgTextChunks;
+ Vector<SVGChar>::iterator it;
+
+ SVGTextChunk chunk;
+};
+
+struct SVGTextDecorationInfo {
+ // ETextDecoration is meant to be used here
+ HashMap<int, RenderObject*> fillServerMap;
+ HashMap<int, RenderObject*> strokeServerMap;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // SVGCharacterLayoutInfo_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.cpp
new file mode 100644
index 0000000..3ea1193
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.cpp
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * (C) 2006 Apple Computer Inc.
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGInlineFlowBox.h"
+#include "SVGNames.h"
+
+namespace WebCore {
+
+using namespace SVGNames;
+
+void SVGInlineFlowBox::paint(RenderObject::PaintInfo&, int, int)
+{
+ ASSERT_NOT_REACHED();
+}
+
+int SVGInlineFlowBox::placeBoxesHorizontally(int, int&, int&, bool&)
+{
+ // no-op
+ return 0;
+}
+
+void SVGInlineFlowBox::verticallyAlignBoxes(int&)
+{
+ // no-op
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.h b/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.h
new file mode 100644
index 0000000..96c5d4a
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGInlineFlowBox.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * (C) 2006 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
+ * 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 SVGInlineFlowBox_h
+#define SVGInlineFlowBox_h
+
+#if ENABLE(SVG)
+#include "InlineFlowBox.h"
+
+namespace WebCore {
+
+class SVGInlineFlowBox : public InlineFlowBox {
+public:
+ SVGInlineFlowBox(RenderObject* obj)
+ : InlineFlowBox(obj)
+ {
+ }
+
+ virtual void paint(RenderObject::PaintInfo&, int tx, int ty);
+ virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing);
+ virtual void verticallyAlignBoxes(int& heightOfBlock);
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+
+#endif // SVGInlineFlowBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp
new file mode 100644
index 0000000..5f59700
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.cpp
@@ -0,0 +1,548 @@
+/**
+ * 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>
+ *
+ * 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"
+
+#if ENABLE(SVG)
+#include "SVGInlineTextBox.h"
+
+#include "Document.h"
+#include "Editor.h"
+#include "Frame.h"
+#include "GraphicsContext.h"
+#include "InlineFlowBox.h"
+#include "Range.h"
+#include "SVGPaintServer.h"
+#include "SVGRootInlineBox.h"
+#include "Text.h"
+
+#include <float.h>
+
+using std::max;
+
+namespace WebCore {
+
+SVGInlineTextBox::SVGInlineTextBox(RenderObject* obj)
+ : InlineTextBox(obj)
+{
+}
+
+int SVGInlineTextBox::selectionTop()
+{
+ return m_y;
+}
+
+int SVGInlineTextBox::selectionHeight()
+{
+ return m_height;
+}
+
+SVGRootInlineBox* SVGInlineTextBox::svgRootInlineBox() const
+{
+ // Find associated root inline box
+ InlineFlowBox* parentBox = parent();
+
+ while (parentBox && !parentBox->isRootInlineBox())
+ parentBox = parentBox->parent();
+
+ ASSERT(parentBox);
+ ASSERT(parentBox->isRootInlineBox());
+
+ if (!parentBox->isSVGRootInlineBox())
+ return 0;
+
+ return static_cast<SVGRootInlineBox*>(parentBox);
+}
+
+float SVGInlineTextBox::calculateGlyphWidth(RenderStyle* style, int offset, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
+{
+ ASSERT(style);
+ return style->font().floatWidth(svgTextRunForInlineTextBox(textObject()->text()->characters() + offset, 1, style, this, 0), extraCharsAvailable, charsConsumed, glyphName);
+}
+
+float SVGInlineTextBox::calculateGlyphHeight(RenderStyle* style, int, int) const
+{
+ // This is just a guess, and the only purpose of this function is to centralize this hack.
+ // In real-life top-top-bottom scripts this won't be enough, I fear.
+ return style->font().ascent() + style->font().descent();
+}
+
+FloatRect SVGInlineTextBox::calculateGlyphBoundaries(RenderStyle* style, int offset, const SVGChar& svgChar) const
+{
+ const Font& font = style->font();
+
+ // Take RTL text into account and pick right glyph width/height.
+ float glyphWidth = 0.0f;
+
+ // FIXME: account for multi-character glyphs
+ int charsConsumed;
+ String glyphName;
+ if (direction() == LTR)
+ glyphWidth = calculateGlyphWidth(style, offset, 0, charsConsumed, glyphName);
+ else
+ glyphWidth = calculateGlyphWidth(style, start() + end() - offset, 0, charsConsumed, glyphName);
+
+ float x1 = svgChar.x;
+ float x2 = svgChar.x + glyphWidth;
+
+ float y1 = svgChar.y - font.ascent();
+ float y2 = svgChar.y + font.descent();
+
+ 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);
+
+ return glyphRect;
+}
+
+// Helper class for closestCharacterToPosition()
+struct SVGInlineTextBoxClosestCharacterToPositionWalker {
+ SVGInlineTextBoxClosestCharacterToPositionWalker(int x, int y)
+ : m_character(0)
+ , m_distance(FLT_MAX)
+ , m_x(x)
+ , m_y(y)
+ , m_offset(0)
+ {
+ }
+
+ void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
+ const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
+ {
+ RenderStyle* style = textBox->textObject()->style();
+
+ Vector<SVGChar>::iterator closestCharacter = 0;
+ unsigned int closestOffset = UINT_MAX;
+
+ for (Vector<SVGChar>::iterator it = start; it != end; ++it) {
+ if (it->isHidden())
+ continue;
+
+ unsigned int newOffset = textBox->start() + (it - start) + startOffset;
+ FloatRect glyphRect = chunkCtm.mapRect(textBox->calculateGlyphBoundaries(style, newOffset, *it));
+
+ // Take RTL text into account and pick right glyph width/height.
+ // NOTE: This offset has to be corrected _after_ calling calculateGlyphBoundaries
+ if (textBox->direction() == RTL)
+ newOffset = textBox->start() + textBox->end() - newOffset;
+
+ // Calculate distances relative to the glyph mid-point. I hope this is accurate enough.
+ float xDistance = glyphRect.x() + glyphRect.width() / 2.0f - m_x;
+ float yDistance = glyphRect.y() - glyphRect.height() / 2.0f - m_y;
+
+ float newDistance = sqrtf(xDistance * xDistance + yDistance * yDistance);
+ if (newDistance <= m_distance) {
+ m_distance = newDistance;
+ closestOffset = newOffset;
+ closestCharacter = it;
+ }
+ }
+
+ if (closestOffset != UINT_MAX) {
+ // Record current chunk, if it contains the current closest character next to the mouse.
+ m_character = closestCharacter;
+ m_offset = closestOffset;
+ }
+ }
+
+ SVGChar* character() const
+ {
+ return m_character;
+ }
+
+ int offset() const
+ {
+ if (!m_character)
+ return 0;
+
+ return m_offset;
+ }
+
+private:
+ Vector<SVGChar>::iterator m_character;
+ float m_distance;
+
+ int m_x;
+ int m_y;
+ int m_offset;
+};
+
+// Helper class for selectionRect()
+struct SVGInlineTextBoxSelectionRectWalker {
+ SVGInlineTextBoxSelectionRectWalker()
+ {
+ }
+
+ void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
+ const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
+ {
+ RenderStyle* style = textBox->textObject()->style();
+
+ for (Vector<SVGChar>::iterator it = start; it != end; ++it) {
+ if (it->isHidden())
+ continue;
+
+ unsigned int newOffset = textBox->start() + (it - start) + startOffset;
+ m_selectionRect.unite(textBox->calculateGlyphBoundaries(style, newOffset, *it));
+ }
+
+ m_selectionRect = chunkCtm.mapRect(m_selectionRect);
+ }
+
+ FloatRect selectionRect() const
+ {
+ return m_selectionRect;
+ }
+
+private:
+ FloatRect m_selectionRect;
+};
+
+SVGChar* SVGInlineTextBox::closestCharacterToPosition(int x, int y, int& offset) const
+{
+ SVGRootInlineBox* rootBox = svgRootInlineBox();
+ if (!rootBox)
+ return 0;
+
+ SVGInlineTextBoxClosestCharacterToPositionWalker walkerCallback(x, y);
+ SVGTextChunkWalker<SVGInlineTextBoxClosestCharacterToPositionWalker> walker(&walkerCallback, &SVGInlineTextBoxClosestCharacterToPositionWalker::chunkPortionCallback);
+
+ rootBox->walkTextChunks(&walker, this);
+
+ offset = walkerCallback.offset();
+ return walkerCallback.character();
+}
+
+bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& offset) const
+{
+ SVGChar* charAtPosPtr = closestCharacterToPosition(x, y, offset);
+ if (!charAtPosPtr)
+ return false;
+
+ SVGChar& charAtPos = *charAtPosPtr;
+ RenderStyle* style = textObject()->style(m_firstLine);
+ FloatRect glyphRect = calculateGlyphBoundaries(style, offset, charAtPos);
+
+ if (direction() == RTL)
+ offset++;
+
+ // FIXME: todo list
+ // (#13910) This code does not handle bottom-to-top/top-to-bottom vertical text.
+
+ // Check whether y position hits the current character
+ if (y < charAtPos.y - glyphRect.height() || y > charAtPos.y)
+ return false;
+
+ // Check whether x position hits the current character
+ if (x < charAtPos.x) {
+ if (offset > 0 && direction() == LTR)
+ return true;
+ else if (offset < (int) end() && direction() == RTL)
+ return true;
+
+ return false;
+ }
+
+ // If we are past the last glyph of this box, don't mark it as 'hit' anymore.
+ if (x >= charAtPos.x + glyphRect.width() && offset == (int) end())
+ return false;
+
+ // Snap to character at half of it's advance
+ if (x >= charAtPos.x + glyphRect.width() / 2.0)
+ offset += direction() == RTL ? -1 : 1;
+
+ return true;
+}
+
+int SVGInlineTextBox::offsetForPosition(int, bool) const
+{
+ // SVG doesn't use the offset <-> position selection system.
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+int SVGInlineTextBox::positionForOffset(int) const
+{
+ // SVG doesn't use the offset <-> position selection system.
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int x, int y, int tx, int ty)
+{
+ ASSERT(!isLineBreak());
+
+ IntRect rect = selectionRect(0, 0, 0, len());
+ if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) {
+ object()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
+ return true;
+ }
+
+ return false;
+}
+
+IntRect SVGInlineTextBox::selectionRect(int, int, int startPos, int endPos)
+{
+ if (startPos >= endPos)
+ return IntRect();
+
+ // TODO: Actually respect startPos/endPos - we're returning the _full_ selectionRect
+ // here. This won't lead to visible bugs, but to extra work being done. Investigate.
+ SVGRootInlineBox* rootBox = svgRootInlineBox();
+ if (!rootBox)
+ return IntRect();
+
+ SVGInlineTextBoxSelectionRectWalker walkerCallback;
+ SVGTextChunkWalker<SVGInlineTextBoxSelectionRectWalker> walker(&walkerCallback, &SVGInlineTextBoxSelectionRectWalker::chunkPortionCallback);
+
+ rootBox->walkTextChunks(&walker, this);
+ return enclosingIntRect(walkerCallback.selectionRect());
+}
+
+void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int tx, int ty, const SVGChar& svgChar, const UChar* chars, int length, SVGPaintServer* activePaintServer)
+{
+ if (object()->style()->visibility() != VISIBLE || paintInfo.phase == PaintPhaseOutline)
+ return;
+
+ ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines);
+
+ RenderText* text = textObject();
+ ASSERT(text);
+
+ bool isPrinting = text->document()->printing();
+
+ // Determine whether or not we're selected.
+ bool haveSelection = !isPrinting && selectionState() != RenderObject::SelectionNone;
+ if (!haveSelection && paintInfo.phase == PaintPhaseSelection)
+ // When only painting the selection, don't bother to paint if there is none.
+ return;
+
+ // Determine whether or not we have a composition.
+ bool containsComposition = text->document()->frame()->editor()->compositionNode() == text->node();
+ bool useCustomUnderlines = containsComposition && text->document()->frame()->editor()->compositionUsesCustomUnderlines();
+
+ // Set our font
+ RenderStyle* styleToUse = text->style(isFirstLineStyle());
+ const Font* font = &styleToUse->font();
+ if (*font != paintInfo.context->font())
+ paintInfo.context->setFont(*font);
+
+ TransformationMatrix 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 PLATFORM(MAC)
+ // Custom highlighters go behind everything else.
+ if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
+ paintCustomHighlight(tx, ty, styleToUse->highlight());
+#endif
+
+ if (containsComposition && !useCustomUnderlines)
+ paintCompositionBackground(paintInfo.context, tx, ty, styleToUse, font,
+ text->document()->frame()->editor()->compositionStart(),
+ text->document()->frame()->editor()->compositionEnd());
+
+ paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, true);
+
+ if (haveSelection && !useCustomUnderlines) {
+ int boxStartOffset = chars - text->characters() - start();
+ paintSelection(boxStartOffset, svgChar, chars, length, paintInfo.context, styleToUse, font);
+ }
+ }
+
+ // 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;
+ }
+
+ 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);
+#endif
+
+ paintInfo.context->drawText(run, origin);
+
+ if (paintInfo.phase != PaintPhaseSelection) {
+ paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, false);
+
+ if (useCustomUnderlines) {
+ const Vector<CompositionUnderline>& underlines = text->document()->frame()->editor()->customCompositionUnderlines();
+ size_t numUnderlines = underlines.size();
+
+ for (size_t index = 0; index < numUnderlines; ++index) {
+ const CompositionUnderline& underline = underlines[index];
+
+ if (underline.endOffset <= start())
+ // underline is completely before this run. This might be an underline that sits
+ // before the first run we draw, or underlines that were within runs we skipped
+ // due to truncation.
+ continue;
+
+ if (underline.startOffset <= end()) {
+ // underline intersects this run. Paint it.
+ paintCompositionUnderline(paintInfo.context, tx, ty, underline);
+ if (underline.endOffset > end() + 1)
+ // underline also runs into the next run. Bail now, no more marker advancement.
+ break;
+ } else
+ // underline is completely after this run, bail. A later run will paint it.
+ break;
+ }
+ }
+
+ }
+
+ if (setShadow)
+ paintInfo.context->clearShadow();
+
+ if (!ctm.isIdentity())
+ paintInfo.context->concatCTM(ctm.inverse());
+}
+
+void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar, const UChar*, int length, GraphicsContext* p, RenderStyle* style, const Font* f)
+{
+ if (selectionState() == RenderObject::SelectionNone)
+ return;
+
+ int startPos, endPos;
+ selectionStartEnd(startPos, endPos);
+
+ if (startPos >= endPos)
+ return;
+
+ Color textColor = style->color();
+ Color color = object()->selectionBackgroundColor();
+ if (!color.isValid() || color.alpha() == 0)
+ return;
+
+ // If the text color ends up being the same as the selection background, invert the selection
+ // background. This should basically never happen, since the selection has transparency.
+ if (textColor == color)
+ color = Color(0xff - color.red(), 0xff - color.green(), 0xff - color.blue());
+
+ // Map from text box positions and a given start offset to chunk positions
+ // 'boxStartOffset' represents the beginning of the text chunk.
+ if ((startPos > boxStartOffset && endPos > boxStartOffset + length) || boxStartOffset >= endPos)
+ return;
+
+ if (endPos > boxStartOffset + length)
+ endPos = boxStartOffset + length;
+
+ if (startPos < boxStartOffset)
+ startPos = boxStartOffset;
+
+ ASSERT(startPos >= boxStartOffset);
+ ASSERT(endPos <= boxStartOffset + length);
+ ASSERT(startPos < endPos);
+
+ p->save();
+
+ int adjust = startPos >= boxStartOffset ? boxStartOffset : 0;
+ p->drawHighlightForText(svgTextRunForInlineTextBox(textObject()->text()->characters() + start() + boxStartOffset, length, style, this, svgChar.x),
+ IntPoint((int) svgChar.x, (int) svgChar.y - f->ascent()),
+ f->ascent() + f->descent(), color, startPos - adjust, endPos - adjust);
+
+ p->restore();
+}
+
+static inline Path pathForDecoration(ETextDecoration decoration, RenderObject* object, float x, float y, float width)
+{
+ float thickness = SVGRenderStyle::cssPrimitiveToLength(object, object->style()->svgStyle()->strokeWidth(), 1.0f);
+
+ const Font& font = object->style()->font();
+ thickness = max(thickness * powf(font.size(), 2.0f) / font.unitsPerEm(), 1.0f);
+
+ if (decoration == UNDERLINE)
+ y += thickness * 1.5f; // For compatibility with Batik/Opera
+ else if (decoration == OVERLINE)
+ y += thickness;
+
+ float halfThickness = thickness / 2.0f;
+ return Path::createRectangle(FloatRect(x + halfThickness, y, width - 2.0f * halfThickness, thickness));
+}
+
+void SVGInlineTextBox::paintDecoration(ETextDecoration decoration, GraphicsContext* context, int tx, int ty, int width, const SVGChar& svgChar, const SVGTextDecorationInfo& info)
+{
+ if (object()->style()->visibility() != VISIBLE)
+ return;
+
+ // This function does NOT accept combinated text decorations. It's meant to be invoked for just one.
+ ASSERT(decoration == TDNONE || decoration == UNDERLINE || decoration == OVERLINE || decoration == LINE_THROUGH || decoration == BLINK);
+
+ bool isFilled = info.fillServerMap.contains(decoration);
+ bool isStroked = info.strokeServerMap.contains(decoration);
+
+ if (!isFilled && !isStroked)
+ return;
+
+ if (decoration == UNDERLINE)
+ ty += m_baseline;
+ else if (decoration == LINE_THROUGH)
+ ty += 2 * m_baseline / 3;
+
+ context->save();
+ context->beginPath();
+
+ TransformationMatrix ctm = svgChar.characterTransform();
+ if (!ctm.isIdentity())
+ context->concatCTM(ctm);
+
+ if (isFilled) {
+ if (RenderObject* fillObject = info.fillServerMap.get(decoration)) {
+ if (SVGPaintServer* fillPaintServer = SVGPaintServer::fillPaintServer(fillObject->style(), fillObject)) {
+ context->addPath(pathForDecoration(decoration, fillObject, tx, ty, width));
+ fillPaintServer->draw(context, fillObject, ApplyToFillTargetType);
+ }
+ }
+ }
+
+ if (isStroked) {
+ if (RenderObject* strokeObject = info.strokeServerMap.get(decoration)) {
+ if (SVGPaintServer* strokePaintServer = SVGPaintServer::strokePaintServer(strokeObject->style(), strokeObject)) {
+ context->addPath(pathForDecoration(decoration, strokeObject, tx, ty, width));
+ strokePaintServer->draw(context, strokeObject, ApplyToStrokeTargetType);
+ }
+ }
+ }
+
+ context->restore();
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h
new file mode 100644
index 0000000..1ddc23a
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGInlineTextBox.h
@@ -0,0 +1,75 @@
+/*
+ * 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>
+ *
+ * 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 SVGInlineTextBox_h
+#define SVGInlineTextBox_h
+
+#if ENABLE(SVG)
+#include "InlineTextBox.h"
+
+namespace WebCore {
+
+ class SVGChar;
+ class SVGRootInlineBox;
+ class SVGTextDecorationInfo;
+
+ class SVGInlineTextBox : public InlineTextBox {
+ public:
+ SVGInlineTextBox(RenderObject* obj);
+
+ virtual int selectionTop();
+ virtual int selectionHeight();
+
+ virtual int offsetForPosition(int x, bool includePartialGlyphs = true) const;
+ virtual int positionForOffset(int offset) const;
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty);
+ 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*);
+
+ // SVGs custom paint selection method
+ void paintSelection(int boxStartOffset, const SVGChar&, const UChar*, int length, GraphicsContext*, RenderStyle*, const Font*);
+
+ // SVGs custom paint decoration method
+ void paintDecoration(ETextDecoration, GraphicsContext*, int tx, int ty, int width, const SVGChar&, const SVGTextDecorationInfo&);
+
+ SVGRootInlineBox* svgRootInlineBox() const;
+
+ // Helper functions shared with SVGRootInlineBox
+ float calculateGlyphWidth(RenderStyle* style, int offset, int extraCharsAvailable, int& charsConsumed, String& glyphName) const;
+ float calculateGlyphHeight(RenderStyle*, int offset, int extraCharsAvailable) const;
+
+ FloatRect calculateGlyphBoundaries(RenderStyle*, int offset, const SVGChar&) const;
+ SVGChar* closestCharacterToPosition(int x, int y, int& offset) const;
+
+ private:
+ friend class RenderSVGInlineText;
+ bool svgCharacterHitsPosition(int x, int y, int& offset) const;
+ };
+
+} // namespace WebCore
+
+#endif
+#endif // SVGInlineTextBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp
new file mode 100644
index 0000000..c88e8e8
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2007, 2008 Rob Buis <buis@kde.org>
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGRenderSupport.h"
+
+#include "TransformationMatrix.h"
+#include "ImageBuffer.h"
+#include "RenderObject.h"
+#include "RenderSVGContainer.h"
+#include "RenderView.h"
+#include "SVGResourceClipper.h"
+#include "SVGResourceFilter.h"
+#include "SVGResourceMasker.h"
+#include "SVGStyledElement.h"
+#include "SVGURIReference.h"
+
+namespace WebCore {
+
+void prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter)
+{
+ SVGElement* svgElement = static_cast<SVGElement*>(object->element());
+ ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
+ ASSERT(object);
+
+ SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement);
+ const RenderStyle* style = object->style();
+ ASSERT(style);
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ ASSERT(svgStyle);
+
+ // Setup transparency layers before setting up filters!
+ float opacity = style->opacity();
+ if (opacity < 1.0f) {
+ paintInfo.context->clip(enclosingIntRect(boundingBox));
+ paintInfo.context->beginTransparencyLayer(opacity);
+ }
+
+#if ENABLE(SVG_FILTERS)
+ AtomicString filterId(svgStyle->filter());
+#endif
+
+ AtomicString clipperId(svgStyle->clipPath());
+ AtomicString maskerId(svgStyle->maskElement());
+
+ Document* document = object->document();
+
+#if ENABLE(SVG_FILTERS)
+ SVGResourceFilter* newFilter = getFilterById(document, filterId);
+ 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!
+ filter = 0;
+ filterId = String();
+ } else
+ filter = newFilter;
+#endif
+
+ SVGResourceClipper* clipper = getClipperById(document, clipperId);
+ SVGResourceMasker* masker = getMaskerById(document, maskerId);
+
+#if ENABLE(SVG_FILTERS)
+ if (filter) {
+ filter->addClient(styledElement);
+ filter->prepareFilter(paintInfo.context, boundingBox);
+ } 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);
+}
+
+void finishRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, GraphicsContext* savedContext)
+{
+ ASSERT(object);
+
+ const RenderStyle* style = object->style();
+ ASSERT(style);
+
+#if ENABLE(SVG_FILTERS)
+ if (filter) {
+ filter->applyFilter(paintInfo.context, boundingBox);
+ paintInfo.context = savedContext;
+ }
+#endif
+
+ float opacity = style->opacity();
+ if (opacity < 1.0f)
+ paintInfo.context->endTransparencyLayer();
+}
+
+void renderSubtreeToImage(ImageBuffer* image, RenderObject* item)
+{
+ ASSERT(item);
+ ASSERT(image);
+ ASSERT(image->context());
+ RenderObject::PaintInfo info(image->context(), IntRect(), PaintPhaseForeground, 0, 0, 0);
+
+ RenderSVGContainer* svgContainer = 0;
+ if (item && item->isSVGContainer())
+ svgContainer = static_cast<RenderSVGContainer*>(item);
+
+ bool drawsContents = svgContainer ? svgContainer->drawsContents() : false;
+ if (svgContainer && !drawsContents)
+ svgContainer->setDrawsContents(true);
+
+ item->layoutIfNeeded();
+ item->paint(info, 0, 0);
+
+ if (svgContainer && !drawsContents)
+ svgContainer->setDrawsContents(false);
+}
+
+void clampImageBufferSizeToViewport(RenderObject* object, IntSize& size)
+{
+ if (!object || !object->isRenderView())
+ return;
+
+ RenderView* view = static_cast<RenderView*>(object);
+ if (!view->frameView())
+ return;
+
+ int viewWidth = view->frameView()->visibleWidth();
+ int viewHeight = view->frameView()->visibleHeight();
+
+ if (size.width() > viewWidth)
+ size.setWidth(viewWidth);
+
+ if (size.height() > viewHeight)
+ size.setHeight(viewHeight);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h
new file mode 100644
index 0000000..7fdfcf8
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderSupport.h
@@ -0,0 +1,42 @@
+/**
+ * This file is part of the DOM implementation for WebKit.
+ *
+ * Copyright (C) 2007 Rob Buis <buis@kde.org>
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#if ENABLE(SVG)
+#include "RenderObject.h"
+
+namespace WebCore {
+
+class SVGResourceFilter;
+void prepareToRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, const FloatRect& boundingBox, SVGResourceFilter*&, SVGResourceFilter* rootFilter = 0);
+void finishRenderSVGContent(RenderObject*, RenderObject::PaintInfo&, const FloatRect& boundingBox, SVGResourceFilter*&, GraphicsContext* savedContext);
+
+// This offers a way to render parts of a WebKit rendering tree into a ImageBuffer.
+class ImageBuffer;
+void renderSubtreeToImage(ImageBuffer*, RenderObject*);
+
+void clampImageBufferSizeToViewport(RenderObject*, IntSize&);
+
+}
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp
new file mode 100644
index 0000000..eff2fff
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.cpp
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Apple Inc. All rights reserved.
+ * (C) 2005 Rob Buis <buis@kde.org>
+ * (C) 2006 Alexander Kellett <lypanov@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGRenderTreeAsText.h"
+
+#include "GraphicsTypes.h"
+#include "InlineTextBox.h"
+#include "HTMLNames.h"
+#include "RenderSVGContainer.h"
+#include "RenderSVGInlineText.h"
+#include "RenderSVGText.h"
+#include "RenderSVGRoot.h"
+#include "RenderTreeAsText.h"
+#include "SVGCharacterLayoutInfo.h"
+#include "SVGInlineTextBox.h"
+#include "SVGPaintServerGradient.h"
+#include "SVGPaintServerPattern.h"
+#include "SVGPaintServerSolid.h"
+#include "SVGResourceClipper.h"
+#include "SVGRootInlineBox.h"
+#include "SVGStyledElement.h"
+#include <math.h>
+
+namespace WebCore {
+
+/** class + iomanip to help streaming list separators, i.e. ", " in string "a, b, c, d"
+ * Can be used in cases where you don't know which item in the list is the first
+ * one to be printed, but still want to avoid strings like ", b, c".
+ */
+class TextStreamSeparator {
+public:
+ TextStreamSeparator(const String& s)
+ : m_separator(s)
+ , m_needToSeparate(false)
+ {
+ }
+
+private:
+ friend TextStream& operator<<(TextStream&, TextStreamSeparator&);
+
+ String m_separator;
+ bool m_needToSeparate;
+};
+
+TextStream& operator<<(TextStream& ts, TextStreamSeparator& sep)
+{
+ if (sep.m_needToSeparate)
+ ts << sep.m_separator;
+ else
+ sep.m_needToSeparate = true;
+ return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const IntPoint& p)
+{
+ return ts << "(" << p.x() << "," << p.y() << ")";
+}
+
+TextStream& operator<<(TextStream& ts, const IntRect& r)
+{
+ return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height();
+}
+
+bool hasFractions(double val)
+{
+ double epsilon = 0.0001;
+ int ival = static_cast<int>(val);
+ double dval = static_cast<double>(ival);
+ return fabs(val - dval) > epsilon;
+}
+
+TextStream& operator<<(TextStream& ts, const FloatRect &r)
+{
+ ts << "at (";
+ if (hasFractions(r.x()))
+ ts << r.x();
+ else
+ ts << int(r.x());
+ ts << ",";
+ if (hasFractions(r.y()))
+ ts << r.y();
+ else
+ ts << int(r.y());
+ ts << ") size ";
+ if (hasFractions(r.width()))
+ ts << r.width();
+ else
+ ts << int(r.width());
+ ts << "x";
+ if (hasFractions(r.height()))
+ ts << r.height();
+ else
+ ts << int(r.height());
+ return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const FloatPoint& p)
+{
+ ts << "(";
+ if (hasFractions(p.x()))
+ ts << p.x();
+ else
+ ts << int(p.x());
+ ts << ",";
+ if (hasFractions(p.y()))
+ ts << p.y();
+ else
+ ts << int(p.y());
+ return ts << ")";
+}
+
+TextStream& operator<<(TextStream& ts, const FloatSize& s)
+{
+ ts << "width=";
+ if (hasFractions(s.width()))
+ ts << s.width();
+ else
+ ts << int(s.width());
+ ts << " height=";
+ if (hasFractions(s.height()))
+ ts << s.height();
+ else
+ ts << int(s.height());
+ return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const TransformationMatrix& transform)
+{
+ if (transform.isIdentity())
+ ts << "identity";
+ else
+ ts << "{m=(("
+ << transform.a() << "," << transform.b()
+ << ")("
+ << transform.c() << "," << transform.d()
+ << ")) t=("
+ << transform.e() << "," << transform.f()
+ << ")}";
+
+ return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const Color& c)
+{
+ return ts << c.name();
+}
+
+static void writeIndent(TextStream& ts, int indent)
+{
+ for (int i = 0; i != indent; ++i)
+ ts << " ";
+}
+
+// FIXME: Maybe this should be in KCanvasRenderingStyle.cpp
+static TextStream& operator<<(TextStream& ts, const DashArray& a)
+{
+ ts << "{";
+ DashArray::const_iterator end = a.end();
+ for (DashArray::const_iterator it = a.begin(); it != end; ++it) {
+ if (it != a.begin())
+ ts << ", ";
+ ts << *it;
+ }
+ ts << "}";
+ return ts;
+}
+
+// FIXME: Maybe this should be in GraphicsTypes.cpp
+static TextStream& operator<<(TextStream& ts, LineCap style)
+{
+ switch (style) {
+ case ButtCap:
+ ts << "BUTT";
+ break;
+ case RoundCap:
+ ts << "ROUND";
+ break;
+ case SquareCap:
+ ts << "SQUARE";
+ break;
+ }
+ return ts;
+}
+
+// FIXME: Maybe this should be in GraphicsTypes.cpp
+static TextStream& operator<<(TextStream& ts, LineJoin style)
+{
+ switch (style) {
+ case MiterJoin:
+ ts << "MITER";
+ break;
+ case RoundJoin:
+ ts << "ROUND";
+ break;
+ case BevelJoin:
+ ts << "BEVEL";
+ break;
+ }
+ return ts;
+}
+
+static void writeStyle(TextStream& ts, const RenderObject& object)
+{
+ const RenderStyle* style = object.style();
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+
+ if (!object.localTransform().isIdentity())
+ ts << " [transform=" << object.localTransform() << "]";
+ if (svgStyle->imageRendering() != SVGRenderStyle::initialImageRendering())
+ ts << " [image rendering=" << svgStyle->imageRendering() << "]";
+ if (style->opacity() != RenderStyle::initialOpacity())
+ ts << " [opacity=" << style->opacity() << "]";
+ if (object.isRenderPath()) {
+ const RenderPath& path = static_cast<const RenderPath&>(object);
+ SVGPaintServer* strokePaintServer = SVGPaintServer::strokePaintServer(style, &path);
+ if (strokePaintServer) {
+ TextStreamSeparator s(" ");
+ ts << " [stroke={";
+ if (strokePaintServer)
+ ts << s << *strokePaintServer;
+
+ double dashOffset = SVGRenderStyle::cssPrimitiveToLength(&path, svgStyle->strokeDashOffset(), 0.0f);
+ const DashArray& dashArray = dashArrayFromRenderingStyle(style);
+ double strokeWidth = SVGRenderStyle::cssPrimitiveToLength(&path, svgStyle->strokeWidth(), 1.0f);
+
+ if (svgStyle->strokeOpacity() != 1.0f)
+ ts << s << "[opacity=" << svgStyle->strokeOpacity() << "]";
+ if (strokeWidth != 1.0f)
+ ts << s << "[stroke width=" << strokeWidth << "]";
+ if (svgStyle->strokeMiterLimit() != 4)
+ ts << s << "[miter limit=" << svgStyle->strokeMiterLimit() << "]";
+ if (svgStyle->capStyle() != 0)
+ ts << s << "[line cap=" << svgStyle->capStyle() << "]";
+ if (svgStyle->joinStyle() != 0)
+ ts << s << "[line join=" << svgStyle->joinStyle() << "]";
+ if (dashOffset != 0.0f)
+ ts << s << "[dash offset=" << dashOffset << "]";
+ if (!dashArray.isEmpty())
+ ts << s << "[dash array=" << dashArray << "]";
+ ts << "}]";
+ }
+ SVGPaintServer* fillPaintServer = SVGPaintServer::fillPaintServer(style, &path);
+ if (fillPaintServer) {
+ TextStreamSeparator s(" ");
+ ts << " [fill={";
+ if (fillPaintServer)
+ ts << s << *fillPaintServer;
+
+ if (style->svgStyle()->fillOpacity() != 1.0f)
+ ts << s << "[opacity=" << style->svgStyle()->fillOpacity() << "]";
+ if (style->svgStyle()->fillRule() != RULE_NONZERO)
+ ts << s << "[fill rule=" << style->svgStyle()->fillRule() << "]";
+ ts << "}]";
+ }
+ }
+ if (!svgStyle->clipPath().isEmpty())
+ ts << " [clip path=\"" << svgStyle->clipPath() << "\"]";
+ if (!svgStyle->startMarker().isEmpty())
+ ts << " [start marker=" << svgStyle->startMarker() << "]";
+ if (!svgStyle->midMarker().isEmpty())
+ ts << " [middle marker=" << svgStyle->midMarker() << "]";
+ if (!svgStyle->endMarker().isEmpty())
+ ts << " [end marker=" << svgStyle->endMarker() << "]";
+ if (!svgStyle->filter().isEmpty())
+ ts << " [filter=" << svgStyle->filter() << "]";
+}
+
+static TextStream& operator<<(TextStream& ts, const RenderPath& path)
+{
+ ts << " " << path.absoluteTransform().mapRect(path.relativeBBox());
+
+ writeStyle(ts, path);
+
+ ts << " [data=\"" << path.path().debugString() << "\"]";
+
+ return ts;
+}
+
+static TextStream& operator<<(TextStream& ts, const RenderSVGContainer& container)
+{
+ ts << " " << container.absoluteTransform().mapRect(container.relativeBBox());
+
+ writeStyle(ts, container);
+
+ return ts;
+}
+
+static TextStream& operator<<(TextStream& ts, const RenderSVGRoot& root)
+{
+ ts << " " << root.absoluteTransform().mapRect(root.relativeBBox());
+
+ writeStyle(ts, root);
+
+ return ts;
+}
+
+static TextStream& operator<<(TextStream& ts, const RenderSVGText& text)
+{
+ SVGRootInlineBox* box = static_cast<SVGRootInlineBox*>(text.firstRootBox());
+
+ if (!box)
+ return ts;
+
+ Vector<SVGTextChunk>& chunks = const_cast<Vector<SVGTextChunk>& >(box->svgTextChunks());
+ ts << " at (" << text.xPos() << "," << text.yPos() << ") size " << box->width() << "x" << box->height() << " contains " << chunks.size() << " chunk(s)";
+
+ if (text.parent() && (text.parent()->style()->color() != text.style()->color()))
+ ts << " [color=" << text.style()->color().name() << "]";
+
+ return ts;
+}
+
+static inline bool containsInlineTextBox(SVGTextChunk& chunk, SVGInlineTextBox* box)
+{
+ Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin();
+ Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end();
+
+ bool found = false;
+ for (; boxIt != boxEnd; ++boxIt) {
+ SVGInlineBoxCharacterRange& range = *boxIt;
+
+ if (box == static_cast<SVGInlineTextBox*>(range.box)) {
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
+static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textBox, int indent)
+{
+ SVGRootInlineBox* rootBox = textBox->svgRootInlineBox();
+ if (!rootBox)
+ return;
+
+ Vector<SVGTextChunk>& chunks = const_cast<Vector<SVGTextChunk>& >(rootBox->svgTextChunks());
+
+ Vector<SVGTextChunk>::iterator it = chunks.begin();
+ Vector<SVGTextChunk>::iterator end = chunks.end();
+
+ // Write text chunks
+ unsigned int i = 1;
+ for (; it != end; ++it) {
+ SVGTextChunk& cur = *it;
+
+ // Write inline box character ranges
+ Vector<SVGInlineBoxCharacterRange>::iterator boxIt = cur.boxes.begin();
+ Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = cur.boxes.end();
+
+ if (!containsInlineTextBox(cur, textBox)) {
+ i++;
+ continue;
+ }
+
+ writeIndent(ts, indent + 1);
+
+ unsigned int j = 1;
+ ts << "chunk " << i << " ";
+
+ if (cur.anchor == TA_MIDDLE) {
+ ts << "(middle anchor";
+ if (cur.isVerticalText)
+ ts << ", vertical";
+ ts << ") ";
+ } else if (cur.anchor == TA_END) {
+ ts << "(end anchor";
+ if (cur.isVerticalText)
+ ts << ", vertical";
+ ts << ") ";
+ } else if (cur.isVerticalText)
+ ts << "(vertical) ";
+
+ unsigned int totalOffset = 0;
+
+ for (; boxIt != boxEnd; ++boxIt) {
+ SVGInlineBoxCharacterRange& range = *boxIt;
+
+ unsigned int offset = range.endOffset - range.startOffset;
+ ASSERT(cur.start + totalOffset <= cur.end);
+
+ totalOffset += offset;
+
+ if (textBox != static_cast<SVGInlineTextBox*>(range.box)) {
+ j++;
+ continue;
+ }
+
+ FloatPoint topLeft = topLeftPositionOfCharacterRange(cur.start + totalOffset - offset, cur.start + totalOffset);
+
+ ts << "text run " << j << " at (" << topLeft.x() << "," << topLeft.y() << ") ";
+ ts << "startOffset " << range.startOffset << " endOffset " << range.endOffset;
+
+ if (cur.isVerticalText)
+ ts << " height " << cummulatedHeightOfInlineBoxCharacterRange(range);
+ else
+ ts << " width " << cummulatedWidthOfInlineBoxCharacterRange(range);
+
+ if (textBox->direction() == RTL || textBox->m_dirOverride) {
+ ts << (textBox->direction() == RTL ? " RTL" : " LTR");
+
+ if (textBox->m_dirOverride)
+ ts << " override";
+ }
+
+ ts << ": " << quoteAndEscapeNonPrintables(String(textBox->textObject()->text()).substring(textBox->start() + range.startOffset, offset)) << "\n";
+
+ j++;
+ }
+
+ i++;
+ }
+}
+
+static inline void writeSVGInlineText(TextStream& ts, const RenderSVGInlineText& text, int indent)
+{
+ for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox())
+ writeSVGInlineTextBox(ts, static_cast<SVGInlineTextBox*>(box), indent);
+}
+
+static String getTagName(SVGStyledElement* elem)
+{
+ if (elem)
+ return elem->nodeName();
+ return "";
+}
+
+void write(TextStream& ts, const RenderSVGContainer& container, int indent)
+{
+ writeIndent(ts, indent);
+ ts << container.renderName();
+
+ if (container.element()) {
+ String tagName = getTagName(static_cast<SVGStyledElement*>(container.element()));
+ if (!tagName.isEmpty())
+ ts << " {" << tagName << "}";
+ }
+
+ ts << container << "\n";
+
+ for (RenderObject* child = container.firstChild(); child; child = child->nextSibling())
+ write(ts, *child, indent + 1);
+}
+
+void write(TextStream& ts, const RenderSVGRoot& root, int indent)
+{
+ writeIndent(ts, indent);
+ ts << root.renderName();
+
+ if (root.element()) {
+ String tagName = getTagName(static_cast<SVGStyledElement*>(root.element()));
+ if (!tagName.isEmpty())
+ ts << " {" << tagName << "}";
+ }
+
+ ts << root << "\n";
+
+ for (RenderObject* child = root.firstChild(); child; child = child->nextSibling())
+ write(ts, *child, indent + 1);
+}
+
+void write(TextStream& ts, const RenderSVGText& text, int indent)
+{
+ writeIndent(ts, indent);
+ ts << text.renderName();
+
+ if (text.element()) {
+ String tagName = getTagName(static_cast<SVGStyledElement*>(text.element()));
+ if (!tagName.isEmpty())
+ ts << " {" << tagName << "}";
+ }
+
+ ts << text << "\n";
+
+ for (RenderObject* child = text.firstChild(); child; child = child->nextSibling())
+ write(ts, *child, indent + 1);
+}
+
+void write(TextStream& ts, const RenderSVGInlineText& text, int indent)
+{
+ writeIndent(ts, indent);
+ ts << text.renderName();
+
+ if (text.element()) {
+ String tagName = getTagName(static_cast<SVGStyledElement*>(text.element()));
+ if (!tagName.isEmpty())
+ ts << " {" << tagName << "}";
+ }
+
+ ts << " at (" << text.xPos() << "," << text.yPos() << ") size " << text.width() << "x" << text.height() << "\n";
+ writeSVGInlineText(ts, text, indent);
+}
+
+void write(TextStream& ts, const RenderPath& path, int indent)
+{
+ writeIndent(ts, indent);
+ ts << path.renderName();
+
+ if (path.element()) {
+ String tagName = getTagName(static_cast<SVGStyledElement*>(path.element()));
+ if (!tagName.isEmpty())
+ ts << " {" << tagName << "}";
+ }
+
+ ts << path << "\n";
+}
+
+void writeRenderResources(TextStream& ts, Node* parent)
+{
+ ASSERT(parent);
+ Node* node = parent;
+ do {
+ if (!node->isSVGElement())
+ continue;
+ SVGElement* svgElement = static_cast<SVGElement*>(node);
+ if (!svgElement->isStyled())
+ continue;
+
+ SVGStyledElement* styled = static_cast<SVGStyledElement*>(svgElement);
+ RefPtr<SVGResource> resource(styled->canvasResource());
+ if (!resource)
+ continue;
+
+ String elementId = svgElement->getAttribute(HTMLNames::idAttr);
+ if (resource->isPaintServer()) {
+ RefPtr<SVGPaintServer> paintServer = WTF::static_pointer_cast<SVGPaintServer>(resource);
+ ts << "KRenderingPaintServer {id=\"" << elementId << "\" " << *paintServer << "}" << "\n";
+ } else
+ ts << "KCanvasResource {id=\"" << elementId << "\" " << *resource << "}" << "\n";
+ } while ((node = node->traverseNextNode(parent)));
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h
new file mode 100644
index 0000000..c4d832d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGRenderTreeAsText.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2004, 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SVGRenderTreeAsText_h
+#define SVGRenderTreeAsText_h
+
+#if ENABLE(SVG)
+
+#include "TextStream.h"
+
+namespace WebCore {
+
+ class TransformationMatrix;
+ class Color;
+ class FloatPoint;
+ class FloatRect;
+ class FloatSize;
+ class IntPoint;
+ class IntRect;
+ class Node;
+ class RenderPath;
+ class RenderSVGContainer;
+ class RenderSVGInlineText;
+ class RenderSVGRoot;
+ class RenderSVGText;
+
+// functions used by the main RenderTreeAsText code
+void write(TextStream&, const RenderPath&, int indent = 0);
+void write(TextStream&, const RenderSVGContainer&, int indent = 0);
+void write(TextStream&, const RenderSVGInlineText&, int ident = 0);
+void write(TextStream&, const RenderSVGRoot&, int indent = 0);
+void write(TextStream&, const RenderSVGText&, int ident = 0);
+
+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 IntRect&);
+TextStream& operator<<(TextStream&, const Color&);
+TextStream& operator<<(TextStream&, const IntPoint&);
+TextStream& operator<<(TextStream&, const FloatSize&);
+TextStream& operator<<(TextStream&, const FloatRect&);
+TextStream& operator<<(TextStream&, const FloatPoint&);
+
+// helper operators specific to dumping the render tree. these are used in various classes to dump the render tree
+// these could be defined in separate namespace to avoid matching these generic signatures unintentionally.
+
+template<typename Item>
+TextStream& operator<<(TextStream& ts, const Vector<Item*>& v)
+{
+ ts << "[";
+
+ for (unsigned i = 0; i < v.size(); i++) {
+ ts << *v[i];
+ if (i < v.size() - 1)
+ ts << ", ";
+ }
+
+ ts << "]";
+ return ts;
+}
+
+template<typename Item>
+TextStream& operator<<(TextStream& ts, const Vector<Item>& v)
+{
+ ts << "[";
+
+ for (unsigned i = 0; i < v.size(); i++) {
+ ts << v[i];
+ if (i < v.size() - 1)
+ ts << ", ";
+ }
+
+ ts << "]";
+ return ts;
+}
+
+template<typename Pointer>
+TextStream& operator<<(TextStream& ts, Pointer* t)
+{
+ ts << reinterpret_cast<intptr_t>(t);
+ return ts;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+
+#endif // SVGRenderTreeAsText_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp
new file mode 100644
index 0000000..f7623ba
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.cpp
@@ -0,0 +1,1718 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * (C) 2006 Apple Computer Inc.
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGRootInlineBox.h"
+
+#include "Editor.h"
+#include "Frame.h"
+#include "GraphicsContext.h"
+#include "RenderSVGRoot.h"
+#include "SVGInlineFlowBox.h"
+#include "SVGInlineTextBox.h"
+#include "SVGFontElement.h"
+#include "SVGPaintServer.h"
+#include "SVGRenderStyleDefs.h"
+#include "SVGRenderSupport.h"
+#include "SVGResourceFilter.h"
+#include "SVGTextPositioningElement.h"
+#include "SVGURIReference.h"
+#include "Text.h"
+#include "UnicodeRange.h"
+
+#include <float.h>
+
+// Text chunk creation is complex and the whole process
+// can easily be traced by setting this variable > 0.
+#define DEBUG_CHUNK_BUILDING 0
+
+namespace WebCore {
+
+static inline bool isVerticalWritingMode(const SVGRenderStyle* style)
+{
+ return style->writingMode() == WM_TBRL || style->writingMode() == WM_TB;
+}
+
+static inline EAlignmentBaseline dominantBaselineToShift(bool isVerticalText, const RenderObject* text, const Font& font)
+{
+ ASSERT(text);
+
+ const SVGRenderStyle* style = text->style() ? text->style()->svgStyle() : 0;
+ ASSERT(style);
+
+ const SVGRenderStyle* parentStyle = text->parent() && text->parent()->style() ? text->parent()->style()->svgStyle() : 0;
+
+ EDominantBaseline baseline = style->dominantBaseline();
+ if (baseline == DB_AUTO) {
+ if (isVerticalText)
+ baseline = DB_CENTRAL;
+ else
+ baseline = DB_ALPHABETIC;
+ }
+
+ switch (baseline) {
+ case DB_USE_SCRIPT:
+ // TODO: The dominant-baseline and the baseline-table components are set by
+ // determining the predominant script of the character data content.
+ return AB_ALPHABETIC;
+ case DB_NO_CHANGE:
+ {
+ if (parentStyle)
+ return dominantBaselineToShift(isVerticalText, text->parent(), font);
+
+ ASSERT_NOT_REACHED();
+ return AB_AUTO;
+ }
+ case DB_RESET_SIZE:
+ {
+ if (parentStyle)
+ return dominantBaselineToShift(isVerticalText, text->parent(), font);
+
+ ASSERT_NOT_REACHED();
+ return AB_AUTO;
+ }
+ case DB_IDEOGRAPHIC:
+ return AB_IDEOGRAPHIC;
+ case DB_ALPHABETIC:
+ return AB_ALPHABETIC;
+ case DB_HANGING:
+ return AB_HANGING;
+ case DB_MATHEMATICAL:
+ return AB_MATHEMATICAL;
+ case DB_CENTRAL:
+ return AB_CENTRAL;
+ case DB_MIDDLE:
+ return AB_MIDDLE;
+ case DB_TEXT_AFTER_EDGE:
+ return AB_TEXT_AFTER_EDGE;
+ case DB_TEXT_BEFORE_EDGE:
+ return AB_TEXT_BEFORE_EDGE;
+ default:
+ ASSERT_NOT_REACHED();
+ return AB_AUTO;
+ }
+}
+
+static inline float alignmentBaselineToShift(bool isVerticalText, const RenderObject* text, const Font& font)
+{
+ ASSERT(text);
+
+ const SVGRenderStyle* style = text->style() ? text->style()->svgStyle() : 0;
+ ASSERT(style);
+
+ const SVGRenderStyle* parentStyle = text->parent() && text->parent()->style() ? text->parent()->style()->svgStyle() : 0;
+
+ EAlignmentBaseline baseline = style->alignmentBaseline();
+ if (baseline == AB_AUTO) {
+ if (parentStyle && style->dominantBaseline() == DB_AUTO)
+ baseline = dominantBaselineToShift(isVerticalText, text->parent(), font);
+ else
+ baseline = dominantBaselineToShift(isVerticalText, text, font);
+
+ ASSERT(baseline != AB_AUTO);
+ }
+
+ // Note: http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
+ switch (baseline) {
+ case AB_BASELINE:
+ {
+ if (parentStyle)
+ return dominantBaselineToShift(isVerticalText, text->parent(), font);
+
+ return 0.0f;
+ }
+ case AB_BEFORE_EDGE:
+ case AB_TEXT_BEFORE_EDGE:
+ return font.ascent();
+ case AB_MIDDLE:
+ return font.xHeight() / 2.0f;
+ case AB_CENTRAL:
+ // Not needed, we're taking this into account already for vertical text!
+ // return (font.ascent() - font.descent()) / 2.0f;
+ return 0.0f;
+ case AB_AFTER_EDGE:
+ case AB_TEXT_AFTER_EDGE:
+ case AB_IDEOGRAPHIC:
+ return font.descent();
+ case AB_ALPHABETIC:
+ return 0.0f;
+ case AB_HANGING:
+ return font.ascent() * 8.0f / 10.0f;
+ case AB_MATHEMATICAL:
+ return font.ascent() / 2.0f;
+ default:
+ ASSERT_NOT_REACHED();
+ return 0.0f;
+ }
+}
+
+static inline float glyphOrientationToAngle(const SVGRenderStyle* svgStyle, bool isVerticalText, const UChar& character)
+{
+ switch (isVerticalText ? svgStyle->glyphOrientationVertical() : svgStyle->glyphOrientationHorizontal()) {
+ case GO_AUTO:
+ {
+ // Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees.
+ // Text which is not fullwidth will be set with a glyph-orientation of 90-degrees.
+ unsigned int unicodeRange = findCharUnicodeRange(character);
+ if (unicodeRange == cRangeSetLatin || unicodeRange == cRangeArabic)
+ return 90.0f;
+
+ return 0.0f;
+ }
+ case GO_90DEG:
+ return 90.0f;
+ case GO_180DEG:
+ return 180.0f;
+ case GO_270DEG:
+ return 270.0f;
+ case GO_0DEG:
+ default:
+ return 0.0f;
+ }
+}
+
+static inline bool glyphOrientationIsMultiplyOf180Degrees(float orientationAngle)
+{
+ return fabsf(fmodf(orientationAngle, 180.0f)) == 0.0f;
+}
+
+static inline float calculateGlyphAdvanceAndShiftRespectingOrientation(bool isVerticalText, float orientationAngle, float glyphWidth, float glyphHeight, const Font& font, SVGChar& svgChar, float& xOrientationShift, float& yOrientationShift)
+{
+ bool orientationIsMultiplyOf180Degrees = glyphOrientationIsMultiplyOf180Degrees(orientationAngle);
+
+ // The function is based on spec requirements:
+ //
+ // Spec: If the 'glyph-orientation-horizontal' results in an orientation angle that is not a multiple of
+ // of 180 degrees, then the current text position is incremented according to the vertical metrics of the glyph.
+ //
+ // Spec: If if the 'glyph-orientation-vertical' results in an orientation angle that is not a multiple of
+ // 180 degrees,then the current text position is incremented according to the horizontal metrics of the glyph.
+
+ // vertical orientation handling
+ if (isVerticalText) {
+ if (orientationAngle == 0.0f) {
+ xOrientationShift = -glyphWidth / 2.0f;
+ yOrientationShift = font.ascent();
+ } else if (orientationAngle == 90.0f) {
+ xOrientationShift = -glyphHeight;
+ yOrientationShift = font.descent();
+ svgChar.orientationShiftY = -font.ascent();
+ } else if (orientationAngle == 270.0f) {
+ xOrientationShift = glyphHeight;
+ yOrientationShift = font.descent();
+ svgChar.orientationShiftX = -glyphWidth;
+ svgChar.orientationShiftY = -font.ascent();
+ } else if (orientationAngle == 180.0f) {
+ yOrientationShift = font.ascent();
+ svgChar.orientationShiftX = -glyphWidth / 2.0f;
+ svgChar.orientationShiftY = font.ascent() - font.descent();
+ }
+
+ // vertical advance calculation
+ if (orientationAngle != 0.0f && !orientationIsMultiplyOf180Degrees)
+ return glyphWidth;
+
+ return glyphHeight;
+ }
+
+ // horizontal orientation handling
+ if (orientationAngle == 90.0f) {
+ xOrientationShift = glyphWidth / 2.0f;
+ yOrientationShift = -font.descent();
+ svgChar.orientationShiftX = -glyphWidth / 2.0f - font.descent();
+ svgChar.orientationShiftY = font.descent();
+ } else if (orientationAngle == 270.0f) {
+ xOrientationShift = -glyphWidth / 2.0f;
+ yOrientationShift = -font.descent();
+ svgChar.orientationShiftX = -glyphWidth / 2.0f + font.descent();
+ svgChar.orientationShiftY = glyphHeight;
+ } else if (orientationAngle == 180.0f) {
+ xOrientationShift = glyphWidth / 2.0f;
+ svgChar.orientationShiftX = -glyphWidth / 2.0f;
+ svgChar.orientationShiftY = font.ascent() - font.descent();
+ }
+
+ // horizontal advance calculation
+ if (orientationAngle != 0.0f && !orientationIsMultiplyOf180Degrees)
+ return glyphHeight;
+
+ return glyphWidth;
+}
+
+static inline void startTextChunk(SVGTextChunkLayoutInfo& info)
+{
+ info.chunk.boxes.clear();
+ info.chunk.boxes.append(SVGInlineBoxCharacterRange());
+
+ info.chunk.start = info.it;
+ info.assignChunkProperties = true;
+}
+
+static inline void closeTextChunk(SVGTextChunkLayoutInfo& info)
+{
+ ASSERT(!info.chunk.boxes.last().isOpen());
+ ASSERT(info.chunk.boxes.last().isClosed());
+
+ info.chunk.end = info.it;
+ ASSERT(info.chunk.end >= info.chunk.start);
+
+ info.svgTextChunks.append(info.chunk);
+}
+
+RenderSVGRoot* findSVGRootObject(RenderObject* start)
+{
+ // Find associated root inline box
+ while (start && !start->isSVGRoot())
+ start = start->parent();
+
+ ASSERT(start);
+ ASSERT(start->isSVGRoot());
+
+ return static_cast<RenderSVGRoot*>(start);
+}
+
+static inline FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>& chars)
+{
+ return topLeftPositionOfCharacterRange(chars.begin(), chars.end());
+}
+
+FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>::iterator it, Vector<SVGChar>::iterator end)
+{
+ float lowX = FLT_MAX, lowY = FLT_MAX;
+ for (; it != end; ++it) {
+ if (it->isHidden())
+ continue;
+
+ float x = (*it).x;
+ float y = (*it).y;
+
+ if (x < lowX)
+ lowX = x;
+
+ if (y < lowY)
+ lowY = y;
+ }
+
+ return FloatPoint(lowX, lowY);
+}
+
+// Helper function
+static float calculateKerning(RenderObject* item)
+{
+ const Font& font = item->style()->font();
+ const SVGRenderStyle* svgStyle = item->style()->svgStyle();
+
+ float kerning = 0.0f;
+ if (CSSPrimitiveValue* primitive = static_cast<CSSPrimitiveValue*>(svgStyle->kerning())) {
+ kerning = primitive->getFloatValue();
+
+ if (primitive->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE && font.pixelSize() > 0)
+ kerning = kerning / 100.0f * font.pixelSize();
+ }
+
+ return kerning;
+}
+
+// Helper class for paint()
+struct SVGRootInlineBoxPaintWalker {
+ SVGRootInlineBoxPaintWalker(SVGRootInlineBox* rootBox, SVGResourceFilter* rootFilter, RenderObject::PaintInfo paintInfo, int tx, int ty)
+ : m_rootBox(rootBox)
+ , m_chunkStarted(false)
+ , m_paintInfo(paintInfo)
+ , m_savedInfo(paintInfo)
+ , m_boundingBox(tx + rootBox->xPos(), ty + rootBox->yPos(), rootBox->width(), rootBox->height())
+ , m_filter(0)
+ , m_rootFilter(rootFilter)
+ , m_fillPaintServer(0)
+ , m_strokePaintServer(0)
+ , m_fillPaintServerObject(0)
+ , m_strokePaintServerObject(0)
+ , m_tx(tx)
+ , m_ty(ty)
+ {
+ }
+
+ ~SVGRootInlineBoxPaintWalker()
+ {
+ ASSERT(!m_filter);
+ ASSERT(!m_fillPaintServer);
+ ASSERT(!m_fillPaintServerObject);
+ ASSERT(!m_strokePaintServer);
+ ASSERT(!m_strokePaintServerObject);
+ ASSERT(!m_chunkStarted);
+ }
+
+ void teardownFillPaintServer()
+ {
+ if (!m_fillPaintServer)
+ return;
+
+ m_fillPaintServer->teardown(m_paintInfo.context, m_fillPaintServerObject, ApplyToFillTargetType, true);
+
+ m_fillPaintServer = 0;
+ m_fillPaintServerObject = 0;
+ }
+
+ void teardownStrokePaintServer()
+ {
+ if (!m_strokePaintServer)
+ return;
+
+ m_strokePaintServer->teardown(m_paintInfo.context, m_strokePaintServerObject, ApplyToStrokeTargetType, true);
+
+ m_strokePaintServer = 0;
+ m_strokePaintServerObject = 0;
+ }
+
+ void chunkStartCallback(InlineBox* box)
+ {
+ ASSERT(!m_chunkStarted);
+ m_chunkStarted = true;
+
+ InlineFlowBox* flowBox = box->parent();
+
+ // Initialize text rendering
+ RenderObject* object = flowBox->object();
+ ASSERT(object);
+
+ m_savedInfo = m_paintInfo;
+ m_paintInfo.context->save();
+
+ if (!flowBox->isRootInlineBox())
+ m_paintInfo.context->concatCTM(m_rootBox->object()->localTransform());
+
+ m_paintInfo.context->concatCTM(object->localTransform());
+
+ if (!flowBox->isRootInlineBox()) {
+ prepareToRenderSVGContent(object, m_paintInfo, m_boundingBox, m_filter, m_rootFilter);
+ m_paintInfo.rect = object->localTransform().inverse().mapRect(m_paintInfo.rect);
+ }
+ }
+
+ void chunkEndCallback(InlineBox* box)
+ {
+ ASSERT(m_chunkStarted);
+ m_chunkStarted = false;
+
+ InlineFlowBox* flowBox = box->parent();
+
+ RenderObject* object = flowBox->object();
+ ASSERT(object);
+
+ // Clean up last used paint server
+ teardownFillPaintServer();
+ teardownStrokePaintServer();
+
+ // Finalize text rendering
+ if (!flowBox->isRootInlineBox()) {
+ finishRenderSVGContent(object, m_paintInfo, m_boundingBox, m_filter, m_savedInfo.context);
+ m_filter = 0;
+ }
+
+ // Restore context & repaint rect
+ m_paintInfo.context->restore();
+ m_paintInfo.rect = m_savedInfo.rect;
+ }
+
+ bool chunkSetupFillCallback(InlineBox* box)
+ {
+ InlineFlowBox* flowBox = box->parent();
+
+ // Setup fill paint server
+ RenderObject* object = flowBox->object();
+ ASSERT(object);
+
+ ASSERT(!m_strokePaintServer);
+ teardownFillPaintServer();
+
+ m_fillPaintServer = SVGPaintServer::fillPaintServer(object->style(), object);
+ if (m_fillPaintServer) {
+ m_fillPaintServer->setup(m_paintInfo.context, object, ApplyToFillTargetType, true);
+ m_fillPaintServerObject = object;
+ return true;
+ }
+
+ return false;
+ }
+
+ bool chunkSetupStrokeCallback(InlineBox* box)
+ {
+ InlineFlowBox* flowBox = box->parent();
+
+ // Setup stroke paint server
+ RenderObject* object = flowBox->object();
+ ASSERT(object);
+
+ // If we're both stroked & filled, teardown fill paint server before stroking.
+ teardownFillPaintServer();
+ teardownStrokePaintServer();
+
+ m_strokePaintServer = SVGPaintServer::strokePaintServer(object->style(), object);
+
+ if (m_strokePaintServer) {
+ m_strokePaintServer->setup(m_paintInfo.context, object, ApplyToStrokeTargetType, true);
+ m_strokePaintServerObject = object;
+ return true;
+ }
+
+ return false;
+ }
+
+ void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
+ const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
+ {
+ RenderText* text = textBox->textObject();
+ ASSERT(text);
+
+ RenderStyle* styleToUse = text->style(textBox->isFirstLineStyle());
+ ASSERT(styleToUse);
+
+ startOffset += textBox->start();
+
+ int textDecorations = styleToUse->textDecorationsInEffect();
+
+ int textWidth = 0;
+ IntPoint decorationOrigin;
+ SVGTextDecorationInfo info;
+
+ if (!chunkCtm.isIdentity())
+ m_paintInfo.context->concatCTM(chunkCtm);
+
+ for (Vector<SVGChar>::iterator it = start; it != end; ++it) {
+ if (it->isHidden())
+ continue;
+
+ // Determine how many characters - starting from the current - can be drawn at once.
+ Vector<SVGChar>::iterator itSearch = it + 1;
+ while (itSearch != end) {
+ if (itSearch->drawnSeperated || itSearch->isHidden())
+ break;
+
+ itSearch++;
+ }
+
+ const UChar* stringStart = text->characters() + startOffset + (it - start);
+ unsigned int stringLength = itSearch - it;
+
+ // Paint decorations, that have to be drawn before the text gets drawn
+ if (textDecorations != TDNONE && m_paintInfo.phase != PaintPhaseSelection) {
+ textWidth = styleToUse->font().width(svgTextRunForInlineTextBox(stringStart, stringLength, styleToUse, textBox, (*it).x));
+ decorationOrigin = IntPoint((int) (*it).x, (int) (*it).y - styleToUse->font().ascent());
+ info = m_rootBox->retrievePaintServersForTextDecoration(text);
+ }
+
+ if (textDecorations & UNDERLINE && textWidth != 0.0f)
+ textBox->paintDecoration(UNDERLINE, m_paintInfo.context, decorationOrigin.x(), decorationOrigin.y(), textWidth, *it, info);
+
+ if (textDecorations & OVERLINE && textWidth != 0.0f)
+ 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);
+
+ // Paint decorations, that have to be drawn afterwards
+ if (textDecorations & LINE_THROUGH && textWidth != 0.0f)
+ textBox->paintDecoration(LINE_THROUGH, m_paintInfo.context, decorationOrigin.x(), decorationOrigin.y(), textWidth, *it, info);
+
+ // Skip processed characters
+ it = itSearch - 1;
+ }
+
+ if (!chunkCtm.isIdentity())
+ m_paintInfo.context->concatCTM(chunkCtm.inverse());
+ }
+
+private:
+ SVGRootInlineBox* m_rootBox;
+ bool m_chunkStarted : 1;
+
+ RenderObject::PaintInfo m_paintInfo;
+ RenderObject::PaintInfo m_savedInfo;
+
+ FloatRect m_boundingBox;
+ SVGResourceFilter* m_filter;
+ SVGResourceFilter* m_rootFilter;
+
+ SVGPaintServer* m_fillPaintServer;
+ SVGPaintServer* m_strokePaintServer;
+
+ RenderObject* m_fillPaintServerObject;
+ RenderObject* m_strokePaintServerObject;
+
+ int m_tx;
+ int m_ty;
+};
+
+void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
+{
+ if (paintInfo.context->paintingDisabled() || paintInfo.phase != PaintPhaseForeground)
+ return;
+
+ RenderObject::PaintInfo savedInfo(paintInfo);
+ paintInfo.context->save();
+
+ SVGResourceFilter* filter = 0;
+ FloatRect boundingBox(tx + xPos(), ty + yPos(), width(), height());
+
+ // Initialize text rendering
+ paintInfo.context->concatCTM(object()->localTransform());
+ prepareToRenderSVGContent(object(), paintInfo, boundingBox, filter);
+ paintInfo.context->concatCTM(object()->localTransform().inverse());
+
+ // 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);
+
+ // Finalize text rendering
+ finishRenderSVGContent(object(), paintInfo, boundingBox, filter, savedInfo.context);
+ paintInfo.context->restore();
+}
+
+int SVGRootInlineBox::placeBoxesHorizontally(int, int& leftPosition, int& rightPosition, bool&)
+{
+ // Remove any offsets caused by RTL text layout
+ leftPosition = 0;
+ rightPosition = 0;
+ return 0;
+}
+
+void SVGRootInlineBox::verticallyAlignBoxes(int& heightOfBlock)
+{
+ // height is set by layoutInlineBoxes.
+ heightOfBlock = height();
+}
+
+float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range)
+{
+ ASSERT(!range.isOpen());
+ ASSERT(range.isClosed());
+ ASSERT(range.box->isInlineTextBox());
+
+ InlineTextBox* textBox = static_cast<InlineTextBox*>(range.box);
+ RenderText* text = textBox->textObject();
+ RenderStyle* style = text->style();
+
+ return style->font().floatWidth(svgTextRunForInlineTextBox(text->characters() + textBox->start() + range.startOffset, range.endOffset - range.startOffset, style, textBox, 0));
+}
+
+float cummulatedHeightOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range)
+{
+ ASSERT(!range.isOpen());
+ ASSERT(range.isClosed());
+ ASSERT(range.box->isInlineTextBox());
+
+ InlineTextBox* textBox = static_cast<InlineTextBox*>(range.box);
+ RenderText* text = textBox->textObject();
+ const Font& font = text->style()->font();
+
+ return (range.endOffset - range.startOffset) * (font.ascent() + font.descent());
+}
+
+TextRun svgTextRunForInlineTextBox(const UChar* c, int len, RenderStyle* style, const InlineTextBox* textBox, float xPos)
+{
+ ASSERT(textBox);
+ ASSERT(style);
+
+ TextRun run(c, len, false, static_cast<int>(xPos), textBox->toAdd(), textBox->direction() == RTL, textBox->m_dirOverride || style->visuallyOrdered());
+
+#if ENABLE(SVG_FONTS)
+ run.setReferencingRenderObject(textBox->textObject()->parent());
+#endif
+
+ // We handle letter & word spacing ourselves
+ run.disableSpacing();
+ return run;
+}
+
+static float cummulatedWidthOrHeightOfTextChunk(SVGTextChunk& chunk, bool calcWidthOnly)
+{
+ float length = 0.0f;
+ Vector<SVGChar>::iterator charIt = chunk.start;
+
+ Vector<SVGInlineBoxCharacterRange>::iterator it = chunk.boxes.begin();
+ Vector<SVGInlineBoxCharacterRange>::iterator end = chunk.boxes.end();
+
+ for (; it != end; ++it) {
+ SVGInlineBoxCharacterRange& range = *it;
+
+ SVGInlineTextBox* box = static_cast<SVGInlineTextBox*>(range.box);
+ RenderStyle* style = box->object()->style();
+
+ for (int i = range.startOffset; i < range.endOffset; ++i) {
+ ASSERT(charIt <= chunk.end);
+
+ // Determine how many characters - starting from the current - can be measured at once.
+ // Important for non-absolute positioned non-latin1 text (ie. Arabic) where ie. the width
+ // of a string is not the sum of the boundaries of all contained glyphs.
+ Vector<SVGChar>::iterator itSearch = charIt + 1;
+ Vector<SVGChar>::iterator endSearch = charIt + range.endOffset - i;
+ while (itSearch != endSearch) {
+ // No need to check for 'isHidden()' here as this function is not called for text paths.
+ if (itSearch->drawnSeperated)
+ break;
+
+ itSearch++;
+ }
+
+ unsigned int positionOffset = itSearch - charIt;
+
+ // Calculate width/height of subrange
+ SVGInlineBoxCharacterRange subRange;
+ subRange.box = range.box;
+ subRange.startOffset = i;
+ subRange.endOffset = i + positionOffset;
+
+ if (calcWidthOnly)
+ length += cummulatedWidthOfInlineBoxCharacterRange(subRange);
+ else
+ length += cummulatedHeightOfInlineBoxCharacterRange(subRange);
+
+ // Calculate gap between the previous & current range
+ // <text x="10 50 70">ABCD</text> - we need to take the gaps between A & B into account
+ // so add "40" as width, and analogous for B & C, add "20" as width.
+ if (itSearch > chunk.start && itSearch < chunk.end) {
+ SVGChar& lastCharacter = *(itSearch - 1);
+ SVGChar& currentCharacter = *itSearch;
+
+ int offset = box->direction() == RTL ? box->end() - i - positionOffset + 1 : box->start() + i + positionOffset - 1;
+
+ // FIXME: does this need to change to handle multichar glyphs?
+ int charsConsumed = 1;
+ String glyphName;
+ if (calcWidthOnly) {
+ float lastGlyphWidth = box->calculateGlyphWidth(style, offset, 0, charsConsumed, glyphName);
+ length += currentCharacter.x - lastCharacter.x - lastGlyphWidth;
+ } else {
+ float lastGlyphHeight = box->calculateGlyphHeight(style, offset, 0);
+ length += currentCharacter.y - lastCharacter.y - lastGlyphHeight;
+ }
+ }
+
+ // Advance processed characters
+ i += positionOffset - 1;
+ charIt = itSearch;
+ }
+ }
+
+ ASSERT(charIt == chunk.end);
+ return length;
+}
+
+static float cummulatedWidthOfTextChunk(SVGTextChunk& chunk)
+{
+ return cummulatedWidthOrHeightOfTextChunk(chunk, true);
+}
+
+static float cummulatedHeightOfTextChunk(SVGTextChunk& chunk)
+{
+ return cummulatedWidthOrHeightOfTextChunk(chunk, false);
+}
+
+static float calculateTextAnchorShiftForTextChunk(SVGTextChunk& chunk, ETextAnchor anchor)
+{
+ float shift = 0.0f;
+
+ if (chunk.isVerticalText)
+ shift = cummulatedHeightOfTextChunk(chunk);
+ else
+ shift = cummulatedWidthOfTextChunk(chunk);
+
+ if (anchor == TA_MIDDLE)
+ shift *= -0.5f;
+ else
+ shift *= -1.0f;
+
+ return shift;
+}
+
+static void applyTextAnchorToTextChunk(SVGTextChunk& chunk)
+{
+ // This method is not called for chunks containing chars aligned on a path.
+ // -> all characters are visible, no need to check for "isHidden()" anywhere.
+
+ if (chunk.anchor == TA_START)
+ return;
+
+ float shift = calculateTextAnchorShiftForTextChunk(chunk, chunk.anchor);
+
+ // Apply correction to chunk
+ Vector<SVGChar>::iterator chunkIt = chunk.start;
+ for (; chunkIt != chunk.end; ++chunkIt) {
+ SVGChar& curChar = *chunkIt;
+
+ if (chunk.isVerticalText)
+ curChar.y += shift;
+ else
+ curChar.x += shift;
+ }
+
+ // Move inline boxes
+ Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin();
+ Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end();
+
+ for (; boxIt != boxEnd; ++boxIt) {
+ SVGInlineBoxCharacterRange& range = *boxIt;
+
+ InlineBox* curBox = range.box;
+ ASSERT(curBox->isInlineTextBox());
+ ASSERT(curBox->parent() && (curBox->parent()->isRootInlineBox() || curBox->parent()->isInlineFlowBox()));
+
+ // Move target box
+ if (chunk.isVerticalText)
+ curBox->setYPos(curBox->yPos() + static_cast<int>(shift));
+ else
+ curBox->setXPos(curBox->xPos() + static_cast<int>(shift));
+ }
+}
+
+static float calculateTextLengthCorrectionForTextChunk(SVGTextChunk& chunk, ELengthAdjust lengthAdjust, float& computedLength)
+{
+ if (chunk.textLength <= 0.0f)
+ return 0.0f;
+
+ float computedWidth = cummulatedWidthOfTextChunk(chunk);
+ float computedHeight = cummulatedHeightOfTextChunk(chunk);
+
+ if ((computedWidth <= 0.0f && !chunk.isVerticalText) ||
+ (computedHeight <= 0.0f && chunk.isVerticalText))
+ return 0.0f;
+
+ if (chunk.isVerticalText)
+ computedLength = computedHeight;
+ else
+ computedLength = computedWidth;
+
+ if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) {
+ if (chunk.isVerticalText)
+ chunk.ctm.scale(1.0f, chunk.textLength / computedLength);
+ else
+ chunk.ctm.scale(chunk.textLength / computedLength, 1.0f);
+
+ return 0.0f;
+ }
+
+ return (chunk.textLength - computedLength) / float(chunk.end - chunk.start);
+}
+
+static void applyTextLengthCorrectionToTextChunk(SVGTextChunk& chunk)
+{
+ // This method is not called for chunks containing chars aligned on a path.
+ // -> all characters are visible, no need to check for "isHidden()" anywhere.
+
+ // lengthAdjust="spacingAndGlyphs" is handled by modifying chunk.ctm
+ float computedLength = 0.0f;
+ float spacingToApply = calculateTextLengthCorrectionForTextChunk(chunk, chunk.lengthAdjust, computedLength);
+
+ if (!chunk.ctm.isIdentity() && chunk.lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) {
+ 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;
+ newChunkCtm.translate(-firstChar.x, -firstChar.y);
+
+ chunk.ctm = newChunkCtm;
+ }
+
+ // Apply correction to chunk
+ if (spacingToApply != 0.0f) {
+ Vector<SVGChar>::iterator chunkIt = chunk.start;
+ for (; chunkIt != chunk.end; ++chunkIt) {
+ SVGChar& curChar = *chunkIt;
+ curChar.drawnSeperated = true;
+
+ if (chunk.isVerticalText)
+ curChar.y += (chunkIt - chunk.start) * spacingToApply;
+ else
+ curChar.x += (chunkIt - chunk.start) * spacingToApply;
+ }
+ }
+}
+
+void SVGRootInlineBox::computePerCharacterLayoutInformation()
+{
+ // Clean up any previous layout information
+ m_svgChars.clear();
+ m_svgTextChunks.clear();
+
+ // Build layout information for all contained render objects
+ SVGCharacterLayoutInfo info(m_svgChars);
+ buildLayoutInformation(this, info);
+
+ // Now all layout information are available for every character
+ // contained in any of our child inline/flow boxes. Build list
+ // of text chunks now, to be able to apply text-anchor shifts.
+ buildTextChunks(m_svgChars, m_svgTextChunks, this);
+
+ // Layout all text chunks
+ // text-anchor needs to be applied to individual chunks.
+ layoutTextChunks();
+
+ // Finally the top left position of our box is known.
+ // Propogate this knownledge to our RenderSVGText parent.
+ FloatPoint topLeft = topLeftPositionOfCharacterRange(m_svgChars);
+ object()->setPos((int) floorf(topLeft.x()), (int) floorf(topLeft.y()));
+
+ // Layout all InlineText/Flow boxes
+ // BEWARE: This requires the root top/left position to be set correctly before!
+ layoutInlineBoxes();
+}
+
+void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacterLayoutInfo& info)
+{
+ if (start->isRootInlineBox()) {
+ ASSERT(start->object()->element()->hasTagName(SVGNames::textTag));
+
+ SVGTextPositioningElement* positioningElement = static_cast<SVGTextPositioningElement*>(start->object()->element());
+ ASSERT(positioningElement);
+ ASSERT(positioningElement->parentNode());
+
+ info.addLayoutInformation(positioningElement);
+ }
+
+ LastGlyphInfo lastGlyph;
+
+ for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->object()->isText())
+ buildLayoutInformationForTextBox(info, static_cast<InlineTextBox*>(curr), lastGlyph);
+ else {
+ ASSERT(curr->isInlineFlowBox());
+ InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr);
+
+ if (!flowBox->object()->element())
+ continue; // Skip generated content.
+
+ bool isAnchor = flowBox->object()->element()->hasTagName(SVGNames::aTag);
+ bool isTextPath = flowBox->object()->element()->hasTagName(SVGNames::textPathTag);
+
+ if (!isTextPath && !isAnchor) {
+ SVGTextPositioningElement* positioningElement = static_cast<SVGTextPositioningElement*>(flowBox->object()->element());
+ ASSERT(positioningElement);
+ ASSERT(positioningElement->parentNode());
+
+ info.addLayoutInformation(positioningElement);
+ } else if (!isAnchor) {
+ info.setInPathLayout(true);
+
+ // Handle text-anchor/textLength on path, which is special.
+ SVGTextContentElement* textContent = 0;
+ Node* node = flowBox->object()->element();
+ if (node && node->isSVGElement())
+ textContent = static_cast<SVGTextContentElement*>(node);
+ ASSERT(textContent);
+
+ ELengthAdjust lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();
+ ETextAnchor anchor = flowBox->object()->style()->svgStyle()->textAnchor();
+ float textAnchorStartOffset = 0.0f;
+
+ // Initialize sub-layout. We need to create text chunks from the textPath
+ // children using our standard layout code, to be able to measure the
+ // text length using our normal methods and not textPath specific hacks.
+ Vector<SVGChar> tempChars;
+ Vector<SVGTextChunk> tempChunks;
+
+ SVGCharacterLayoutInfo tempInfo(tempChars);
+ buildLayoutInformation(flowBox, tempInfo);
+
+ buildTextChunks(tempChars, tempChunks, flowBox);
+
+ Vector<SVGTextChunk>::iterator it = tempChunks.begin();
+ Vector<SVGTextChunk>::iterator end = tempChunks.end();
+
+ TransformationMatrix ctm;
+ float computedLength = 0.0f;
+
+ for (; it != end; ++it) {
+ SVGTextChunk& chunk = *it;
+
+ // Apply text-length calculation
+ info.pathExtraAdvance += calculateTextLengthCorrectionForTextChunk(chunk, lengthAdjust, computedLength);
+
+ if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) {
+ info.pathTextLength += computedLength;
+ info.pathChunkLength += chunk.textLength;
+ }
+
+ // Calculate text-anchor start offset
+ if (anchor == TA_START)
+ continue;
+
+ textAnchorStartOffset += calculateTextAnchorShiftForTextChunk(chunk, anchor);
+ }
+
+ info.addLayoutInformation(flowBox, textAnchorStartOffset);
+ }
+
+ float shiftxSaved = info.shiftx;
+ float shiftySaved = info.shifty;
+
+ buildLayoutInformation(flowBox, info);
+ info.processedChunk(shiftxSaved, shiftySaved);
+
+ if (isTextPath)
+ info.setInPathLayout(false);
+ }
+ }
+}
+
+void SVGRootInlineBox::layoutInlineBoxes()
+{
+ int lowX = INT_MAX;
+ int lowY = INT_MAX;
+ int highX = INT_MIN;
+ int highY = INT_MIN;
+
+ // Layout all child boxes
+ Vector<SVGChar>::iterator it = m_svgChars.begin();
+ layoutInlineBoxes(this, it, lowX, highX, lowY, highY);
+ ASSERT(it == m_svgChars.end());
+}
+
+void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>::iterator& it, int& lowX, int& highX, int& lowY, int& highY)
+{
+ for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) {
+ RenderStyle* style = curr->object()->style();
+ const Font& font = style->font();
+
+ if (curr->object()->isText()) {
+ SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(curr);
+ unsigned length = textBox->len();
+
+ SVGChar curChar = *it;
+ ASSERT(it != m_svgChars.end());
+
+ FloatRect stringRect;
+ for (unsigned i = 0; i < length; ++i) {
+ ASSERT(it != m_svgChars.end());
+
+ if (it->isHidden()) {
+ ++it;
+ continue;
+ }
+
+ stringRect.unite(textBox->calculateGlyphBoundaries(style, textBox->start() + i, *it));
+ ++it;
+ }
+
+ IntRect enclosedStringRect = enclosingIntRect(stringRect);
+
+ int minX = enclosedStringRect.x();
+ int maxX = minX + enclosedStringRect.width();
+
+ int minY = enclosedStringRect.y();
+ int maxY = minY + enclosedStringRect.height();
+
+ curr->setXPos(minX - object()->xPos());
+ curr->setWidth(enclosedStringRect.width());
+
+ curr->setYPos(minY - object()->yPos());
+ curr->setBaseline(font.ascent());
+ curr->setHeight(enclosedStringRect.height());
+
+ if (minX < lowX)
+ lowX = minX;
+
+ if (maxX > highX)
+ highX = maxX;
+
+ if (minY < lowY)
+ lowY = minY;
+
+ if (maxY > highY)
+ highY = maxY;
+ } else {
+ ASSERT(curr->isInlineFlowBox());
+
+ int minX = INT_MAX;
+ int minY = INT_MAX;
+ int maxX = INT_MIN;
+ int maxY = INT_MIN;
+
+ InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr);
+
+ if (!flowBox->object()->element())
+ continue; // Skip generated content.
+
+ layoutInlineBoxes(flowBox, it, minX, maxX, minY, maxY);
+
+ curr->setXPos(minX - object()->xPos());
+ curr->setWidth(maxX - minX);
+
+ curr->setYPos(minY - object()->yPos());
+ curr->setBaseline(font.ascent());
+ curr->setHeight(maxY - minY);
+
+ if (minX < lowX)
+ lowX = minX;
+
+ if (maxX > highX)
+ highX = maxX;
+
+ if (minY < lowY)
+ lowY = minY;
+
+ if (maxY > highY)
+ highY = maxY;
+ }
+ }
+
+ if (start->isRootInlineBox()) {
+ int top = lowY - object()->yPos();
+ int bottom = highY - object()->yPos();
+
+ start->setXPos(lowX - object()->xPos());
+ start->setYPos(top);
+
+ start->setWidth(highX - lowX);
+ start->setHeight(highY - lowY);
+
+ start->setVerticalOverflowPositions(top, bottom);
+ start->setVerticalSelectionPositions(top, bottom);
+ }
+}
+
+void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo& info, InlineTextBox* textBox, LastGlyphInfo& lastGlyph)
+{
+ RenderText* text = textBox->textObject();
+ ASSERT(text);
+
+ RenderStyle* style = text->style(textBox->isFirstLineStyle());
+ ASSERT(style);
+
+ const Font& font = style->font();
+ SVGInlineTextBox* svgTextBox = static_cast<SVGInlineTextBox*>(textBox);
+
+ unsigned length = textBox->len();
+
+ const SVGRenderStyle* svgStyle = style->svgStyle();
+ bool isVerticalText = isVerticalWritingMode(svgStyle);
+
+ int charsConsumed = 0;
+ for (unsigned i = 0; i < length; i += charsConsumed) {
+ SVGChar svgChar;
+
+ if (info.inPathLayout())
+ svgChar.pathData = SVGCharOnPath::create();
+
+ float glyphWidth = 0.0f;
+ float glyphHeight = 0.0f;
+
+ int extraCharsAvailable = length - i - 1;
+
+ String unicodeStr;
+ String glyphName;
+ if (textBox->direction() == RTL) {
+ glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->end() - i, extraCharsAvailable, charsConsumed, glyphName);
+ glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->end() - i, extraCharsAvailable);
+ unicodeStr = String(textBox->textObject()->text()->characters() + textBox->end() - i, charsConsumed);
+ } else {
+ glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->start() + i, extraCharsAvailable, charsConsumed, glyphName);
+ glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->start() + i, extraCharsAvailable);
+ unicodeStr = String(textBox->textObject()->text()->characters() + textBox->start() + i, charsConsumed);
+ }
+
+ bool assignedX = false;
+ bool assignedY = false;
+
+ if (info.xValueAvailable() && (!info.inPathLayout() || (info.inPathLayout() && !isVerticalText))) {
+ if (!isVerticalText)
+ svgChar.newTextChunk = true;
+
+ assignedX = true;
+ svgChar.drawnSeperated = true;
+ info.curx = info.xValueNext();
+ }
+
+ if (info.yValueAvailable() && (!info.inPathLayout() || (info.inPathLayout() && isVerticalText))) {
+ if (isVerticalText)
+ svgChar.newTextChunk = true;
+
+ assignedY = true;
+ svgChar.drawnSeperated = true;
+ info.cury = info.yValueNext();
+ }
+
+ float dx = 0.0f;
+ float dy = 0.0f;
+
+ // Apply x-axis shift
+ if (info.dxValueAvailable()) {
+ svgChar.drawnSeperated = true;
+
+ dx = info.dxValueNext();
+ info.dx += dx;
+
+ if (!info.inPathLayout())
+ info.curx += dx;
+ }
+
+ // Apply y-axis shift
+ if (info.dyValueAvailable()) {
+ svgChar.drawnSeperated = true;
+
+ dy = info.dyValueNext();
+ info.dy += dy;
+
+ if (!info.inPathLayout())
+ info.cury += dy;
+ }
+
+ // Take letter & word spacing and kerning into account
+ float spacing = font.letterSpacing() + calculateKerning(textBox->object()->element()->renderer());
+
+ const UChar* currentCharacter = text->characters() + (textBox->direction() == RTL ? textBox->end() - i : textBox->start() + i);
+ const UChar* lastCharacter = 0;
+
+ if (textBox->direction() == RTL) {
+ if (i < textBox->end())
+ lastCharacter = text->characters() + textBox->end() - i + 1;
+ } else {
+ if (i > 0)
+ lastCharacter = text->characters() + textBox->start() + i - 1;
+ }
+
+ if (info.nextDrawnSeperated || spacing != 0.0f) {
+ info.nextDrawnSeperated = false;
+ svgChar.drawnSeperated = true;
+ }
+
+ if (currentCharacter && Font::treatAsSpace(*currentCharacter) && lastCharacter && !Font::treatAsSpace(*lastCharacter)) {
+ spacing += font.wordSpacing();
+
+ if (spacing != 0.0f && !info.inPathLayout())
+ info.nextDrawnSeperated = true;
+ }
+
+ float orientationAngle = glyphOrientationToAngle(svgStyle, isVerticalText, *currentCharacter);
+
+ float xOrientationShift = 0.0f;
+ float yOrientationShift = 0.0f;
+ float glyphAdvance = calculateGlyphAdvanceAndShiftRespectingOrientation(isVerticalText, orientationAngle, glyphWidth, glyphHeight,
+ font, svgChar, xOrientationShift, yOrientationShift);
+
+ // Handle textPath layout mode
+ if (info.inPathLayout()) {
+ float extraAdvance = isVerticalText ? dy : dx;
+ float newOffset = FLT_MIN;
+
+ if (assignedX && !isVerticalText)
+ newOffset = info.curx;
+ else if (assignedY && isVerticalText)
+ newOffset = info.cury;
+
+ float correctedGlyphAdvance = glyphAdvance;
+
+ // Handle lengthAdjust="spacingAndGlyphs" by specifying per-character scale operations
+ if (info.pathTextLength > 0.0f && info.pathChunkLength > 0.0f) {
+ if (isVerticalText) {
+ svgChar.pathData->yScale = info.pathChunkLength / info.pathTextLength;
+ spacing *= svgChar.pathData->yScale;
+ correctedGlyphAdvance *= svgChar.pathData->yScale;
+ } else {
+ svgChar.pathData->xScale = info.pathChunkLength / info.pathTextLength;
+ spacing *= svgChar.pathData->xScale;
+ correctedGlyphAdvance *= svgChar.pathData->xScale;
+ }
+ }
+
+ // Handle letter & word spacing on text path
+ float pathExtraAdvance = info.pathExtraAdvance;
+ info.pathExtraAdvance += spacing;
+
+ svgChar.pathData->hidden = !info.nextPathLayoutPointAndAngle(correctedGlyphAdvance, extraAdvance, newOffset);
+ svgChar.drawnSeperated = true;
+
+ info.pathExtraAdvance = pathExtraAdvance;
+ }
+
+ // Apply rotation
+ if (info.angleValueAvailable())
+ info.angle = info.angleValueNext();
+
+ // Apply baseline-shift
+ if (info.baselineShiftValueAvailable()) {
+ svgChar.drawnSeperated = true;
+ float shift = info.baselineShiftValueNext();
+
+ if (isVerticalText)
+ info.shiftx += shift;
+ else
+ info.shifty -= shift;
+ }
+
+ // Take dominant-baseline / alignment-baseline into account
+ yOrientationShift += alignmentBaselineToShift(isVerticalText, text, font);
+
+ svgChar.x = info.curx;
+ svgChar.y = info.cury;
+ svgChar.angle = info.angle;
+
+ // For text paths any shift (dx/dy/baseline-shift) has to be applied after the rotation
+ if (!info.inPathLayout()) {
+ svgChar.x += info.shiftx + xOrientationShift;
+ svgChar.y += info.shifty + yOrientationShift;
+
+ if (orientationAngle != 0.0f)
+ svgChar.angle += orientationAngle;
+
+ if (svgChar.angle != 0.0f)
+ svgChar.drawnSeperated = true;
+ } else {
+ svgChar.pathData->orientationAngle = orientationAngle;
+
+ if (isVerticalText)
+ svgChar.angle -= 90.0f;
+
+ svgChar.pathData->xShift = info.shiftx + xOrientationShift;
+ svgChar.pathData->yShift = info.shifty + yOrientationShift;
+
+ // Translate to glyph midpoint
+ if (isVerticalText) {
+ svgChar.pathData->xShift += info.dx;
+ svgChar.pathData->yShift -= glyphAdvance / 2.0f;
+ } else {
+ svgChar.pathData->xShift -= glyphAdvance / 2.0f;
+ svgChar.pathData->yShift += info.dy;
+ }
+ }
+
+ double kerning = 0.0;
+#if ENABLE(SVG_FONTS)
+ SVGFontElement* svgFont = 0;
+ if (style->font().isSVGFont())
+ svgFont = style->font().svgFont();
+
+ if (lastGlyph.isValid && style->font().isSVGFont()) {
+ SVGHorizontalKerningPair kerningPair;
+ if (svgFont->getHorizontalKerningPairForStringsAndGlyphs(lastGlyph.unicode, lastGlyph.glyphName, unicodeStr, glyphName, kerningPair))
+ kerning = kerningPair.kerning;
+ }
+
+ if (style->font().isSVGFont()) {
+ lastGlyph.unicode = unicodeStr;
+ lastGlyph.glyphName = glyphName;
+ lastGlyph.isValid = true;
+ } else
+ lastGlyph.isValid = false;
+#endif
+
+ svgChar.x -= (float)kerning;
+
+ // Advance to new position
+ if (isVerticalText) {
+ svgChar.drawnSeperated = true;
+ info.cury += glyphAdvance + spacing;
+ } else
+ info.curx += glyphAdvance + spacing - (float)kerning;
+
+ // Advance to next character group
+ for (int k = 0; k < charsConsumed; ++k) {
+ info.svgChars.append(svgChar);
+ info.processedSingleCharacter();
+ svgChar.drawnSeperated = false;
+ svgChar.newTextChunk = false;
+ }
+ }
+}
+
+void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, Vector<SVGTextChunk>& svgTextChunks, InlineFlowBox* start)
+{
+ SVGTextChunkLayoutInfo info(svgTextChunks);
+ info.it = svgChars.begin();
+ info.chunk.start = svgChars.begin();
+ info.chunk.end = svgChars.begin();
+
+ buildTextChunks(svgChars, start, info);
+ ASSERT(info.it == svgChars.end());
+}
+
+void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox* start, SVGTextChunkLayoutInfo& info)
+{
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " -> buildTextChunks(start=%p)\n", start);
+#endif
+
+ for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->object()->isText()) {
+ InlineTextBox* textBox = static_cast<InlineTextBox*>(curr);
+
+ unsigned length = textBox->len();
+ if (!length)
+ continue;
+
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " -> Handle inline text box (%p) with %i characters (start: %i, end: %i), handlingTextPath=%i\n",
+ textBox, length, textBox->start(), textBox->end(), (int) info.handlingTextPath);
+#endif
+
+ RenderText* text = textBox->textObject();
+ ASSERT(text);
+ ASSERT(text->element());
+
+ SVGTextContentElement* textContent = 0;
+ Node* node = text->element()->parent();
+ while (node && node->isSVGElement() && !textContent) {
+ if (static_cast<SVGElement*>(node)->isTextContent())
+ textContent = static_cast<SVGTextContentElement*>(node);
+ else
+ node = node->parentNode();
+ }
+ ASSERT(textContent);
+
+ // Start new character range for the first chunk
+ bool isFirstCharacter = info.svgTextChunks.isEmpty() && info.chunk.start == info.it && info.chunk.start == info.chunk.end;
+ if (isFirstCharacter) {
+ ASSERT(info.chunk.boxes.isEmpty());
+ info.chunk.boxes.append(SVGInlineBoxCharacterRange());
+ } else
+ ASSERT(!info.chunk.boxes.isEmpty());
+
+ // Walk string to find out new chunk positions, if existant
+ for (unsigned i = 0; i < length; ++i) {
+ ASSERT(info.it != svgChars.end());
+
+ SVGInlineBoxCharacterRange& range = info.chunk.boxes.last();
+ if (range.isOpen()) {
+ range.box = curr;
+ range.startOffset = (i == 0 ? 0 : i - 1);
+
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " | -> Range is open! box=%p, startOffset=%i\n", range.box, range.startOffset);
+#endif
+ }
+
+ // If a new (or the first) chunk has been started, record it's text-anchor and writing mode.
+ if (info.assignChunkProperties) {
+ info.assignChunkProperties = false;
+
+ info.chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle());
+ info.chunk.isTextPath = info.handlingTextPath;
+ info.chunk.anchor = text->style()->svgStyle()->textAnchor();
+ info.chunk.textLength = textContent->textLength().value(textContent);
+ info.chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();
+
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " | -> Assign chunk properties, isVerticalText=%i, anchor=%i\n", info.chunk.isVerticalText, info.chunk.anchor);
+#endif
+ }
+
+ if (i > 0 && !isFirstCharacter && (*info.it).newTextChunk) {
+ // Close mid chunk & character range
+ ASSERT(!range.isOpen());
+ ASSERT(!range.isClosed());
+
+ range.endOffset = i;
+ closeTextChunk(info);
+
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " | -> Close mid-text chunk, at endOffset: %i and starting new mid chunk!\n", range.endOffset);
+#endif
+
+ // Prepare for next chunk, if we're not at the end
+ startTextChunk(info);
+ if (i + 1 == length) {
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " | -> Record last chunk of inline text box!\n");
+#endif
+
+ startTextChunk(info);
+ SVGInlineBoxCharacterRange& range = info.chunk.boxes.last();
+
+ info.assignChunkProperties = false;
+ info.chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle());
+ info.chunk.isTextPath = info.handlingTextPath;
+ info.chunk.anchor = text->style()->svgStyle()->textAnchor();
+ info.chunk.textLength = textContent->textLength().value(textContent);
+ info.chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();
+
+ range.box = curr;
+ range.startOffset = i;
+
+ ASSERT(!range.isOpen());
+ ASSERT(!range.isClosed());
+ }
+ }
+
+ // This should only hold true for the first character of the first chunk
+ if (isFirstCharacter)
+ isFirstCharacter = false;
+
+ ++info.it;
+ }
+
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " -> Finished inline text box!\n");
+#endif
+
+ SVGInlineBoxCharacterRange& range = info.chunk.boxes.last();
+ if (!range.isOpen() && !range.isClosed()) {
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " -> Last range not closed - closing with endOffset: %i\n", length);
+#endif
+
+ // Current text chunk is not yet closed. Finish the current range, but don't start a new chunk.
+ range.endOffset = length;
+
+ if (info.it != svgChars.end()) {
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " -> Not at last character yet!\n");
+#endif
+
+ // If we're not at the end of the last box to be processed, and if the next
+ // character starts a new chunk, then close the current chunk and start a new one.
+ if ((*info.it).newTextChunk) {
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " -> Next character starts new chunk! Closing current chunk, and starting a new one...\n");
+#endif
+
+ closeTextChunk(info);
+ startTextChunk(info);
+ } else {
+ // Just start a new character range
+ info.chunk.boxes.append(SVGInlineBoxCharacterRange());
+
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " -> Next character does NOT start a new chunk! Starting new character range...\n");
+#endif
+ }
+ } else {
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " -> Closing final chunk! Finished processing!\n");
+#endif
+
+ // Close final chunk, once we're at the end of the last box
+ closeTextChunk(info);
+ }
+ }
+ } else {
+ ASSERT(curr->isInlineFlowBox());
+ InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr);
+
+ if (!flowBox->object()->element())
+ continue; // Skip generated content.
+
+ bool isTextPath = flowBox->object()->element()->hasTagName(SVGNames::textPathTag);
+
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " -> Handle inline flow box (%p), isTextPath=%i\n", flowBox, (int) isTextPath);
+#endif
+
+ if (isTextPath)
+ info.handlingTextPath = true;
+
+ buildTextChunks(svgChars, flowBox, info);
+
+ if (isTextPath)
+ info.handlingTextPath = false;
+ }
+ }
+
+#if DEBUG_CHUNK_BUILDING > 1
+ fprintf(stderr, " <- buildTextChunks(start=%p)\n", start);
+#endif
+}
+
+const Vector<SVGTextChunk>& SVGRootInlineBox::svgTextChunks() const
+{
+ return m_svgTextChunks;
+}
+
+void SVGRootInlineBox::layoutTextChunks()
+{
+ Vector<SVGTextChunk>::iterator it = m_svgTextChunks.begin();
+ Vector<SVGTextChunk>::iterator end = m_svgTextChunks.end();
+
+ for (; it != end; ++it) {
+ SVGTextChunk& chunk = *it;
+
+#if DEBUG_CHUNK_BUILDING > 0
+ {
+ fprintf(stderr, "Handle TEXT CHUNK! anchor=%i, textLength=%f, lengthAdjust=%i, isVerticalText=%i, isTextPath=%i start=%p, end=%p -> dist: %i\n",
+ (int) chunk.anchor, chunk.textLength, (int) chunk.lengthAdjust, (int) chunk.isVerticalText,
+ (int) chunk.isTextPath, chunk.start, chunk.end, (unsigned int) (chunk.end - chunk.start));
+
+ Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin();
+ Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end();
+
+ unsigned int i = 0;
+ for (; boxIt != boxEnd; ++boxIt) {
+ SVGInlineBoxCharacterRange& range = *boxIt; i++;
+ fprintf(stderr, " -> RANGE %i STARTOFFSET: %i, ENDOFFSET: %i, BOX: %p\n", i, range.startOffset, range.endOffset, range.box);
+ }
+ }
+#endif
+
+ if (chunk.isTextPath)
+ continue;
+
+ // text-path & textLength, with lengthAdjust="spacing" is already handled for textPath layouts.
+ applyTextLengthCorrectionToTextChunk(chunk);
+
+ // text-anchor is already handled for textPath layouts.
+ applyTextAnchorToTextChunk(chunk);
+ }
+}
+
+static inline void addPaintServerToTextDecorationInfo(ETextDecoration decoration, SVGTextDecorationInfo& info, RenderObject* object)
+{
+ if (object->style()->svgStyle()->hasFill())
+ info.fillServerMap.set(decoration, object);
+
+ if (object->style()->svgStyle()->hasStroke())
+ info.strokeServerMap.set(decoration, object);
+}
+
+SVGTextDecorationInfo SVGRootInlineBox::retrievePaintServersForTextDecoration(RenderObject* start)
+{
+ ASSERT(start);
+
+ Vector<RenderObject*> parentChain;
+ while ((start = start->parent())) {
+ parentChain.prepend(start);
+
+ // Stop at our direct <text> parent.
+ if (start->isSVGText())
+ break;
+ }
+
+ Vector<RenderObject*>::iterator it = parentChain.begin();
+ Vector<RenderObject*>::iterator end = parentChain.end();
+
+ SVGTextDecorationInfo info;
+
+ for (; it != end; ++it) {
+ RenderObject* object = *it;
+ ASSERT(object);
+
+ RenderStyle* style = object->style();
+ ASSERT(style);
+
+ int decorations = style->textDecoration();
+ if (decorations != NONE) {
+ if (decorations & OVERLINE)
+ addPaintServerToTextDecorationInfo(OVERLINE, info, object);
+
+ if (decorations & UNDERLINE)
+ addPaintServerToTextDecorationInfo(UNDERLINE, info, object);
+
+ if (decorations & LINE_THROUGH)
+ addPaintServerToTextDecorationInfo(LINE_THROUGH, info, object);
+ }
+ }
+
+ return info;
+}
+
+void SVGRootInlineBox::walkTextChunks(SVGTextChunkWalkerBase* walker, const SVGInlineTextBox* textBox)
+{
+ ASSERT(walker);
+
+ Vector<SVGTextChunk>::iterator it = m_svgTextChunks.begin();
+ Vector<SVGTextChunk>::iterator itEnd = m_svgTextChunks.end();
+
+ for (; it != itEnd; ++it) {
+ SVGTextChunk& curChunk = *it;
+
+ Vector<SVGInlineBoxCharacterRange>::iterator boxIt = curChunk.boxes.begin();
+ Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = curChunk.boxes.end();
+
+ InlineBox* lastNotifiedBox = 0;
+ InlineBox* prevBox = 0;
+
+ unsigned int chunkOffset = 0;
+ bool startedFirstChunk = false;
+
+ for (; boxIt != boxEnd; ++boxIt) {
+ SVGInlineBoxCharacterRange& range = *boxIt;
+
+ ASSERT(range.box->isInlineTextBox());
+ SVGInlineTextBox* rangeTextBox = static_cast<SVGInlineTextBox*>(range.box);
+
+ if (textBox && rangeTextBox != textBox) {
+ chunkOffset += range.endOffset - range.startOffset;
+ continue;
+ }
+
+ // Eventually notify that we started a new chunk
+ if (!textBox && !startedFirstChunk) {
+ startedFirstChunk = true;
+
+ lastNotifiedBox = range.box;
+ walker->start(range.box);
+ } else {
+ // Eventually apply new style, as this chunk spans multiple boxes (with possible different styling)
+ if (prevBox && prevBox != range.box) {
+ lastNotifiedBox = range.box;
+
+ walker->end(prevBox);
+ walker->start(lastNotifiedBox);
+ }
+ }
+
+ unsigned int length = range.endOffset - range.startOffset;
+
+ Vector<SVGChar>::iterator itCharBegin = curChunk.start + chunkOffset;
+ Vector<SVGChar>::iterator itCharEnd = curChunk.start + chunkOffset + length;
+ ASSERT(itCharEnd <= curChunk.end);
+
+ // Process this chunk portion
+ if (textBox)
+ (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+ else {
+ if (walker->setupFill(range.box))
+ (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+
+ if (walker->setupStroke(range.box))
+ (*walker)(rangeTextBox, range.startOffset, curChunk.ctm, itCharBegin, itCharEnd);
+ }
+
+ chunkOffset += length;
+
+ if (!textBox)
+ prevBox = range.box;
+ }
+
+ if (!textBox && startedFirstChunk)
+ walker->end(lastNotifiedBox);
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h
new file mode 100644
index 0000000..800664b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/SVGRootInlineBox.h
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+ * (C) 2006 Apple Computer Inc.
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SVGRootInlineBox_h
+#define SVGRootInlineBox_h
+
+#if ENABLE(SVG)
+#include "RootInlineBox.h"
+#include "SVGCharacterLayoutInfo.h"
+
+namespace WebCore {
+
+class InlineTextBox;
+class RenderSVGRoot;
+class SVGInlineTextBox;
+
+struct LastGlyphInfo {
+ LastGlyphInfo() : isValid(false) { }
+
+ String unicode;
+ String glyphName;
+ bool isValid;
+};
+
+class SVGRootInlineBox : public RootInlineBox {
+public:
+ SVGRootInlineBox(RenderObject* obj)
+ : RootInlineBox(obj)
+ {
+ }
+
+ virtual bool isSVGRootInlineBox() { return true; }
+
+ virtual void paint(RenderObject::PaintInfo&, int tx, int ty);
+
+ virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing);
+ virtual void verticallyAlignBoxes(int& heightOfBlock);
+
+ virtual void computePerCharacterLayoutInformation();
+
+ // Used by SVGInlineTextBox
+ const Vector<SVGTextChunk>& svgTextChunks() const;
+
+ void walkTextChunks(SVGTextChunkWalkerBase*, const SVGInlineTextBox* textBox = 0);
+
+private:
+ friend struct SVGRootInlineBoxPaintWalker;
+
+ void layoutInlineBoxes();
+ void layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>::iterator& it, int& minX, int& maxX, int& minY, int& maxY);
+
+ void buildLayoutInformation(InlineFlowBox* start, SVGCharacterLayoutInfo&);
+ void buildLayoutInformationForTextBox(SVGCharacterLayoutInfo&, InlineTextBox*, LastGlyphInfo&);
+
+ void buildTextChunks(Vector<SVGChar>&, Vector<SVGTextChunk>&, InlineFlowBox* start);
+ void buildTextChunks(Vector<SVGChar>&, InlineFlowBox* start, SVGTextChunkLayoutInfo&);
+ void layoutTextChunks();
+
+ SVGTextDecorationInfo retrievePaintServersForTextDecoration(RenderObject* start);
+
+private:
+ Vector<SVGChar> m_svgChars;
+ Vector<SVGTextChunk> m_svgTextChunks;
+};
+
+// Shared with SVGRenderTreeAsText / SVGInlineTextBox
+TextRun svgTextRunForInlineTextBox(const UChar*, int len, RenderStyle* style, const InlineTextBox* textBox, float xPos);
+FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>::iterator start, Vector<SVGChar>::iterator end);
+float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range);
+float cummulatedHeightOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range);
+
+RenderSVGRoot* findSVGRootObject(RenderObject* start);
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+
+#endif // SVGRootInlineBox_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/TableLayout.h b/src/3rdparty/webkit/WebCore/rendering/TableLayout.h
new file mode 100644
index 0000000..8ae0ce7
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/TableLayout.h
@@ -0,0 +1,48 @@
+/*
+ * 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)
+ *
+ * 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.
+ *
+ * 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 TableLayout_h
+#define TableLayout_h
+
+namespace WebCore {
+
+class RenderTable;
+
+class TableLayout {
+public:
+ TableLayout(RenderTable* table)
+ : m_table(table)
+ {
+ }
+
+ virtual ~TableLayout() { }
+
+ virtual void calcPrefWidths(int& minWidth, int& maxWidth) = 0;
+ virtual void layout() = 0;
+
+protected:
+ RenderTable* m_table;
+};
+
+} // namespace WebCore
+
+#endif // TableLayout_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp b/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp
new file mode 100644
index 0000000..452333c
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextControlInnerElements.h"
+
+#include "BeforeTextInsertedEvent.h"
+#include "Document.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HTMLTextAreaElement.h"
+#include "MouseEvent.h"
+#include "RenderTextControlSingleLine.h"
+
+namespace WebCore {
+
+class RenderTextControlInnerBlock : public RenderBlock {
+public:
+ RenderTextControlInnerBlock(Node* node) : RenderBlock(node) { }
+
+ virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
+};
+
+bool RenderTextControlInnerBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
+{
+ RenderObject* renderer = node()->shadowAncestorNode()->renderer();
+
+ bool placeholderIsVisible = false;
+ if (renderer->isTextField())
+ placeholderIsVisible = static_cast<RenderTextControlSingleLine*>(renderer)->placeholderIsVisible();
+
+ return RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, placeholderIsVisible ? HitTestBlockBackground : hitTestAction);
+}
+
+TextControlInnerElement::TextControlInnerElement(Document* doc, Node* shadowParent)
+ : HTMLDivElement(HTMLNames::divTag, doc)
+ , m_shadowParent(shadowParent)
+{
+}
+
+void TextControlInnerElement::attachInnerElement(Node* parent, PassRefPtr<RenderStyle> style, RenderArena* arena)
+{
+ // When adding these elements, create the renderer & style first before adding to the DOM.
+ // Otherwise, the render tree will create some anonymous blocks that will mess up our layout.
+
+ // 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();
+ setInDocument(true);
+
+ // For elements without a shadow parent, add the node to the DOM normally.
+ if (!m_shadowParent)
+ parent->addChild(this);
+
+ // Add the renderer to the render tree
+ if (renderer)
+ parent->renderer()->addChild(renderer);
+}
+
+TextControlInnerTextElement::TextControlInnerTextElement(Document* doc, Node* shadowParent)
+ : TextControlInnerElement(doc, shadowParent)
+{
+}
+
+void TextControlInnerTextElement::defaultEventHandler(Event* evt)
+{
+ // FIXME: In the future, we should add a way to have default event listeners. Then we would add one to the text field's inner div, and we wouldn't need this subclass.
+ Node* shadowAncestor = shadowAncestorNode();
+ if (shadowAncestor && shadowAncestor->renderer()) {
+ ASSERT(shadowAncestor->renderer()->isTextField() || shadowAncestor->renderer()->isTextArea());
+ if (evt->isBeforeTextInsertedEvent())
+ if (shadowAncestor->renderer()->isTextField())
+ static_cast<HTMLInputElement*>(shadowAncestor)->defaultEventHandler(evt);
+ else
+ static_cast<HTMLTextAreaElement*>(shadowAncestor)->defaultEventHandler(evt);
+ if (evt->type() == eventNames().webkitEditableContentChangedEvent)
+ static_cast<RenderTextControl*>(shadowAncestor->renderer())->subtreeHasChanged();
+ }
+ if (!evt->defaultHandled())
+ HTMLDivElement::defaultEventHandler(evt);
+}
+
+RenderObject* TextControlInnerTextElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+ return new (arena) RenderTextControlInnerBlock(this);
+}
+
+SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document* doc)
+ : TextControlInnerElement(doc)
+{
+}
+
+void SearchFieldResultsButtonElement::defaultEventHandler(Event* evt)
+{
+ // On mousedown, bring up a menu, if needed
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
+ if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
+ input->focus();
+ input->select();
+ RenderTextControlSingleLine* renderer = static_cast<RenderTextControlSingleLine*>(input->renderer());
+ if (renderer->popupIsVisible())
+ renderer->hidePopup();
+ else if (input->maxResults() > 0)
+ renderer->showPopup();
+ evt->setDefaultHandled();
+ }
+ if (!evt->defaultHandled())
+ HTMLDivElement::defaultEventHandler(evt);
+}
+
+SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document* doc)
+ : TextControlInnerElement(doc)
+ , m_capturing(false)
+{
+}
+
+void SearchFieldCancelButtonElement::defaultEventHandler(Event* evt)
+{
+ // If the element is visible, on mouseup, clear the value, and set selection
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
+ if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
+ input->focus();
+ input->select();
+ evt->setDefaultHandled();
+ if (renderer() && renderer()->visibleToHitTesting())
+ if (Frame* frame = document()->frame()) {
+ frame->eventHandler()->setCapturingMouseEventsNode(this);
+ m_capturing = true;
+ }
+ } else if (evt->type() == eventNames().mouseupEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
+ if (m_capturing && renderer() && renderer()->visibleToHitTesting()) {
+ if (hovered()) {
+ input->setValue("");
+ input->onSearch();
+ evt->setDefaultHandled();
+ }
+ if (Frame* frame = document()->frame()) {
+ frame->eventHandler()->setCapturingMouseEventsNode(0);
+ m_capturing = false;
+ }
+ }
+ }
+ if (!evt->defaultHandled())
+ HTMLDivElement::defaultEventHandler(evt);
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.h b/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.h
new file mode 100644
index 0000000..9e81ada
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/TextControlInnerElements.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TextControlInnerElements_h
+#define TextControlInnerElements_h
+
+#include "HTMLDivElement.h"
+
+namespace WebCore {
+
+class String;
+
+class TextControlInnerElement : public HTMLDivElement
+{
+public:
+ TextControlInnerElement(Document*, Node* shadowParent = 0);
+
+ virtual bool isMouseFocusable() const { return false; }
+ virtual bool isShadowNode() const { return m_shadowParent; }
+ virtual Node* shadowParentNode() { return m_shadowParent; }
+ void setShadowParentNode(Node* node) { m_shadowParent = node; }
+ void attachInnerElement(Node*, PassRefPtr<RenderStyle>, RenderArena*);
+
+private:
+ Node* m_shadowParent;
+};
+
+class TextControlInnerTextElement : public TextControlInnerElement {
+public:
+ TextControlInnerTextElement(Document*, Node* shadowParent);
+ virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+ virtual void defaultEventHandler(Event*);
+};
+
+class SearchFieldResultsButtonElement : public TextControlInnerElement {
+public:
+ SearchFieldResultsButtonElement(Document*);
+ virtual void defaultEventHandler(Event*);
+};
+
+class SearchFieldCancelButtonElement : public TextControlInnerElement {
+public:
+ SearchFieldCancelButtonElement(Document*);
+ virtual void defaultEventHandler(Event*);
+private:
+ bool m_capturing;
+};
+
+} //namespace
+
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/bidi.cpp b/src/3rdparty/webkit/WebCore/rendering/bidi.cpp
new file mode 100644
index 0000000..6ff2d59
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/bidi.cpp
@@ -0,0 +1,2222 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All right 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 "bidi.h"
+
+#include "CharacterNames.h"
+#include "Document.h"
+#include "Element.h"
+#include "FrameView.h"
+#include "InlineTextBox.h"
+#include "Logging.h"
+#include "RenderArena.h"
+#include "RenderLayer.h"
+#include "RenderListMarker.h"
+#include "RenderView.h"
+#include "break_lines.h"
+#include <wtf/AlwaysInline.h>
+#include <wtf/RefCountedLeakCounter.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+using namespace WTF;
+using namespace Unicode;
+
+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;
+ WTF::Unicode::Direction direction() const;
+
+ RenderBlock* block;
+ RenderObject* obj;
+ unsigned pos;
+ int nextBreakablePosition;
+};
+
+// Midpoint globals. The goal is not to do any allocation when dealing with
+// these midpoints, so we just keep an array around and never clear it. We track
+// the number of items and position using the two other variables.
+static Vector<InlineIterator>* smidpoints;
+static unsigned sNumMidpoints;
+static unsigned sCurrMidpoint;
+static bool betweenMidpoints;
+
+static bool isLineEmpty = true;
+static bool previousLineBrokeCleanly = true;
+
+static int getBorderPaddingMargin(RenderObject* child, bool endOfInline)
+{
+ bool leftSide = (child->style()->direction() == LTR) ? !endOfInline : endOfInline;
+ if (leftSide)
+ return child->marginLeft() + child->paddingLeft() + child->borderLeft();
+ return child->marginRight() + child->paddingRight() + child->borderRight();
+}
+
+static int inlineWidth(RenderObject* child, bool start = true, bool end = true)
+{
+ unsigned lineDepth = 1;
+ int extraWidth = 0;
+ RenderObject* parent = child->parent();
+ while (parent->isInline() && !parent->isInlineBlockOrInlineTable() && lineDepth++ < cMaxLineDepth) {
+ if (start && parent->firstChild() == child)
+ extraWidth += getBorderPaddingMargin(parent, false);
+ if (end && parent->lastChild() == child)
+ extraWidth += getBorderPaddingMargin(parent, true);
+ child = parent;
+ parent = child->parent();
+ }
+ return extraWidth;
+}
+
+#ifndef NDEBUG
+static WTF::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()) {
+ next = current->firstChild();
+ if (next && resolver && next->isInlineFlow()) {
+ 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->isInlineFlow()) {
+ next = current;
+ endOfInline = true;
+ break;
+ }
+
+ while (current && current != block) {
+ if (resolver && current->isInlineFlow() && current->style()->unicodeBidi() != UBNormal)
+ resolver->embed(PopDirectionalFormat);
+
+ next = current->nextSibling();
+ if (next) {
+ if (resolver && next->isInlineFlow()) {
+ 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->isInlineFlow()) {
+ 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->isInlineFlow()))
+ 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->isInlineFlow()) {
+ 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 >= static_cast<RenderText*>(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 = static_cast<RenderText*>(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(RenderObject* obj, unsigned pos)
+{
+ if (!sNumMidpoints)
+ return;
+ InlineIterator* midpoints = smidpoints->data();
+ for (int i = sNumMidpoints - 1; i >= 0; i--) {
+ const InlineIterator& point = midpoints[i];
+ if (point.obj == obj && point.pos == pos) {
+ sNumMidpoints = i;
+ break;
+ }
+ }
+}
+
+static void checkMidpoints(InlineIterator& lBreak)
+{
+ // Check to see if our last midpoint is a start point beyond the line break. If so,
+ // shave it off the list, and shave off a trailing space if the previous end point doesn't
+ // preserve whitespace.
+ if (lBreak.obj && sNumMidpoints && sNumMidpoints % 2 == 0) {
+ InlineIterator* midpoints = smidpoints->data();
+ InlineIterator& endpoint = midpoints[sNumMidpoints-2];
+ const InlineIterator& startpoint = midpoints[sNumMidpoints-1];
+ InlineIterator currpoint = endpoint;
+ while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak)
+ currpoint.increment();
+ if (currpoint == lBreak) {
+ // We hit the line break before the start point. Shave off the start point.
+ sNumMidpoints--;
+ if (endpoint.obj->style()->collapseWhiteSpace()) {
+ if (endpoint.obj->isText()) {
+ // Don't shave a character off the endpoint if it was from a soft hyphen.
+ RenderText* textObj = static_cast<RenderText*>(endpoint.obj);
+ if (endpoint.pos + 1 < textObj->textLength()) {
+ if (textObj->characters()[endpoint.pos+1] == softHyphen)
+ return;
+ } else if (startpoint.obj->isText()) {
+ RenderText *startText = static_cast<RenderText*>(startpoint.obj);
+ if (startText->textLength() && startText->characters()[0] == softHyphen)
+ return;
+ }
+ }
+ endpoint.pos--;
+ }
+ }
+ }
+}
+
+static void addMidpoint(const InlineIterator& midpoint)
+{
+ if (smidpoints->size() <= sNumMidpoints)
+ smidpoints->grow(sNumMidpoints + 10);
+
+ InlineIterator* midpoints = smidpoints->data();
+ midpoints[sNumMidpoints++] = midpoint;
+}
+
+static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
+{
+ if (start > end || obj->isFloating() ||
+ (obj->isPositioned() && !obj->hasStaticX() && !obj->hasStaticY() && !obj->container()->isInlineFlow()))
+ return;
+
+ bool haveNextMidpoint = (sCurrMidpoint < sNumMidpoints);
+ InlineIterator nextMidpoint;
+ if (haveNextMidpoint)
+ nextMidpoint = smidpoints->at(sCurrMidpoint);
+ if (betweenMidpoints) {
+ if (!(haveNextMidpoint && nextMidpoint.obj == obj))
+ return;
+ // This is a new start point. Stop ignoring objects and
+ // adjust our start.
+ betweenMidpoints = false;
+ start = nextMidpoint.pos;
+ sCurrMidpoint++;
+ if (start < end)
+ return appendRunsForObject(start, end, obj, resolver);
+ } else {
+ if (!haveNextMidpoint || (obj != nextMidpoint.obj)) {
+ resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir()));
+ return;
+ }
+
+ // An end midpoint has been encountered within our object. We
+ // need to go ahead and append a run with our endpoint.
+ if (static_cast<int>(nextMidpoint.pos + 1) <= end) {
+ betweenMidpoints = true;
+ sCurrMidpoint++;
+ if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
+ if (static_cast<int>(nextMidpoint.pos + 1) > start)
+ resolver.addRun(new (obj->renderArena())
+ BidiRun(start, nextMidpoint.pos + 1, obj, resolver.context(), resolver.dir()));
+ return appendRunsForObject(nextMidpoint.pos + 1, end, obj, resolver);
+ }
+ } else
+ resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir()));
+ }
+}
+
+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;
+}
+
+InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj)
+{
+ // See if we have an unconstructed line box for this object that is also
+ // the last item on the line.
+ unsigned lineDepth = 1;
+ InlineFlowBox* childBox = 0;
+ InlineFlowBox* parentBox = 0;
+ InlineFlowBox* result = 0;
+ do {
+ ASSERT(obj->isInlineFlow() || obj == this);
+ RenderFlow* flow = static_cast<RenderFlow*>(obj);
+
+ // Get the last box we made for this render object.
+ parentBox = flow->lastLineBox();
+
+ // If this box is constructed then it is from a previous line, and we need
+ // to make a new box for our line. If this box is unconstructed but it has
+ // something following it on the line, then we know we have to make a new box
+ // as well. In this situation our inline has actually been split in two on
+ // the same line (this can happen with very fancy language mixtures).
+ bool constructedNewBox = false;
+ if (!parentBox || parentBox->isConstructed() || parentBox->nextOnLine()) {
+ // We need to make a new box for this render object. Once
+ // made, we need to place it at the end of the current line.
+ InlineBox* newBox = obj->createInlineBox(false, obj == this);
+ ASSERT(newBox->isInlineFlowBox());
+ parentBox = static_cast<InlineFlowBox*>(newBox);
+ parentBox->setFirstLineStyleBit(m_firstLine);
+ constructedNewBox = true;
+ }
+
+ if (!result)
+ result = parentBox;
+
+ // If we have hit the block itself, then |box| represents the root
+ // inline box for the line, and it doesn't have to be appended to any parent
+ // inline.
+ if (childBox)
+ parentBox->addToLine(childBox);
+
+ if (!constructedNewBox || obj == this)
+ break;
+
+ childBox = parentBox;
+
+ // If we've exceeded our line depth, then jump straight to the root and skip all the remaining
+ // intermediate inline flows.
+ obj = (++lineDepth >= cMaxLineDepth) ? this : obj->parent();
+
+ } while (true);
+
+ return result;
+}
+
+RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool lastLine, RenderObject* endObject)
+{
+ ASSERT(firstRun);
+
+ InlineFlowBox* parentBox = 0;
+ for (BidiRun* r = firstRun; r; r = r->next()) {
+ // Create a box for our object.
+ bool isOnlyRun = (runCount == 1);
+ if (runCount == 2 && !r->m_object->isListMarker())
+ isOnlyRun = ((style()->direction() == RTL) ? lastRun : firstRun)->m_object->isListMarker();
+
+ InlineBox* box = r->m_object->createInlineBox(r->m_object->isPositioned(), false, isOnlyRun);
+ r->m_box = box;
+
+ if (box) {
+ // If we have no parent box yet, or if the run is not simply a sibling,
+ // then we need to construct inline boxes as necessary to properly enclose the
+ // run's inline box.
+ if (!parentBox || parentBox->object() != r->m_object->parent())
+ // Create new inline boxes all the way back to the appropriate insertion point.
+ parentBox = createLineBoxes(r->m_object->parent());
+
+ // Append the inline box to this line.
+ parentBox->addToLine(box);
+
+ bool visuallyOrdered = r->m_object->style()->visuallyOrdered();
+ box->setBidiLevel(visuallyOrdered ? 0 : r->level());
+
+ if (box->isInlineTextBox()) {
+ InlineTextBox* text = static_cast<InlineTextBox*>(box);
+ text->setStart(r->m_start);
+ text->setLen(r->m_stop - r->m_start);
+ text->m_dirOverride = r->dirOverride(visuallyOrdered);
+ }
+ }
+ }
+
+ // We should have a root inline box. It should be unconstructed and
+ // be the last continuation of our line list.
+ ASSERT(lastLineBox() && !lastLineBox()->isConstructed());
+
+ // Set bits on our inline flow boxes that indicate which sides should
+ // paint borders/margins/padding. This knowledge will ultimately be used when
+ // we determine the horizontal positions and widths of all the inline boxes on
+ // the line.
+ lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject);
+
+ // Now mark the line boxes as being constructed.
+ lastLineBox()->setConstructed();
+
+ // Return the last line.
+ return lastRootBox();
+}
+
+void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd)
+{
+ // First determine our total width.
+ int availableWidth = lineWidth(m_height);
+ int totWidth = lineBox->getFlowSpacingWidth();
+ bool needsWordSpacing = false;
+ unsigned numSpaces = 0;
+ ETextAlign textAlign = style()->textAlign();
+
+ for (BidiRun* r = firstRun; r; r = r->next()) {
+ if (!r->m_box || r->m_object->isPositioned() || r->m_box->isLineBreak())
+ continue; // Positioned objects are only participating to figure out their
+ // correct static x position. They have no effect on the width.
+ // Similarly, line break boxes have no effect on the width.
+ if (r->m_object->isText()) {
+ RenderText* rt = static_cast<RenderText*>(r->m_object);
+
+ if (textAlign == JUSTIFY && r != trailingSpaceRun) {
+ const UChar* characters = rt->characters();
+ for (int i = r->m_start; i < r->m_stop; i++) {
+ UChar c = characters[i];
+ if (c == ' ' || c == '\n' || c == '\t')
+ numSpaces++;
+ }
+ }
+
+ if (int length = rt->textLength()) {
+ if (!r->m_compact && !r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start]))
+ totWidth += rt->style(m_firstLine)->font().wordSpacing();
+ needsWordSpacing = !isSpaceOrNewline(rt->characters()[r->m_stop - 1]) && r->m_stop == length;
+ }
+ r->m_box->setWidth(rt->width(r->m_start, r->m_stop - r->m_start, totWidth, m_firstLine));
+ } else if (!r->m_object->isInlineFlow()) {
+ r->m_object->calcWidth();
+ r->m_box->setWidth(r->m_object->width());
+ if (!r->m_compact)
+ totWidth += r->m_object->marginLeft() + r->m_object->marginRight();
+ }
+
+ // Compacts don't contribute to the width of the line, since they are placed in the margin.
+ if (!r->m_compact)
+ totWidth += r->m_box->width();
+ }
+
+ // Armed with the total width of the line (without justification),
+ // we now examine our text-align property in order to determine where to position the
+ // objects horizontally. The total width of the line can be increased if we end up
+ // justifying text.
+ int x = leftOffset(m_height);
+ switch(textAlign) {
+ case LEFT:
+ case WEBKIT_LEFT:
+ // The direction of the block should determine what happens with wide lines. In
+ // particular with RTL blocks, wide lines should still spill out to the left.
+ if (style()->direction() == LTR) {
+ if (totWidth > availableWidth && trailingSpaceRun)
+ trailingSpaceRun->m_box->setWidth(trailingSpaceRun->m_box->width() - totWidth + availableWidth);
+ } else {
+ if (trailingSpaceRun)
+ trailingSpaceRun->m_box->setWidth(0);
+ else if (totWidth > availableWidth)
+ x -= (totWidth - availableWidth);
+ }
+ break;
+ case JUSTIFY:
+ if (numSpaces && !reachedEnd && !lineBox->endsWithBreak()) {
+ if (trailingSpaceRun) {
+ totWidth -= trailingSpaceRun->m_box->width();
+ trailingSpaceRun->m_box->setWidth(0);
+ }
+ break;
+ }
+ // fall through
+ case TAAUTO:
+ numSpaces = 0;
+ // for right to left fall through to right aligned
+ if (style()->direction() == LTR) {
+ if (totWidth > availableWidth && trailingSpaceRun)
+ trailingSpaceRun->m_box->setWidth(trailingSpaceRun->m_box->width() - totWidth + availableWidth);
+ break;
+ }
+ case RIGHT:
+ case WEBKIT_RIGHT:
+ // Wide lines spill out of the block based off direction.
+ // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
+ // side of the block.
+ if (style()->direction() == LTR) {
+ if (trailingSpaceRun) {
+ totWidth -= trailingSpaceRun->m_box->width();
+ trailingSpaceRun->m_box->setWidth(0);
+ }
+ if (totWidth < availableWidth)
+ x += availableWidth - totWidth;
+ } else {
+ if (totWidth > availableWidth && trailingSpaceRun) {
+ trailingSpaceRun->m_box->setWidth(trailingSpaceRun->m_box->width() - totWidth + availableWidth);
+ totWidth -= trailingSpaceRun->m_box->width();
+ } else
+ x += availableWidth - totWidth;
+ }
+ break;
+ case CENTER:
+ case WEBKIT_CENTER:
+ int trailingSpaceWidth = 0;
+ if (trailingSpaceRun) {
+ totWidth -= trailingSpaceRun->m_box->width();
+ trailingSpaceWidth = min(trailingSpaceRun->m_box->width(), (availableWidth - totWidth + 1) / 2);
+ trailingSpaceRun->m_box->setWidth(trailingSpaceWidth);
+ }
+ if (style()->direction() == LTR)
+ x += max((availableWidth - totWidth) / 2, 0);
+ else
+ x += totWidth > availableWidth ? (availableWidth - totWidth) : (availableWidth - totWidth) / 2 - trailingSpaceWidth;
+ break;
+ }
+
+ if (numSpaces) {
+ for (BidiRun* r = firstRun; r; r = r->next()) {
+ if (!r->m_box || r == trailingSpaceRun)
+ continue;
+
+ int spaceAdd = 0;
+ if (r->m_object->isText() && !r->m_compact) {
+ unsigned spaces = 0;
+ const UChar* characters = static_cast<RenderText*>(r->m_object)->characters();
+ for (int i = r->m_start; i < r->m_stop; i++) {
+ UChar c = characters[i];
+ if (c == ' ' || c == '\n' || c == '\t')
+ spaces++;
+ }
+
+ ASSERT(spaces <= numSpaces);
+
+ // Only justify text if whitespace is collapsed.
+ if (r->m_object->style()->collapseWhiteSpace()) {
+ spaceAdd = (availableWidth - totWidth) * spaces / numSpaces;
+ static_cast<InlineTextBox*>(r->m_box)->setSpaceAdd(spaceAdd);
+ totWidth += spaceAdd;
+ }
+ numSpaces -= spaces;
+ if (!numSpaces)
+ break;
+ }
+ }
+ }
+
+ // 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);
+}
+
+void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun)
+{
+ lineBox->verticallyAlignBoxes(m_height);
+ lineBox->setBlockHeight(m_height);
+
+ // See if the line spilled out. If so set overflow height accordingly.
+ int bottomOfLine = lineBox->bottomOverflow();
+ if (bottomOfLine > m_height && bottomOfLine > m_overflowHeight)
+ m_overflowHeight = bottomOfLine;
+
+ // Now make sure we place replaced render objects correctly.
+ for (BidiRun* r = firstRun; r; r = r->next()) {
+ if (!r->m_box)
+ continue; // Skip runs with no line boxes.
+
+ // Align positioned boxes with the top of the line box. This is
+ // a reasonable approximation of an appropriate y position.
+ if (r->m_object->isPositioned())
+ r->m_box->setYPos(m_height);
+
+ // Position is used to properly position both replaced elements and
+ // to update the static normal flow x/y of positioned elements.
+ r->m_object->position(r->m_box);
+ }
+ // Positioned objects and zero-length text nodes destroy their boxes in
+ // position(), which unnecessarily dirties the line.
+ lineBox->markDirty(false);
+}
+
+// collects one line of the paragraph and transforms it to visual order
+void RenderBlock::bidiReorderLine(InlineBidiResolver& resolver, const InlineIterator& end)
+{
+ resolver.createBidiRunsForLine(end, style()->visuallyOrdered(), previousLineBrokeCleanly);
+}
+
+static void buildCompactRuns(RenderObject* compactObj, InlineBidiResolver& resolver)
+{
+ ASSERT(compactObj->isRenderBlock());
+ ASSERT(!resolver.firstRun());
+
+ // Format the compact like it is its own single line. We build up all the runs for
+ // the little compact and then reorder them for bidi.
+ RenderBlock* compactBlock = static_cast<RenderBlock*>(compactObj);
+
+ InlineIterator start(compactBlock, bidiFirst(compactBlock, &resolver), 0);
+ resolver.setPosition(start);
+
+ betweenMidpoints = false;
+ isLineEmpty = true;
+ previousLineBrokeCleanly = true;
+
+ InlineIterator end = compactBlock->findNextLineBreak(resolver);
+ if (!isLineEmpty)
+ compactBlock->bidiReorderLine(resolver, end);
+
+ for (BidiRun* run = resolver.firstRun(); run; run = run->next())
+ run->m_compact = true;
+
+ sNumMidpoints = 0;
+ sCurrMidpoint = 0;
+ betweenMidpoints = false;
+}
+
+static inline bool isCollapsibleSpace(UChar character, RenderText* renderer)
+{
+ if (character == ' ' || character == '\t' || character == softHyphen)
+ return true;
+ if (character == '\n')
+ return !renderer->style()->preserveNewline();
+ if (character == noBreakSpace)
+ return renderer->style()->nbspMode() == SPACE;
+ return false;
+}
+
+void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom)
+{
+ bool useRepaintBounds = false;
+
+ invalidateVerticalPosition();
+
+ m_overflowHeight = 0;
+
+ m_height = borderTop() + paddingTop();
+ int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
+
+ // Figure out if we should clear out our line boxes.
+ // FIXME: Handle resize eventually!
+ // FIXME: Do something better when floats are present.
+ bool fullLayout = !firstLineBox() || !firstChild() || selfNeedsLayout() || relayoutChildren;
+ if (fullLayout)
+ deleteLineBoxes();
+
+ // Text truncation only kicks in if your overflow isn't visible and your text-overflow-mode isn't
+ // clip.
+ // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely
+ // difficult to figure out (especially in the middle of doing layout), and is really an esoteric pile of nonsense
+ // anyway, so we won't worry about following the draft here.
+ bool hasTextOverflow = style()->textOverflow() && hasOverflowClip();
+
+ // Walk all the lines and delete our ellipsis line boxes if they exist.
+ if (hasTextOverflow)
+ deleteEllipsisLineBoxes();
+
+ if (firstChild()) {
+ // layout replaced elements
+ bool endOfInline = false;
+ RenderObject* o = bidiFirst(this, 0, false);
+ Vector<FloatWithRect> floats;
+ int containerWidth = max(0, containingBlockWidth());
+ while (o) {
+ o->invalidateVerticalPosition();
+ if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
+ if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent())
+ o->setChildNeedsLayout(true, false);
+
+ // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
+ if (relayoutChildren && (o->style()->paddingLeft().isPercent() || o->style()->paddingRight().isPercent()))
+ o->setPrefWidthsDirty(true, false);
+
+ if (o->isPositioned())
+ o->containingBlock()->insertPositionedObject(o);
+ else {
+ if (o->isFloating())
+ floats.append(FloatWithRect(o));
+ else if (fullLayout || o->needsLayout()) // Replaced elements
+ o->dirtyLineBoxes(fullLayout);
+
+ o->layoutIfNeeded();
+ }
+ } else if (o->isText() || (o->isInlineFlow() && !endOfInline)) {
+ if (fullLayout || o->selfNeedsLayout())
+ o->dirtyLineBoxes(fullLayout);
+
+ // Calculate margins of inline flows so that they can be used later by line layout.
+ if (o->isInlineFlow())
+ static_cast<RenderFlow*>(o)->calcMargins(containerWidth);
+ o->setNeedsLayout(false);
+ }
+ o = bidiNext(this, o, 0, false, &endOfInline);
+ }
+
+ // We want to skip ahead to the first dirty line
+ InlineBidiResolver resolver;
+ unsigned floatIndex;
+ RootInlineBox* startLine = determineStartPosition(fullLayout, resolver, floats, floatIndex);
+
+ if (fullLayout && !selfNeedsLayout()) {
+ setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like
+ // we're supposed to.
+ if (!document()->view()->needsFullRepaint() && m_layer) {
+ // Because we waited until we were already inside layout to discover
+ // that the block really needed a full layout, we missed our chance to repaint the layer
+ // before layout started. Luckily the layer has cached the repaint rect for its original
+ // position and size, and so we can use that to make a repaint happen now.
+ RenderView* c = view();
+ if (c && !c->printing())
+ c->repaintViewRectangle(m_layer->repaintRect());
+ }
+ }
+
+ FloatingObject* lastFloat = m_floatingObjects ? m_floatingObjects->last() : 0;
+
+ if (!smidpoints)
+ smidpoints = new Vector<InlineIterator>();
+
+ sNumMidpoints = 0;
+ sCurrMidpoint = 0;
+
+ // We also find the first clean line and extract these lines. We will add them back
+ // if we determine that we're able to synchronize after handling all our dirty lines.
+ InlineIterator cleanLineStart;
+ BidiStatus cleanLineBidiStatus;
+ int endLineYPos = 0;
+ RootInlineBox* endLine = (fullLayout || !startLine) ?
+ 0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, endLineYPos);
+
+ if (startLine) {
+ useRepaintBounds = true;
+ repaintTop = m_height;
+ repaintBottom = m_height;
+ RenderArena* arena = renderArena();
+ RootInlineBox* box = startLine;
+ while (box) {
+ repaintTop = min(repaintTop, box->topOverflow());
+ repaintBottom = max(repaintBottom, box->bottomOverflow());
+ RootInlineBox* next = box->nextRootBox();
+ box->deleteLine(arena);
+ box = next;
+ }
+ }
+
+ InlineIterator end = resolver.position();
+
+ if (!fullLayout && lastRootBox() && lastRootBox()->endsWithBreak()) {
+ // If the last line before the start line ends with a line break that clear floats,
+ // adjust the height accordingly.
+ // A line break can be either the first or the last object on a line, depending on its direction.
+ if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) {
+ RenderObject* lastObject = lastLeafChild->object();
+ if (!lastObject->isBR())
+ lastObject = lastRootBox()->firstLeafChild()->object();
+ if (lastObject->isBR()) {
+ EClear clear = lastObject->style()->clear();
+ if (clear != CNONE)
+ newLine(clear);
+ }
+ }
+ }
+
+ bool endLineMatched = false;
+ bool checkForEndLineMatch = endLine;
+ bool checkForFloatsFromLastLine = false;
+ int lastHeight = m_height;
+
+ while (!end.atEnd()) {
+ // FIXME: Is this check necessary before the first iteration or can it be moved to the end?
+ if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineYPos, repaintBottom, repaintTop)))
+ break;
+
+ betweenMidpoints = false;
+ isLineEmpty = true;
+ if (m_firstLine && firstChild()->isCompact() && firstChild()->isRenderBlock()) {
+ buildCompactRuns(firstChild(), resolver);
+ resolver.setPosition(InlineIterator(this, firstChild()->nextSibling(), 0));
+ }
+ EClear clear = CNONE;
+ end = findNextLineBreak(resolver, &clear);
+ if (resolver.position().atEnd()) {
+ resolver.deleteRuns();
+ checkForFloatsFromLastLine = true;
+ break;
+ }
+ ASSERT(end != resolver.position());
+
+ if (!isLineEmpty) {
+ bidiReorderLine(resolver, end);
+ ASSERT(resolver.position() == end);
+
+ BidiRun* trailingSpaceRun = 0;
+ if (!previousLineBrokeCleanly && resolver.runCount() && resolver.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()) {
+ trailingSpaceRun = resolver.logicallyLastRun();
+ RenderObject* lastObject = trailingSpaceRun->m_object;
+ if (lastObject->isText()) {
+ RenderText* lastText = static_cast<RenderText*>(lastObject);
+ const UChar* characters = lastText->characters();
+ int firstSpace = trailingSpaceRun->stop();
+ while (firstSpace > trailingSpaceRun->start()) {
+ UChar current = characters[firstSpace - 1];
+ if (!isCollapsibleSpace(current, lastText))
+ break;
+ firstSpace--;
+ }
+ if (firstSpace == trailingSpaceRun->stop())
+ trailingSpaceRun = 0;
+ else {
+ TextDirection direction = style()->direction();
+ bool shouldReorder = trailingSpaceRun != (direction == LTR ? resolver.lastRun() : resolver.firstRun());
+ if (firstSpace != trailingSpaceRun->start()) {
+ ETextAlign textAlign = style()->textAlign();
+ // If the trailing white space is at the right hand side of a left-aligned line, then computeHorizontalPositionsForLine()
+ // does not care if trailingSpaceRun includes non-spaces at the beginning. In all other cases, trailingSpaceRun has to
+ // contain only the spaces, either because we re-order them or because computeHorizontalPositionsForLine() needs to know
+ // their width.
+ bool shouldSeparateSpaces = textAlign != LEFT && textAlign != WEBKIT_LEFT && textAlign != TAAUTO || trailingSpaceRun->m_level % 2 || direction == RTL || shouldReorder;
+ if (shouldSeparateSpaces) {
+ BidiContext* baseContext = resolver.context();
+ while (BidiContext* parent = baseContext->parent())
+ baseContext = parent;
+
+ BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral);
+ trailingSpaceRun->m_stop = firstSpace;
+ if (direction == LTR)
+ resolver.addRun(newTrailingRun);
+ else
+ resolver.prependRun(newTrailingRun);
+ trailingSpaceRun = newTrailingRun;
+ shouldReorder = false;
+ }
+ }
+ if (shouldReorder) {
+ if (direction == LTR) {
+ resolver.moveRunToEnd(trailingSpaceRun);
+ trailingSpaceRun->m_level = 0;
+ } else {
+ resolver.moveRunToBeginning(trailingSpaceRun);
+ trailingSpaceRun->m_level = 1;
+ }
+ }
+ }
+ } else
+ trailingSpaceRun = 0;
+ }
+
+ // Now that the runs have been ordered, we create the line boxes.
+ // At the same time we figure out where border/padding/margin should be applied for
+ // inline flow boxes.
+
+ RootInlineBox* lineBox = 0;
+ if (resolver.runCount()) {
+ lineBox = constructLine(resolver.runCount(), resolver.firstRun(), resolver.lastRun(), !end.obj, end.obj && !end.pos ? end.obj : 0);
+ if (lineBox) {
+ lineBox->setEndsWithBreak(previousLineBrokeCleanly);
+
+ // Now we position all of our text runs horizontally.
+ computeHorizontalPositionsForLine(lineBox, resolver.firstRun(), trailingSpaceRun, end.atEnd());
+
+ // Now position our text runs vertically.
+ computeVerticalPositionsForLine(lineBox, resolver.firstRun());
+
+#if ENABLE(SVG)
+ // Special SVG text layout code
+ lineBox->computePerCharacterLayoutInformation();
+#endif
+
+#if PLATFORM(MAC)
+ // Highlight acts as an overflow inflation.
+ if (style()->highlight() != nullAtom)
+ lineBox->addHighlightOverflow();
+#endif
+ }
+ }
+
+ resolver.deleteRuns();
+
+ if (lineBox) {
+ lineBox->setLineBreakInfo(end.obj, end.pos, resolver.status());
+ if (useRepaintBounds) {
+ repaintTop = min(repaintTop, lineBox->topOverflow());
+ repaintBottom = max(repaintBottom, lineBox->bottomOverflow());
+ }
+ }
+
+ m_firstLine = false;
+ newLine(clear);
+ }
+
+ if (m_floatingObjects && lastRootBox()) {
+ if (lastFloat) {
+ for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
+ }
+ m_floatingObjects->next();
+ } else
+ m_floatingObjects->first();
+ for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next()) {
+ if (f->m_bottom > lastHeight)
+ lastRootBox()->floats().append(f->m_renderer);
+ ASSERT(f->m_renderer == floats[floatIndex].object);
+ // If a float's geometry has changed, give up on syncing with clean lines.
+ if (floats[floatIndex].rect != IntRect(f->m_left, f->m_top, f->m_width, f->m_bottom - f->m_top))
+ checkForEndLineMatch = false;
+ floatIndex++;
+ }
+ lastFloat = m_floatingObjects->last();
+ }
+
+ lastHeight = m_height;
+ sNumMidpoints = 0;
+ sCurrMidpoint = 0;
+ resolver.setPosition(end);
+ }
+
+ if (endLine) {
+ if (endLineMatched) {
+ // Attach all the remaining lines, and then adjust their y-positions as needed.
+ int delta = m_height - endLineYPos;
+ 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));
+ line->adjustPosition(0, delta);
+ }
+ if (Vector<RenderObject*>* cleanLineFloats = line->floatsPtr()) {
+ Vector<RenderObject*>::iterator end = cleanLineFloats->end();
+ for (Vector<RenderObject*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
+ int floatTop = (*f)->yPos() - (*f)->marginTop();
+ insertFloatingObject(*f);
+ m_height = floatTop + delta;
+ positionNewFloats();
+ }
+ }
+ }
+ m_height = lastRootBox()->blockHeight();
+ } else {
+ // Delete all the remaining lines.
+ InlineRunBox* line = endLine;
+ RenderArena* arena = renderArena();
+ while (line) {
+ repaintTop = min(repaintTop, line->topOverflow());
+ repaintBottom = max(repaintBottom, line->bottomOverflow());
+ InlineRunBox* next = line->nextLineBox();
+ line->deleteLine(arena);
+ line = next;
+ }
+ }
+ }
+ if (m_floatingObjects && (checkForFloatsFromLastLine || positionNewFloats()) && lastRootBox()) {
+ // 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 (lastFloat) {
+ for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
+ }
+ m_floatingObjects->next();
+ } else
+ m_floatingObjects->first();
+ for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next()) {
+ if (f->m_bottom > lastHeight)
+ lastRootBox()->floats().append(f->m_renderer);
+ }
+ lastFloat = m_floatingObjects->last();
+ }
+ }
+
+ sNumMidpoints = 0;
+ sCurrMidpoint = 0;
+
+ // Now add in the bottom border/padding.
+ m_height += toAdd;
+
+ // Always make sure this is at least our height.
+ m_overflowHeight = max(m_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())
+ m_height += lineHeight(true, true);
+
+ // See if we have any lines that spill out of our block. If we do, then we will possibly need to
+ // truncate text.
+ if (hasTextOverflow)
+ checkLinesForTextOverflow();
+}
+
+RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats)
+{
+ RootInlineBox* curr = 0;
+ RootInlineBox* last = 0;
+
+ bool dirtiedByFloat = false;
+ if (!fullLayout) {
+ size_t floatIndex = 0;
+ for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) {
+ if (Vector<RenderObject*>* cleanLineFloats = curr->floatsPtr()) {
+ Vector<RenderObject*>::iterator end = cleanLineFloats->end();
+ for (Vector<RenderObject*>::iterator o = cleanLineFloats->begin(); o != end; ++o) {
+ RenderObject* f = *o;
+ IntSize newSize(f->width() + f->marginLeft() +f->marginRight(), f->height() + f->marginTop() + f->marginBottom());
+ ASSERT(floatIndex < floats.size());
+ if (floats[floatIndex].object != f) {
+ // A new float has been inserted before this line or before its last known float.
+ // Just do a full layout.
+ fullLayout = true;
+ break;
+ }
+ 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()));
+ floats[floatIndex].rect.setSize(newSize);
+ dirtiedByFloat = true;
+ }
+ floatIndex++;
+ }
+ }
+ if (dirtiedByFloat || fullLayout)
+ break;
+ }
+ // Check if a new float has been inserted after the last known float.
+ if (!curr && floatIndex < floats.size())
+ fullLayout = true;
+ }
+
+ if (fullLayout) {
+ // Nuke all our lines.
+ if (firstRootBox()) {
+ RenderArena* arena = renderArena();
+ curr = firstRootBox();
+ while (curr) {
+ RootInlineBox* next = curr->nextRootBox();
+ curr->deleteLine(arena);
+ curr = next;
+ }
+ ASSERT(!firstLineBox() && !lastLineBox());
+ }
+ } else {
+ if (curr) {
+ // We have a dirty line.
+ if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
+ // We have a previous line.
+ if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= static_cast<RenderText*>(prevRootBox->lineBreakObj())->textLength()))
+ // The previous line didn't break cleanly or broke at a newline
+ // that has been deleted, so treat it as dirty too.
+ curr = prevRootBox;
+ }
+ } else {
+ // No dirty lines were found.
+ // If the last line didn't break cleanly, treat it as dirty.
+ if (lastRootBox() && !lastRootBox()->endsWithBreak())
+ curr = lastRootBox();
+ }
+
+ // If we have no dirty lines, then last is just the last root box.
+ last = curr ? curr->prevRootBox() : lastRootBox();
+ }
+
+ numCleanFloats = 0;
+ if (!floats.isEmpty()) {
+ int savedHeight = m_height;
+ // Restore floats from clean lines.
+ RootInlineBox* line = firstRootBox();
+ while (line != curr) {
+ if (Vector<RenderObject*>* cleanLineFloats = line->floatsPtr()) {
+ Vector<RenderObject*>::iterator end = cleanLineFloats->end();
+ for (Vector<RenderObject*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
+ insertFloatingObject(*f);
+ m_height = (*f)->yPos() - (*f)->marginTop();
+ positionNewFloats();
+ ASSERT(floats[numCleanFloats].object == *f);
+ numCleanFloats++;
+ }
+ }
+ line = line->nextRootBox();
+ }
+ m_height = savedHeight;
+ }
+
+ m_firstLine = !last;
+ previousLineBrokeCleanly = !last || last->endsWithBreak();
+
+ RenderObject* startObj;
+ int pos = 0;
+ if (last) {
+ m_height = last->blockHeight();
+ startObj = last->lineBreakObj();
+ pos = last->lineBreakPos();
+ resolver.setStatus(last->lineBreakBidiStatus());
+ } else {
+ bool ltr = style()->direction() == LTR
+ #if ENABLE(SVG)
+ || (style()->unicodeBidi() == UBNormal && isSVGText())
+ #endif
+ ;
+
+ BidiContext* context = new BidiContext(ltr ? 0 : 1, ltr ? LeftToRight : RightToLeft, style()->unicodeBidi() == Override);
+
+ resolver.setLastStrongDir(context->dir());
+ resolver.setLastDir(context->dir());
+ resolver.setEorDir(context->dir());
+ resolver.setContext(context);
+ startObj = bidiFirst(this, &resolver);
+ }
+
+ resolver.setPosition(InlineIterator(this, startObj, pos));
+
+ return curr;
+}
+
+RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus, int& yPos)
+{
+ RootInlineBox* last = 0;
+ if (!startLine)
+ last = 0;
+ else {
+ for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
+ if (curr->isDirty())
+ last = 0;
+ else if (!last)
+ last = curr;
+ }
+ }
+
+ if (!last)
+ return 0;
+
+ RootInlineBox* prev = last->prevRootBox();
+ cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
+ cleanLineBidiStatus = prev->lineBreakBidiStatus();
+ yPos = prev->blockHeight();
+
+ for (RootInlineBox* line = last; line; line = line->nextRootBox())
+ line->extractLine(); // Disconnect all line boxes from their render objects while preserving
+ // their connections to one another.
+
+ return last;
+}
+
+bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus, RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop)
+{
+ if (resolver.position() == endLineStart) {
+ if (resolver.status() != endLineStatus)
+ return false;
+
+ int delta = m_height - endYPos;
+ if (!delta || !m_floatingObjects)
+ return true;
+
+ // See if any floats end in the range along which we want to shift the lines vertically.
+ int top = min(m_height, endYPos);
+
+ RootInlineBox* lastLine = endLine;
+ while (RootInlineBox* nextLine = lastLine->nextRootBox())
+ lastLine = nextLine;
+
+ int bottom = lastLine->blockHeight() + abs(delta);
+
+ for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) {
+ if (f->m_bottom >= top && f->m_bottom < bottom)
+ return false;
+ }
+
+ return true;
+ }
+
+ // The first clean line doesn't match, but we can check a handful of following lines to try
+ // to match back up.
+ static int numLines = 8; // The # of lines we're willing to match against.
+ RootInlineBox* line = endLine;
+ for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
+ if (line->lineBreakObj() == resolver.position().obj && line->lineBreakPos() == resolver.position().pos) {
+ // We have a match.
+ if (line->lineBreakBidiStatus() != resolver.status())
+ return false; // ...but the bidi state doesn't match.
+ RootInlineBox* result = line->nextRootBox();
+
+ // Set our yPos to be the block height of endLine.
+ if (result)
+ endYPos = line->blockHeight();
+
+ int delta = m_height - endYPos;
+ if (delta && m_floatingObjects) {
+ // See if any floats end in the range along which we want to shift the lines vertically.
+ int top = min(m_height, endYPos);
+
+ RootInlineBox* lastLine = endLine;
+ while (RootInlineBox* nextLine = lastLine->nextRootBox())
+ lastLine = nextLine;
+
+ int bottom = lastLine->blockHeight() + abs(delta);
+
+ for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) {
+ if (f->m_bottom >= top && f->m_bottom < bottom)
+ return false;
+ }
+ }
+
+ // Now delete the lines that we failed to sync.
+ RootInlineBox* boxToDelete = endLine;
+ RenderArena* arena = renderArena();
+ while (boxToDelete && boxToDelete != result) {
+ repaintTop = min(repaintTop, boxToDelete->topOverflow());
+ repaintBottom = max(repaintBottom, boxToDelete->bottomOverflow());
+ RootInlineBox* next = boxToDelete->nextRootBox();
+ boxToDelete->deleteLine(arena);
+ boxToDelete = next;
+ }
+
+ endLine = result;
+ return result;
+ }
+ }
+
+ return false;
+}
+
+static inline bool skipNonBreakingSpace(const InlineIterator& it)
+{
+ if (it.obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace)
+ return false;
+
+ // FIXME: This is bad. It makes nbsp inconsistent with space and won't work correctly
+ // with m_minWidth/m_maxWidth.
+ // Do not skip a non-breaking space if it is the first character
+ // on a line after a clean line break (or on the first line, since previousLineBrokeCleanly starts off
+ // |true|).
+ if (isLineEmpty && previousLineBrokeCleanly)
+ return false;
+
+ return true;
+}
+
+static inline bool shouldCollapseWhiteSpace(const RenderStyle* style)
+{
+ return style->collapseWhiteSpace() || (style->whiteSpace() == PRE_WRAP && (!isLineEmpty || !previousLineBrokeCleanly));
+}
+
+static inline bool shouldPreserveNewline(RenderObject* object)
+{
+#if ENABLE(SVG)
+ if (object->isSVGText())
+ return false;
+#endif
+
+ return object->style()->preserveNewline();
+}
+
+static bool inlineFlowRequiresLineBox(RenderObject* flow)
+{
+ // FIXME: Right now, we only allow line boxes for inlines that are truly empty.
+ // We need to fix this, though, because at the very least, inlines containing only
+ // ignorable whitespace should should also have line boxes.
+ return flow->isInlineFlow() && !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin();
+}
+
+static inline bool requiresLineBox(const InlineIterator& it)
+{
+ if (it.obj->isFloatingOrPositioned())
+ return false;
+
+ if (it.obj->isInlineFlow() && !inlineFlowRequiresLineBox(it.obj))
+ return false;
+
+ if (!shouldCollapseWhiteSpace(it.obj->style()) || it.obj->isBR())
+ return true;
+
+ UChar current = it.current();
+ return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.obj)) && !skipNonBreakingSpace(it);
+}
+
+bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj)
+{
+ ASSERT(inlineObj->parent() == this);
+
+ InlineIterator it(this, inlineObj, 0);
+ while (!it.atEnd() && !requiresLineBox(it))
+ it.increment();
+
+ return !it.atEnd();
+}
+
+// FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building
+// line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned
+// elements quite right. In other words, we need to build this function's work into the normal line
+// object iteration process.
+// NB. this function will insert any floating elements that would otherwise
+// be skipped but it will not position them.
+void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator)
+{
+ while (!iterator.atEnd() && !requiresLineBox(iterator)) {
+ RenderObject* object = iterator.obj;
+ if (object->isFloating()) {
+ insertFloatingObject(object);
+ } else if (object->isPositioned()) {
+ // FIXME: The math here is actually not really right. It's a best-guess approximation that
+ // will work for the common cases
+ RenderObject* c = object->container();
+ if (c->isInlineFlow()) {
+ // A relative positioned inline encloses us. In this case, we also have to determine our
+ // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned
+ // inline so that we can obtain the value later.
+ c->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : rightOffset(m_height));
+ c->setStaticY(m_height);
+ }
+
+ if (object->hasStaticX()) {
+ if (object->style()->isOriginalDisplayInlineType())
+ object->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : width() - rightOffset(m_height));
+ else
+ object->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight());
+ }
+
+ if (object->hasStaticY())
+ object->setStaticY(m_height);
+ }
+ iterator.increment();
+ }
+}
+
+int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver)
+{
+ int availableWidth = lineWidth(m_height);
+ while (!resolver.position().atEnd() && !requiresLineBox(resolver.position())) {
+ RenderObject* object = resolver.position().obj;
+ if (object->isFloating()) {
+ insertFloatingObject(object);
+ positionNewFloats();
+ availableWidth = lineWidth(m_height);
+ } else if (object->isPositioned()) {
+ // FIXME: The math here is actually not really right. It's a best-guess approximation that
+ // will work for the common cases
+ RenderObject* c = object->container();
+ if (c->isInlineFlow()) {
+ // A relative positioned inline encloses us. In this case, we also have to determine our
+ // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned
+ // inline so that we can obtain the value later.
+ c->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : rightOffset(m_height));
+ c->setStaticY(m_height);
+ }
+
+ if (object->hasStaticX()) {
+ if (object->style()->isOriginalDisplayInlineType())
+ object->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : width() - rightOffset(m_height));
+ else
+ object->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight());
+ }
+
+ if (object->hasStaticY())
+ object->setStaticY(m_height);
+ }
+ resolver.increment();
+ }
+ resolver.commitExplicitEmbedding();
+ return availableWidth;
+}
+
+// This is currently just used for list markers and inline flows that have line boxes. Neither should
+// have an effect on whitespace at the start of the line.
+static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o)
+{
+ RenderObject* next = bidiNext(block, o);
+ if (next && !next->isBR() && next->isText() && static_cast<RenderText*>(next)->textLength() > 0) {
+ RenderText* nextText = static_cast<RenderText*>(next);
+ UChar nextChar = nextText->characters()[0];
+ if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) {
+ addMidpoint(InlineIterator(0, o, 0));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void RenderBlock::fitBelowFloats(int widthToFit, int& availableWidth)
+{
+ ASSERT(widthToFit > availableWidth);
+
+ int floatBottom;
+ int lastFloatBottom = m_height;
+ int newLineWidth = availableWidth;
+ while (true) {
+ floatBottom = nextFloatBottomBelow(lastFloatBottom);
+ if (!floatBottom)
+ break;
+
+ newLineWidth = lineWidth(floatBottom);
+ lastFloatBottom = floatBottom;
+ if (newLineWidth >= widthToFit)
+ break;
+ }
+
+ if (newLineWidth > availableWidth) {
+ m_height = lastFloatBottom;
+ availableWidth = newLineWidth;
+ }
+}
+
+InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, EClear* clear)
+{
+ ASSERT(resolver.position().block == this);
+
+ bool appliedStartWidth = resolver.position().pos > 0;
+
+ int width = skipLeadingWhitespace(resolver);
+
+ int w = 0;
+ int tmpW = 0;
+
+ if (resolver.position().atEnd())
+ return resolver.position();
+
+ // This variable is used only if whitespace isn't set to PRE, and it tells us whether
+ // or not we are currently ignoring whitespace.
+ bool ignoringSpaces = false;
+ InlineIterator ignoreStart;
+
+ // This variable tracks whether the very last character we saw was a space. We use
+ // this to detect when we encounter a second space so we know we have to terminate
+ // a run.
+ bool currentCharacterIsSpace = false;
+ bool currentCharacterIsWS = false;
+ RenderObject* trailingSpaceObject = 0;
+
+ InlineIterator lBreak = resolver.position();
+
+ RenderObject *o = resolver.position().obj;
+ RenderObject *last = o;
+ unsigned pos = resolver.position().pos;
+ int nextBreakable = resolver.position().nextBreakablePosition;
+ bool atStart = true;
+
+ bool prevLineBrokeCleanly = previousLineBrokeCleanly;
+ previousLineBrokeCleanly = false;
+
+ bool autoWrapWasEverTrueOnLine = false;
+ bool floatsFitOnLine = true;
+
+ // Firefox and Opera will allow a table cell to grow to fit an image inside it under
+ // very specific circumstances (in order to match common WinIE renderings).
+ // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
+ bool allowImagesToBreak = !style()->htmlHacks() || !isTableCell() || !style()->width().isIntrinsicOrAuto();
+
+ EWhiteSpace currWS = style()->whiteSpace();
+ EWhiteSpace lastWS = currWS;
+ while (o) {
+ currWS = o->isReplaced() ? o->parent()->style()->whiteSpace() : o->style()->whiteSpace();
+ lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : last->style()->whiteSpace();
+
+ bool autoWrap = RenderStyle::autoWrap(currWS);
+ autoWrapWasEverTrueOnLine = autoWrapWasEverTrueOnLine || autoWrap;
+
+#if ENABLE(SVG)
+ bool preserveNewline = o->isSVGText() ? false : RenderStyle::preserveNewline(currWS);
+#else
+ bool preserveNewline = RenderStyle::preserveNewline(currWS);
+#endif
+
+ bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS);
+
+ if (o->isBR()) {
+ if (w + tmpW <= width) {
+ lBreak.obj = o;
+ lBreak.pos = 0;
+ lBreak.nextBreakablePosition = -1;
+ lBreak.increment();
+
+ // A <br> always breaks a line, so don't let the line be collapsed
+ // away. Also, the space at the end of a line with a <br> does not
+ // get collapsed away. It only does this if the previous line broke
+ // cleanly. Otherwise the <br> has no effect on whether the line is
+ // empty or not.
+ if (prevLineBrokeCleanly)
+ isLineEmpty = false;
+ trailingSpaceObject = 0;
+ previousLineBrokeCleanly = true;
+
+ if (!isLineEmpty && clear)
+ *clear = o->style()->clear();
+ }
+ goto end;
+ }
+
+ if (o->isFloatingOrPositioned()) {
+ // add to special objects...
+ if (o->isFloating()) {
+ insertFloatingObject(o);
+ // check if it fits in the current line.
+ // If it does, position it now, otherwise, position
+ // it after moving to next line (in newLine() func)
+ if (floatsFitOnLine && o->width() + o->marginLeft() + o->marginRight() + w + tmpW <= width) {
+ positionNewFloats();
+ width = lineWidth(m_height);
+ } else
+ floatsFitOnLine = false;
+ } else if (o->isPositioned()) {
+ // If our original display wasn't an inline type, then we can
+ // go ahead and determine our static x position now.
+ bool isInlineType = o->style()->isOriginalDisplayInlineType();
+ bool needToSetStaticX = o->hasStaticX();
+ if (o->hasStaticX() && !isInlineType) {
+ o->setStaticX(o->parent()->style()->direction() == LTR ?
+ borderLeft() + paddingLeft() :
+ borderRight() + paddingRight());
+ needToSetStaticX = false;
+ }
+
+ // If our original display was an INLINE type, then we can go ahead
+ // and determine our static y position now.
+ bool needToSetStaticY = o->hasStaticY();
+ if (o->hasStaticY() && isInlineType) {
+ o->setStaticY(m_height);
+ needToSetStaticY = false;
+ }
+
+ bool needToCreateLineBox = needToSetStaticX || needToSetStaticY;
+ RenderObject* c = o->container();
+ if (c->isInlineFlow() && (!needToSetStaticX || !needToSetStaticY))
+ needToCreateLineBox = true;
+
+ // If we're ignoring spaces, we have to stop and include this object and
+ // then start ignoring spaces again.
+ if (needToCreateLineBox) {
+ trailingSpaceObject = 0;
+ ignoreStart.obj = o;
+ ignoreStart.pos = 0;
+ if (ignoringSpaces) {
+ addMidpoint(ignoreStart); // Stop ignoring spaces.
+ addMidpoint(ignoreStart); // Start ignoring again.
+ }
+
+ }
+ }
+ } else if (o->isInlineFlow()) {
+ // Right now, we should only encounter empty inlines here.
+ ASSERT(!o->firstChild());
+
+ // Now that some inline flows have line boxes, if we are already ignoring spaces, we need
+ // to make sure that we stop to include this object and then start ignoring spaces again.
+ // If this object is at the start of the line, we need to behave like list markers and
+ // start ignoring spaces.
+ if (inlineFlowRequiresLineBox(o)) {
+ isLineEmpty = false;
+ if (ignoringSpaces) {
+ trailingSpaceObject = 0;
+ addMidpoint(InlineIterator(0, o, 0)); // Stop ignoring spaces.
+ addMidpoint(InlineIterator(0, o, 0)); // Start ignoring again.
+ } else if (style()->collapseWhiteSpace() && resolver.position().obj == o
+ && shouldSkipWhitespaceAfterStartObject(this, o)) {
+ // Like with list markers, we start ignoring spaces to make sure that any
+ // additional spaces we see will be discarded.
+ currentCharacterIsSpace = true;
+ currentCharacterIsWS = true;
+ ignoringSpaces = true;
+ }
+ }
+
+ tmpW += o->marginLeft() + o->borderLeft() + o->paddingLeft() +
+ o->marginRight() + o->borderRight() + o->paddingRight();
+ } else if (o->isReplaced()) {
+ // Break on replaced elements if either has normal white-space.
+ if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!o->isImage() || allowImagesToBreak)) {
+ w += tmpW;
+ tmpW = 0;
+ lBreak.obj = o;
+ lBreak.pos = 0;
+ lBreak.nextBreakablePosition = -1;
+ }
+
+ if (ignoringSpaces)
+ addMidpoint(InlineIterator(0, o, 0));
+
+ isLineEmpty = false;
+ ignoringSpaces = false;
+ 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() && !static_cast<RenderListMarker*>(o)->isInside()) {
+ if (style()->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(this, o)) {
+ // Like with inline flows, we start ignoring spaces to make sure that any
+ // additional spaces we see will be discarded.
+ currentCharacterIsSpace = true;
+ currentCharacterIsWS = true;
+ ignoringSpaces = true;
+ }
+ } else
+ tmpW += o->width() + o->marginLeft() + o->marginRight() + inlineWidth(o);
+ } else if (o->isText()) {
+ if (!pos)
+ appliedStartWidth = false;
+
+ RenderText* t = static_cast<RenderText*>(o);
+
+ int strlen = t->textLength();
+ int len = strlen - pos;
+ const UChar* str = t->characters();
+
+ const Font& f = t->style(m_firstLine)->font();
+
+ int lastSpace = pos;
+ int wordSpacing = o->style()->wordSpacing();
+ int lastSpaceWordSpacing = 0;
+
+ int wrapW = tmpW + inlineWidth(o, !appliedStartWidth, true);
+ int charWidth = 0;
+ bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE;
+ // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
+ // which is only possible if the word is the first thing on the line, that is, if |w| is zero.
+ bool breakWords = o->style()->breakWords() && ((autoWrap && !w) || currWS == PRE);
+ bool midWordBreak = false;
+ bool breakAll = o->style()->wordBreak() == BreakAllWordBreak && autoWrap;
+
+ if (t->isWordBreak()) {
+ w += tmpW;
+ tmpW = 0;
+ lBreak.obj = o;
+ lBreak.pos = 0;
+ lBreak.nextBreakablePosition = -1;
+ ASSERT(!len);
+ }
+
+ while (len) {
+ bool previousCharacterIsSpace = currentCharacterIsSpace;
+ bool previousCharacterIsWS = currentCharacterIsWS;
+ UChar c = str[pos];
+ currentCharacterIsSpace = c == ' ' || c == '\t' || (!preserveNewline && (c == '\n'));
+
+ if (!collapseWhiteSpace || !currentCharacterIsSpace)
+ isLineEmpty = false;
+
+ // Check for soft hyphens. Go ahead and ignore them.
+ if (c == softHyphen) {
+ if (!ignoringSpaces) {
+ // Ignore soft hyphens
+ InlineIterator beforeSoftHyphen;
+ if (pos)
+ beforeSoftHyphen = InlineIterator(0, o, pos - 1);
+ else
+ beforeSoftHyphen = InlineIterator(0, last, last->isText() ? static_cast<RenderText*>(last)->textLength() - 1 : 0);
+ // Two consecutive soft hyphens. Avoid overlapping midpoints.
+ if (sNumMidpoints && smidpoints->at(sNumMidpoints - 1).obj == o && smidpoints->at(sNumMidpoints - 1).pos == pos)
+ sNumMidpoints--;
+ else
+ addMidpoint(beforeSoftHyphen);
+
+ // Add the width up to but not including the hyphen.
+ tmpW += t->width(lastSpace, pos - lastSpace, f, w + tmpW) + lastSpaceWordSpacing;
+
+ // For wrapping text only, include the hyphen. We need to ensure it will fit
+ // on the line if it shows when we break.
+ if (autoWrap)
+ tmpW += t->width(pos, 1, f, w + tmpW);
+
+ InlineIterator afterSoftHyphen(0, o, pos);
+ afterSoftHyphen.increment();
+ addMidpoint(afterSoftHyphen);
+ }
+
+ pos++;
+ len--;
+ lastSpaceWordSpacing = 0;
+ lastSpace = pos; // Cheesy hack to prevent adding in widths of the run twice.
+ continue;
+ }
+
+ bool applyWordSpacing = false;
+
+ currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c == noBreakSpace);
+
+ if ((breakAll || breakWords) && !midWordBreak) {
+ wrapW += charWidth;
+ charWidth = t->width(pos, 1, f, w + wrapW);
+ midWordBreak = w + wrapW + charWidth > width;
+ }
+
+ bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(str, pos, strlen, nextBreakable, breakNBSP));
+
+ if (betweenWords || midWordBreak) {
+ bool stoppedIgnoringSpaces = false;
+ if (ignoringSpaces) {
+ if (!currentCharacterIsSpace) {
+ // Stop ignoring spaces and begin at this
+ // new point.
+ ignoringSpaces = false;
+ lastSpaceWordSpacing = 0;
+ lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
+ addMidpoint(InlineIterator(0, o, pos));
+ stoppedIgnoringSpaces = true;
+ } else {
+ // Just keep ignoring these spaces.
+ pos++;
+ len--;
+ continue;
+ }
+ }
+
+ int additionalTmpW = t->width(lastSpace, pos - lastSpace, f, w+tmpW) + lastSpaceWordSpacing;
+ tmpW += additionalTmpW;
+ if (!appliedStartWidth) {
+ tmpW += inlineWidth(o, true, false);
+ appliedStartWidth = true;
+ }
+
+ applyWordSpacing = wordSpacing && currentCharacterIsSpace && !previousCharacterIsSpace;
+
+ if (!w && autoWrap && tmpW > width)
+ fitBelowFloats(tmpW, width);
+
+ if (autoWrap || breakWords) {
+ // If we break only after white-space, consider the current character
+ // as candidate width for this line.
+ bool lineWasTooWide = false;
+ if (w + tmpW <= width && currentCharacterIsWS && o->style()->breakOnlyAfterWhiteSpace() && !midWordBreak) {
+ int charWidth = t->width(pos, 1, f, w + tmpW) + (applyWordSpacing ? wordSpacing : 0);
+ // Check if line is too big even without the extra space
+ // at the end of the line. If it is not, do nothing.
+ // If the line needs the extra whitespace to be too long,
+ // then move the line break to the space and skip all
+ // additional whitespace.
+ if (w + tmpW + charWidth > width) {
+ lineWasTooWide = true;
+ lBreak.obj = o;
+ lBreak.pos = pos;
+ lBreak.nextBreakablePosition = nextBreakable;
+ skipTrailingWhitespace(lBreak);
+ }
+ }
+ if (lineWasTooWide || w + tmpW > width) {
+ if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && !static_cast<RenderText*>(lBreak.obj)->isWordBreak() && static_cast<RenderText*>(lBreak.obj)->characters()[lBreak.pos] == '\n') {
+ if (!stoppedIgnoringSpaces && pos > 0) {
+ // We need to stop right before the newline and then start up again.
+ addMidpoint(InlineIterator(0, o, pos - 1)); // Stop
+ addMidpoint(InlineIterator(0, o, pos)); // Start
+ }
+ lBreak.increment();
+ previousLineBrokeCleanly = true;
+ }
+ goto end; // Didn't fit. Jump to the end.
+ } else {
+ if (!betweenWords || (midWordBreak && !autoWrap))
+ tmpW -= additionalTmpW;
+ if (pos > 0 && str[pos-1] == softHyphen)
+ // Subtract the width of the soft hyphen out since we fit on a line.
+ tmpW -= t->width(pos-1, 1, f, w+tmpW);
+ }
+ }
+
+ if (c == '\n' && preserveNewline) {
+ if (!stoppedIgnoringSpaces && pos > 0) {
+ // We need to stop right before the newline and then start up again.
+ addMidpoint(InlineIterator(0, o, pos - 1)); // Stop
+ addMidpoint(InlineIterator(0, o, pos)); // Start
+ }
+ lBreak.obj = o;
+ lBreak.pos = pos;
+ lBreak.nextBreakablePosition = nextBreakable;
+ lBreak.increment();
+ previousLineBrokeCleanly = true;
+ return lBreak;
+ }
+
+ if (autoWrap && betweenWords) {
+ w += tmpW;
+ wrapW = 0;
+ tmpW = 0;
+ lBreak.obj = o;
+ lBreak.pos = pos;
+ lBreak.nextBreakablePosition = nextBreakable;
+ // Auto-wrapping text should not wrap in the middle of a word once it has had an
+ // opportunity to break after a word.
+ breakWords = false;
+ }
+
+ if (midWordBreak) {
+ // Remember this as a breakable position in case
+ // adding the end width forces a break.
+ lBreak.obj = o;
+ lBreak.pos = pos;
+ lBreak.nextBreakablePosition = nextBreakable;
+ midWordBreak &= (breakWords || breakAll);
+ }
+
+ if (betweenWords) {
+ lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
+ lastSpace = pos;
+ }
+
+ if (!ignoringSpaces && o->style()->collapseWhiteSpace()) {
+ // If we encounter a newline, or if we encounter a
+ // second space, we need to go ahead and break up this
+ // run and enter a mode where we start collapsing spaces.
+ if (currentCharacterIsSpace && previousCharacterIsSpace) {
+ ignoringSpaces = true;
+
+ // We just entered a mode where we are ignoring
+ // spaces. Create a midpoint to terminate the run
+ // before the second space.
+ addMidpoint(ignoreStart);
+ }
+ }
+ } else if (ignoringSpaces) {
+ // Stop ignoring spaces and begin at this
+ // new point.
+ ignoringSpaces = false;
+ lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
+ lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
+ addMidpoint(InlineIterator(0, o, pos));
+ }
+
+ if (currentCharacterIsSpace && !previousCharacterIsSpace) {
+ ignoreStart.obj = o;
+ ignoreStart.pos = pos;
+ }
+
+ if (!currentCharacterIsWS && previousCharacterIsWS) {
+ if (autoWrap && o->style()->breakOnlyAfterWhiteSpace()) {
+ lBreak.obj = o;
+ lBreak.pos = pos;
+ lBreak.nextBreakablePosition = nextBreakable;
+ }
+ }
+
+ if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSpaces)
+ trailingSpaceObject = o;
+ else if (!o->style()->collapseWhiteSpace() || !currentCharacterIsSpace)
+ trailingSpaceObject = 0;
+
+ pos++;
+ len--;
+ atStart = false;
+ }
+
+ // IMPORTANT: pos is > length here!
+ if (!ignoringSpaces)
+ tmpW += t->width(lastSpace, pos - lastSpace, f, w+tmpW) + lastSpaceWordSpacing;
+ tmpW += inlineWidth(o, !appliedStartWidth, true);
+ } else
+ ASSERT_NOT_REACHED();
+
+ RenderObject* next = bidiNext(this, o);
+ bool checkForBreak = autoWrap;
+ if (w && w + tmpW > width && lBreak.obj && currWS == NOWRAP)
+ checkForBreak = true;
+ else if (next && o->isText() && next->isText() && !next->isBR()) {
+ if (autoWrap || (next->style()->autoWrap())) {
+ if (currentCharacterIsSpace)
+ checkForBreak = true;
+ else {
+ checkForBreak = false;
+ RenderText* nextText = static_cast<RenderText*>(next);
+ if (nextText->textLength()) {
+ UChar c = nextText->characters()[0];
+ if (c == ' ' || c == '\t' || (c == '\n' && !shouldPreserveNewline(next)))
+ // If the next item on the line is text, and if we did not end with
+ // a space, then the next text run continues our word (and so it needs to
+ // keep adding to |tmpW|. Just update and continue.
+ checkForBreak = true;
+ } else if (nextText->isWordBreak())
+ checkForBreak = true;
+ bool willFitOnLine = w + tmpW <= width;
+ if (!willFitOnLine && !w) {
+ fitBelowFloats(tmpW, width);
+ willFitOnLine = tmpW <= width;
+ }
+ bool canPlaceOnLine = willFitOnLine || !autoWrapWasEverTrueOnLine;
+ if (canPlaceOnLine && checkForBreak) {
+ w += tmpW;
+ tmpW = 0;
+ lBreak.obj = next;
+ lBreak.pos = 0;
+ lBreak.nextBreakablePosition = -1;
+ }
+ }
+ }
+ }
+
+ if (checkForBreak && (w + tmpW > width)) {
+ // if we have floats, try to get below them.
+ if (currentCharacterIsSpace && !ignoringSpaces && o->style()->collapseWhiteSpace())
+ trailingSpaceObject = 0;
+
+ if (w)
+ goto end;
+
+ fitBelowFloats(tmpW, width);
+
+ // |width| may have been adjusted because we got shoved down past a float (thus
+ // giving us more room), so we need to retest, and only jump to
+ // the end label if we still don't fit on the line. -dwh
+ if (w + tmpW > width)
+ goto end;
+ }
+
+ if (!o->isFloatingOrPositioned()) {
+ last = o;
+ if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || static_cast<RenderListMarker*>(last)->isInside())) {
+ w += tmpW;
+ tmpW = 0;
+ lBreak.obj = next;
+ lBreak.pos = 0;
+ lBreak.nextBreakablePosition = -1;
+ }
+ }
+
+ o = next;
+ nextBreakable = -1;
+
+ // Clear out our character space bool, since inline <pre>s don't collapse whitespace
+ // with adjacent inline normal/nowrap spans.
+ if (!collapseWhiteSpace)
+ currentCharacterIsSpace = false;
+
+ pos = 0;
+ atStart = false;
+ }
+
+
+ if (w + tmpW <= width || lastWS == NOWRAP) {
+ lBreak.obj = 0;
+ lBreak.pos = 0;
+ lBreak.nextBreakablePosition = -1;
+ }
+
+ end:
+
+ if (lBreak == resolver.position() && !lBreak.obj->isBR()) {
+ // we just add as much as possible
+ if (style()->whiteSpace() == PRE) {
+ // FIXME: Don't really understand this case.
+ if (pos != 0) {
+ lBreak.obj = o;
+ lBreak.pos = pos - 1;
+ } else {
+ lBreak.obj = last;
+ lBreak.pos = last->isText() ? last->length() : 0;
+ 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;
+ }
+ }
+ }
+
+ // make sure we consume at least one char/object.
+ if (lBreak == resolver.position())
+ lBreak.increment();
+
+ // Sanity check our midpoints.
+ checkMidpoints(lBreak);
+
+ if (trailingSpaceObject) {
+ // This object is either going to be part of the last midpoint, or it is going
+ // to be the actual endpoint. In both cases we just decrease our pos by 1 level to
+ // exclude the space, allowing it to - in effect - collapse into the newline.
+ if (sNumMidpoints%2==1) {
+ InlineIterator* midpoints = smidpoints->data();
+ midpoints[sNumMidpoints-1].pos--;
+ }
+ //else if (lBreak.pos > 0)
+ // lBreak.pos--;
+ else if (lBreak.obj == 0 && trailingSpaceObject->isText()) {
+ // Add a new end midpoint that stops right at the very end.
+ RenderText* text = static_cast<RenderText *>(trailingSpaceObject);
+ unsigned length = text->textLength();
+ unsigned pos = length >= 2 ? length - 2 : UINT_MAX;
+ InlineIterator endMid(0, trailingSpaceObject, pos);
+ addMidpoint(endMid);
+ }
+ }
+
+ // We might have made lBreak an iterator that points past the end
+ // of the object. Do this adjustment to make it point to the start
+ // of the next object instead to avoid confusing the rest of the
+ // code.
+ if (lBreak.pos > 0) {
+ lBreak.pos--;
+ lBreak.increment();
+ }
+
+ if (lBreak.obj && lBreak.pos >= 2 && lBreak.obj->isText()) {
+ // For soft hyphens on line breaks, we have to chop out the midpoints that made us
+ // ignore the hyphen so that it will render at the end of the line.
+ UChar c = static_cast<RenderText*>(lBreak.obj)->characters()[lBreak.pos-1];
+ if (c == softHyphen)
+ chopMidpointsAt(lBreak.obj, lBreak.pos-2);
+ }
+
+ return lBreak;
+}
+
+void RenderBlock::checkLinesForOverflow()
+{
+ m_overflowWidth = m_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);
+ }
+}
+
+void RenderBlock::deleteEllipsisLineBoxes()
+{
+ for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox())
+ curr->clearTruncation();
+}
+
+void RenderBlock::checkLinesForTextOverflow()
+{
+ // Determine the width of the ellipsis using the current font.
+ // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable"
+ TextRun ellipsisRun(&horizontalEllipsis, 1);
+ DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
+ const Font& firstLineFont = firstLineStyle()->font();
+ const Font& font = style()->font();
+ int firstLineEllipsisWidth = firstLineFont.width(ellipsisRun);
+ int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(ellipsisRun);
+
+ // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
+ // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
+ // check the left edge of the line box to see if it is less
+ // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
+ bool ltr = style()->direction() == LTR;
+ for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
+ int blockEdge = ltr ? rightOffset(curr->yPos()) : leftOffset(curr->yPos());
+ int lineBoxEdge = ltr ? curr->xPos() + curr->width() : curr->xPos();
+ if ((ltr && lineBoxEdge > blockEdge) || (!ltr && lineBoxEdge < blockEdge)) {
+ // This line spills out of our box in the appropriate direction. Now we need to see if the line
+ // can be truncated. In order for truncation to be possible, the line must have sufficient space to
+ // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
+ // space.
+ int width = curr == firstRootBox() ? firstLineEllipsisWidth : ellipsisWidth;
+ if (curr->canAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width))
+ curr->placeEllipsis(ellipsisStr, ltr, blockEdge, width);
+ }
+ }
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/bidi.h b/src/3rdparty/webkit/WebCore/rendering/bidi.h
new file mode 100644
index 0000000..fc6de5b
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/bidi.h
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the html renderer for KDE.
+ *
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2003 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
+ * 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 bidi_h
+#define bidi_h
+
+#include "BidiResolver.h"
+
+namespace WebCore {
+
+class RenderArena;
+class RenderBlock;
+class RenderObject;
+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)
+ , m_compact(false)
+ {
+ }
+
+ 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;
+ bool m_compact;
+};
+
+} // namespace WebCore
+
+#endif // bidi_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp b/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp
new file mode 100644
index 0000000..05748ac
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/break_lines.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2005, 2007 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 "break_lines.h"
+
+#include "CharacterNames.h"
+#include "TextBreakIterator.h"
+
+#if PLATFORM(MAC)
+#include <CoreServices/CoreServices.h>
+#endif
+
+namespace WebCore {
+
+static inline bool isBreakableSpace(UChar ch, bool treatNoBreakSpaceAsBreak)
+{
+ switch (ch) {
+ case ' ':
+ case '\n':
+ case '\t':
+ return true;
+ case noBreakSpace:
+ return treatNoBreakSpaceAsBreak;
+ default:
+ return false;
+ }
+}
+
+static inline bool shouldBreakAfter(UChar ch)
+{
+ // 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 '-':
+ 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:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool needsLineBreakIterator(UChar ch)
+{
+ return ch > 0x7F && ch != noBreakSpace;
+}
+
+#ifdef BUILDING_ON_TIGER
+static inline TextBreakLocatorRef lineBreakLocator()
+{
+ TextBreakLocatorRef locator = 0;
+ UCCreateTextBreakLocator(0, 0, kUCTextBreakLineMask, &locator);
+ return locator;
+}
+#endif
+
+int nextBreakablePosition(const UChar* str, int pos, int len, bool treatNoBreakSpaceAsBreak)
+{
+#ifndef BUILDING_ON_TIGER
+ TextBreakIterator* breakIterator = 0;
+#endif
+ int nextBreak = -1;
+
+ UChar lastCh = pos > 0 ? str[pos - 1] : 0;
+ for (int i = pos; i < len; i++) {
+ UChar ch = str[i];
+
+ if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastCh))
+ return i;
+
+ if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) {
+ if (nextBreak < i && i) {
+#ifndef BUILDING_ON_TIGER
+ if (!breakIterator)
+ breakIterator = lineBreakIterator(str, len);
+ if (breakIterator)
+ nextBreak = textBreakFollowing(breakIterator, i - 1);
+#else
+ static TextBreakLocatorRef breakLocator = lineBreakLocator();
+ if (breakLocator) {
+ UniCharArrayOffset nextUCBreak;
+ if (UCFindTextBreak(breakLocator, kUCTextBreakLineMask, 0, str, len, i, &nextUCBreak) == 0)
+ nextBreak = nextUCBreak;
+ }
+#endif
+ }
+ if (i == nextBreak && !isBreakableSpace(lastCh, treatNoBreakSpaceAsBreak))
+ return i;
+ }
+
+ lastCh = ch;
+ }
+
+ return len;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/break_lines.h b/src/3rdparty/webkit/WebCore/rendering/break_lines.h
new file mode 100644
index 0000000..14f740f
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/break_lines.h
@@ -0,0 +1,41 @@
+/*
+ * 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
+ * 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 break_lines_h
+#define break_lines_h
+
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+ int nextBreakablePosition(const UChar*, int pos, int len, bool breakNBSP = false);
+
+ inline bool isBreakable(const UChar* str, int pos, int len, int& nextBreakable, bool breakNBSP = false)
+ {
+ if (pos > nextBreakable)
+ nextBreakable = nextBreakablePosition(str, pos, len, breakNBSP);
+ return pos == nextBreakable;
+ }
+
+} // namespace WebCore
+
+#endif // break_lines_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/BindingURI.cpp b/src/3rdparty/webkit/WebCore/rendering/style/BindingURI.cpp
new file mode 100644
index 0000000..fd96de4
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/BindingURI.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "BindingURI.h"
+
+#if ENABLE(XBL)
+
+namespace WebCore {
+
+BindingURI::BindingURI(StringImpl* uri)
+ : m_next(0)
+{
+ m_uri = uri;
+ if (uri)
+ uri->ref();
+}
+
+BindingURI::~BindingURI()
+{
+ if (m_uri)
+ m_uri->deref();
+ delete m_next;
+}
+
+BindingURI* BindingURI::copy()
+{
+ BindingURI* newBinding = new BindingURI(m_uri);
+ if (next()) {
+ BindingURI* nextCopy = next()->copy();
+ newBinding->setNext(nextCopy);
+ }
+
+ return newBinding;
+}
+
+bool BindingURI::operator==(const BindingURI& o) const
+{
+ if ((m_next && !o.m_next) || (!m_next && o.m_next) ||
+ (m_next && o.m_next && *m_next != *o.m_next))
+ return false;
+
+ if (m_uri == o.m_uri)
+ return true;
+ if (!m_uri || !o.m_uri)
+ return false;
+
+ return String(m_uri) == String(o.m_uri);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(XBL)
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/BindingURI.h b/src/3rdparty/webkit/WebCore/rendering/style/BindingURI.h
new file mode 100644
index 0000000..923f1aa
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/BindingURI.h
@@ -0,0 +1,59 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 BindingURI_h
+#define BindingURI_h
+#if ENABLE(XBL)
+
+#include "StringImpl.h"
+
+namespace WebCore {
+
+// This struct holds information about shadows for the text-shadow and box-shadow properties.
+
+struct BindingURI {
+ BindingURI(StringImpl*);
+ ~BindingURI();
+
+ BindingURI* copy();
+
+ bool operator==(const BindingURI& o) const;
+ bool operator!=(const BindingURI& o) const
+ {
+ return !(*this == o);
+ }
+
+ BindingURI* next() { return m_next; }
+ void setNext(BindingURI* n) { m_next = n; }
+
+ StringImpl* uri() { return m_uri; }
+
+ BindingURI* m_next;
+ StringImpl* m_uri;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(XBL)
+#endif // BindingURI_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/BorderData.h b/src/3rdparty/webkit/WebCore/rendering/style/BorderData.h
new file mode 100644
index 0000000..8ca0d65
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/BorderData.h
@@ -0,0 +1,109 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 BorderData_h
+#define BorderData_h
+
+#include "BorderValue.h"
+#include "IntSize.h"
+#include "NinePieceImage.h"
+
+namespace WebCore {
+
+class BorderData {
+public:
+ BorderValue left;
+ BorderValue right;
+ BorderValue top;
+ BorderValue bottom;
+
+ NinePieceImage image;
+
+ IntSize topLeft;
+ IntSize topRight;
+ IntSize bottomLeft;
+ IntSize bottomRight;
+
+ bool hasBorder() const
+ {
+ bool haveImage = image.hasImage();
+ return left.nonZero(!haveImage) || right.nonZero(!haveImage) || top.nonZero(!haveImage) || bottom.nonZero(!haveImage);
+ }
+
+ bool hasBorderRadius() const
+ {
+ if (topLeft.width() > 0)
+ return true;
+ if (topRight.width() > 0)
+ return true;
+ if (bottomLeft.width() > 0)
+ return true;
+ if (bottomRight.width() > 0)
+ return true;
+ return false;
+ }
+
+ unsigned short borderLeftWidth() const
+ {
+ if (!image.hasImage() && (left.style() == BNONE || left.style() == BHIDDEN))
+ return 0;
+ return left.width;
+ }
+
+ unsigned short borderRightWidth() const
+ {
+ if (!image.hasImage() && (right.style() == BNONE || right.style() == BHIDDEN))
+ return 0;
+ return right.width;
+ }
+
+ unsigned short borderTopWidth() const
+ {
+ if (!image.hasImage() && (top.style() == BNONE || top.style() == BHIDDEN))
+ return 0;
+ return top.width;
+ }
+
+ unsigned short borderBottomWidth() const
+ {
+ if (!image.hasImage() && (bottom.style() == BNONE || bottom.style() == BHIDDEN))
+ return 0;
+ return bottom.width;
+ }
+
+ bool operator==(const BorderData& o) const
+ {
+ return left == o.left && right == o.right && top == o.top && bottom == o.bottom && image == o.image &&
+ topLeft == o.topLeft && topRight == o.topRight && bottomLeft == o.bottomLeft && bottomRight == o.bottomRight;
+ }
+
+ bool operator!=(const BorderData& o) const
+ {
+ return !(*this == o);
+ }
+};
+
+} // namespace WebCore
+
+#endif // BorderData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/BorderValue.h b/src/3rdparty/webkit/WebCore/rendering/style/BorderValue.h
new file mode 100644
index 0000000..e61e708
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/BorderValue.h
@@ -0,0 +1,75 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 BorderValue_h
+#define BorderValue_h
+
+#include "Color.h"
+#include "RenderStyleConstants.h"
+
+namespace WebCore {
+
+class BorderValue {
+public:
+ BorderValue()
+ : width(3)
+ , m_style(BNONE)
+ {
+ }
+
+ Color color;
+ unsigned width : 12;
+ unsigned m_style : 4; // EBorderStyle
+
+ EBorderStyle style() const { return static_cast<EBorderStyle>(m_style); }
+
+ bool nonZero(bool checkStyle = true) const
+ {
+ return width != 0 && (!checkStyle || m_style != BNONE);
+ }
+
+ bool isTransparent() const
+ {
+ return color.isValid() && color.alpha() == 0;
+ }
+
+ bool isVisible(bool checkStyle = true) const
+ {
+ return nonZero(checkStyle) && !isTransparent() && (!checkStyle || m_style != BHIDDEN);
+ }
+
+ bool operator==(const BorderValue& o) const
+ {
+ return width == o.width && m_style == o.m_style && color == o.color;
+ }
+
+ bool operator!=(const BorderValue& o) const
+ {
+ return !(*this == o);
+ }
+};
+
+} // namespace WebCore
+
+#endif // BorderValue_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/CollapsedBorderValue.h b/src/3rdparty/webkit/WebCore/rendering/style/CollapsedBorderValue.h
new file mode 100644
index 0000000..805f474
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/CollapsedBorderValue.h
@@ -0,0 +1,66 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 CollapsedBorderValue_h
+#define CollapsedBorderValue_h
+
+#include "BorderValue.h"
+
+namespace WebCore {
+
+struct CollapsedBorderValue {
+ CollapsedBorderValue()
+ : border(0)
+ , precedence(BOFF)
+ {
+ }
+
+ CollapsedBorderValue(const BorderValue* b, EBorderPrecedence p)
+ : border(b)
+ , precedence(p)
+ {
+ }
+
+ int width() const { return border && border->nonZero() ? border->width : 0; }
+ EBorderStyle style() const { return border ? border->style() : BHIDDEN; }
+ bool exists() const { return border; }
+ Color color() const { return border ? border->color : Color(); }
+ bool isTransparent() const { return border ? border->isTransparent() : true; }
+
+ bool operator==(const CollapsedBorderValue& o) const
+ {
+ if (!border)
+ return !o.border;
+ if (!o.border)
+ return false;
+ return *border == *o.border && precedence == o.precedence;
+ }
+
+ const BorderValue* border;
+ EBorderPrecedence precedence;
+};
+
+} // namespace WebCore
+
+#endif // CollapsedBorderValue_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/ContentData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/ContentData.cpp
new file mode 100644
index 0000000..b38cc49
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/ContentData.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "ContentData.h"
+
+#include "CounterContent.h"
+#include "StringImpl.h"
+#include "StyleImage.h"
+
+namespace WebCore {
+
+void ContentData::clear()
+{
+ switch (m_type) {
+ case CONTENT_NONE:
+ break;
+ case CONTENT_OBJECT:
+ m_content.m_image->deref();
+ break;
+ case CONTENT_TEXT:
+ m_content.m_text->deref();
+ break;
+ case CONTENT_COUNTER:
+ delete m_content.m_counter;
+ break;
+ }
+
+ ContentData* n = m_next;
+ m_type = CONTENT_NONE;
+ m_next = 0;
+
+ // Reverse the list so we can delete without recursing.
+ ContentData* last = 0;
+ ContentData* c;
+ while ((c = n)) {
+ n = c->m_next;
+ c->m_next = last;
+ last = c;
+ }
+ for (c = last; c; c = n) {
+ n = c->m_next;
+ c->m_next = 0;
+ delete c;
+ }
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h b/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h
new file mode 100644
index 0000000..d924d1a
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/ContentData.h
@@ -0,0 +1,62 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 ContentData_h
+#define ContentData_h
+
+#include "RenderStyleConstants.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class CounterContent;
+class StringImpl;
+class StyleImage;
+
+struct ContentData : Noncopyable {
+ ContentData()
+ : m_type(CONTENT_NONE)
+ , m_next(0)
+ {
+ }
+
+ ~ContentData()
+ {
+ clear();
+ }
+
+ void clear();
+
+ ContentType m_type;
+ union {
+ StyleImage* m_image;
+ StringImpl* m_text;
+ CounterContent* m_counter;
+ } m_content;
+ ContentData* m_next;
+};
+
+} // namespace WebCore
+
+#endif // ContentData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h b/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h
new file mode 100644
index 0000000..06440ad
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/CounterContent.h
@@ -0,0 +1,62 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 CounterContent_h
+#define CounterContent_h
+
+#include "AtomicString.h"
+#include "RenderStyleConstants.h"
+
+namespace WebCore {
+
+class CounterContent {
+public:
+ CounterContent(const AtomicString& identifier, EListStyleType style, const AtomicString& separator)
+ : m_identifier(identifier)
+ , m_listStyle(style)
+ , m_separator(separator)
+ {
+ }
+
+ const AtomicString& identifier() const { return m_identifier; }
+ EListStyleType listStyle() const { return m_listStyle; }
+ const AtomicString& separator() const { return m_separator; }
+
+private:
+ AtomicString m_identifier;
+ EListStyleType m_listStyle;
+ AtomicString m_separator;
+};
+
+static inline bool operator!=(const CounterContent& a, const CounterContent& b)
+{
+ return a.identifier() != b.identifier()
+ || a.listStyle() != b.listStyle()
+ || a.separator() != b.separator();
+}
+
+
+} // namespace WebCore
+
+#endif // CounterContent_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/CounterDirectives.cpp b/src/3rdparty/webkit/WebCore/rendering/style/CounterDirectives.cpp
new file mode 100644
index 0000000..a0ff52f
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/CounterDirectives.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "CounterDirectives.h"
+
+namespace WebCore {
+
+bool operator==(const CounterDirectives& a, const CounterDirectives& b)
+{
+ if (a.m_reset != b.m_reset || a.m_increment != b.m_increment)
+ return false;
+ if (a.m_reset && a.m_resetValue != b.m_resetValue)
+ return false;
+ if (a.m_increment && a.m_incrementValue != b.m_incrementValue)
+ return false;
+ return true;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/CounterDirectives.h b/src/3rdparty/webkit/WebCore/rendering/style/CounterDirectives.h
new file mode 100644
index 0000000..9cbdeae
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/CounterDirectives.h
@@ -0,0 +1,54 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 CounterDirectives_h
+#define CounterDirectives_h
+
+#include "AtomicStringImpl.h"
+#include <wtf/HashMap.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+struct CounterDirectives {
+ CounterDirectives()
+ : m_reset(false)
+ , m_increment(false)
+ {
+ }
+
+ bool m_reset;
+ int m_resetValue;
+ bool m_increment;
+ int m_incrementValue;
+};
+
+bool operator==(const CounterDirectives&, const CounterDirectives&);
+inline bool operator!=(const CounterDirectives& a, const CounterDirectives& b) { return !(a == b); }
+
+typedef HashMap<RefPtr<AtomicStringImpl>, CounterDirectives> CounterDirectiveMap;
+
+} // namespace WebCore
+
+#endif // CounterDirectives_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/CursorData.h b/src/3rdparty/webkit/WebCore/rendering/style/CursorData.h
new file mode 100644
index 0000000..7c6b31d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/CursorData.h
@@ -0,0 +1,56 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 CursorData_h
+#define CursorData_h
+
+#include "CachedImage.h"
+#include "CachedResourceHandle.h"
+#include "IntPoint.h"
+
+namespace WebCore {
+
+struct CursorData {
+ CursorData()
+ : cursorImage(0)
+ {
+ }
+
+ bool operator==(const CursorData& o) const
+ {
+ return hotSpot == o.hotSpot && cursorImage == o.cursorImage;
+ }
+
+ bool operator!=(const CursorData& o) const
+ {
+ return !(*this == o);
+ }
+
+ IntPoint hotSpot; // for CSS3 support
+ CachedResourceHandle<CachedImage> cursorImage;
+};
+
+} // namespace WebCore
+
+#endif // CursorData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/CursorList.h b/src/3rdparty/webkit/WebCore/rendering/style/CursorList.h
new file mode 100644
index 0000000..bdd65d4
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/CursorList.h
@@ -0,0 +1,59 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 CursorList_h
+#define CursorList_h
+
+#include "CursorData.h"
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class CursorList : public RefCounted<CursorList> {
+public:
+ static PassRefPtr<CursorList> create()
+ {
+ return adoptRef(new CursorList);
+ }
+
+ const CursorData& operator[](int i) const { return m_vector[i]; }
+
+ bool operator==(const CursorList& o) const { return m_vector == o.m_vector; }
+ bool operator!=(const CursorList& o) const { return m_vector != o.m_vector; }
+
+ size_t size() const { return m_vector.size(); }
+ void append(const CursorData& cursorData) { m_vector.append(cursorData); }
+
+private:
+ CursorList()
+ {
+ }
+
+ Vector<CursorData> m_vector;
+};
+
+} // namespace WebCore
+
+#endif // CursorList_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/DataRef.h b/src/3rdparty/webkit/WebCore/rendering/style/DataRef.h
new file mode 100644
index 0000000..c8d8072
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/DataRef.h
@@ -0,0 +1,71 @@
+/*
+ * 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, 2008 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 DataRef_h
+#define DataRef_h
+
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+template <typename T> class DataRef {
+public:
+ const T* get() const { return m_data.get(); }
+
+ const T& operator*() const { return *get(); }
+ const T* operator->() const { return get(); }
+
+ T* access()
+ {
+ if (!m_data->hasOneRef())
+ m_data = m_data->copy();
+ return m_data.get();
+ }
+
+ void init()
+ {
+ ASSERT(!m_data);
+ m_data = T::create();
+ }
+
+ bool operator==(const DataRef<T>& o) const
+ {
+ ASSERT(m_data);
+ ASSERT(o.m_data);
+ return m_data == o.m_data || *m_data == *o.m_data;
+ }
+
+ bool operator!=(const DataRef<T>& o) const
+ {
+ ASSERT(m_data);
+ ASSERT(o.m_data);
+ return m_data != o.m_data && *m_data != *o.m_data;
+ }
+
+private:
+ RefPtr<T> m_data;
+};
+
+} // namespace WebCore
+
+#endif // DataRef_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.cpp b/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.cpp
new file mode 100644
index 0000000..9c491aa
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "FillLayer.h"
+
+namespace WebCore {
+
+FillLayer::FillLayer(EFillLayerType type)
+ : m_image(FillLayer::initialFillImage(type))
+ , m_xPosition(FillLayer::initialFillXPosition(type))
+ , m_yPosition(FillLayer::initialFillYPosition(type))
+ , m_attachment(FillLayer::initialFillAttachment(type))
+ , m_clip(FillLayer::initialFillClip(type))
+ , m_origin(FillLayer::initialFillOrigin(type))
+ , m_repeat(FillLayer::initialFillRepeat(type))
+ , m_composite(FillLayer::initialFillComposite(type))
+ , m_size(FillLayer::initialFillSize(type))
+ , m_imageSet(false)
+ , m_attachmentSet(false)
+ , m_clipSet(false)
+ , m_originSet(false)
+ , m_repeatSet(false)
+ , m_xPosSet(false)
+ , m_yPosSet(false)
+ , m_compositeSet(type == MaskFillLayer)
+ , m_sizeSet(false)
+ , m_type(type)
+ , m_next(0)
+{
+}
+
+FillLayer::FillLayer(const FillLayer& o)
+ : m_image(o.m_image)
+ , m_xPosition(o.m_xPosition)
+ , m_yPosition(o.m_yPosition)
+ , m_attachment(o.m_attachment)
+ , m_clip(o.m_clip)
+ , m_origin(o.m_origin)
+ , m_repeat(o.m_repeat)
+ , m_composite(o.m_composite)
+ , m_size(o.m_size)
+ , 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_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)
+{
+}
+
+FillLayer::~FillLayer()
+{
+ delete m_next;
+}
+
+FillLayer& FillLayer::operator=(const FillLayer& o)
+{
+ if (m_next != o.m_next) {
+ delete m_next;
+ m_next = o.m_next ? new FillLayer(*o.m_next) : 0;
+ }
+
+ m_image = o.m_image;
+ 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_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_xPosSet = o.m_xPosSet;
+ m_yPosSet = o.m_yPosSet;
+ m_sizeSet = o.m_sizeSet;
+
+ m_type = o.m_type;
+
+ return *this;
+}
+
+bool FillLayer::operator==(const FillLayer& o) const
+{
+ // We do not check the "isSet" booleans for each property, since those are only used during initial construction
+ // 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);
+}
+
+void FillLayer::fillUnsetProperties()
+{
+ FillLayer* curr;
+ for (curr = this; curr && curr->isImageSet(); 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_image = pattern->m_image;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isXPositionSet(); 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_xPosition = pattern->m_xPosition;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isYPositionSet(); 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_yPosition = pattern->m_yPosition;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isAttachmentSet(); 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_attachment = pattern->m_attachment;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isClipSet(); 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_clip = pattern->m_clip;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isCompositeSet(); 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_composite = pattern->m_composite;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isOriginSet(); 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_origin = pattern->m_origin;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isRepeatSet(); 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;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isSizeSet(); 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_size = pattern->m_size;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+}
+
+void FillLayer::cullEmptyLayers()
+{
+ FillLayer* next;
+ for (FillLayer* p = this; p; p = next) {
+ next = p->m_next;
+ if (next && !next->isImageSet() &&
+ !next->isXPositionSet() && !next->isYPositionSet() &&
+ !next->isAttachmentSet() && !next->isClipSet() &&
+ !next->isCompositeSet() && !next->isOriginSet() &&
+ !next->isRepeatSet() && !next->isSizeSet()) {
+ delete next;
+ p->m_next = 0;
+ break;
+ }
+ }
+}
+
+bool FillLayer::containsImage(StyleImage* s) const
+{
+ if (!s)
+ return false;
+ if (m_image && *s == *m_image)
+ return true;
+ if (m_next)
+ return m_next->containsImage(s);
+ return false;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.h b/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.h
new file mode 100644
index 0000000..2dc5871
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/FillLayer.h
@@ -0,0 +1,161 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 FillLayer_h
+#define FillLayer_h
+
+#include "GraphicsTypes.h"
+#include "Length.h"
+#include "LengthSize.h"
+#include "RenderStyleConstants.h"
+#include "StyleImage.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+struct FillLayer {
+public:
+ FillLayer(EFillLayerType);
+ ~FillLayer();
+
+ StyleImage* image() const { return m_image.get(); }
+ Length xPosition() const { return m_xPosition; }
+ Length yPosition() const { return m_yPosition; }
+ bool attachment() const { return 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); }
+ CompositeOperator composite() const { return static_cast<CompositeOperator>(m_composite); }
+ LengthSize size() const { return m_size; }
+
+ const FillLayer* next() const { return m_next; }
+ FillLayer* next() { return m_next; }
+
+ bool isImageSet() const { return m_imageSet; }
+ bool isXPositionSet() const { return m_xPosSet; }
+ bool isYPositionSet() const { return m_yPosSet; }
+ 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 isCompositeSet() const { return m_compositeSet; }
+ bool isSizeSet() const { return m_sizeSet; }
+
+ 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 setAttachment(bool b) { m_attachment = b; 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 setComposite(CompositeOperator c) { m_composite = c; m_compositeSet = true; }
+ void setSize(const LengthSize& b) { m_size = b; m_sizeSet = true; }
+
+ void clearImage() { m_imageSet = false; }
+ void clearXPosition() { m_xPosSet = false; }
+ void clearYPosition() { m_yPosSet = false; }
+ void clearAttachment() { m_attachmentSet = false; }
+ void clearClip() { m_clipSet = false; }
+ void clearOrigin() { m_originSet = false; }
+ void clearRepeat() { m_repeatSet = false; }
+ void clearComposite() { m_compositeSet = false; }
+ void clearSize() { m_sizeSet = false; }
+
+ void setNext(FillLayer* n) { if (m_next != n) { delete m_next; m_next = n; } }
+
+ FillLayer& operator=(const FillLayer& o);
+ FillLayer(const FillLayer& o);
+
+ bool operator==(const FillLayer& o) const;
+ bool operator!=(const FillLayer& o) const
+ {
+ return !(*this == o);
+ }
+
+ bool containsImage(StyleImage*) const;
+
+ bool hasImage() const
+ {
+ if (m_image)
+ return true;
+ return m_next ? m_next->hasImage() : false;
+ }
+
+ bool hasFixedImage() const
+ {
+ if (m_image && !m_attachment)
+ return true;
+ return m_next ? m_next->hasFixedImage() : false;
+ }
+
+ EFillLayerType type() const { return static_cast<EFillLayerType>(m_type); }
+
+ void fillUnsetProperties();
+ void cullEmptyLayers();
+
+ static bool initialFillAttachment(EFillLayerType) { return true; }
+ static EFillBox initialFillClip(EFillLayerType) { return BorderFillBox; }
+ static EFillBox initialFillOrigin(EFillLayerType type) { return type == BackgroundFillLayer ? PaddingFillBox : BorderFillBox; }
+ static EFillRepeat initialFillRepeat(EFillLayerType) { return RepeatFill; }
+ static CompositeOperator initialFillComposite(EFillLayerType) { return CompositeSourceOver; }
+ static LengthSize initialFillSize(EFillLayerType) { return LengthSize(); }
+ static Length initialFillXPosition(EFillLayerType) { return Length(0.0, Percent); }
+ static Length initialFillYPosition(EFillLayerType) { return Length(0.0, Percent); }
+ static StyleImage* initialFillImage(EFillLayerType) { return 0; }
+
+private:
+ FillLayer() { }
+
+public:
+ RefPtr<StyleImage> m_image;
+
+ Length m_xPosition;
+ Length m_yPosition;
+
+ bool m_attachment : 1;
+ unsigned m_clip : 2; // EFillBox
+ unsigned m_origin : 2; // EFillBox
+ unsigned m_repeat : 2; // EFillRepeat
+ unsigned m_composite : 4; // CompositeOperator
+
+ LengthSize m_size;
+
+ bool m_imageSet : 1;
+ bool m_attachmentSet : 1;
+ bool m_clipSet : 1;
+ bool m_originSet : 1;
+ bool m_repeatSet : 1;
+ bool m_xPosSet : 1;
+ bool m_yPosSet : 1;
+ bool m_compositeSet : 1;
+ bool m_sizeSet : 1;
+
+ unsigned m_type : 1; // EFillLayerType
+
+ FillLayer* m_next;
+};
+
+} // namespace WebCore
+
+#endif // FillLayer_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/KeyframeList.cpp b/src/3rdparty/webkit/WebCore/rendering/style/KeyframeList.cpp
new file mode 100644
index 0000000..41fbbe2
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/KeyframeList.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "KeyframeList.h"
+#include "RenderObject.h"
+
+namespace WebCore {
+
+KeyframeList::~KeyframeList()
+{
+ clear();
+}
+
+void KeyframeList::clear()
+{
+ m_keyframes.clear();
+ m_properties.clear();
+}
+
+bool KeyframeList::operator==(const KeyframeList& o) const
+{
+ if (m_keyframes.size() != o.m_keyframes.size())
+ return false;
+
+ Vector<KeyframeValue>::const_iterator it2 = o.m_keyframes.begin();
+ for (Vector<KeyframeValue>::const_iterator it1 = m_keyframes.begin(); it1 != m_keyframes.end(); ++it1) {
+ if (it1->m_key != it2->m_key)
+ return false;
+ const RenderStyle& style1 = *it1->m_style;
+ const RenderStyle& style2 = *it2->m_style;
+ if (style1 != style2)
+ return false;
+ ++it2;
+ }
+
+ return true;
+}
+
+void KeyframeList::insert(float key, PassRefPtr<RenderStyle> style)
+{
+ if (key < 0 || key > 1)
+ return;
+
+ int index = -1;
+
+ for (size_t i = 0; i < m_keyframes.size(); ++i) {
+ if (m_keyframes[i].m_key == key) {
+ index = (int) i;
+ break;
+ }
+ if (m_keyframes[i].m_key > key) {
+ // insert before
+ m_keyframes.insert(i, KeyframeValue());
+ index = (int) i;
+ break;
+ }
+ }
+
+ if (index < 0) {
+ // append
+ index = (int) m_keyframes.size();
+ m_keyframes.append(KeyframeValue());
+ }
+
+ m_keyframes[index].m_key = key;
+ m_keyframes[index].m_style = style;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/KeyframeList.h b/src/3rdparty/webkit/WebCore/rendering/style/KeyframeList.h
new file mode 100644
index 0000000..b1009d2
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/KeyframeList.h
@@ -0,0 +1,90 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 KeyframeList_h
+#define KeyframeList_h
+
+#include "AtomicString.h"
+#include <wtf/Vector.h>
+#include <wtf/HashSet.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class RenderObject;
+class RenderStyle;
+
+class KeyframeValue {
+public:
+ KeyframeValue()
+ : m_key(-1)
+ {
+ }
+
+ float key() const { return m_key; }
+ const RenderStyle* style() const { return m_style.get(); }
+
+ float m_key;
+ RefPtr<RenderStyle> m_style;
+};
+
+class KeyframeList {
+public:
+ KeyframeList(RenderObject* renderer, const AtomicString& animationName)
+ : m_animationName(animationName)
+ , m_renderer(renderer)
+ {
+ insert(0, 0);
+ insert(1, 0);
+ }
+ ~KeyframeList();
+
+ bool operator==(const KeyframeList& o) const;
+ bool operator!=(const KeyframeList& o) const { return !(*this == o); }
+
+ const AtomicString& animationName() const { return m_animationName; }
+
+ void insert(float key, PassRefPtr<RenderStyle> style);
+
+ void addProperty(int prop) { m_properties.add(prop); }
+ bool containsProperty(int prop) const { return m_properties.contains(prop); }
+ HashSet<int>::const_iterator beginProperties() const { return m_properties.begin(); }
+ HashSet<int>::const_iterator endProperties() const { return m_properties.end(); }
+
+ void clear();
+ bool isEmpty() const { return m_keyframes.isEmpty(); }
+ size_t size() const { return m_keyframes.size(); }
+ Vector<KeyframeValue>::const_iterator beginKeyframes() const { return m_keyframes.begin(); }
+ Vector<KeyframeValue>::const_iterator endKeyframes() const { return m_keyframes.end(); }
+
+private:
+ AtomicString m_animationName;
+ Vector<KeyframeValue> m_keyframes;
+ HashSet<int> m_properties; // the properties being animated
+ RenderObject* m_renderer;
+};
+
+} // namespace WebCore
+
+#endif // KeyframeList_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/NinePieceImage.cpp b/src/3rdparty/webkit/WebCore/rendering/style/NinePieceImage.cpp
new file mode 100644
index 0000000..d585e8f
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/NinePieceImage.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * 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 "NinePieceImage.h"
+
+namespace WebCore {
+
+bool NinePieceImage::operator==(const NinePieceImage& o) const
+{
+ return StyleImage::imagesEquivalent(m_image.get(), o.m_image.get()) && m_slices == o.m_slices && m_horizontalRule == o.m_horizontalRule &&
+ m_verticalRule == o.m_verticalRule;
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/NinePieceImage.h b/src/3rdparty/webkit/WebCore/rendering/style/NinePieceImage.h
new file mode 100644
index 0000000..bf47ce6
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/NinePieceImage.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ *
+ * 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 NinePieceImage_h
+#define NinePieceImage_h
+
+#include "LengthBox.h"
+#include "StyleImage.h"
+
+namespace WebCore {
+
+enum ENinePieceImageRule {
+ StretchImageRule, RoundImageRule, RepeatImageRule
+};
+
+class NinePieceImage {
+public:
+ NinePieceImage()
+ : m_image(0)
+ , m_horizontalRule(StretchImageRule)
+ , m_verticalRule(StretchImageRule)
+ {
+ }
+
+ NinePieceImage(StyleImage* image, LengthBox slices, ENinePieceImageRule h, ENinePieceImageRule v)
+ : m_image(image)
+ , m_slices(slices)
+ , m_horizontalRule(h)
+ , m_verticalRule(v)
+ {
+ }
+
+ bool operator==(const NinePieceImage& o) const;
+ bool operator!=(const NinePieceImage& o) const { return !(*this == o); }
+
+ bool hasImage() const { return m_image != 0; }
+ StyleImage* image() const { return m_image.get(); }
+
+ ENinePieceImageRule horizontalRule() const { return static_cast<ENinePieceImageRule>(m_horizontalRule); }
+ ENinePieceImageRule verticalRule() const { return static_cast<ENinePieceImageRule>(m_verticalRule); }
+
+ RefPtr<StyleImage> m_image;
+ LengthBox m_slices;
+ unsigned m_horizontalRule : 2; // ENinePieceImageRule
+ unsigned m_verticalRule : 2; // ENinePieceImageRule
+};
+
+} // namespace WebCore
+
+#endif // NinePieceImage_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/OutlineValue.h b/src/3rdparty/webkit/WebCore/rendering/style/OutlineValue.h
new file mode 100644
index 0000000..2628b7f
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/OutlineValue.h
@@ -0,0 +1,56 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 OutlineValue_h
+#define OutlineValue_h
+
+#include "BorderValue.h"
+
+namespace WebCore {
+
+class OutlineValue : public BorderValue {
+public:
+ OutlineValue()
+ : _offset(0)
+ , _auto(false)
+ {
+ }
+
+ bool operator==(const OutlineValue& o) const
+ {
+ return width == o.width && m_style == o.m_style && color == o.color && _offset == o._offset && _auto == o._auto;
+ }
+
+ bool operator!=(const OutlineValue& o) const
+ {
+ return !(*this == o);
+ }
+
+ int _offset;
+ bool _auto;
+};
+
+} // namespace WebCore
+
+#endif // OutlineValue_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp
new file mode 100644
index 0000000..872ee9c
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.cpp
@@ -0,0 +1,844 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "RenderStyle.h"
+
+#include "CSSStyleSelector.h"
+#include "CachedImage.h"
+#include "CounterContent.h"
+#include "FontSelector.h"
+#include "RenderArena.h"
+#include "RenderObject.h"
+#include "StyleImage.h"
+#include <wtf/StdLibExtras.h>
+#include <algorithm>
+
+namespace WebCore {
+
+TransformOperations RenderStyle::s_initialTransform;
+
+inline RenderStyle* defaultStyle()
+{
+ static RenderStyle* s_defaultStyle = RenderStyle::createDefaultStyle().releaseRef();
+ return s_defaultStyle;
+}
+
+PassRefPtr<RenderStyle> RenderStyle::create()
+{
+ return adoptRef(new RenderStyle());
+}
+
+PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle()
+{
+ return adoptRef(new RenderStyle(true));
+}
+
+PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other)
+{
+ return adoptRef(new RenderStyle(*other));
+}
+
+RenderStyle::RenderStyle()
+ : box(defaultStyle()->box)
+ , visual(defaultStyle()->visual)
+ , background(defaultStyle()->background)
+ , surround(defaultStyle()->surround)
+ , rareNonInheritedData(defaultStyle()->rareNonInheritedData)
+ , rareInheritedData(defaultStyle()->rareInheritedData)
+ , inherited(defaultStyle()->inherited)
+ , m_pseudoState(PseudoUnknown)
+ , m_affectedByAttributeSelectors(false)
+ , m_unique(false)
+ , m_affectedByEmpty(false)
+ , m_emptyState(false)
+ , m_childrenAffectedByFirstChildRules(false)
+ , m_childrenAffectedByLastChildRules(false)
+ , m_childrenAffectedByDirectAdjacentRules(false)
+ , m_childrenAffectedByForwardPositionalRules(false)
+ , m_childrenAffectedByBackwardPositionalRules(false)
+ , m_firstChildState(false)
+ , m_lastChildState(false)
+ , m_childIndex(0)
+#if ENABLE(SVG)
+ , m_svgStyle(defaultStyle()->m_svgStyle)
+#endif
+{
+ setBitDefaults(); // Would it be faster to copy this from the default style?
+}
+
+RenderStyle::RenderStyle(bool)
+ : m_pseudoState(PseudoUnknown)
+ , m_affectedByAttributeSelectors(false)
+ , m_unique(false)
+ , m_affectedByEmpty(false)
+ , m_emptyState(false)
+ , m_childrenAffectedByFirstChildRules(false)
+ , m_childrenAffectedByLastChildRules(false)
+ , m_childrenAffectedByDirectAdjacentRules(false)
+ , m_childrenAffectedByForwardPositionalRules(false)
+ , m_childrenAffectedByBackwardPositionalRules(false)
+ , m_firstChildState(false)
+ , m_lastChildState(false)
+ , m_childIndex(0)
+{
+ setBitDefaults();
+
+ box.init();
+ visual.init();
+ background.init();
+ surround.init();
+ rareNonInheritedData.init();
+ rareNonInheritedData.access()->flexibleBox.init();
+ rareNonInheritedData.access()->marquee.init();
+ rareNonInheritedData.access()->m_multiCol.init();
+ rareNonInheritedData.access()->m_transform.init();
+ rareInheritedData.init();
+ inherited.init();
+
+#if ENABLE(SVG)
+ m_svgStyle.init();
+#endif
+}
+
+RenderStyle::RenderStyle(const RenderStyle& o)
+ : RefCounted<RenderStyle>()
+ , inherited_flags(o.inherited_flags)
+ , noninherited_flags(o.noninherited_flags)
+ , box(o.box)
+ , visual(o.visual)
+ , background(o.background)
+ , surround(o.surround)
+ , rareNonInheritedData(o.rareNonInheritedData)
+ , rareInheritedData(o.rareInheritedData)
+ , inherited(o.inherited)
+ , m_pseudoState(o.m_pseudoState)
+ , m_affectedByAttributeSelectors(false)
+ , m_unique(false)
+ , m_affectedByEmpty(false)
+ , m_emptyState(false)
+ , m_childrenAffectedByFirstChildRules(false)
+ , m_childrenAffectedByLastChildRules(false)
+ , m_childrenAffectedByDirectAdjacentRules(false)
+ , m_childrenAffectedByForwardPositionalRules(false)
+ , m_childrenAffectedByBackwardPositionalRules(false)
+ , m_firstChildState(false)
+ , m_lastChildState(false)
+ , m_childIndex(0)
+#if ENABLE(SVG)
+ , m_svgStyle(o.m_svgStyle)
+#endif
+{
+}
+
+void RenderStyle::inheritFrom(const RenderStyle* inheritParent)
+{
+ rareInheritedData = inheritParent->rareInheritedData;
+ inherited = inheritParent->inherited;
+ inherited_flags = inheritParent->inherited_flags;
+#if ENABLE(SVG)
+ if (m_svgStyle != inheritParent->m_svgStyle)
+ m_svgStyle.access()->inheritFrom(inheritParent->m_svgStyle.get());
+#endif
+}
+
+RenderStyle::~RenderStyle()
+{
+}
+
+bool RenderStyle::operator==(const RenderStyle& o) const
+{
+ // compare everything except the pseudoStyle pointer
+ return inherited_flags == o.inherited_flags &&
+ noninherited_flags == o.noninherited_flags &&
+ box == o.box &&
+ visual == o.visual &&
+ background == o.background &&
+ surround == o.surround &&
+ rareNonInheritedData == o.rareNonInheritedData &&
+ rareInheritedData == o.rareInheritedData &&
+ inherited == o.inherited
+#if ENABLE(SVG)
+ && m_svgStyle == o.m_svgStyle
+#endif
+ ;
+}
+
+bool RenderStyle::isStyleAvailable() const
+{
+ return this != CSSStyleSelector::styleNotYetAvailable();
+}
+
+static inline int pseudoBit(RenderStyle::PseudoId pseudo)
+{
+ return 1 << (pseudo - 1);
+}
+
+bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const
+{
+ ASSERT(pseudo > NOPSEUDO);
+ ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
+ return pseudoBit(pseudo) & noninherited_flags._pseudoBits;
+}
+
+void RenderStyle::setHasPseudoStyle(PseudoId pseudo)
+{
+ ASSERT(pseudo > NOPSEUDO);
+ ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
+ noninherited_flags._pseudoBits |= pseudoBit(pseudo);
+}
+
+RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid)
+{
+ if (!m_cachedPseudoStyle || styleType() != NOPSEUDO)
+ return 0;
+ RenderStyle* ps = m_cachedPseudoStyle.get();
+ while (ps && ps->styleType() != pid)
+ ps = ps->m_cachedPseudoStyle.get();
+ return ps;
+}
+
+RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo)
+{
+ if (!pseudo)
+ return 0;
+ pseudo->m_cachedPseudoStyle = m_cachedPseudoStyle;
+ m_cachedPseudoStyle = pseudo;
+ return m_cachedPseudoStyle.get();
+}
+
+bool RenderStyle::inheritedNotEqual(RenderStyle* other) const
+{
+ return inherited_flags != other->inherited_flags ||
+ inherited != other->inherited ||
+#if ENABLE(SVG)
+ m_svgStyle->inheritedNotEqual(other->m_svgStyle.get()) ||
+#endif
+ rareInheritedData != other->rareInheritedData;
+}
+
+bool positionedObjectMoved(const LengthBox& a, const LengthBox& b)
+{
+ // If any unit types are different, then we can't guarantee
+ // that this was just a movement.
+ if (a.left().type() != b.left().type() ||
+ a.right().type() != b.right().type() ||
+ a.top().type() != b.top().type() ||
+ a.bottom().type() != b.bottom().type())
+ return false;
+
+ // Only one unit can be non-auto in the horizontal direction and
+ // in the vertical direction. Otherwise the adjustment of values
+ // is changing the size of the box.
+ if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto())
+ return false;
+ if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto())
+ return false;
+
+ // One of the units is fixed or percent in both directions and stayed
+ // that way in the new style. Therefore all we are doing is moving.
+ return true;
+}
+
+/*
+ compares two styles. The result gives an idea of the action that
+ needs to be taken when replacing the old style with a new one.
+
+ CbLayout: The containing block of the object needs a relayout.
+ Layout: the RenderObject needs a relayout after the style change
+ Visible: The change is visible, but no relayout is needed
+ NonVisible: The object does need neither repaint nor relayout after
+ the change.
+
+ ### TODO:
+ A lot can be optimised here based on the display type, lots of
+ optimisations are unimplemented, and currently result in the
+ worst case result causing a relayout of the containing block.
+*/
+RenderStyle::Diff RenderStyle::diff(const RenderStyle* other) const
+{
+#if ENABLE(SVG)
+ // This is horribly inefficient. Eventually we'll have to integrate
+ // this more directly by calling: Diff svgDiff = svgStyle->diff(other)
+ // and then checking svgDiff and returning from the appropriate places below.
+ if (m_svgStyle != other->m_svgStyle)
+ return Layout;
+#endif
+
+ if (box->width != other->box->width ||
+ box->min_width != other->box->min_width ||
+ box->max_width != other->box->max_width ||
+ box->height != other->box->height ||
+ box->min_height != other->box->min_height ||
+ box->max_height != other->box->max_height)
+ return Layout;
+
+ if (box->vertical_align != other->box->vertical_align || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align)
+ return Layout;
+
+ if (box->boxSizing != other->box->boxSizing)
+ return Layout;
+
+ if (surround->margin != other->surround->margin)
+ return Layout;
+
+ if (surround->padding != other->surround->padding)
+ return Layout;
+
+ if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
+ if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance ||
+ rareNonInheritedData->marginTopCollapse != other->rareNonInheritedData->marginTopCollapse ||
+ rareNonInheritedData->marginBottomCollapse != other->rareNonInheritedData->marginBottomCollapse ||
+ rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp ||
+ rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow)
+ return Layout;
+
+ if (rareNonInheritedData->flexibleBox.get() != other->rareNonInheritedData->flexibleBox.get() &&
+ *rareNonInheritedData->flexibleBox.get() != *other->rareNonInheritedData->flexibleBox.get())
+ return Layout;
+
+ if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get()))
+ return Layout;
+
+ if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get()))
+ return Layout;
+
+ if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get() &&
+ *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get())
+ return Layout;
+
+ if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get() &&
+ *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get())
+ return Layout;
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ // If regions change, trigger a relayout to re-calc regions.
+ if (rareNonInheritedData->m_dashboardRegions != other->rareNonInheritedData->m_dashboardRegions)
+ return Layout;
+#endif
+ }
+
+ if (rareInheritedData.get() != other->rareInheritedData.get()) {
+ if (rareInheritedData->highlight != other->rareInheritedData->highlight ||
+ rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust ||
+ rareInheritedData->wordBreak != other->rareInheritedData->wordBreak ||
+ rareInheritedData->wordWrap != other->rareInheritedData->wordWrap ||
+ rareInheritedData->nbspMode != other->rareInheritedData->nbspMode ||
+ rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak ||
+ rareInheritedData->textSecurity != other->rareInheritedData->textSecurity)
+ return Layout;
+
+ if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get()))
+ return Layout;
+
+ if (textStrokeWidth() != other->textStrokeWidth())
+ return Layout;
+ }
+
+ if (inherited->indent != other->inherited->indent ||
+ inherited->line_height != other->inherited->line_height ||
+ inherited->list_style_image != other->inherited->list_style_image ||
+ inherited->font != other->inherited->font ||
+ inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing ||
+ inherited->vertical_border_spacing != other->inherited->vertical_border_spacing ||
+ inherited_flags._box_direction != other->inherited_flags._box_direction ||
+ inherited_flags._visuallyOrdered != other->inherited_flags._visuallyOrdered ||
+ inherited_flags._htmlHacks != other->inherited_flags._htmlHacks ||
+ noninherited_flags._position != other->noninherited_flags._position ||
+ noninherited_flags._floating != other->noninherited_flags._floating ||
+ noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay)
+ return Layout;
+
+
+ if (((int)noninherited_flags._effectiveDisplay) >= TABLE) {
+ if (inherited_flags._border_collapse != other->inherited_flags._border_collapse ||
+ inherited_flags._empty_cells != other->inherited_flags._empty_cells ||
+ inherited_flags._caption_side != other->inherited_flags._caption_side ||
+ noninherited_flags._table_layout != other->noninherited_flags._table_layout)
+ return Layout;
+
+ // In the collapsing border model, 'hidden' suppresses other borders, while 'none'
+ // does not, so these style differences can be width differences.
+ if (inherited_flags._border_collapse &&
+ (borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE ||
+ borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN ||
+ borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE ||
+ borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN ||
+ borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE ||
+ borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN ||
+ borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE ||
+ borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN))
+ return Layout;
+ }
+
+ if (noninherited_flags._effectiveDisplay == LIST_ITEM) {
+ if (inherited_flags._list_style_type != other->inherited_flags._list_style_type ||
+ inherited_flags._list_style_position != other->inherited_flags._list_style_position)
+ return Layout;
+ }
+
+ if (inherited_flags._text_align != other->inherited_flags._text_align ||
+ inherited_flags._text_transform != other->inherited_flags._text_transform ||
+ inherited_flags._direction != other->inherited_flags._direction ||
+ inherited_flags._white_space != other->inherited_flags._white_space ||
+ noninherited_flags._clear != other->noninherited_flags._clear)
+ return Layout;
+
+ // Overflow returns a layout hint.
+ if (noninherited_flags._overflowX != other->noninherited_flags._overflowX ||
+ noninherited_flags._overflowY != other->noninherited_flags._overflowY)
+ return Layout;
+
+ // If our border widths change, then we need to layout. Other changes to borders
+ // only necessitate a repaint.
+ if (borderLeftWidth() != other->borderLeftWidth() ||
+ borderTopWidth() != other->borderTopWidth() ||
+ borderBottomWidth() != other->borderBottomWidth() ||
+ borderRightWidth() != other->borderRightWidth())
+ return Layout;
+
+ // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree.
+ const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get();
+ const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get();
+ if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB)))
+ return Layout;
+ if (visual->counterIncrement != other->visual->counterIncrement ||
+ visual->counterReset != other->visual->counterReset)
+ return Layout;
+
+ if (inherited->m_effectiveZoom != other->inherited->m_effectiveZoom)
+ return Layout;
+
+ // Make sure these left/top/right/bottom checks stay below all layout checks and above
+ // all visible checks.
+ if (position() != StaticPosition) {
+ if (surround->offset != other->surround->offset) {
+ // Optimize for the case where a positioned layer is moving but not changing size.
+ if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset))
+ return LayoutPositionedMovementOnly;
+
+ // FIXME: We will need to do a bit of work in RenderObject/Box::setStyle before we
+ // can stop doing a layout when relative positioned objects move. In particular, we'll need
+ // to update scrolling positions and figure out how to do a repaint properly of the updated layer.
+ //if (other->position() == RelativePosition)
+ // return RepaintLayer;
+ //else
+ return Layout;
+ } else if (box->z_index != other->box->z_index || box->z_auto != other->box->z_auto ||
+ visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip)
+ return RepaintLayer;
+ }
+
+ if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity ||
+ rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask ||
+ rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage)
+ return RepaintLayer;
+
+ if (inherited->color != other->inherited->color ||
+ inherited_flags._visibility != other->inherited_flags._visibility ||
+ inherited_flags._text_decorations != other->inherited_flags._text_decorations ||
+ inherited_flags._force_backgrounds_to_white != other->inherited_flags._force_backgrounds_to_white ||
+ surround->border != other->surround->border ||
+ *background.get() != *other->background.get() ||
+ visual->textDecoration != other->visual->textDecoration ||
+ rareInheritedData->userModify != other->rareInheritedData->userModify ||
+ rareInheritedData->userSelect != other->rareInheritedData->userSelect ||
+ rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag ||
+ rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit ||
+ rareInheritedData->textFillColor != other->rareInheritedData->textFillColor ||
+ rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor)
+ return Repaint;
+
+ // Cursors are not checked, since they will be set appropriately in response to mouse events,
+ // so they don't need to cause any repaint or layout.
+
+ // Animations don't need to be checked either. We always set the new style on the RenderObject, so we will get a chance to fire off
+ // the resulting transition properly.
+ return Equal;
+}
+
+void RenderStyle::setClip(Length top, Length right, Length bottom, Length left)
+{
+ StyleVisualData *data = visual.access();
+ data->clip.m_top = top;
+ data->clip.m_right = right;
+ data->clip.m_bottom = bottom;
+ data->clip.m_left = left;
+}
+
+void RenderStyle::addCursor(CachedImage* image, const IntPoint& hotSpot)
+{
+ CursorData data;
+ data.cursorImage = image;
+ data.hotSpot = hotSpot;
+ if (!inherited.access()->cursorData)
+ inherited.access()->cursorData = CursorList::create();
+ inherited.access()->cursorData->append(data);
+}
+
+void RenderStyle::setCursorList(PassRefPtr<CursorList> other)
+{
+ inherited.access()->cursorData = other;
+}
+
+void RenderStyle::clearCursorList()
+{
+ inherited.access()->cursorData = CursorList::create();
+}
+
+bool RenderStyle::contentDataEquivalent(const RenderStyle* otherStyle) const
+{
+ ContentData* c1 = rareNonInheritedData->m_content.get();
+ ContentData* c2 = otherStyle->rareNonInheritedData->m_content.get();
+
+ while (c1 && c2) {
+ if (c1->m_type != c2->m_type)
+ return false;
+
+ switch (c1->m_type) {
+ case CONTENT_NONE:
+ break;
+ case CONTENT_TEXT:
+ if (!equal(c1->m_content.m_text, c2->m_content.m_text))
+ return false;
+ break;
+ case CONTENT_OBJECT:
+ if (!StyleImage::imagesEquivalent(c1->m_content.m_image, c2->m_content.m_image))
+ return false;
+ break;
+ case CONTENT_COUNTER:
+ if (*c1->m_content.m_counter != *c2->m_content.m_counter)
+ return false;
+ break;
+ }
+
+ c1 = c1->m_next;
+ c2 = c2->m_next;
+ }
+
+ return !c1 && !c2;
+}
+
+void RenderStyle::clearContent()
+{
+ if (rareNonInheritedData->m_content)
+ rareNonInheritedData->m_content->clear();
+}
+
+void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add)
+{
+ if (!image)
+ return; // The object is null. Nothing to do. Just bail.
+
+ OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
+ ContentData* lastContent = content.get();
+ while (lastContent && lastContent->m_next)
+ lastContent = lastContent->m_next;
+
+ bool reuseContent = !add;
+ ContentData* newContentData;
+ if (reuseContent && content) {
+ content->clear();
+ newContentData = content.release();
+ } else
+ newContentData = new ContentData;
+
+ if (lastContent && !reuseContent)
+ lastContent->m_next = newContentData;
+ else
+ content.set(newContentData);
+
+ newContentData->m_content.m_image = image.releaseRef();
+ newContentData->m_type = CONTENT_OBJECT;
+}
+
+void RenderStyle::setContent(StringImpl* s, bool add)
+{
+ if (!s)
+ return; // The string is null. Nothing to do. Just bail.
+
+ OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
+ ContentData* lastContent = content.get();
+ while (lastContent && lastContent->m_next)
+ lastContent = lastContent->m_next;
+
+ bool reuseContent = !add;
+ if (add && lastContent) {
+ if (lastContent->m_type == CONTENT_TEXT) {
+ // We can augment the existing string and share this ContentData node.
+ StringImpl* oldStr = lastContent->m_content.m_text;
+ String newStr = oldStr;
+ newStr.append(s);
+ newStr.impl()->ref();
+ oldStr->deref();
+ lastContent->m_content.m_text = newStr.impl();
+ return;
+ }
+ }
+
+ ContentData* newContentData = 0;
+ if (reuseContent && content) {
+ content->clear();
+ newContentData = content.release();
+ } else
+ newContentData = new ContentData;
+
+ if (lastContent && !reuseContent)
+ lastContent->m_next = newContentData;
+ else
+ content.set(newContentData);
+
+ newContentData->m_content.m_text = s;
+ newContentData->m_content.m_text->ref();
+ newContentData->m_type = CONTENT_TEXT;
+}
+
+void RenderStyle::setContent(CounterContent* c, bool add)
+{
+ if (!c)
+ return;
+
+ OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
+ ContentData* lastContent = content.get();
+ while (lastContent && lastContent->m_next)
+ lastContent = lastContent->m_next;
+
+ bool reuseContent = !add;
+ ContentData* newContentData = 0;
+ if (reuseContent && content) {
+ content->clear();
+ newContentData = content.release();
+ } else
+ newContentData = new ContentData;
+
+ if (lastContent && !reuseContent)
+ lastContent->m_next = newContentData;
+ else
+ content.set(newContentData);
+
+ newContentData->m_content.m_counter = c;
+ newContentData->m_type = CONTENT_COUNTER;
+}
+
+void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& borderBoxSize, bool includeTransformOrigin) const
+{
+ // transform-origin brackets the transform with translate operations.
+ // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant
+ // in that case.
+ bool applyTransformOrigin = false;
+ unsigned s = rareNonInheritedData->m_transform->m_operations.operations().size();
+ unsigned i;
+ if (includeTransformOrigin) {
+ for (i = 0; i < s; i++) {
+ TransformOperation::OperationType type = rareNonInheritedData->m_transform->m_operations.operations()[i]->getOperationType();
+ if (type != TransformOperation::TRANSLATE_X &&
+ type != TransformOperation::TRANSLATE_Y &&
+ type != TransformOperation::TRANSLATE) {
+ applyTransformOrigin = true;
+ break;
+ }
+ }
+ }
+
+ if (applyTransformOrigin)
+ transform.translate(transformOriginX().calcFloatValue(borderBoxSize.width()), transformOriginY().calcFloatValue(borderBoxSize.height()));
+
+ for (i = 0; i < s; i++)
+ rareNonInheritedData->m_transform->m_operations.operations()[i]->apply(transform, borderBoxSize);
+
+ if (applyTransformOrigin)
+ transform.translate(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height()));
+}
+
+#if ENABLE(XBL)
+void RenderStyle::addBindingURI(StringImpl* uri)
+{
+ BindingURI* binding = new BindingURI(uri);
+ if (!bindingURIs())
+ SET_VAR(rareNonInheritedData, bindingURI, binding)
+ else
+ for (BindingURI* b = bindingURIs(); b; b = b->next()) {
+ if (!b->next())
+ b->setNext(binding);
+ }
+}
+#endif
+
+void RenderStyle::setTextShadow(ShadowData* val, bool add)
+{
+ StyleRareInheritedData* rareData = rareInheritedData.access();
+ if (!add) {
+ delete rareData->textShadow;
+ rareData->textShadow = val;
+ return;
+ }
+
+ val->next = rareData->textShadow;
+ rareData->textShadow = val;
+}
+
+void RenderStyle::setBoxShadow(ShadowData* shadowData, bool add)
+{
+ StyleRareNonInheritedData* rareData = rareNonInheritedData.access();
+ if (!add) {
+ rareData->m_boxShadow.set(shadowData);
+ return;
+ }
+
+ shadowData->next = rareData->m_boxShadow.release();
+ rareData->m_boxShadow.set(shadowData);
+}
+
+const CounterDirectiveMap* RenderStyle::counterDirectives() const
+{
+ return rareNonInheritedData->m_counterDirectives.get();
+}
+
+CounterDirectiveMap& RenderStyle::accessCounterDirectives()
+{
+ OwnPtr<CounterDirectiveMap>& map = rareNonInheritedData.access()->m_counterDirectives;
+ if (!map)
+ map.set(new CounterDirectiveMap);
+ return *map.get();
+}
+
+#if ENABLE(DASHBOARD_SUPPORT)
+const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions()
+{
+ DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ());
+ return emptyList;
+}
+
+const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions()
+{
+ DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, noneList, ());
+ static bool noneListInitialized = false;
+
+ if (!noneListInitialized) {
+ StyleDashboardRegion region;
+ region.label = "";
+ region.offset.m_top = Length();
+ region.offset.m_right = Length();
+ region.offset.m_bottom = Length();
+ region.offset.m_left = Length();
+ region.type = StyleDashboardRegion::None;
+ noneList.append(region);
+ noneListInitialized = true;
+ }
+ return noneList;
+}
+#endif
+
+void RenderStyle::adjustAnimations()
+{
+ AnimationList* animationList = rareNonInheritedData->m_animations.get();
+ if (!animationList)
+ return;
+
+ // get rid of empty transitions and anything beyond them
+ for (size_t i = 0; i < animationList->size(); ++i) {
+ if (animationList->animation(i)->isEmpty()) {
+ animationList->resize(i);
+ break;
+ }
+ }
+
+ if (animationList->isEmpty()) {
+ clearAnimations();
+ return;
+ }
+
+ // Repeat patterns into layers that don't have some properties set.
+ animationList->fillUnsetProperties();
+}
+
+void RenderStyle::adjustTransitions()
+{
+ AnimationList* transitionList = rareNonInheritedData->m_transitions.get();
+ if (!transitionList)
+ return;
+
+ // get rid of empty transitions and anything beyond them
+ for (size_t i = 0; i < transitionList->size(); ++i) {
+ if (transitionList->animation(i)->isEmpty()) {
+ transitionList->resize(i);
+ break;
+ }
+ }
+
+ if (transitionList->isEmpty()) {
+ clearTransitions();
+ return;
+ }
+
+ // Repeat patterns into layers that don't have some properties set.
+ transitionList->fillUnsetProperties();
+
+ // Make sure there are no duplicate properties. This is an O(n^2) algorithm
+ // but the lists tend to be very short, so it is probably ok
+ for (size_t i = 0; i < transitionList->size(); ++i) {
+ for (size_t j = i+1; j < transitionList->size(); ++j) {
+ if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) {
+ // toss i
+ transitionList->remove(i);
+ j = i;
+ }
+ }
+ }
+}
+
+AnimationList* RenderStyle::accessAnimations()
+{
+ if (!rareNonInheritedData.access()->m_animations)
+ rareNonInheritedData.access()->m_animations.set(new AnimationList());
+ return rareNonInheritedData->m_animations.get();
+}
+
+AnimationList* RenderStyle::accessTransitions()
+{
+ if (!rareNonInheritedData.access()->m_transitions)
+ rareNonInheritedData.access()->m_transitions.set(new AnimationList());
+ return rareNonInheritedData->m_transitions.get();
+}
+
+const Animation* RenderStyle::transitionForProperty(int property)
+{
+ if (transitions()) {
+ for (size_t i = 0; i < transitions()->size(); ++i) {
+ const Animation* p = transitions()->animation(i);
+ if (p->property() == cAnimateAll || p->property() == property) {
+ return p;
+ }
+ }
+ }
+ return 0;
+}
+
+void RenderStyle::setBlendedFontSize(int size)
+{
+ FontDescription desc(fontDescription());
+ desc.setSpecifiedSize(size);
+ desc.setComputedSize(size);
+ setFontDescription(desc);
+ font().update(font().fontSelector());
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h
new file mode 100644
index 0000000..f38f943
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyle.h
@@ -0,0 +1,1129 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 RenderStyle_h
+#define RenderStyle_h
+
+#include "TransformationMatrix.h"
+#include "AnimationList.h"
+#include "BorderData.h"
+#include "BorderValue.h"
+#include "CSSHelper.h"
+#include "CSSImageGeneratorValue.h"
+#include "CSSPrimitiveValue.h"
+#include "CSSReflectionDirection.h"
+#include "CSSValueList.h"
+#include "CachedImage.h"
+#include "CollapsedBorderValue.h"
+#include "Color.h"
+#include "ContentData.h"
+#include "CounterDirectives.h"
+#include "CursorList.h"
+#include "DataRef.h"
+#include "FillLayer.h"
+#include "FloatPoint.h"
+#include "Font.h"
+#include "GraphicsTypes.h"
+#include "IntRect.h"
+#include "Length.h"
+#include "LengthBox.h"
+#include "LengthSize.h"
+#include "NinePieceImage.h"
+#include "OutlineValue.h"
+#include "Pair.h"
+#include "RenderStyleConstants.h"
+#include "ShadowData.h"
+#include "StyleBackgroundData.h"
+#include "StyleBoxData.h"
+#include "StyleFlexibleBoxData.h"
+#include "StyleInheritedData.h"
+#include "StyleMarqueeData.h"
+#include "StyleMultiColData.h"
+#include "StyleRareInheritedData.h"
+#include "StyleRareNonInheritedData.h"
+#include "StyleReflection.h"
+#include "StyleSurroundData.h"
+#include "StyleTransformData.h"
+#include "StyleVisualData.h"
+#include "TextDirection.h"
+#include "ThemeTypes.h"
+#include "TimingFunction.h"
+#include "TransformOperations.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+#if ENABLE(DASHBOARD_SUPPORT)
+#include "StyleDashboardRegion.h"
+#endif
+
+#if ENABLE(SVG)
+#include "SVGRenderStyle.h"
+#endif
+
+#if ENABLE(XBL)
+#include "BindingURI.h"
+#endif
+
+template<typename T, typename U> inline bool compareEqual(const T& t, const U& u) { return t == static_cast<T>(u); }
+
+#define SET_VAR(group, variable, value) \
+ if (!compareEqual(group->variable, value)) \
+ group.access()->variable = value;
+
+namespace WebCore {
+
+using std::max;
+
+class CSSStyleSelector;
+class CSSValueList;
+class CachedImage;
+class Pair;
+class StringImpl;
+class StyleImage;
+
+class RenderStyle: public RefCounted<RenderStyle> {
+ friend class CSSStyleSelector;
+
+public:
+ // static pseudo styles. Dynamic ones are produced on the fly.
+ 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_TIME_DISPLAY,
+ MEDIA_CONTROLS_SEEK_BACK_BUTTON, MEDIA_CONTROLS_SEEK_FORWARD_BUTTON , MEDIA_CONTROLS_FULLSCREEN_BUTTON,
+ SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER };
+ static const int FIRST_INTERNAL_PSEUDOID = FILE_UPLOAD_BUTTON;
+
+private:
+ static TransformOperations s_initialTransform;
+
+protected:
+
+// !START SYNC!: Keep this in sync with the copy constructor in RenderStyle.cpp
+
+ // inherit
+ struct InheritedFlags {
+ bool operator==(const InheritedFlags& other) const
+ {
+ return (_empty_cells == other._empty_cells) &&
+ (_caption_side == other._caption_side) &&
+ (_list_style_type == other._list_style_type) &&
+ (_list_style_position == other._list_style_position) &&
+ (_visibility == other._visibility) &&
+ (_text_align == other._text_align) &&
+ (_text_transform == other._text_transform) &&
+ (_text_decorations == other._text_decorations) &&
+ (_text_transform == other._text_transform) &&
+ (_cursor_style == other._cursor_style) &&
+ (_direction == other._direction) &&
+ (_border_collapse == other._border_collapse) &&
+ (_white_space == other._white_space) &&
+ (_box_direction == other._box_direction) &&
+ (_visuallyOrdered == other._visuallyOrdered) &&
+ (_htmlHacks == other._htmlHacks) &&
+ (_force_backgrounds_to_white == other._force_backgrounds_to_white) &&
+ (_pointerEvents == other._pointerEvents);
+ }
+
+ bool operator!=(const InheritedFlags& other) const { return !(*this == other); }
+
+ unsigned _empty_cells : 1; // EEmptyCell
+ unsigned _caption_side : 2; // ECaptionSide
+ unsigned _list_style_type : 5 ; // EListStyleType
+ unsigned _list_style_position : 1; // EListStylePosition
+ unsigned _visibility : 2; // EVisibility
+ unsigned _text_align : 3; // ETextAlign
+ unsigned _text_transform : 2; // ETextTransform
+ unsigned _text_decorations : 4;
+ unsigned _cursor_style : 6; // ECursor
+ unsigned _direction : 1; // TextDirection
+ bool _border_collapse : 1 ;
+ unsigned _white_space : 3; // EWhiteSpace
+ unsigned _box_direction : 1; // EBoxDirection (CSS3 box_direction property, flexible box layout module)
+
+ // non CSS2 inherited
+ bool _visuallyOrdered : 1;
+ bool _htmlHacks :1;
+ bool _force_backgrounds_to_white : 1;
+ unsigned _pointerEvents : 4; // EPointerEvents
+ } 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);
+ }
+
+ bool operator!=(const NonInheritedFlags& other) const { return !(*this == other); }
+
+ unsigned _effectiveDisplay : 5; // EDisplay
+ unsigned _originalDisplay : 5; // EDisplay
+ unsigned _overflowX : 3; // EOverflow
+ unsigned _overflowY : 3; // EOverflow
+ unsigned _vertical_align : 4; // EVerticalAlign
+ unsigned _clear : 2; // EClear
+ unsigned _position : 2; // EPosition
+ unsigned _floating : 2; // EFloat
+ unsigned _table_layout : 1; // ETableLayout
+
+ unsigned _page_break_before : 2; // EPageBreak
+ unsigned _page_break_after : 2; // EPageBreak
+
+ unsigned _styleType : 5; // PseudoId
+ bool _affectedByHover : 1;
+ bool _affectedByActive : 1;
+ bool _affectedByDrag : 1;
+ unsigned _pseudoBits : 7;
+ unsigned _unicodeBidi : 2; // EUnicodeBidi
+ } noninherited_flags;
+
+ // non-inherited attributes
+ DataRef<StyleBoxData> box;
+ DataRef<StyleVisualData> visual;
+ DataRef<StyleBackgroundData> background;
+ DataRef<StyleSurroundData> surround;
+ DataRef<StyleRareNonInheritedData> rareNonInheritedData;
+
+ // inherited attributes
+ DataRef<StyleRareInheritedData> rareInheritedData;
+ DataRef<StyleInheritedData> inherited;
+
+ // list of associated pseudo styles
+ RefPtr<RenderStyle> m_cachedPseudoStyle;
+
+ unsigned m_pseudoState : 3; // PseudoState
+ bool m_affectedByAttributeSelectors : 1;
+ bool m_unique : 1;
+
+ // Bits for dynamic child matching.
+ bool m_affectedByEmpty : 1;
+ bool m_emptyState : 1;
+
+ // We optimize for :first-child and :last-child. The other positional child selectors like nth-child or
+ // *-child-of-type, we will just give up and re-evaluate whenever children change at all.
+ bool m_childrenAffectedByFirstChildRules : 1;
+ bool m_childrenAffectedByLastChildRules : 1;
+ bool m_childrenAffectedByDirectAdjacentRules : 1;
+ bool m_childrenAffectedByForwardPositionalRules : 1;
+ bool m_childrenAffectedByBackwardPositionalRules : 1;
+ bool m_firstChildState : 1;
+ bool m_lastChildState : 1;
+ unsigned m_childIndex : 18; // Plenty of bits to cache an index.
+
+#if ENABLE(SVG)
+ DataRef<SVGRenderStyle> m_svgStyle;
+#endif
+
+// !END SYNC!
+
+protected:
+ void setBitDefaults()
+ {
+ inherited_flags._empty_cells = initialEmptyCells();
+ inherited_flags._caption_side = initialCaptionSide();
+ inherited_flags._list_style_type = initialListStyleType();
+ inherited_flags._list_style_position = initialListStylePosition();
+ inherited_flags._visibility = initialVisibility();
+ inherited_flags._text_align = initialTextAlign();
+ inherited_flags._text_transform = initialTextTransform();
+ inherited_flags._text_decorations = initialTextDecoration();
+ inherited_flags._cursor_style = initialCursor();
+ inherited_flags._direction = initialDirection();
+ inherited_flags._border_collapse = initialBorderCollapse();
+ inherited_flags._white_space = initialWhiteSpace();
+ inherited_flags._visuallyOrdered = initialVisuallyOrdered();
+ inherited_flags._htmlHacks=false;
+ inherited_flags._box_direction = initialBoxDirection();
+ inherited_flags._force_backgrounds_to_white = false;
+ inherited_flags._pointerEvents = initialPointerEvents();
+
+ noninherited_flags._effectiveDisplay = noninherited_flags._originalDisplay = initialDisplay();
+ noninherited_flags._overflowX = initialOverflowX();
+ noninherited_flags._overflowY = initialOverflowY();
+ noninherited_flags._vertical_align = initialVerticalAlign();
+ noninherited_flags._clear = initialClear();
+ noninherited_flags._position = initialPosition();
+ noninherited_flags._floating = initialFloating();
+ noninherited_flags._table_layout = initialTableLayout();
+ noninherited_flags._page_break_before = initialPageBreak();
+ noninherited_flags._page_break_after = initialPageBreak();
+ noninherited_flags._styleType = NOPSEUDO;
+ noninherited_flags._affectedByHover = false;
+ noninherited_flags._affectedByActive = false;
+ noninherited_flags._affectedByDrag = false;
+ noninherited_flags._pseudoBits = 0;
+ noninherited_flags._unicodeBidi = initialUnicodeBidi();
+ }
+
+protected:
+ RenderStyle();
+ // used to create the default style.
+ RenderStyle(bool);
+ RenderStyle(const RenderStyle&);
+
+public:
+ static PassRefPtr<RenderStyle> create();
+ static PassRefPtr<RenderStyle> createDefaultStyle();
+ static PassRefPtr<RenderStyle> clone(const RenderStyle*);
+
+ ~RenderStyle();
+
+ void inheritFrom(const RenderStyle* inheritParent);
+
+ PseudoId styleType() { return static_cast<PseudoId>(noninherited_flags._styleType); }
+ void setStyleType(PseudoId styleType) { noninherited_flags._styleType = styleType; }
+
+ RenderStyle* getCachedPseudoStyle(PseudoId);
+ RenderStyle* addCachedPseudoStyle(PassRefPtr<RenderStyle>);
+
+ bool affectedByHoverRules() const { return noninherited_flags._affectedByHover; }
+ bool affectedByActiveRules() const { return noninherited_flags._affectedByActive; }
+ bool affectedByDragRules() const { return noninherited_flags._affectedByDrag; }
+
+ void setAffectedByHoverRules(bool b) { noninherited_flags._affectedByHover = b; }
+ void setAffectedByActiveRules(bool b) { noninherited_flags._affectedByActive = b; }
+ void setAffectedByDragRules(bool b) { noninherited_flags._affectedByDrag = b; }
+
+ bool operator==(const RenderStyle& other) const;
+ bool operator!=(const RenderStyle& other) const { return !(*this == other); }
+ bool isFloating() const { return !(noninherited_flags._floating == FNONE); }
+ bool hasMargin() const { return surround->margin.nonZero(); }
+ bool hasBorder() const { return surround->border.hasBorder(); }
+ bool hasPadding() const { return surround->padding.nonZero(); }
+ bool hasOffset() const { return surround->offset.nonZero(); }
+
+ bool hasBackground() const
+ {
+ if (backgroundColor().isValid() && backgroundColor().alpha() > 0)
+ return true;
+ return background->m_background.hasImage();
+ }
+ bool hasFixedBackgroundImage() const { return background->m_background.hasFixedImage(); }
+ bool hasAppearance() const { return appearance() != NoControlPart; }
+
+ bool visuallyOrdered() const { return inherited_flags._visuallyOrdered; }
+ void setVisuallyOrdered(bool b) { inherited_flags._visuallyOrdered = b; }
+
+ bool isStyleAvailable() const;
+
+ bool hasPseudoStyle(PseudoId pseudo) const;
+ void setHasPseudoStyle(PseudoId pseudo);
+
+ // attribute getter methods
+
+ EDisplay display() const { return static_cast<EDisplay>(noninherited_flags._effectiveDisplay); }
+ EDisplay originalDisplay() const { return static_cast<EDisplay>(noninherited_flags._originalDisplay); }
+
+ Length left() const { return surround->offset.left(); }
+ Length right() const { return surround->offset.right(); }
+ Length top() const { return surround->offset.top(); }
+ Length bottom() const { return surround->offset.bottom(); }
+
+ EPosition position() const { return static_cast<EPosition>(noninherited_flags._position); }
+ EFloat floating() const { return static_cast<EFloat>(noninherited_flags._floating); }
+
+ Length width() const { return box->width; }
+ Length height() const { return box->height; }
+ Length minWidth() const { return box->min_width; }
+ Length maxWidth() const { return box->max_width; }
+ Length minHeight() const { return box->min_height; }
+ Length maxHeight() const { return box->max_height; }
+
+ const BorderData& border() const { return surround->border; }
+ const BorderValue& borderLeft() const { return surround->border.left; }
+ const BorderValue& borderRight() const { return surround->border.right; }
+ const BorderValue& borderTop() const { return surround->border.top; }
+ const BorderValue& borderBottom() const { return surround->border.bottom; }
+
+ const NinePieceImage& borderImage() const { return surround->border.image; }
+
+ const IntSize& borderTopLeftRadius() const { return surround->border.topLeft; }
+ const IntSize& borderTopRightRadius() const { return surround->border.topRight; }
+ const IntSize& borderBottomLeftRadius() const { return surround->border.bottomLeft; }
+ const IntSize& borderBottomRightRadius() const { return surround->border.bottomRight; }
+ bool hasBorderRadius() const { return surround->border.hasBorderRadius(); }
+
+ unsigned short borderLeftWidth() const { return surround->border.borderLeftWidth(); }
+ EBorderStyle borderLeftStyle() const { return surround->border.left.style(); }
+ const Color& borderLeftColor() const { return surround->border.left.color; }
+ bool borderLeftIsTransparent() const { return surround->border.left.isTransparent(); }
+ unsigned short borderRightWidth() const { return surround->border.borderRightWidth(); }
+ EBorderStyle borderRightStyle() const { return surround->border.right.style(); }
+ const Color& borderRightColor() const { return surround->border.right.color; }
+ bool borderRightIsTransparent() const { return surround->border.right.isTransparent(); }
+ unsigned short borderTopWidth() const { return surround->border.borderTopWidth(); }
+ EBorderStyle borderTopStyle() const { return surround->border.top.style(); }
+ const Color& borderTopColor() const { return surround->border.top.color; }
+ bool borderTopIsTransparent() const { return surround->border.top.isTransparent(); }
+ unsigned short borderBottomWidth() const { return surround->border.borderBottomWidth(); }
+ EBorderStyle borderBottomStyle() const { return surround->border.bottom.style(); }
+ const Color& borderBottomColor() const { return surround->border.bottom.color; }
+ bool borderBottomIsTransparent() const { return surround->border.bottom.isTransparent(); }
+
+ unsigned short outlineSize() const { return max(0, outlineWidth() + outlineOffset()); }
+ unsigned short outlineWidth() const
+ {
+ if (background->m_outline.style() == BNONE)
+ return 0;
+ return background->m_outline.width;
+ }
+ bool hasOutline() const { return outlineWidth() > 0 && outlineStyle() > BHIDDEN; }
+ EBorderStyle outlineStyle() const { return background->m_outline.style(); }
+ bool outlineStyleIsAuto() const { return background->m_outline._auto; }
+ const Color& outlineColor() const { return background->m_outline.color; }
+
+ EOverflow overflowX() const { return static_cast<EOverflow>(noninherited_flags._overflowX); }
+ EOverflow overflowY() const { return static_cast<EOverflow>(noninherited_flags._overflowY); }
+
+ EVisibility visibility() const { return static_cast<EVisibility>(inherited_flags._visibility); }
+ EVerticalAlign verticalAlign() const { return static_cast<EVerticalAlign>(noninherited_flags._vertical_align); }
+ Length verticalAlignLength() const { return box->vertical_align; }
+
+ Length clipLeft() const { return visual->clip.left(); }
+ Length clipRight() const { return visual->clip.right(); }
+ Length clipTop() const { return visual->clip.top(); }
+ Length clipBottom() const { return visual->clip.bottom(); }
+ LengthBox clip() const { return visual->clip; }
+ bool hasClip() const { return visual->hasClip; }
+
+ EUnicodeBidi unicodeBidi() const { return static_cast<EUnicodeBidi>(noninherited_flags._unicodeBidi); }
+
+ EClear clear() const { return static_cast<EClear>(noninherited_flags._clear); }
+ ETableLayout tableLayout() const { return static_cast<ETableLayout>(noninherited_flags._table_layout); }
+
+ const Font& font() const { return inherited->font; }
+ const FontDescription& fontDescription() const { return inherited->font.fontDescription(); }
+ int fontSize() const { return inherited->font.pixelSize(); }
+
+ const Color& color() const { return inherited->color; }
+ Length textIndent() const { return inherited->indent; }
+ ETextAlign textAlign() const { return static_cast<ETextAlign>(inherited_flags._text_align); }
+ ETextTransform textTransform() const { return static_cast<ETextTransform>(inherited_flags._text_transform); }
+ int textDecorationsInEffect() const { return inherited_flags._text_decorations; }
+ int textDecoration() const { return visual->textDecoration; }
+ int wordSpacing() const { return inherited->font.wordSpacing(); }
+ int letterSpacing() const { return inherited->font.letterSpacing(); }
+
+ float zoom() const { return visual->m_zoom; }
+ float effectiveZoom() const { return inherited->m_effectiveZoom; }
+
+ TextDirection direction() const { return static_cast<TextDirection>(inherited_flags._direction); }
+ Length lineHeight() const { return inherited->line_height; }
+
+ EWhiteSpace whiteSpace() const { return static_cast<EWhiteSpace>(inherited_flags._white_space); }
+ static bool autoWrap(EWhiteSpace ws)
+ {
+ // Nowrap and pre don't automatically wrap.
+ return ws != NOWRAP && ws != PRE;
+ }
+
+ bool autoWrap() const
+ {
+ return autoWrap(whiteSpace());
+ }
+
+ static bool preserveNewline(EWhiteSpace ws)
+ {
+ // Normal and nowrap do not preserve newlines.
+ return ws != NORMAL && ws != NOWRAP;
+ }
+
+ bool preserveNewline() const
+ {
+ return preserveNewline(whiteSpace());
+ }
+
+ static bool collapseWhiteSpace(EWhiteSpace ws)
+ {
+ // Pre and prewrap do not collapse whitespace.
+ return ws != PRE && ws != PRE_WRAP;
+ }
+
+ bool collapseWhiteSpace() const
+ {
+ return collapseWhiteSpace(whiteSpace());
+ }
+
+ bool isCollapsibleWhiteSpace(UChar c) const
+ {
+ switch (c) {
+ case ' ':
+ case '\t':
+ return collapseWhiteSpace();
+ case '\n':
+ return !preserveNewline();
+ }
+ return false;
+ }
+
+ bool breakOnlyAfterWhiteSpace() const
+ {
+ return whiteSpace() == PRE_WRAP || khtmlLineBreak() == AFTER_WHITE_SPACE;
+ }
+
+ bool breakWords() const
+ {
+ return wordBreak() == BreakWordBreak || wordWrap() == BreakWordWrap;
+ }
+
+ 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); }
+ CompositeOperator backgroundComposite() const { return static_cast<CompositeOperator>(background->m_background.m_composite); }
+ bool backgroundAttachment() const { return 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; }
+ 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); }
+ CompositeOperator maskComposite() const { return static_cast<CompositeOperator>(rareNonInheritedData->m_mask.m_composite); }
+ bool maskAttachment() const { return 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; }
+ FillLayer* accessMaskLayers() { return &(rareNonInheritedData.access()->m_mask); }
+ const FillLayer* maskLayers() const { return &(rareNonInheritedData->m_mask); }
+ const NinePieceImage& maskBoxImage() const { return rareNonInheritedData->m_maskBoxImage; }
+
+ // returns true for collapsing borders, false for separate borders
+ bool borderCollapse() const { return inherited_flags._border_collapse; }
+ short horizontalBorderSpacing() const { return inherited->horizontal_border_spacing; }
+ short verticalBorderSpacing() const { return inherited->vertical_border_spacing; }
+ EEmptyCell emptyCells() const { return static_cast<EEmptyCell>(inherited_flags._empty_cells); }
+ ECaptionSide captionSide() const { return static_cast<ECaptionSide>(inherited_flags._caption_side); }
+
+ short counterIncrement() const { return visual->counterIncrement; }
+ short counterReset() const { return visual->counterReset; }
+
+ EListStyleType listStyleType() const { return static_cast<EListStyleType>(inherited_flags._list_style_type); }
+ StyleImage* listStyleImage() const { return inherited->list_style_image.get(); }
+ EListStylePosition listStylePosition() const { return static_cast<EListStylePosition>(inherited_flags._list_style_position); }
+
+ Length marginTop() const { return surround->margin.top(); }
+ Length marginBottom() const { return surround->margin.bottom(); }
+ Length marginLeft() const { return surround->margin.left(); }
+ Length marginRight() const { return surround->margin.right(); }
+
+ LengthBox paddingBox() const { return surround->padding; }
+ Length paddingTop() const { return surround->padding.top(); }
+ Length paddingBottom() const { return surround->padding.bottom(); }
+ Length paddingLeft() const { return surround->padding.left(); }
+ Length paddingRight() const { return surround->padding.right(); }
+
+ ECursor cursor() const { return static_cast<ECursor>(inherited_flags._cursor_style); }
+
+ CursorList* cursors() const { return inherited->cursorData.get(); }
+
+ short widows() const { return inherited->widows; }
+ short orphans() const { return inherited->orphans; }
+ EPageBreak pageBreakInside() const { return static_cast<EPageBreak>(inherited->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); }
+
+ // CSS3 Getter Methods
+#if ENABLE(XBL)
+ BindingURI* bindingURIs() const { return rareNonInheritedData->bindingURI; }
+#endif
+
+ int outlineOffset() const
+ {
+ if (background->m_outline.style() == BNONE)
+ return 0;
+ return background->m_outline._offset;
+ }
+
+ ShadowData* textShadow() const { return rareInheritedData->textShadow; }
+ const Color& textStrokeColor() const { return rareInheritedData->textStrokeColor; }
+ float textStrokeWidth() const { return rareInheritedData->textStrokeWidth; }
+ const Color& textFillColor() const { return rareInheritedData->textFillColor; }
+ 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); }
+ EBoxDirection boxDirection() const { return static_cast<EBoxDirection>(inherited_flags._box_direction); }
+ float boxFlex() { return rareNonInheritedData->flexibleBox->flex; }
+ unsigned int boxFlexGroup() const { return rareNonInheritedData->flexibleBox->flex_group; }
+ EBoxLines boxLines() { return static_cast<EBoxLines>(rareNonInheritedData->flexibleBox->lines); }
+ unsigned int boxOrdinalGroup() const { return rareNonInheritedData->flexibleBox->ordinal_group; }
+ EBoxOrient boxOrient() const { return static_cast<EBoxOrient>(rareNonInheritedData->flexibleBox->orient); }
+ EBoxAlignment boxPack() const { return static_cast<EBoxAlignment>(rareNonInheritedData->flexibleBox->pack); }
+ ShadowData* boxShadow() const { return rareNonInheritedData->m_boxShadow.get(); }
+ StyleReflection* boxReflect() const { return rareNonInheritedData->m_boxReflect.get(); }
+ EBoxSizing boxSizing() const { return static_cast<EBoxSizing>(box->boxSizing); }
+ Length marqueeIncrement() const { return rareNonInheritedData->marquee->increment; }
+ int marqueeSpeed() const { return rareNonInheritedData->marquee->speed; }
+ int marqueeLoopCount() const { return rareNonInheritedData->marquee->loops; }
+ EMarqueeBehavior marqueeBehavior() const { return static_cast<EMarqueeBehavior>(rareNonInheritedData->marquee->behavior); }
+ EMarqueeDirection marqueeDirection() const { return static_cast<EMarqueeDirection>(rareNonInheritedData->marquee->direction); }
+ EUserModify userModify() const { return static_cast<EUserModify>(rareInheritedData->userModify); }
+ EUserDrag userDrag() const { return static_cast<EUserDrag>(rareNonInheritedData->userDrag); }
+ EUserSelect userSelect() const { return static_cast<EUserSelect>(rareInheritedData->userSelect); }
+ bool textOverflow() const { return rareNonInheritedData->textOverflow; }
+ EMarginCollapse marginTopCollapse() const { return static_cast<EMarginCollapse>(rareNonInheritedData->marginTopCollapse); }
+ EMarginCollapse marginBottomCollapse() const { return static_cast<EMarginCollapse>(rareNonInheritedData->marginBottomCollapse); }
+ EWordBreak wordBreak() const { return static_cast<EWordBreak>(rareInheritedData->wordBreak); }
+ EWordWrap wordWrap() const { return static_cast<EWordWrap>(rareInheritedData->wordWrap); }
+ ENBSPMode nbspMode() const { return static_cast<ENBSPMode>(rareInheritedData->nbspMode); }
+ EKHTMLLineBreak khtmlLineBreak() const { return static_cast<EKHTMLLineBreak>(rareInheritedData->khtmlLineBreak); }
+ EMatchNearestMailBlockquoteColor matchNearestMailBlockquoteColor() const { return static_cast<EMatchNearestMailBlockquoteColor>(rareNonInheritedData->matchNearestMailBlockquoteColor); }
+ const AtomicString& highlight() const { return rareInheritedData->highlight; }
+ EBorderFit borderFit() const { return static_cast<EBorderFit>(rareNonInheritedData->m_borderFit); }
+ EResize resize() const { return static_cast<EResize>(rareInheritedData->resize); }
+ float columnWidth() const { return rareNonInheritedData->m_multiCol->m_width; }
+ bool hasAutoColumnWidth() const { return rareNonInheritedData->m_multiCol->m_autoWidth; }
+ unsigned short columnCount() const { return rareNonInheritedData->m_multiCol->m_count; }
+ bool hasAutoColumnCount() const { return rareNonInheritedData->m_multiCol->m_autoCount; }
+ float columnGap() const { return rareNonInheritedData->m_multiCol->m_gap; }
+ bool hasNormalColumnGap() const { return rareNonInheritedData->m_multiCol->m_normalGap; }
+ const Color& columnRuleColor() const { return rareNonInheritedData->m_multiCol->m_rule.color; }
+ EBorderStyle columnRuleStyle() const { return rareNonInheritedData->m_multiCol->m_rule.style(); }
+ unsigned short columnRuleWidth() const { return rareNonInheritedData->m_multiCol->ruleWidth(); }
+ bool columnRuleIsTransparent() const { return rareNonInheritedData->m_multiCol->m_rule.isTransparent(); }
+ EPageBreak columnBreakBefore() const { return static_cast<EPageBreak>(rareNonInheritedData->m_multiCol->m_breakBefore); }
+ EPageBreak columnBreakInside() const { return static_cast<EPageBreak>(rareNonInheritedData->m_multiCol->m_breakInside); }
+ EPageBreak columnBreakAfter() const { return static_cast<EPageBreak>(rareNonInheritedData->m_multiCol->m_breakAfter); }
+ const TransformOperations& transform() const { return rareNonInheritedData->m_transform->m_operations; }
+ Length transformOriginX() const { return rareNonInheritedData->m_transform->m_x; }
+ Length transformOriginY() const { return rareNonInheritedData->m_transform->m_y; }
+ bool hasTransform() const { return !rareNonInheritedData->m_transform->m_operations.operations().isEmpty(); }
+ void applyTransform(TransformationMatrix&, const IntSize& borderBoxSize, bool includeTransformOrigin = true) const;
+ bool hasMask() const { return rareNonInheritedData->m_mask.hasImage() || rareNonInheritedData->m_maskBoxImage.hasImage(); }
+ // End CSS3 Getters
+
+ // Apple-specific property getter methods
+ EPointerEvents pointerEvents() const { return static_cast<EPointerEvents>(inherited_flags._pointerEvents); }
+ const AnimationList* animations() const { return rareNonInheritedData->m_animations.get(); }
+ const AnimationList* transitions() const { return rareNonInheritedData->m_transitions.get(); }
+
+ AnimationList* accessAnimations();
+ AnimationList* accessTransitions();
+
+ bool hasAnimations() const { return rareNonInheritedData->m_animations && rareNonInheritedData->m_animations->size() > 0; }
+ bool hasTransitions() const { return rareNonInheritedData->m_transitions && rareNonInheritedData->m_transitions->size() > 0; }
+
+ // return the first found Animation (including 'all' transitions)
+ const Animation* transitionForProperty(int property);
+
+ int lineClamp() const { return rareNonInheritedData->lineClamp; }
+ bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; }
+ ETextSecurity textSecurity() const { return static_cast<ETextSecurity>(rareInheritedData->textSecurity); }
+
+// attribute setter methods
+
+ void setDisplay(EDisplay v) { noninherited_flags._effectiveDisplay = v; }
+ void setOriginalDisplay(EDisplay v) { noninherited_flags._originalDisplay = v; }
+ void setPosition(EPosition v) { noninherited_flags._position = v; }
+ void setFloating(EFloat v) { noninherited_flags._floating = v; }
+
+ void setLeft(Length v) { SET_VAR(surround, offset.m_left, v) }
+ void setRight(Length v) { SET_VAR(surround, offset.m_right, v) }
+ void setTop(Length v) { SET_VAR(surround, offset.m_top, v) }
+ void setBottom(Length v) { SET_VAR(surround, offset.m_bottom, v) }
+
+ void setWidth(Length v) { SET_VAR(box, width, v) }
+ void setHeight(Length v) { SET_VAR(box, height, v) }
+
+ void setMinWidth(Length v) { SET_VAR(box, min_width, v) }
+ void setMaxWidth(Length v) { SET_VAR(box, max_width, v) }
+ void setMinHeight(Length v) { SET_VAR(box, min_height, v) }
+ void setMaxHeight(Length v) { SET_VAR(box, max_height, v) }
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ Vector<StyleDashboardRegion> dashboardRegions() const { return rareNonInheritedData->m_dashboardRegions; }
+ void setDashboardRegions(Vector<StyleDashboardRegion> regions) { SET_VAR(rareNonInheritedData, m_dashboardRegions, regions); }
+
+ void setDashboardRegion(int type, const String& label, Length t, Length r, Length b, Length l, bool append)
+ {
+ StyleDashboardRegion region;
+ region.label = label;
+ region.offset.m_top = t;
+ region.offset.m_right = r;
+ region.offset.m_bottom = b;
+ region.offset.m_left = l;
+ region.type = type;
+ if (!append)
+ rareNonInheritedData.access()->m_dashboardRegions.clear();
+ rareNonInheritedData.access()->m_dashboardRegions.append(region);
+ }
+#endif
+
+ void resetBorder() { resetBorderImage(); resetBorderTop(); resetBorderRight(); resetBorderBottom(); resetBorderLeft(); resetBorderRadius(); }
+ void resetBorderTop() { SET_VAR(surround, border.top, BorderValue()) }
+ void resetBorderRight() { SET_VAR(surround, border.right, BorderValue()) }
+ void resetBorderBottom() { SET_VAR(surround, border.bottom, BorderValue()) }
+ void resetBorderLeft() { SET_VAR(surround, border.left, BorderValue()) }
+ void resetBorderImage() { SET_VAR(surround, border.image, NinePieceImage()) }
+ void resetBorderRadius() { resetBorderTopLeftRadius(); resetBorderTopRightRadius(); resetBorderBottomLeftRadius(); resetBorderBottomRightRadius(); }
+ void resetBorderTopLeftRadius() { SET_VAR(surround, border.topLeft, initialBorderRadius()) }
+ void resetBorderTopRightRadius() { SET_VAR(surround, border.topRight, initialBorderRadius()) }
+ void resetBorderBottomLeftRadius() { SET_VAR(surround, border.bottomLeft, initialBorderRadius()) }
+ void resetBorderBottomRightRadius() { SET_VAR(surround, border.bottomRight, initialBorderRadius()) }
+
+ void resetOutline() { SET_VAR(background, m_outline, OutlineValue()) }
+
+ void setBackgroundColor(const Color& v) { SET_VAR(background, m_color, v) }
+
+ void setBorderImage(const NinePieceImage& b) { SET_VAR(surround, border.image, b) }
+
+ void setBorderTopLeftRadius(const IntSize& s) { SET_VAR(surround, border.topLeft, s) }
+ void setBorderTopRightRadius(const IntSize& s) { SET_VAR(surround, border.topRight, s) }
+ void setBorderBottomLeftRadius(const IntSize& s) { SET_VAR(surround, border.bottomLeft, s) }
+ void setBorderBottomRightRadius(const IntSize& s) { SET_VAR(surround, border.bottomRight, s) }
+
+ void setBorderRadius(const IntSize& s)
+ {
+ setBorderTopLeftRadius(s);
+ setBorderTopRightRadius(s);
+ setBorderBottomLeftRadius(s);
+ setBorderBottomRightRadius(s);
+ }
+
+ void setBorderLeftWidth(unsigned short v) { SET_VAR(surround, border.left.width, v) }
+ void setBorderLeftStyle(EBorderStyle v) { SET_VAR(surround, border.left.m_style, v) }
+ void setBorderLeftColor(const Color& v) { SET_VAR(surround, border.left.color, v) }
+ void setBorderRightWidth(unsigned short v) { SET_VAR(surround, border.right.width, v) }
+ void setBorderRightStyle(EBorderStyle v) { SET_VAR(surround, border.right.m_style, v) }
+ void setBorderRightColor(const Color& v) { SET_VAR(surround, border.right.color, v) }
+ void setBorderTopWidth(unsigned short v) { SET_VAR(surround, border.top.width, v) }
+ void setBorderTopStyle(EBorderStyle v) { SET_VAR(surround, border.top.m_style, v) }
+ void setBorderTopColor(const Color& v) { SET_VAR(surround, border.top.color, v) }
+ void setBorderBottomWidth(unsigned short v) { SET_VAR(surround, border.bottom.width, v) }
+ void setBorderBottomStyle(EBorderStyle v) { SET_VAR(surround, border.bottom.m_style, v) }
+ void setBorderBottomColor(const Color& v) { SET_VAR(surround, border.bottom.color, v) }
+ void setOutlineWidth(unsigned short v) { SET_VAR(background, m_outline.width, v) }
+
+ void setOutlineStyle(EBorderStyle v, bool isAuto = false)
+ {
+ SET_VAR(background, m_outline.m_style, v)
+ SET_VAR(background, m_outline._auto, isAuto)
+ }
+
+ void setOutlineColor(const Color& v) { SET_VAR(background, m_outline.color, v) }
+
+ void setOverflowX(EOverflow v) { noninherited_flags._overflowX = v; }
+ void setOverflowY(EOverflow v) { noninherited_flags._overflowY = v; }
+ void setVisibility(EVisibility v) { inherited_flags._visibility = v; }
+ void setVerticalAlign(EVerticalAlign v) { noninherited_flags._vertical_align = v; }
+ void setVerticalAlignLength(Length l) { SET_VAR(box, vertical_align, l ) }
+
+ void setHasClip(bool b = true) { SET_VAR(visual, hasClip, b) }
+ void setClipLeft(Length v) { SET_VAR(visual, clip.m_left, v) }
+ void setClipRight(Length v) { SET_VAR(visual, clip.m_right, v) }
+ void setClipTop(Length v) { SET_VAR(visual, clip.m_top, v) }
+ void setClipBottom(Length v) { SET_VAR(visual, clip.m_bottom, v) }
+ void setClip(Length top, Length right, Length bottom, Length left);
+
+ void setUnicodeBidi( EUnicodeBidi b ) { noninherited_flags._unicodeBidi = b; }
+
+ void setClear(EClear v) { noninherited_flags._clear = v; }
+ void setTableLayout(ETableLayout v) { noninherited_flags._table_layout = v; }
+
+ bool setFontDescription(const FontDescription& v)
+ {
+ if (inherited->font.fontDescription() != v) {
+ inherited.access()->font = Font(v, inherited->font.letterSpacing(), inherited->font.wordSpacing());
+ return true;
+ }
+ return false;
+ }
+
+ // Only used for blending font sizes when animating.
+ void setBlendedFontSize(int);
+
+ void setColor(const Color& v) { SET_VAR(inherited, color, v) }
+ void setTextIndent(Length v) { SET_VAR(inherited, indent, v) }
+ void setTextAlign(ETextAlign v) { inherited_flags._text_align = v; }
+ void setTextTransform(ETextTransform v) { inherited_flags._text_transform = v; }
+ void addToTextDecorationsInEffect(int v) { inherited_flags._text_decorations |= v; }
+ void setTextDecorationsInEffect(int v) { inherited_flags._text_decorations = v; }
+ void setTextDecoration(int v) { SET_VAR(visual, textDecoration, v); }
+ void setDirection(TextDirection v) { inherited_flags._direction = v; }
+ void setLineHeight(Length v) { SET_VAR(inherited, line_height, v) }
+ void setZoom(float f) { SET_VAR(visual, m_zoom, f); setEffectiveZoom(effectiveZoom() * zoom()); }
+ void setEffectiveZoom(float f) { SET_VAR(inherited, m_effectiveZoom, f) }
+
+ void setWhiteSpace(EWhiteSpace v) { inherited_flags._white_space = v; }
+
+ void setWordSpacing(int v) { inherited.access()->font.setWordSpacing(v); }
+ void setLetterSpacing(int v) { inherited.access()->font.setLetterSpacing(v); }
+
+ void clearBackgroundLayers() { background.access()->m_background = FillLayer(BackgroundFillLayer); }
+ void inheritBackgroundLayers(const FillLayer& parent) { background.access()->m_background = parent; }
+
+ void adjustBackgroundLayers()
+ {
+ if (backgroundLayers()->next()) {
+ accessBackgroundLayers()->cullEmptyLayers();
+ accessBackgroundLayers()->fillUnsetProperties();
+ }
+ }
+
+ void clearMaskLayers() { rareNonInheritedData.access()->m_mask = FillLayer(MaskFillLayer); }
+ void inheritMaskLayers(const FillLayer& parent) { rareNonInheritedData.access()->m_mask = parent; }
+
+ void adjustMaskLayers()
+ {
+ if (maskLayers()->next()) {
+ accessMaskLayers()->cullEmptyLayers();
+ accessMaskLayers()->fillUnsetProperties();
+ }
+ }
+
+ void setMaskBoxImage(const NinePieceImage& b) { SET_VAR(rareNonInheritedData, m_maskBoxImage, b) }
+
+ void setBorderCollapse(bool collapse) { inherited_flags._border_collapse = collapse; }
+ void setHorizontalBorderSpacing(short v) { SET_VAR(inherited, horizontal_border_spacing, v) }
+ void setVerticalBorderSpacing(short v) { SET_VAR(inherited, vertical_border_spacing, v) }
+ void setEmptyCells(EEmptyCell v) { inherited_flags._empty_cells = v; }
+ void setCaptionSide(ECaptionSide v) { inherited_flags._caption_side = v; }
+
+ void setCounterIncrement(short v) { SET_VAR(visual, counterIncrement, v) }
+ void setCounterReset(short v) { SET_VAR(visual, counterReset, v) }
+
+ void setListStyleType(EListStyleType v) { inherited_flags._list_style_type = v; }
+ void setListStyleImage(StyleImage* v) { if (inherited->list_style_image != v) inherited.access()->list_style_image = v; }
+ void setListStylePosition(EListStylePosition v) { inherited_flags._list_style_position = v; }
+
+ void resetMargin() { SET_VAR(surround, margin, LengthBox(Fixed)) }
+ void setMarginTop(Length v) { SET_VAR(surround, margin.m_top, v) }
+ void setMarginBottom(Length v) { SET_VAR(surround, margin.m_bottom, v) }
+ void setMarginLeft(Length v) { SET_VAR(surround, margin.m_left, v) }
+ void setMarginRight(Length v) { SET_VAR(surround, margin.m_right, v) }
+
+ void resetPadding() { SET_VAR(surround, padding, LengthBox(Auto)) }
+ void setPaddingBox(const LengthBox& b) { SET_VAR(surround, padding, b) }
+ void setPaddingTop(Length v) { SET_VAR(surround, padding.m_top, v) }
+ void setPaddingBottom(Length v) { SET_VAR(surround, padding.m_bottom, v) }
+ void setPaddingLeft(Length v) { SET_VAR(surround, padding.m_left, v) }
+ void setPaddingRight(Length v) { SET_VAR(surround, padding.m_right, v) }
+
+ void setCursor( ECursor c ) { inherited_flags._cursor_style = c; }
+ void addCursor(CachedImage*, const IntPoint& = IntPoint());
+ void setCursorList(PassRefPtr<CursorList>);
+ void clearCursorList();
+
+ bool forceBackgroundsToWhite() const { return inherited_flags._force_backgrounds_to_white; }
+ void setForceBackgroundsToWhite(bool b=true) { inherited_flags._force_backgrounds_to_white = b; }
+
+ bool htmlHacks() const { return inherited_flags._htmlHacks; }
+ void setHtmlHacks(bool b=true) { inherited_flags._htmlHacks = b; }
+
+ bool hasAutoZIndex() const { return box->z_auto; }
+ void setHasAutoZIndex() { SET_VAR(box, z_auto, true); SET_VAR(box, z_index, 0) }
+ int zIndex() const { return box->z_index; }
+ void setZIndex(int v) { SET_VAR(box, z_auto, false); SET_VAR(box, z_index, v) }
+
+ 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 setPageBreakBefore(EPageBreak b) { noninherited_flags._page_break_before = b; }
+ void setPageBreakAfter(EPageBreak b) { noninherited_flags._page_break_after = b; }
+
+ // CSS3 Setters
+#if ENABLE(XBL)
+ void deleteBindingURIs() { SET_VAR(rareNonInheritedData, bindingURI, static_cast<BindingURI*>(0)); }
+ void inheritBindingURIs(BindingURI* other) { SET_VAR(rareNonInheritedData, bindingURI, other->copy()); }
+ void addBindingURI(StringImpl* uri);
+#endif
+
+ void setOutlineOffset(int v) { SET_VAR(background, m_outline._offset, v) }
+ void setTextShadow(ShadowData* val, bool add=false);
+ 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 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); }
+ void setBoxDirection(EBoxDirection d) { inherited_flags._box_direction = d; }
+ void setBoxFlex(float f) { SET_VAR(rareNonInheritedData.access()->flexibleBox, flex, f); }
+ void setBoxFlexGroup(unsigned int fg) { SET_VAR(rareNonInheritedData.access()->flexibleBox, flex_group, fg); }
+ void setBoxLines(EBoxLines l) { SET_VAR(rareNonInheritedData.access()->flexibleBox, lines, l); }
+ void setBoxOrdinalGroup(unsigned int og) { SET_VAR(rareNonInheritedData.access()->flexibleBox, ordinal_group, og); }
+ void setBoxOrient(EBoxOrient o) { SET_VAR(rareNonInheritedData.access()->flexibleBox, orient, o); }
+ void setBoxPack(EBoxAlignment p) { SET_VAR(rareNonInheritedData.access()->flexibleBox, pack, p); }
+ void setBoxShadow(ShadowData* val, bool add=false);
+ void setBoxReflect(PassRefPtr<StyleReflection> reflect) { if (rareNonInheritedData->m_boxReflect != reflect) rareNonInheritedData.access()->m_boxReflect = reflect; }
+ void setBoxSizing(EBoxSizing s) { SET_VAR(box, boxSizing, s); }
+ void setMarqueeIncrement(const Length& f) { SET_VAR(rareNonInheritedData.access()->marquee, increment, f); }
+ void setMarqueeSpeed(int f) { SET_VAR(rareNonInheritedData.access()->marquee, speed, f); }
+ void setMarqueeDirection(EMarqueeDirection d) { SET_VAR(rareNonInheritedData.access()->marquee, direction, d); }
+ void setMarqueeBehavior(EMarqueeBehavior b) { SET_VAR(rareNonInheritedData.access()->marquee, behavior, b); }
+ void setMarqueeLoopCount(int i) { SET_VAR(rareNonInheritedData.access()->marquee, loops, i); }
+ void setUserModify(EUserModify u) { SET_VAR(rareInheritedData, userModify, u); }
+ void setUserDrag(EUserDrag d) { SET_VAR(rareNonInheritedData, userDrag, d); }
+ void setUserSelect(EUserSelect s) { SET_VAR(rareInheritedData, userSelect, s); }
+ void setTextOverflow(bool b) { SET_VAR(rareNonInheritedData, textOverflow, b); }
+ void setMarginTopCollapse(EMarginCollapse c) { SET_VAR(rareNonInheritedData, marginTopCollapse, c); }
+ void setMarginBottomCollapse(EMarginCollapse c) { SET_VAR(rareNonInheritedData, marginBottomCollapse, c); }
+ void setWordBreak(EWordBreak b) { SET_VAR(rareInheritedData, wordBreak, b); }
+ void setWordWrap(EWordWrap b) { SET_VAR(rareInheritedData, wordWrap, b); }
+ void setNBSPMode(ENBSPMode b) { SET_VAR(rareInheritedData, nbspMode, b); }
+ void setKHTMLLineBreak(EKHTMLLineBreak b) { SET_VAR(rareInheritedData, khtmlLineBreak, b); }
+ void setMatchNearestMailBlockquoteColor(EMatchNearestMailBlockquoteColor c) { SET_VAR(rareNonInheritedData, matchNearestMailBlockquoteColor, c); }
+ void setHighlight(const AtomicString& h) { SET_VAR(rareInheritedData, highlight, h); }
+ void setBorderFit(EBorderFit b) { SET_VAR(rareNonInheritedData, m_borderFit, b); }
+ void setResize(EResize r) { SET_VAR(rareInheritedData, resize, r); }
+ void setColumnWidth(float f) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoWidth, false); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_width, f); }
+ void setHasAutoColumnWidth() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoWidth, true); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_width, 0); }
+ void setColumnCount(unsigned short c) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoCount, false); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_count, c); }
+ void setHasAutoColumnCount() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoCount, true); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_count, 0); }
+ void setColumnGap(float f) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_normalGap, false); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_gap, f); }
+ void setHasNormalColumnGap() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_normalGap, true); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_gap, 0); }
+ void setColumnRuleColor(const Color& c) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule.color, c); }
+ void setColumnRuleStyle(EBorderStyle b) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule.m_style, b); }
+ void setColumnRuleWidth(unsigned short w) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule.width, w); }
+ void resetColumnRule() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule, BorderValue()) }
+ void setColumnBreakBefore(EPageBreak p) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_breakBefore, p); }
+ void setColumnBreakInside(EPageBreak p) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_breakInside, p); }
+ void setColumnBreakAfter(EPageBreak p) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_breakAfter, p); }
+ void setTransform(const TransformOperations& ops) { SET_VAR(rareNonInheritedData.access()->m_transform, m_operations, ops); }
+ void setTransformOriginX(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_x, l); }
+ void setTransformOriginY(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_y, l); }
+ // End CSS3 Setters
+
+ // Apple-specific property setters
+ void setPointerEvents(EPointerEvents p) { inherited_flags._pointerEvents = p; }
+
+ void clearAnimations()
+ {
+ rareNonInheritedData.access()->m_animations.clear();
+ }
+
+ void clearTransitions()
+ {
+ rareNonInheritedData.access()->m_transitions.clear();
+ }
+
+ void inheritAnimations(const AnimationList* parent) { rareNonInheritedData.access()->m_animations.set(parent ? new AnimationList(*parent) : 0); }
+ void inheritTransitions(const AnimationList* parent) { rareNonInheritedData.access()->m_transitions.set(parent ? new AnimationList(*parent) : 0); }
+ void adjustAnimations();
+ void adjustTransitions();
+
+ void setLineClamp(int c) { SET_VAR(rareNonInheritedData, lineClamp, c); }
+ void setTextSizeAdjust(bool b) { SET_VAR(rareInheritedData, textSizeAdjust, b); }
+ void setTextSecurity(ETextSecurity aTextSecurity) { SET_VAR(rareInheritedData, textSecurity, aTextSecurity); }
+
+#if ENABLE(SVG)
+ const SVGRenderStyle* svgStyle() const { return m_svgStyle.get(); }
+ SVGRenderStyle* accessSVGStyle() { return m_svgStyle.access(); }
+
+ float fillOpacity() const { return svgStyle()->fillOpacity(); }
+ void setFillOpacity(float f) { accessSVGStyle()->setFillOpacity(f); }
+
+ float strokeOpacity() const { return svgStyle()->strokeOpacity(); }
+ void setStrokeOpacity(float f) { accessSVGStyle()->setStrokeOpacity(f); }
+
+ float floodOpacity() const { return svgStyle()->floodOpacity(); }
+ void setFloodOpacity(float f) { accessSVGStyle()->setFloodOpacity(f); }
+#endif
+
+ const ContentData* contentData() const { return rareNonInheritedData->m_content.get(); }
+ bool contentDataEquivalent(const RenderStyle* otherStyle) const;
+ void clearContent();
+ void setContent(StringImpl*, bool add = false);
+ void setContent(PassRefPtr<StyleImage>, bool add = false);
+ void setContent(CounterContent*, bool add = false);
+
+ const CounterDirectiveMap* counterDirectives() const;
+ CounterDirectiveMap& accessCounterDirectives();
+
+ bool inheritedNotEqual(RenderStyle*) const;
+
+ // The difference between two styles. The following values are used:
+ // (1) Equal - The two styles are identical
+ // (2) Repaint - The object just needs to be repainted.
+ // (3) RepaintLayer - The layer and its descendant layers needs to be repainted.
+ // (4) Layout - A layout is required.
+ enum Diff { Equal, Repaint, RepaintLayer, LayoutPositionedMovementOnly, Layout };
+ Diff diff(const RenderStyle*) const;
+
+ bool isDisplayReplacedType() const
+ {
+ return display() == INLINE_BLOCK || display() == INLINE_BOX || display() == INLINE_TABLE;
+ }
+
+ bool isDisplayInlineType() const
+ {
+ return display() == INLINE || isDisplayReplacedType();
+ }
+
+ bool isOriginalDisplayInlineType() const
+ {
+ return originalDisplay() == INLINE || originalDisplay() == INLINE_BLOCK ||
+ originalDisplay() == INLINE_BOX || originalDisplay() == INLINE_TABLE;
+ }
+
+ // To obtain at any time the pseudo state for a given link.
+ PseudoState pseudoState() const { return static_cast<PseudoState>(m_pseudoState); }
+ void setPseudoState(PseudoState s) { m_pseudoState = s; }
+
+ // To tell if this style matched attribute selectors. This makes it impossible to share.
+ bool affectedByAttributeSelectors() const { return m_affectedByAttributeSelectors; }
+ void setAffectedByAttributeSelectors() { m_affectedByAttributeSelectors = true; }
+
+ bool unique() const { return m_unique; }
+ void setUnique() { m_unique = true; }
+
+ // Methods for indicating the style is affected by dynamic updates (e.g., children changing, our position changing in our sibling list, etc.)
+ bool affectedByEmpty() const { return m_affectedByEmpty; }
+ bool emptyState() const { return m_emptyState; }
+ void setEmptyState(bool b) { m_affectedByEmpty = true; m_unique = true; m_emptyState = b; }
+ bool childrenAffectedByPositionalRules() const { return childrenAffectedByForwardPositionalRules() || childrenAffectedByBackwardPositionalRules(); }
+ bool childrenAffectedByFirstChildRules() const { return m_childrenAffectedByFirstChildRules; }
+ void setChildrenAffectedByFirstChildRules() { m_childrenAffectedByFirstChildRules = true; }
+ bool childrenAffectedByLastChildRules() const { return m_childrenAffectedByLastChildRules; }
+ void setChildrenAffectedByLastChildRules() { m_childrenAffectedByLastChildRules = true; }
+ bool childrenAffectedByDirectAdjacentRules() const { return m_childrenAffectedByDirectAdjacentRules; }
+ void setChildrenAffectedByDirectAdjacentRules() { m_childrenAffectedByDirectAdjacentRules = true; }
+ bool childrenAffectedByForwardPositionalRules() const { return m_childrenAffectedByForwardPositionalRules; }
+ void setChildrenAffectedByForwardPositionalRules() { m_childrenAffectedByForwardPositionalRules = true; }
+ bool childrenAffectedByBackwardPositionalRules() const { return m_childrenAffectedByBackwardPositionalRules; }
+ void setChildrenAffectedByBackwardPositionalRules() { m_childrenAffectedByBackwardPositionalRules = true; }
+ bool firstChildState() const { return m_firstChildState; }
+ void setFirstChildState() { m_firstChildState = true; }
+ bool lastChildState() const { return m_lastChildState; }
+ void setLastChildState() { m_lastChildState = true; }
+ unsigned childIndex() const { return m_childIndex; }
+ void setChildIndex(unsigned index) { m_childIndex = index; }
+
+ // Initial values for all the properties
+ static bool initialBorderCollapse() { return false; }
+ static EBorderStyle initialBorderStyle() { return BNONE; }
+ static NinePieceImage initialNinePieceImage() { return NinePieceImage(); }
+ static IntSize initialBorderRadius() { return IntSize(0, 0); }
+ static ECaptionSide initialCaptionSide() { return CAPTOP; }
+ static EClear initialClear() { return CNONE; }
+ static TextDirection initialDirection() { return LTR; }
+ static EDisplay initialDisplay() { return INLINE; }
+ static EEmptyCell initialEmptyCells() { return SHOW; }
+ static EFloat initialFloating() { return FNONE; }
+ static EListStylePosition initialListStylePosition() { return OUTSIDE; }
+ static EListStyleType initialListStyleType() { return DISC; }
+ static EOverflow initialOverflowX() { return OVISIBLE; }
+ static EOverflow initialOverflowY() { return OVISIBLE; }
+ static EPageBreak initialPageBreak() { return PBAUTO; }
+ static EPosition initialPosition() { return StaticPosition; }
+ static ETableLayout initialTableLayout() { return TAUTO; }
+ static EUnicodeBidi initialUnicodeBidi() { return UBNormal; }
+ static ETextTransform initialTextTransform() { return TTNONE; }
+ static EVisibility initialVisibility() { return VISIBLE; }
+ static EWhiteSpace initialWhiteSpace() { return NORMAL; }
+ static short initialHorizontalBorderSpacing() { return 0; }
+ static short initialVerticalBorderSpacing() { return 0; }
+ static ECursor initialCursor() { return CURSOR_AUTO; }
+ static Color initialColor() { return Color::black; }
+ static StyleImage* initialListStyleImage() { return 0; }
+ static unsigned short initialBorderWidth() { return 3; }
+ static int initialLetterWordSpacing() { return 0; }
+ static Length initialSize() { return Length(); }
+ static Length initialMinSize() { return Length(0, Fixed); }
+ static Length initialMaxSize() { return Length(undefinedLength, Fixed); }
+ static Length initialOffset() { return Length(); }
+ static Length initialMargin() { return Length(Fixed); }
+ static Length initialPadding() { return Length(Fixed); }
+ static Length initialTextIndent() { return Length(Fixed); }
+ static EVerticalAlign initialVerticalAlign() { return BASELINE; }
+ static int initialWidows() { return 2; }
+ static int initialOrphans() { return 2; }
+ static Length initialLineHeight() { return Length(-100.0, Percent); }
+ static ETextAlign initialTextAlign() { return TAAUTO; }
+ static ETextDecoration initialTextDecoration() { return TDNONE; }
+ static float initialZoom() { return 1.0f; }
+ static int initialOutlineOffset() { return 0; }
+ static float initialOpacity() { return 1.0f; }
+ static EBoxAlignment initialBoxAlign() { return BSTRETCH; }
+ static EBoxDirection initialBoxDirection() { return BNORMAL; }
+ static EBoxLines initialBoxLines() { return SINGLE; }
+ static EBoxOrient initialBoxOrient() { return HORIZONTAL; }
+ static EBoxAlignment initialBoxPack() { return BSTART; }
+ static float initialBoxFlex() { return 0.0f; }
+ static int initialBoxFlexGroup() { return 1; }
+ static int initialBoxOrdinalGroup() { return 1; }
+ static EBoxSizing initialBoxSizing() { return CONTENT_BOX; }
+ static StyleReflection* initialBoxReflect() { return 0; }
+ static int initialMarqueeLoopCount() { return -1; }
+ static int initialMarqueeSpeed() { return 85; }
+ static Length initialMarqueeIncrement() { return Length(6, Fixed); }
+ static EMarqueeBehavior initialMarqueeBehavior() { return MSCROLL; }
+ static EMarqueeDirection initialMarqueeDirection() { return MAUTO; }
+ static EUserModify initialUserModify() { return READ_ONLY; }
+ static EUserDrag initialUserDrag() { return DRAG_AUTO; }
+ static EUserSelect initialUserSelect() { return SELECT_TEXT; }
+ static bool initialTextOverflow() { return false; }
+ static EMarginCollapse initialMarginTopCollapse() { return MCOLLAPSE; }
+ static EMarginCollapse initialMarginBottomCollapse() { return MCOLLAPSE; }
+ static EWordBreak initialWordBreak() { return NormalWordBreak; }
+ static EWordWrap initialWordWrap() { return NormalWordWrap; }
+ static ENBSPMode initialNBSPMode() { return NBNORMAL; }
+ static EKHTMLLineBreak initialKHTMLLineBreak() { return LBNORMAL; }
+ static EMatchNearestMailBlockquoteColor initialMatchNearestMailBlockquoteColor() { return BCNORMAL; }
+ static const AtomicString& initialHighlight() { return nullAtom; }
+ static EBorderFit initialBorderFit() { return BorderFitBorder; }
+ static EResize initialResize() { return RESIZE_NONE; }
+ static ControlPart initialAppearance() { return NoControlPart; }
+ static bool initialVisuallyOrdered() { return false; }
+ static float initialTextStrokeWidth() { return 0; }
+ static unsigned short initialColumnCount() { return 1; }
+ static const TransformOperations& initialTransform() { return s_initialTransform; }
+ static Length initialTransformOriginX() { return Length(50.0, Percent); }
+ static Length initialTransformOriginY() { return Length(50.0, Percent); }
+ static EPointerEvents initialPointerEvents() { return PE_AUTO; }
+
+ // Keep these at the end.
+ static int initialLineClamp() { return -1; }
+ static bool initialTextSizeAdjust() { return true; }
+ static ETextSecurity initialTextSecurity() { return TSNONE; }
+#if ENABLE(DASHBOARD_SUPPORT)
+ static const Vector<StyleDashboardRegion>& initialDashboardRegions();
+ static const Vector<StyleDashboardRegion>& noneDashboardRegions();
+#endif
+};
+
+} // namespace WebCore
+
+#endif // RenderStyle_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h
new file mode 100644
index 0000000..40ad3cc
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/RenderStyleConstants.h
@@ -0,0 +1,268 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 RenderStyleConstants_h
+#define RenderStyleConstants_h
+
+namespace WebCore {
+
+/*
+ * WARNING:
+ * --------
+ *
+ * The order of the values in the enums have to agree with the order specified
+ * in CSSValueKeywords.in, otherwise some optimizations in the parser will fail,
+ * and produce invalid results.
+ */
+
+
+// These have been defined in the order of their precedence for border-collapsing. Do
+// not change this order!
+enum EBorderStyle { BNONE, BHIDDEN, INSET, GROOVE, RIDGE, OUTSET, DOTTED, DASHED, SOLID, DOUBLE };
+
+enum EBorderPrecedence { BOFF, BTABLE, BCOLGROUP, BCOL, BROWGROUP, BROW, BCELL };
+
+enum PseudoState { PseudoUnknown, PseudoNone, PseudoAnyLink, PseudoLink, PseudoVisited};
+
+enum EPosition {
+ StaticPosition, RelativePosition, AbsolutePosition, FixedPosition
+};
+
+enum EFloat {
+ FNONE = 0, FLEFT, FRIGHT
+};
+
+
+enum EMarginCollapse { MCOLLAPSE, MSEPARATE, MDISCARD };
+
+// Box attributes. Not inherited.
+
+enum EBoxSizing { CONTENT_BOX, BORDER_BOX };
+
+// Random visual rendering model attributes. Not inherited.
+
+enum EOverflow {
+ OVISIBLE, OHIDDEN, OSCROLL, OAUTO, OOVERLAY, OMARQUEE
+};
+
+enum EVerticalAlign {
+ BASELINE, MIDDLE, SUB, SUPER, TEXT_TOP,
+ TEXT_BOTTOM, TOP, BOTTOM, BASELINE_MIDDLE, LENGTH
+};
+
+enum EClear{
+ CNONE = 0, CLEFT = 1, CRIGHT = 2, CBOTH = 3
+};
+
+enum ETableLayout {
+ TAUTO, TFIXED
+};
+
+enum EUnicodeBidi {
+ UBNormal, Embed, Override
+};
+
+enum EFillBox {
+ BorderFillBox, PaddingFillBox, ContentFillBox, TextFillBox
+};
+
+enum EFillRepeat {
+ RepeatFill, RepeatXFill, RepeatYFill, NoRepeatFill
+};
+
+enum EFillLayerType {
+ BackgroundFillLayer, MaskFillLayer
+};
+
+// CSS3 Marquee Properties
+
+enum EMarqueeBehavior { MNONE, MSCROLL, MSLIDE, MALTERNATE };
+enum EMarqueeDirection { MAUTO = 0, MLEFT = 1, MRIGHT = -1, MUP = 2, MDOWN = -2, MFORWARD = 3, MBACKWARD = -3 };
+
+// CSS3 Flexible Box Properties
+
+enum EBoxAlignment { BSTRETCH, BSTART, BCENTER, BEND, BJUSTIFY, BBASELINE };
+enum EBoxOrient { HORIZONTAL, VERTICAL };
+enum EBoxLines { SINGLE, MULTIPLE };
+enum EBoxDirection { BNORMAL, BREVERSE };
+
+enum ETextSecurity {
+ TSNONE, TSDISC, TSCIRCLE, TSSQUARE
+};
+
+// CSS3 User Modify Properties
+
+enum EUserModify {
+ READ_ONLY, READ_WRITE, READ_WRITE_PLAINTEXT_ONLY
+};
+
+// CSS3 User Drag Values
+
+enum EUserDrag {
+ DRAG_AUTO, DRAG_NONE, DRAG_ELEMENT
+};
+
+// CSS3 User Select Values
+
+enum EUserSelect {
+ SELECT_NONE, SELECT_TEXT
+};
+
+// Word Break Values. Matches WinIE, rather than CSS3
+
+enum EWordBreak {
+ NormalWordBreak, BreakAllWordBreak, BreakWordBreak
+};
+
+enum EWordWrap {
+ NormalWordWrap, BreakWordWrap
+};
+
+enum ENBSPMode {
+ NBNORMAL, SPACE
+};
+
+enum EKHTMLLineBreak {
+ LBNORMAL, AFTER_WHITE_SPACE
+};
+
+enum EMatchNearestMailBlockquoteColor {
+ BCNORMAL, MATCH
+};
+
+enum EResize {
+ RESIZE_NONE, RESIZE_BOTH, RESIZE_HORIZONTAL, RESIZE_VERTICAL
+};
+
+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
+};
+
+enum ContentType {
+ CONTENT_NONE, CONTENT_OBJECT, CONTENT_TEXT, CONTENT_COUNTER
+};
+
+enum EBorderFit { BorderFitBorder, BorderFitLines };
+
+enum ETimingFunctionType { LinearTimingFunction, CubicBezierTimingFunction };
+
+enum EAnimPlayState {
+ AnimPlayStatePlaying = 0x0,
+ AnimPlayStatePaused = 0x1
+};
+
+enum EWhiteSpace {
+ NORMAL, PRE, PRE_WRAP, PRE_LINE, NOWRAP, KHTML_NOWRAP
+};
+
+enum ETextAlign {
+ TAAUTO, LEFT, RIGHT, CENTER, JUSTIFY, WEBKIT_LEFT, WEBKIT_RIGHT, WEBKIT_CENTER
+};
+
+enum ETextTransform {
+ CAPITALIZE, UPPERCASE, LOWERCASE, TTNONE
+};
+
+enum ETextDecoration {
+ TDNONE = 0x0 , UNDERLINE = 0x1, OVERLINE = 0x2, LINE_THROUGH= 0x4, BLINK = 0x8
+};
+
+enum EPageBreak {
+ PBAUTO, PBALWAYS, PBAVOID
+};
+
+enum EEmptyCell {
+ SHOW, HIDE
+};
+
+enum ECaptionSide {
+ CAPTOP, CAPBOTTOM, CAPLEFT, CAPRIGHT
+};
+
+enum EListStylePosition { OUTSIDE, INSIDE };
+
+enum EVisibility { VISIBLE, HIDDEN, COLLAPSE };
+
+enum ECursor {
+ // The following must match the order in CSSValueKeywords.in.
+ CURSOR_AUTO,
+ CURSOR_CROSS,
+ CURSOR_DEFAULT,
+ CURSOR_POINTER,
+ CURSOR_MOVE,
+ CURSOR_VERTICAL_TEXT,
+ CURSOR_CELL,
+ CURSOR_CONTEXT_MENU,
+ CURSOR_ALIAS,
+ CURSOR_PROGRESS,
+ CURSOR_NO_DROP,
+ CURSOR_NOT_ALLOWED,
+ CURSOR_WEBKIT_ZOOM_IN,
+ CURSOR_WEBKIT_ZOOM_OUT,
+ CURSOR_E_RESIZE,
+ CURSOR_NE_RESIZE,
+ CURSOR_NW_RESIZE,
+ CURSOR_N_RESIZE,
+ CURSOR_SE_RESIZE,
+ CURSOR_SW_RESIZE,
+ CURSOR_S_RESIZE,
+ CURSOR_W_RESIZE,
+ CURSOR_EW_RESIZE,
+ CURSOR_NS_RESIZE,
+ CURSOR_NESW_RESIZE,
+ CURSOR_NWSE_RESIZE,
+ CURSOR_COL_RESIZE,
+ CURSOR_ROW_RESIZE,
+ CURSOR_TEXT,
+ CURSOR_WAIT,
+ CURSOR_HELP,
+ CURSOR_ALL_SCROLL,
+ CURSOR_WEBKIT_GRAB,
+ CURSOR_WEBKIT_GRABBING,
+
+ // The following are handled as exceptions so don't need to match.
+ CURSOR_COPY,
+ CURSOR_NONE
+};
+
+enum EDisplay {
+ INLINE, BLOCK, LIST_ITEM, RUN_IN, COMPACT, INLINE_BLOCK,
+ 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
+};
+
+enum EPointerEvents {
+ PE_NONE, PE_AUTO, PE_STROKE, PE_FILL, PE_PAINTED, PE_VISIBLE,
+ PE_VISIBLE_STROKE, PE_VISIBLE_FILL, PE_VISIBLE_PAINTED, PE_ALL
+};
+
+} // namespace WebCore
+
+#endif // RenderStyleConstants_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp
new file mode 100644
index 0000000..1749978
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.cpp
@@ -0,0 +1,146 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+
+ Based on khtml code by:
+ Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
+ 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
+ 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"
+#if ENABLE(SVG)
+#include "SVGRenderStyle.h"
+
+#include "CSSPrimitiveValue.h"
+#include "CSSValueList.h"
+#include "RenderObject.h"
+#include "RenderStyle.h"
+#include "SVGStyledElement.h"
+
+namespace WebCore {
+
+SVGRenderStyle::SVGRenderStyle()
+{
+ static SVGRenderStyle* defaultStyle = new SVGRenderStyle(CreateDefault);
+
+ fill = defaultStyle->fill;
+ stroke = defaultStyle->stroke;
+ text = defaultStyle->text;
+ stops = defaultStyle->stops;
+ clip = defaultStyle->clip;
+ mask = defaultStyle->mask;
+ misc = defaultStyle->misc;
+ markers = defaultStyle->markers;
+
+ setBitDefaults();
+}
+
+SVGRenderStyle::SVGRenderStyle(CreateDefaultType)
+{
+ setBitDefaults();
+
+ fill.init();
+ stroke.init();
+ text.init();
+ stops.init();
+ clip.init();
+ mask.init();
+ misc.init();
+ markers.init();
+}
+
+SVGRenderStyle::SVGRenderStyle(const SVGRenderStyle& other)
+ : RefCounted<SVGRenderStyle>()
+{
+ fill = other.fill;
+ stroke = other.stroke;
+ text = other.text;
+ stops = other.stops;
+ clip = other.clip;
+ mask = other.mask;
+ misc = other.misc;
+ markers = other.markers;
+
+ svg_inherited_flags = other.svg_inherited_flags;
+ svg_noninherited_flags = other.svg_noninherited_flags;
+}
+
+SVGRenderStyle::~SVGRenderStyle()
+{
+}
+
+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 &&
+ svg_inherited_flags == o.svg_inherited_flags &&
+ svg_noninherited_flags == o.svg_noninherited_flags);
+}
+
+bool SVGRenderStyle::inheritedNotEqual(const SVGRenderStyle* other) const
+{
+ return (fill != other->fill
+ || stroke != other->stroke
+ || markers != other->markers
+ || text != other->text
+ || svg_inherited_flags != other->svg_inherited_flags);
+}
+
+void SVGRenderStyle::inheritFrom(const SVGRenderStyle* svgInheritParent)
+{
+ if (!svgInheritParent)
+ return;
+
+ fill = svgInheritParent->fill;
+ stroke = svgInheritParent->stroke;
+ markers = svgInheritParent->markers;
+ text = svgInheritParent->text;
+
+ svg_inherited_flags = svgInheritParent->svg_inherited_flags;
+}
+
+float SVGRenderStyle::cssPrimitiveToLength(const RenderObject* item, CSSValue* value, float defaultValue)
+{
+ CSSPrimitiveValue* primitive = static_cast<CSSPrimitiveValue*>(value);
+
+ unsigned short cssType = (primitive ? primitive->primitiveType() : (unsigned short) CSSPrimitiveValue::CSS_UNKNOWN);
+ if (!(cssType > CSSPrimitiveValue::CSS_UNKNOWN && cssType <= CSSPrimitiveValue::CSS_PC))
+ return defaultValue;
+
+ if (cssType == CSSPrimitiveValue::CSS_PERCENTAGE) {
+ SVGStyledElement* element = static_cast<SVGStyledElement*>(item->element());
+ SVGElement* viewportElement = (element ? element->viewportElement() : 0);
+ if (viewportElement) {
+ float result = primitive->getFloatValue() / 100.0f;
+ return SVGLength::PercentageOfViewport(result, element, LengthModeOther);
+ }
+ }
+
+ return primitive->computeLengthFloat(const_cast<RenderStyle*>(item->style()));
+}
+
+}
+
+#endif // ENABLE(SVG)
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.h b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.h
new file mode 100644
index 0000000..0e9dae4
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyle.h
@@ -0,0 +1,215 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 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
+ 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 SVGRenderStyle_h
+#define SVGRenderStyle_h
+
+#if ENABLE(SVG)
+#include "CSSValueList.h"
+#include "DataRef.h"
+#include "GraphicsTypes.h"
+#include "SVGPaint.h"
+#include "SVGRenderStyleDefs.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();
+
+ 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()
+ {
+ 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();
+ }
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // SVGRenderStyle_h
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.cpp b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.cpp
new file mode 100644
index 0000000..f5faad3
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.cpp
@@ -0,0 +1,218 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 2007 Rob Buis <buis@kde.org>
+
+ Based on khtml code by:
+ Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
+ 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
+ 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"
+#if ENABLE(SVG)
+#include "SVGRenderStyleDefs.h"
+
+#include "RenderStyle.h"
+#include "SVGRenderStyle.h"
+
+using namespace WebCore;
+
+StyleFillData::StyleFillData()
+{
+ paint = SVGRenderStyle::initialFillPaint();
+ opacity = SVGRenderStyle::initialFillOpacity();
+}
+
+StyleFillData::StyleFillData(const StyleFillData& other)
+ : RefCounted<StyleFillData>()
+{
+ paint = other.paint;
+ opacity = other.opacity;
+}
+
+bool StyleFillData::operator==(const StyleFillData &other) const
+{
+ if (opacity != other.opacity)
+ return false;
+
+ if (!paint || !other.paint)
+ return paint == other.paint;
+
+ if (paint->paintType() != other.paint->paintType())
+ return false;
+
+ if (paint->paintType() == SVGPaint::SVG_PAINTTYPE_URI)
+ return paint->uri() == other.paint->uri();
+
+ if (paint->paintType() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR)
+ return paint->color() == other.paint->color();
+
+ return paint == other.paint;
+}
+
+StyleStrokeData::StyleStrokeData()
+{
+ width = SVGRenderStyle::initialStrokeWidth();
+ paint = SVGRenderStyle::initialStrokePaint();
+ opacity = SVGRenderStyle::initialStrokeOpacity();
+ miterLimit = SVGRenderStyle::initialStrokeMiterLimit();
+ dashOffset = SVGRenderStyle::initialStrokeDashOffset();
+ dashArray = SVGRenderStyle::initialStrokeDashArray();
+}
+
+StyleStrokeData::StyleStrokeData(const StyleStrokeData& other)
+ : RefCounted<StyleStrokeData>()
+{
+ width = other.width;
+ paint = other.paint;
+ opacity = other.opacity;
+ miterLimit = other.miterLimit;
+ dashOffset = other.dashOffset;
+ dashArray = other.dashArray;
+}
+
+bool StyleStrokeData::operator==(const StyleStrokeData &other) const
+{
+ return (paint == other.paint) &&
+ (width == other.width) &&
+ (opacity == other.opacity) &&
+ (miterLimit == other.miterLimit) &&
+ (dashOffset == other.dashOffset) &&
+ (dashArray == other.dashArray);
+}
+
+StyleStopData::StyleStopData()
+{
+ color = SVGRenderStyle::initialStopColor();
+ opacity = SVGRenderStyle::initialStopOpacity();
+}
+
+StyleStopData::StyleStopData(const StyleStopData& other)
+ : RefCounted<StyleStopData>()
+{
+ color = other.color;
+ opacity = other.opacity;
+}
+
+bool StyleStopData::operator==(const StyleStopData &other) const
+{
+ return (color == other.color) &&
+ (opacity == other.opacity);
+}
+
+StyleTextData::StyleTextData()
+{
+ kerning = SVGRenderStyle::initialKerning();
+}
+
+StyleTextData::StyleTextData(const StyleTextData& other)
+ : RefCounted<StyleTextData>()
+{
+ kerning = other.kerning;
+}
+
+bool StyleTextData::operator==(const StyleTextData& other) const
+{
+ return kerning == other.kerning;
+}
+
+StyleClipData::StyleClipData()
+{
+ clipPath = SVGRenderStyle::initialClipPath();
+}
+
+StyleClipData::StyleClipData(const StyleClipData& other)
+ : RefCounted<StyleClipData>()
+{
+ clipPath = other.clipPath;
+}
+
+bool StyleClipData::operator==(const StyleClipData &other) const
+{
+ return (clipPath == other.clipPath);
+}
+
+StyleMaskData::StyleMaskData()
+{
+ maskElement = SVGRenderStyle::initialMaskElement();
+}
+
+StyleMaskData::StyleMaskData(const StyleMaskData& other)
+ : RefCounted<StyleMaskData>()
+{
+ maskElement = other.maskElement;
+}
+
+bool StyleMaskData::operator==(const StyleMaskData &other) const
+{
+ return (maskElement == other.maskElement);
+}
+
+StyleMarkerData::StyleMarkerData()
+{
+ startMarker = SVGRenderStyle::initialStartMarker();
+ midMarker = SVGRenderStyle::initialMidMarker();
+ endMarker = SVGRenderStyle::initialEndMarker();
+}
+
+StyleMarkerData::StyleMarkerData(const StyleMarkerData& other)
+ : RefCounted<StyleMarkerData>()
+{
+ startMarker = other.startMarker;
+ midMarker = other.midMarker;
+ endMarker = other.endMarker;
+}
+
+bool StyleMarkerData::operator==(const StyleMarkerData &other) const
+{
+ return (startMarker == other.startMarker && midMarker == other.midMarker && endMarker == other.endMarker);
+}
+
+StyleMiscData::StyleMiscData()
+{
+ floodColor = SVGRenderStyle::initialFloodColor();
+ floodOpacity = SVGRenderStyle::initialFloodOpacity();
+ lightingColor = SVGRenderStyle::initialLightingColor();
+ baselineShiftValue = SVGRenderStyle::initialBaselineShiftValue();
+}
+
+StyleMiscData::StyleMiscData(const StyleMiscData& other)
+ : RefCounted<StyleMiscData>()
+{
+ filter = other.filter;
+ floodColor = other.floodColor;
+ floodOpacity = other.floodOpacity;
+ lightingColor = other.lightingColor;
+ baselineShiftValue = other.baselineShiftValue;
+}
+
+bool StyleMiscData::operator==(const StyleMiscData &other) const
+{
+ return filter == other.filter
+ && floodOpacity == other.floodOpacity
+ && floodColor == other.floodColor
+ && lightingColor == other.lightingColor
+ && baselineShiftValue == other.baselineShiftValue;
+}
+
+#endif // ENABLE(SVG)
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.h b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.h
new file mode 100644
index 0000000..cb504d2
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/SVGRenderStyleDefs.h
@@ -0,0 +1,292 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+
+ Based on khtml code by:
+ Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org)
+ (C) 2000 Antti Koivisto (koivisto@kde.org)
+ (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
+ 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 SVGRenderStyleDefs_h
+#define SVGRenderStyleDefs_h
+
+#if ENABLE(SVG)
+#include "Color.h"
+#include "Path.h"
+#include "PlatformString.h"
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+// Helper macros for 'SVGRenderStyle'
+#define SVG_RS_DEFINE_ATTRIBUTE(Data, Type, Name, Initial) \
+ void set##Type(Data val) { svg_noninherited_flags.f._##Name = val; } \
+ Data Name() const { return (Data) svg_noninherited_flags.f._##Name; } \
+ static Data initial##Type() { return Initial; }
+
+#define SVG_RS_DEFINE_ATTRIBUTE_INHERITED(Data, Type, Name, Initial) \
+ void set##Type(Data val) { svg_inherited_flags._##Name = val; } \
+ Data Name() const { return (Data) svg_inherited_flags._##Name; } \
+ static Data initial##Type() { return Initial; }
+
+// "Helper" macros for SVG's RenderStyle properties
+// FIXME: These are impossible to work with or debug.
+#define SVG_RS_DEFINE_ATTRIBUTE_DATAREF(Data, Group, Variable, Type, Name) \
+ Data Name() const { return Group->Variable; } \
+ void set##Type(Data obj) { SVG_RS_SET_VARIABLE(Group, Variable, obj) }
+
+#define SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL(Data, Group, Variable, Type, Name, Initial) \
+ SVG_RS_DEFINE_ATTRIBUTE_DATAREF(Data, Group, Variable, Type, Name) \
+ static Data initial##Type() { return Initial; }
+
+#define SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(Data, Group, Variable, Type, Name, Initial) \
+ Data* Name() const { return Group->Variable.get(); } \
+ void set##Type(PassRefPtr<Data> obj) { \
+ if(!(Group->Variable == obj)) \
+ Group.access()->Variable = obj; \
+ } \
+ static Data* initial##Type() { return Initial; }
+
+#define SVG_RS_SET_VARIABLE(Group, Variable, Value) \
+ if(!(Group->Variable == Value)) \
+ Group.access()->Variable = Value;
+
+namespace WebCore {
+
+ enum EBaselineShift {
+ BS_BASELINE, BS_SUB, BS_SUPER, BS_LENGTH
+ };
+
+ enum ETextAnchor {
+ TA_START, TA_MIDDLE, TA_END
+ };
+
+ enum EColorInterpolation {
+ CI_AUTO, CI_SRGB, CI_LINEARRGB
+ };
+
+ enum EColorRendering {
+ CR_AUTO, CR_OPTIMIZESPEED, CR_OPTIMIZEQUALITY
+ };
+
+ enum EImageRendering {
+ IR_AUTO, IR_OPTIMIZESPEED, IR_OPTIMIZEQUALITY
+ };
+
+ enum EShapeRendering {
+ 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
+ };
+
+ enum EGlyphOrientation {
+ GO_0DEG, GO_90DEG, GO_180DEG, GO_270DEG, GO_AUTO
+ };
+
+ enum EAlignmentBaseline {
+ AB_AUTO, AB_BASELINE, AB_BEFORE_EDGE, AB_TEXT_BEFORE_EDGE,
+ AB_MIDDLE, AB_CENTRAL, AB_AFTER_EDGE, AB_TEXT_AFTER_EDGE,
+ AB_IDEOGRAPHIC, AB_ALPHABETIC, AB_HANGING, AB_MATHEMATICAL
+ };
+
+ enum EDominantBaseline {
+ DB_AUTO, DB_USE_SCRIPT, DB_NO_CHANGE, DB_RESET_SIZE,
+ DB_IDEOGRAPHIC, DB_ALPHABETIC, DB_HANGING, DB_MATHEMATICAL,
+ DB_CENTRAL, DB_MIDDLE, DB_TEXT_AFTER_EDGE, DB_TEXT_BEFORE_EDGE
+ };
+
+ class CSSValue;
+ class CSSValueList;
+ class SVGPaint;
+
+ // Inherited/Non-Inherited Style Datastructures
+ class StyleFillData : public RefCounted<StyleFillData> {
+ public:
+ static PassRefPtr<StyleFillData> create() { return adoptRef(new StyleFillData); }
+ PassRefPtr<StyleFillData> copy() const { return adoptRef(new StyleFillData(*this)); }
+
+ bool operator==(const StyleFillData &other) const;
+ bool operator!=(const StyleFillData &other) const
+ {
+ return !(*this == other);
+ }
+
+ float opacity;
+ RefPtr<SVGPaint> paint;
+
+ private:
+ StyleFillData();
+ StyleFillData(const StyleFillData&);
+ };
+
+ class StyleStrokeData : public RefCounted<StyleStrokeData> {
+ public:
+ static PassRefPtr<StyleStrokeData> create() { return adoptRef(new StyleStrokeData); }
+ PassRefPtr<StyleStrokeData> copy() const { return adoptRef(new StyleStrokeData(*this)); }
+
+ bool operator==(const StyleStrokeData&) const;
+ bool operator!=(const StyleStrokeData& other) const
+ {
+ return !(*this == other);
+ }
+
+ float opacity;
+ float miterLimit;
+
+ RefPtr<CSSValue> width;
+ RefPtr<CSSValue> dashOffset;
+
+ RefPtr<SVGPaint> paint;
+ RefPtr<CSSValueList> dashArray;
+
+ private:
+ StyleStrokeData();
+ StyleStrokeData(const StyleStrokeData&);
+ };
+
+ class StyleStopData : public RefCounted<StyleStopData> {
+ public:
+ static PassRefPtr<StyleStopData> create() { return adoptRef(new StyleStopData); }
+ PassRefPtr<StyleStopData> copy() const { return adoptRef(new StyleStopData(*this)); }
+
+ bool operator==(const StyleStopData &other) const;
+ bool operator!=(const StyleStopData &other) const
+ {
+ return !(*this == other);
+ }
+
+ float opacity;
+ Color color;
+
+ private:
+ StyleStopData();
+ StyleStopData(const StyleStopData&);
+ };
+
+ class StyleTextData : public RefCounted<StyleTextData> {
+ public:
+ static PassRefPtr<StyleTextData> create() { return adoptRef(new StyleTextData); }
+ PassRefPtr<StyleTextData> copy() const { return adoptRef(new StyleTextData(*this)); }
+
+ bool operator==(const StyleTextData& other) const;
+ bool operator!=(const StyleTextData& other) const
+ {
+ return !(*this == other);
+ }
+
+ RefPtr<CSSValue> kerning;
+
+ private:
+ StyleTextData();
+ StyleTextData(const StyleTextData& other);
+ };
+
+ class StyleClipData : public RefCounted<StyleClipData> {
+ public:
+ static PassRefPtr<StyleClipData> create() { return adoptRef(new StyleClipData); }
+ PassRefPtr<StyleClipData> copy() const { return adoptRef(new StyleClipData(*this)); }
+
+ bool operator==(const StyleClipData &other) const;
+ bool operator!=(const StyleClipData &other) const
+ {
+ return !(*this == other);
+ }
+
+ String clipPath;
+
+ private:
+ StyleClipData();
+ StyleClipData(const StyleClipData&);
+ };
+
+ class StyleMaskData : public RefCounted<StyleMaskData> {
+ public:
+ static PassRefPtr<StyleMaskData> create() { return adoptRef(new StyleMaskData); }
+ PassRefPtr<StyleMaskData> copy() const { return adoptRef(new StyleMaskData(*this)); }
+
+ bool operator==(const StyleMaskData &other) const;
+ bool operator!=(const StyleMaskData &other) const { return !(*this == other); }
+
+ String maskElement;
+
+ private:
+ StyleMaskData();
+ StyleMaskData(const StyleMaskData&);
+ };
+
+ class StyleMarkerData : public RefCounted<StyleMarkerData> {
+ public:
+ static PassRefPtr<StyleMarkerData> create() { return adoptRef(new StyleMarkerData); }
+ PassRefPtr<StyleMarkerData> copy() const { return adoptRef(new StyleMarkerData(*this)); }
+
+ bool operator==(const StyleMarkerData &other) const;
+ bool operator!=(const StyleMarkerData &other) const
+ {
+ return !(*this == other);
+ }
+
+ String startMarker;
+ String midMarker;
+ String endMarker;
+
+ private:
+ StyleMarkerData();
+ StyleMarkerData(const StyleMarkerData&);
+ };
+
+ // Note : the rule for this class is, *no inheritance* of these props
+ class StyleMiscData : public RefCounted<StyleMiscData> {
+ public:
+ static PassRefPtr<StyleMiscData> create() { return adoptRef(new StyleMiscData); }
+ PassRefPtr<StyleMiscData> copy() const { return adoptRef(new StyleMiscData(*this)); }
+
+ bool operator==(const StyleMiscData &other) const;
+ bool operator!=(const StyleMiscData &other) const
+ {
+ return !(*this == other);
+ }
+
+ String filter;
+ Color floodColor;
+ float floodOpacity;
+
+ Color lightingColor;
+
+ // non-inherited text stuff lives here not in StyleTextData.
+ RefPtr<CSSValue> baselineShiftValue;
+
+ private:
+ StyleMiscData();
+ StyleMiscData(const StyleMiscData&);
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // SVGRenderStyleDefs_h
+
+// vim:ts=4:noet
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/ShadowData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/ShadowData.cpp
new file mode 100644
index 0000000..75fb9dc
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/ShadowData.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "ShadowData.h"
+
+namespace WebCore {
+
+ShadowData::ShadowData(const ShadowData& o)
+ : x(o.x)
+ , y(o.y)
+ , blur(o.blur)
+ , color(o.color)
+{
+ next = o.next ? new ShadowData(*o.next) : 0;
+}
+
+bool ShadowData::operator==(const ShadowData& o) const
+{
+ if ((next && !o.next) || (!next && o.next) ||
+ (next && o.next && *next != *o.next))
+ return false;
+
+ return x == o.x && y == o.y && blur == o.blur && color == o.color;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/ShadowData.h b/src/3rdparty/webkit/WebCore/rendering/style/ShadowData.h
new file mode 100644
index 0000000..dac2b18
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/ShadowData.h
@@ -0,0 +1,71 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 ShadowData_h
+#define ShadowData_h
+
+#include "Color.h"
+
+namespace WebCore {
+
+// This struct holds information about shadows for the text-shadow and box-shadow properties.
+
+struct ShadowData {
+ ShadowData()
+ : x(0)
+ , y(0)
+ , blur(0)
+ , next(0)
+ {
+ }
+
+ ShadowData(int _x, int _y, int _blur, const Color& _color)
+ : x(_x)
+ , y(_y)
+ , blur(_blur)
+ , color(_color)
+ , next(0)
+ {
+ }
+
+ ShadowData(const ShadowData& o);
+
+ ~ShadowData() { delete next; }
+
+ bool operator==(const ShadowData& o) const;
+ bool operator!=(const ShadowData& o) const
+ {
+ return !(*this == o);
+ }
+
+ int x;
+ int y;
+ int blur;
+ Color color;
+ ShadowData* next;
+};
+
+} // namespace WebCore
+
+#endif // ShadowData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleBackgroundData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleBackgroundData.cpp
new file mode 100644
index 0000000..68a9ddd
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleBackgroundData.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleBackgroundData.h"
+
+#include "RenderStyleConstants.h"
+
+namespace WebCore {
+
+StyleBackgroundData::StyleBackgroundData()
+ : m_background(BackgroundFillLayer)
+{
+}
+
+StyleBackgroundData::StyleBackgroundData(const StyleBackgroundData& o)
+ : RefCounted<StyleBackgroundData>()
+ , m_background(o.m_background)
+ , m_color(o.m_color)
+ , m_outline(o.m_outline)
+{
+}
+
+bool StyleBackgroundData::operator==(const StyleBackgroundData& o) const
+{
+ return m_background == o.m_background && m_color == o.m_color && m_outline == o.m_outline;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleBackgroundData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleBackgroundData.h
new file mode 100644
index 0000000..8f2da36
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleBackgroundData.h
@@ -0,0 +1,59 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleBackgroundData_h
+#define StyleBackgroundData_h
+
+#include "Color.h"
+#include "FillLayer.h"
+#include "OutlineValue.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class StyleBackgroundData : public RefCounted<StyleBackgroundData> {
+public:
+ static PassRefPtr<StyleBackgroundData> create() { return adoptRef(new StyleBackgroundData); }
+ PassRefPtr<StyleBackgroundData> copy() const { return adoptRef(new StyleBackgroundData(*this)); }
+ ~StyleBackgroundData() { }
+
+ bool operator==(const StyleBackgroundData& o) const;
+ bool operator!=(const StyleBackgroundData& o) const
+ {
+ return !(*this == o);
+ }
+
+ FillLayer m_background;
+ Color m_color;
+ OutlineValue m_outline;
+
+private:
+ StyleBackgroundData();
+ StyleBackgroundData(const StyleBackgroundData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleBackgroundData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleBoxData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleBoxData.cpp
new file mode 100644
index 0000000..d9734d1
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleBoxData.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleBoxData.h"
+
+#include "RenderStyle.h"
+#include "RenderStyleConstants.h"
+
+namespace WebCore {
+
+StyleBoxData::StyleBoxData()
+ : z_index(0)
+ , z_auto(true)
+ , boxSizing(CONTENT_BOX)
+{
+ // Initialize our min/max widths/heights.
+ min_width = min_height = RenderStyle::initialMinSize();
+ max_width = max_height = RenderStyle::initialMaxSize();
+}
+
+StyleBoxData::StyleBoxData(const StyleBoxData& o)
+ : RefCounted<StyleBoxData>()
+ , width(o.width)
+ , height(o.height)
+ , min_width(o.min_width)
+ , max_width(o.max_width)
+ , min_height(o.min_height)
+ , max_height(o.max_height)
+ , z_index(o.z_index)
+ , z_auto(o.z_auto)
+ , boxSizing(o.boxSizing)
+{
+}
+
+bool StyleBoxData::operator==(const StyleBoxData& o) const
+{
+ return width == o.width &&
+ height == o.height &&
+ min_width == o.min_width &&
+ max_width == o.max_width &&
+ min_height == o.min_height &&
+ max_height == o.max_height &&
+ z_index == o.z_index &&
+ z_auto == o.z_auto &&
+ boxSizing == o.boxSizing;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleBoxData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleBoxData.h
new file mode 100644
index 0000000..a5bd2ff
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleBoxData.h
@@ -0,0 +1,67 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleBoxData_h
+#define StyleBoxData_h
+
+#include "Length.h"
+#include <wtf/RefCounted.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class StyleBoxData : public RefCounted<StyleBoxData> {
+public:
+ static PassRefPtr<StyleBoxData> create() { return adoptRef(new StyleBoxData); }
+ PassRefPtr<StyleBoxData> copy() const { return adoptRef(new StyleBoxData(*this)); }
+
+ bool operator==(const StyleBoxData& o) const;
+ bool operator!=(const StyleBoxData& o) const
+ {
+ return !(*this == o);
+ }
+
+ Length width;
+ Length height;
+
+ Length min_width;
+ Length max_width;
+
+ Length min_height;
+ Length max_height;
+
+ Length vertical_align;
+
+ int z_index;
+ bool z_auto : 1;
+ unsigned boxSizing : 1; // EBoxSizing
+
+private:
+ StyleBoxData();
+ StyleBoxData(const StyleBoxData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleBoxData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleCachedImage.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleCachedImage.cpp
new file mode 100644
index 0000000..b55c5b9
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleCachedImage.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ * 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 "StyleCachedImage.h"
+
+#include "CachedImage.h"
+#include "RenderObject.h"
+
+namespace WebCore {
+
+PassRefPtr<CSSValue> StyleCachedImage::cssValue()
+{
+ return CSSPrimitiveValue::create(m_image->url(), CSSPrimitiveValue::CSS_URI);
+}
+
+bool StyleCachedImage::canRender(float multiplier) const
+{
+ return m_image->canRender(multiplier);
+}
+
+bool StyleCachedImage::isLoaded() const
+{
+ return m_image->isLoaded();
+}
+
+bool StyleCachedImage::errorOccurred() const
+{
+ return m_image->errorOccurred();
+}
+
+IntSize StyleCachedImage::imageSize(const RenderObject* /*renderer*/, float multiplier) const
+{
+ return m_image->imageSize(multiplier);
+}
+
+bool StyleCachedImage::imageHasRelativeWidth() const
+{
+ return m_image->imageHasRelativeWidth();
+}
+
+bool StyleCachedImage::imageHasRelativeHeight() const
+{
+ return m_image->imageHasRelativeHeight();
+}
+
+bool StyleCachedImage::usesImageContainerSize() const
+{
+ return m_image->usesImageContainerSize();
+}
+
+void StyleCachedImage::setImageContainerSize(const IntSize& size)
+{
+ return m_image->setImageContainerSize(size);
+}
+
+void StyleCachedImage::addClient(RenderObject* renderer)
+{
+ return m_image->addClient(renderer);
+}
+
+void StyleCachedImage::removeClient(RenderObject* renderer)
+{
+ return m_image->removeClient(renderer);
+}
+
+Image* StyleCachedImage::image(RenderObject*, const IntSize&) const
+{
+ return m_image->image();
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleCachedImage.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleCachedImage.h
new file mode 100644
index 0000000..3d22868
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleCachedImage.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ *
+ * 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 StyleCachedImage_h
+#define StyleCachedImage_h
+
+#include "CachedResourceHandle.h"
+#include "StyleImage.h"
+
+namespace WebCore {
+
+class CachedImage;
+
+class StyleCachedImage : public StyleImage {
+public:
+ static PassRefPtr<StyleCachedImage> create(CachedImage* image) { return adoptRef(new StyleCachedImage(image)); }
+ virtual WrappedImagePtr data() const { return m_image.get(); }
+
+ virtual bool isCachedImage() const { return true; }
+
+ virtual PassRefPtr<CSSValue> cssValue();
+
+ CachedImage* cachedImage() const { return m_image.get(); }
+
+ virtual bool canRender(float multiplier) const;
+ virtual bool isLoaded() const;
+ virtual bool errorOccurred() const;
+ virtual IntSize imageSize(const RenderObject*, float multiplier) const;
+ virtual bool imageHasRelativeWidth() const;
+ virtual bool imageHasRelativeHeight() const;
+ virtual bool usesImageContainerSize() const;
+ virtual void setImageContainerSize(const IntSize&);
+ virtual void addClient(RenderObject*);
+ virtual void removeClient(RenderObject*);
+ virtual Image* image(RenderObject*, const IntSize&) const;
+
+private:
+ StyleCachedImage(CachedImage* image)
+ : m_image(image)
+ {
+ }
+
+ CachedResourceHandle<CachedImage> m_image;
+};
+
+}
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleDashboardRegion.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleDashboardRegion.h
new file mode 100644
index 0000000..bbb0cda
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleDashboardRegion.h
@@ -0,0 +1,61 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleDashboardRegion_h
+#define StyleDashboardRegion_h
+#if ENABLE(DASHBOARD_SUPPORT)
+
+#include "LengthBox.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+// Dashboard region attributes. Not inherited.
+
+struct StyleDashboardRegion {
+ String label;
+ LengthBox offset;
+ int type;
+
+ enum {
+ None,
+ Circle,
+ Rectangle
+ };
+
+ bool operator==(const StyleDashboardRegion& o) const
+ {
+ return type == o.type && offset == o.offset && label == o.label;
+ }
+
+ bool operator!=(const StyleDashboardRegion& o) const
+ {
+ return !(*this == o);
+ }
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DASHBOARD_SUPPORT)
+#endif // StyleDashboardRegion_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleFlexibleBoxData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleFlexibleBoxData.cpp
new file mode 100644
index 0000000..7c00080
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleFlexibleBoxData.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleFlexibleBoxData.h"
+
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+StyleFlexibleBoxData::StyleFlexibleBoxData()
+ : flex(RenderStyle::initialBoxFlex())
+ , flex_group(RenderStyle::initialBoxFlexGroup())
+ , ordinal_group(RenderStyle::initialBoxOrdinalGroup())
+ , align(RenderStyle::initialBoxAlign())
+ , pack(RenderStyle::initialBoxPack())
+ , orient(RenderStyle::initialBoxOrient())
+ , lines(RenderStyle::initialBoxLines())
+{
+}
+
+StyleFlexibleBoxData::StyleFlexibleBoxData(const StyleFlexibleBoxData& o)
+ : RefCounted<StyleFlexibleBoxData>()
+ , flex(o.flex)
+ , flex_group(o.flex_group)
+ , ordinal_group(o.ordinal_group)
+ , align(o.align)
+ , pack(o.pack)
+ , orient(o.orient)
+ , lines(o.lines)
+{
+}
+
+bool StyleFlexibleBoxData::operator==(const StyleFlexibleBoxData& o) const
+{
+ return flex == o.flex && flex_group == o.flex_group &&
+ ordinal_group == o.ordinal_group && align == o.align &&
+ pack == o.pack && orient == o.orient && lines == o.lines;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleFlexibleBoxData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleFlexibleBoxData.h
new file mode 100644
index 0000000..f5d5e74
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleFlexibleBoxData.h
@@ -0,0 +1,60 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleFlexibleBoxData_h
+#define StyleFlexibleBoxData_h
+
+#include <wtf/RefCounted.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class StyleFlexibleBoxData : public RefCounted<StyleFlexibleBoxData> {
+public:
+ static PassRefPtr<StyleFlexibleBoxData> create() { return adoptRef(new StyleFlexibleBoxData); }
+ PassRefPtr<StyleFlexibleBoxData> copy() const { return adoptRef(new StyleFlexibleBoxData(*this)); }
+
+ bool operator==(const StyleFlexibleBoxData& o) const;
+ bool operator!=(const StyleFlexibleBoxData& o) const
+ {
+ return !(*this == o);
+ }
+
+ float flex;
+ unsigned int flex_group;
+ unsigned int ordinal_group;
+
+ unsigned align : 3; // EBoxAlignment
+ unsigned pack: 3; // EBoxAlignment
+ unsigned orient: 1; // EBoxOrient
+ unsigned lines : 1; // EBoxLines
+
+private:
+ StyleFlexibleBoxData();
+ StyleFlexibleBoxData(const StyleFlexibleBoxData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleFlexibleBoxData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.cpp
new file mode 100644
index 0000000..fa361e8
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ * 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 "StyleGeneratedImage.h"
+
+#include "CSSImageGeneratorValue.h"
+#include "RenderObject.h"
+
+namespace WebCore {
+
+PassRefPtr<CSSValue> StyleGeneratedImage::cssValue()
+{
+ return m_generator;
+}
+
+IntSize StyleGeneratedImage::imageSize(const RenderObject* renderer, float /* multiplier */) const
+{
+ // We can ignore the multiplier, since we always store a raw zoomed size.
+ if (m_fixedSize)
+ return m_generator->fixedSize(renderer);
+ return m_containerSize;
+}
+
+void StyleGeneratedImage::setImageContainerSize(const IntSize& size)
+{
+ m_containerSize = size;
+}
+
+void StyleGeneratedImage::addClient(RenderObject* renderer)
+{
+ m_generator->addClient(renderer, IntSize());
+}
+
+void StyleGeneratedImage::removeClient(RenderObject* renderer)
+{
+ m_generator->removeClient(renderer);
+}
+
+Image* StyleGeneratedImage::image(RenderObject* renderer, const IntSize& size) const
+{
+ return m_generator->image(renderer, size);
+}
+
+}
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.h
new file mode 100644
index 0000000..532e383
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleGeneratedImage.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ *
+ * 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 StyleGeneratedImage_h
+#define StyleGeneratedImage_h
+
+#include "StyleImage.h"
+
+namespace WebCore {
+
+class CSSValue;
+class CSSImageGeneratorValue;
+
+class StyleGeneratedImage : public StyleImage {
+public:
+ static PassRefPtr<StyleGeneratedImage> create(CSSImageGeneratorValue* val, bool fixedSize)
+ {
+ return adoptRef(new StyleGeneratedImage(val, fixedSize));
+ }
+
+ virtual WrappedImagePtr data() const { return m_generator; }
+
+ virtual bool isGeneratedImage() const { return true; }
+
+ virtual PassRefPtr<CSSValue> cssValue();
+
+ virtual IntSize imageSize(const RenderObject*, float multiplier) const;
+ virtual bool imageHasRelativeWidth() const { return !m_fixedSize; }
+ virtual bool imageHasRelativeHeight() const { return !m_fixedSize; }
+ virtual bool usesImageContainerSize() const { return !m_fixedSize; }
+ virtual void setImageContainerSize(const IntSize&);
+ virtual void addClient(RenderObject*);
+ virtual void removeClient(RenderObject*);
+ virtual Image* image(RenderObject*, const IntSize&) const;
+
+private:
+ StyleGeneratedImage(CSSImageGeneratorValue* val, bool fixedSize)
+ : m_generator(val)
+ , m_fixedSize(fixedSize)
+ {
+ }
+
+ CSSImageGeneratorValue* m_generator; // The generator holds a reference to us.
+ IntSize m_containerSize;
+ bool m_fixedSize;
+};
+
+}
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleImage.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleImage.h
new file mode 100644
index 0000000..cb90288
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleImage.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ * 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 StyleImage_h
+#define StyleImage_h
+
+#include "IntSize.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class CSSValue;
+class Image;
+class RenderObject;
+
+typedef void* WrappedImagePtr;
+
+class StyleImage : public RefCounted<StyleImage> {
+public:
+ virtual ~StyleImage() { }
+
+ bool operator==(const StyleImage& other)
+ {
+ return data() == other.data();
+ }
+
+ virtual PassRefPtr<CSSValue> cssValue() = 0;
+
+ virtual bool canRender(float /*multiplier*/) const { return true; }
+ virtual bool isLoaded() const { return true; }
+ virtual bool errorOccurred() const { return false; }
+ virtual IntSize imageSize(const RenderObject*, float multiplier) const = 0;
+ virtual bool imageHasRelativeWidth() const = 0;
+ virtual bool imageHasRelativeHeight() const = 0;
+ virtual bool usesImageContainerSize() const = 0;
+ virtual void setImageContainerSize(const IntSize&) = 0;
+ virtual void addClient(RenderObject*) = 0;
+ virtual void removeClient(RenderObject*) = 0;
+ virtual Image* image(RenderObject*, const IntSize&) const = 0;
+ virtual WrappedImagePtr data() const = 0;
+ virtual bool isCachedImage() const { return false; }
+ virtual bool isGeneratedImage() const { return false; }
+
+ static bool imagesEquivalent(StyleImage* image1, StyleImage* image2)
+ {
+ if (image1 != image2) {
+ if (!image1 || !image2)
+ return false;
+ return *image1 == *image2;
+ }
+ return true;
+ }
+
+protected:
+ StyleImage() { }
+};
+
+}
+#endif
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp
new file mode 100644
index 0000000..56d2686
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleRareInheritedData.h"
+
+#include "RenderStyle.h"
+#include "StyleImage.h"
+
+namespace WebCore {
+
+StyleInheritedData::StyleInheritedData()
+ : indent(RenderStyle::initialTextIndent())
+ , line_height(RenderStyle::initialLineHeight())
+ , list_style_image(RenderStyle::initialListStyleImage())
+ , color(RenderStyle::initialColor())
+ , m_effectiveZoom(RenderStyle::initialZoom())
+ , horizontal_border_spacing(RenderStyle::initialHorizontalBorderSpacing())
+ , vertical_border_spacing(RenderStyle::initialVerticalBorderSpacing())
+ , widows(RenderStyle::initialWidows())
+ , orphans(RenderStyle::initialOrphans())
+ , page_break_inside(RenderStyle::initialPageBreak())
+{
+}
+
+StyleInheritedData::~StyleInheritedData()
+{
+}
+
+StyleInheritedData::StyleInheritedData(const StyleInheritedData& o)
+ : RefCounted<StyleInheritedData>()
+ , indent(o.indent)
+ , line_height(o.line_height)
+ , list_style_image(o.list_style_image)
+ , cursorData(o.cursorData)
+ , font(o.font)
+ , color(o.color)
+ , m_effectiveZoom(o.m_effectiveZoom)
+ , 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)
+{
+}
+
+static bool cursorDataEquivalent(const CursorList* c1, const CursorList* c2)
+{
+ if (c1 == c2)
+ return true;
+ if (!c1 && c2 || c1 && !c2)
+ return false;
+ return (*c1 == *c2);
+}
+
+bool StyleInheritedData::operator==(const StyleInheritedData& o) const
+{
+ return
+ indent == o.indent &&
+ line_height == o.line_height &&
+ StyleImage::imagesEquivalent(list_style_image.get(), o.list_style_image.get()) &&
+ cursorDataEquivalent(cursorData.get(), o.cursorData.get()) &&
+ font == o.font &&
+ color == o.color &&
+ m_effectiveZoom == o.m_effectiveZoom &&
+ 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;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.h
new file mode 100644
index 0000000..5f1077e
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleInheritedData.h
@@ -0,0 +1,80 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleInheritedData_h
+#define StyleInheritedData_h
+
+#include "Color.h"
+#include "Font.h"
+#include "Length.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class StyleImage;
+class CursorList;
+
+class StyleInheritedData : public RefCounted<StyleInheritedData> {
+public:
+ static PassRefPtr<StyleInheritedData> create() { return adoptRef(new StyleInheritedData); }
+ PassRefPtr<StyleInheritedData> copy() const { return adoptRef(new StyleInheritedData(*this)); }
+ ~StyleInheritedData();
+
+ bool operator==(const StyleInheritedData& o) const;
+ bool operator!=( const StyleInheritedData& o) const
+ {
+ return !(*this == o);
+ }
+
+ Length indent;
+ // could be packed in a short but doesn't
+ // make a difference currently because of padding
+ Length line_height;
+
+ RefPtr<StyleImage> list_style_image;
+ RefPtr<CursorList> cursorData;
+
+ Font font;
+ Color color;
+
+ float m_effectiveZoom;
+
+ short horizontal_border_spacing;
+ short vertical_border_spacing;
+
+ // Paged media properties.
+ short widows;
+ short orphans;
+ unsigned page_break_inside : 2; // EPageBreak
+
+private:
+ StyleInheritedData();
+ StyleInheritedData(const StyleInheritedData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleInheritedData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleMarqueeData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleMarqueeData.cpp
new file mode 100644
index 0000000..f0e824d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleMarqueeData.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleBackgroundData.h"
+
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+StyleMarqueeData::StyleMarqueeData()
+ : increment(RenderStyle::initialMarqueeIncrement())
+ , speed(RenderStyle::initialMarqueeSpeed())
+ , loops(RenderStyle::initialMarqueeLoopCount())
+ , behavior(RenderStyle::initialMarqueeBehavior())
+ , direction(RenderStyle::initialMarqueeDirection())
+{
+}
+
+StyleMarqueeData::StyleMarqueeData(const StyleMarqueeData& o)
+ : RefCounted<StyleMarqueeData>()
+ , increment(o.increment)
+ , speed(o.speed)
+ , loops(o.loops)
+ , behavior(o.behavior)
+ , direction(o.direction)
+{
+}
+
+bool StyleMarqueeData::operator==(const StyleMarqueeData& o) const
+{
+ return increment == o.increment && speed == o.speed && direction == o.direction &&
+ behavior == o.behavior && loops == o.loops;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleMarqueeData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleMarqueeData.h
new file mode 100644
index 0000000..5765f5d
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleMarqueeData.h
@@ -0,0 +1,61 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleMarqueeData_h
+#define StyleMarqueeData_h
+
+#include "Length.h"
+#include "RenderStyleConstants.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class StyleMarqueeData : public RefCounted<StyleMarqueeData> {
+public:
+ static PassRefPtr<StyleMarqueeData> create() { return adoptRef(new StyleMarqueeData); }
+ PassRefPtr<StyleMarqueeData> copy() const { return adoptRef(new StyleMarqueeData(*this)); }
+
+ bool operator==(const StyleMarqueeData& o) const;
+ bool operator!=(const StyleMarqueeData& o) const
+ {
+ return !(*this == o);
+ }
+
+ Length increment;
+ int speed;
+
+ int loops; // -1 means infinite.
+
+ unsigned behavior : 2; // EMarqueeBehavior
+ EMarqueeDirection direction : 3; // not unsigned because EMarqueeDirection has negative values
+
+private:
+ StyleMarqueeData();
+ StyleMarqueeData(const StyleMarqueeData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleMarqueeData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleMultiColData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleMultiColData.cpp
new file mode 100644
index 0000000..bff4fb3
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleMultiColData.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleMultiColData.h"
+
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+StyleMultiColData::StyleMultiColData()
+ : m_width(0)
+ , m_count(RenderStyle::initialColumnCount())
+ , m_gap(0)
+ , m_autoWidth(true)
+ , m_autoCount(true)
+ , m_normalGap(true)
+ , m_breakBefore(RenderStyle::initialPageBreak())
+ , m_breakAfter(RenderStyle::initialPageBreak())
+ , m_breakInside(RenderStyle::initialPageBreak())
+{
+}
+
+StyleMultiColData::StyleMultiColData(const StyleMultiColData& o)
+ : RefCounted<StyleMultiColData>()
+ , m_width(o.m_width)
+ , m_count(o.m_count)
+ , m_gap(o.m_gap)
+ , m_rule(o.m_rule)
+ , m_autoWidth(o.m_autoWidth)
+ , m_autoCount(o.m_autoCount)
+ , m_normalGap(o.m_normalGap)
+ , m_breakBefore(o.m_breakBefore)
+ , m_breakAfter(o.m_breakAfter)
+ , m_breakInside(o.m_breakInside)
+{
+}
+
+bool StyleMultiColData::operator==(const StyleMultiColData& o) const
+{
+ return m_width == o.m_width && m_count == o.m_count && m_gap == o.m_gap &&
+ m_rule == o.m_rule && m_breakBefore == o.m_breakBefore &&
+ m_autoWidth == o.m_autoWidth && m_autoCount == o.m_autoCount && m_normalGap == o.m_normalGap &&
+ m_breakAfter == o.m_breakAfter && m_breakInside == o.m_breakInside;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleMultiColData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleMultiColData.h
new file mode 100644
index 0000000..dec0a55
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleMultiColData.h
@@ -0,0 +1,75 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleMultiColData_h
+#define StyleMultiColData_h
+
+#include "BorderValue.h"
+#include "Length.h"
+#include "RenderStyleConstants.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+// CSS3 Multi Column Layout
+
+class StyleMultiColData : public RefCounted<StyleMultiColData> {
+public:
+ static PassRefPtr<StyleMultiColData> create() { return adoptRef(new StyleMultiColData); }
+ PassRefPtr<StyleMultiColData> copy() const { return adoptRef(new StyleMultiColData(*this)); }
+
+ bool operator==(const StyleMultiColData& o) const;
+ bool operator!=(const StyleMultiColData &o) const
+ {
+ return !(*this == o);
+ }
+
+ unsigned short ruleWidth() const
+ {
+ if (m_rule.style() == BNONE || m_rule.style() == BHIDDEN)
+ return 0;
+ return m_rule.width;
+ }
+
+ float m_width;
+ unsigned short m_count;
+ float m_gap;
+ BorderValue m_rule;
+
+ bool m_autoWidth : 1;
+ bool m_autoCount : 1;
+ bool m_normalGap : 1;
+ unsigned m_breakBefore : 2; // EPageBreak
+ unsigned m_breakAfter : 2; // EPageBreak
+ unsigned m_breakInside : 2; // EPageBreak
+
+private:
+ StyleMultiColData();
+ StyleMultiColData(const StyleMultiColData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleMultiColData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp
new file mode 100644
index 0000000..b8fb2dd
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleRareInheritedData.h"
+
+#include "RenderStyle.h"
+#include "RenderStyleConstants.h"
+
+namespace WebCore {
+
+StyleRareInheritedData::StyleRareInheritedData()
+ : textStrokeWidth(RenderStyle::initialTextStrokeWidth())
+ , textShadow(0)
+ , textSecurity(RenderStyle::initialTextSecurity())
+ , userModify(READ_ONLY)
+ , wordBreak(RenderStyle::initialWordBreak())
+ , wordWrap(RenderStyle::initialWordWrap())
+ , nbspMode(NBNORMAL)
+ , khtmlLineBreak(LBNORMAL)
+ , textSizeAdjust(RenderStyle::initialTextSizeAdjust())
+ , resize(RenderStyle::initialResize())
+ , userSelect(RenderStyle::initialUserSelect())
+{
+}
+
+StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o)
+ : RefCounted<StyleRareInheritedData>()
+ , textStrokeColor(o.textStrokeColor)
+ , textStrokeWidth(o.textStrokeWidth)
+ , textFillColor(o.textFillColor)
+ , textShadow(o.textShadow ? new ShadowData(*o.textShadow) : 0)
+ , highlight(o.highlight)
+ , textSecurity(o.textSecurity)
+ , userModify(o.userModify)
+ , wordBreak(o.wordBreak)
+ , wordWrap(o.wordWrap)
+ , nbspMode(o.nbspMode)
+ , khtmlLineBreak(o.khtmlLineBreak)
+ , textSizeAdjust(o.textSizeAdjust)
+ , resize(o.resize)
+ , userSelect(o.userSelect)
+{
+}
+
+StyleRareInheritedData::~StyleRareInheritedData()
+{
+ delete textShadow;
+}
+
+bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
+{
+ return textStrokeColor == o.textStrokeColor
+ && textStrokeWidth == o.textStrokeWidth
+ && textFillColor == o.textFillColor
+ && shadowDataEquivalent(o)
+ && highlight == o.highlight
+ && textSecurity == o.textSecurity
+ && userModify == o.userModify
+ && wordBreak == o.wordBreak
+ && wordWrap == o.wordWrap
+ && nbspMode == o.nbspMode
+ && khtmlLineBreak == o.khtmlLineBreak
+ && textSizeAdjust == o.textSizeAdjust
+ && userSelect == o.userSelect;
+}
+
+bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& o) const
+{
+ if (!textShadow && o.textShadow || textShadow && !o.textShadow)
+ return false;
+ if (textShadow && o.textShadow && (*textShadow != *o.textShadow))
+ return false;
+ return true;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.h
new file mode 100644
index 0000000..06ad400
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareInheritedData.h
@@ -0,0 +1,76 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleRareInheritedData_h
+#define StyleRareInheritedData_h
+
+#include "AtomicString.h"
+#include "Color.h"
+#include <wtf/RefCounted.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+struct ShadowData;
+
+// This struct is for rarely used inherited CSS3, CSS2, and WebKit-specific properties.
+// By grouping them together, we save space, and only allocate this object when someone
+// actually uses one of these properties.
+class StyleRareInheritedData : public RefCounted<StyleRareInheritedData> {
+public:
+ static PassRefPtr<StyleRareInheritedData> create() { return adoptRef(new StyleRareInheritedData); }
+ PassRefPtr<StyleRareInheritedData> copy() const { return adoptRef(new StyleRareInheritedData(*this)); }
+ ~StyleRareInheritedData();
+
+ bool operator==(const StyleRareInheritedData& o) const;
+ bool operator!=(const StyleRareInheritedData& o) const
+ {
+ return !(*this == o);
+ }
+ bool shadowDataEquivalent(const StyleRareInheritedData&) const;
+
+ Color textStrokeColor;
+ float textStrokeWidth;
+ Color textFillColor;
+
+ ShadowData* textShadow; // Our text shadow information for shadowed text drawing.
+ AtomicString highlight; // Apple-specific extension for custom highlight rendering.
+ unsigned textSecurity : 2; // ETextSecurity
+ unsigned userModify : 2; // EUserModify (editing)
+ unsigned wordBreak : 2; // EWordBreak
+ unsigned wordWrap : 1; // EWordWrap
+ unsigned nbspMode : 1; // ENBSPMode
+ unsigned khtmlLineBreak : 1; // EKHTMLLineBreak
+ bool textSizeAdjust : 1; // An Apple extension.
+ unsigned resize : 2; // EResize
+ unsigned userSelect : 1; // EUserSelect
+
+private:
+ StyleRareInheritedData();
+ StyleRareInheritedData(const StyleRareInheritedData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleRareInheritedData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.cpp
new file mode 100644
index 0000000..e8ceeeb
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleRareNonInheritedData.h"
+
+#include "CSSStyleSelector.h"
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+StyleRareNonInheritedData::StyleRareNonInheritedData()
+ : lineClamp(RenderStyle::initialLineClamp())
+ , opacity(RenderStyle::initialOpacity())
+ , m_content(0)
+ , m_counterDirectives(0)
+ , userDrag(RenderStyle::initialUserDrag())
+ , textOverflow(RenderStyle::initialTextOverflow())
+ , marginTopCollapse(MCOLLAPSE)
+ , marginBottomCollapse(MCOLLAPSE)
+ , matchNearestMailBlockquoteColor(RenderStyle::initialMatchNearestMailBlockquoteColor())
+ , m_appearance(RenderStyle::initialAppearance())
+ , m_borderFit(RenderStyle::initialBorderFit())
+ , m_boxShadow(0)
+ , m_animations(0)
+ , m_transitions(0)
+ , m_mask(FillLayer(MaskFillLayer))
+#if ENABLE(XBL)
+ , bindingURI(0)
+#endif
+{
+}
+
+StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInheritedData& o)
+ : RefCounted<StyleRareNonInheritedData>()
+ , lineClamp(o.lineClamp)
+ , opacity(o.opacity)
+ , flexibleBox(o.flexibleBox)
+ , marquee(o.marquee)
+ , m_multiCol(o.m_multiCol)
+ , m_transform(o.m_transform)
+ , m_content(0)
+ , m_counterDirectives(0)
+ , userDrag(o.userDrag)
+ , textOverflow(o.textOverflow)
+ , marginTopCollapse(o.marginTopCollapse)
+ , marginBottomCollapse(o.marginBottomCollapse)
+ , matchNearestMailBlockquoteColor(o.matchNearestMailBlockquoteColor)
+ , m_appearance(o.m_appearance)
+ , m_borderFit(o.m_borderFit)
+ , m_boxShadow(o.m_boxShadow ? new ShadowData(*o.m_boxShadow) : 0)
+ , m_boxReflect(o.m_boxReflect)
+ , m_animations(o.m_animations ? new AnimationList(*o.m_animations) : 0)
+ , m_transitions(o.m_transitions ? new AnimationList(*o.m_transitions) : 0)
+ , m_mask(o.m_mask)
+ , m_maskBoxImage(o.m_maskBoxImage)
+#if ENABLE(XBL)
+ , bindingURI(o.bindingURI ? o.bindingURI->copy() : 0)
+#endif
+{
+}
+
+StyleRareNonInheritedData::~StyleRareNonInheritedData()
+{
+}
+
+#if ENABLE(XBL)
+bool StyleRareNonInheritedData::bindingsEquivalent(const StyleRareNonInheritedData& o) const
+{
+ if (this == &o) return true;
+ if (!bindingURI && o.bindingURI || bindingURI && !o.bindingURI)
+ return false;
+ if (bindingURI && o.bindingURI && (*bindingURI != *o.bindingURI))
+ return false;
+ return true;
+}
+#endif
+
+bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) const
+{
+ return lineClamp == o.lineClamp
+#if ENABLE(DASHBOARD_SUPPORT)
+ && m_dashboardRegions == o.m_dashboardRegions
+#endif
+ && opacity == o.opacity
+ && flexibleBox == o.flexibleBox
+ && marquee == o.marquee
+ && m_multiCol == o.m_multiCol
+ && m_transform == o.m_transform
+ && m_content == o.m_content
+ && m_counterDirectives == o.m_counterDirectives
+ && userDrag == o.userDrag
+ && textOverflow == o.textOverflow
+ && marginTopCollapse == o.marginTopCollapse
+ && marginBottomCollapse == o.marginBottomCollapse
+ && matchNearestMailBlockquoteColor == o.matchNearestMailBlockquoteColor
+ && m_appearance == o.m_appearance
+ && m_borderFit == o.m_borderFit
+ && shadowDataEquivalent(o)
+ && reflectionDataEquivalent(o)
+ && animationDataEquivalent(o)
+ && transitionDataEquivalent(o)
+ && m_mask == o.m_mask
+ && m_maskBoxImage == o.m_maskBoxImage
+#if ENABLE(XBL)
+ && bindingsEquivalent(o)
+#endif
+ ;
+}
+
+bool StyleRareNonInheritedData::shadowDataEquivalent(const StyleRareNonInheritedData& o) const
+{
+ if (!m_boxShadow && o.m_boxShadow || m_boxShadow && !o.m_boxShadow)
+ return false;
+ if (m_boxShadow && o.m_boxShadow && (*m_boxShadow != *o.m_boxShadow))
+ return false;
+ return true;
+}
+
+bool StyleRareNonInheritedData::reflectionDataEquivalent(const StyleRareNonInheritedData& o) const
+{
+ if (m_boxReflect != o.m_boxReflect) {
+ if (!m_boxReflect || !o.m_boxReflect)
+ return false;
+ return *m_boxReflect == *o.m_boxReflect;
+ }
+ return true;
+
+}
+
+bool StyleRareNonInheritedData::animationDataEquivalent(const StyleRareNonInheritedData& o) const
+{
+ if (!m_animations && o.m_animations || m_animations && !o.m_animations)
+ return false;
+ if (m_animations && o.m_animations && (*m_animations != *o.m_animations))
+ return false;
+ return true;
+}
+
+bool StyleRareNonInheritedData::transitionDataEquivalent(const StyleRareNonInheritedData& o) const
+{
+ if (!m_transitions && o.m_transitions || m_transitions && !o.m_transitions)
+ return false;
+ if (m_transitions && o.m_transitions && (*m_transitions != *o.m_transitions))
+ return false;
+ return true;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h
new file mode 100644
index 0000000..6ce6a33
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleRareNonInheritedData.h
@@ -0,0 +1,120 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleRareNonInheritedData_h
+#define StyleRareNonInheritedData_h
+
+#include "CounterDirectives.h"
+#include "CursorData.h"
+#include "DataRef.h"
+#include "FillLayer.h"
+#include "NinePieceImage.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class AnimationList;
+class CSSStyleSelector;
+class StyleFlexibleBoxData;
+class StyleMarqueeData;
+class StyleMultiColData;
+class StyleReflection;
+class StyleTransformData;
+struct ContentData;
+struct ShadowData;
+
+#if ENABLE(DASHBOARD_SUPPORT)
+class StyleDashboardRegion;
+#endif
+
+#if ENABLE(XBL)
+class BindingURI;
+#endif
+
+// This struct is for rarely used non-inherited CSS3, CSS2, and WebKit-specific properties.
+// By grouping them together, we save space, and only allocate this object when someone
+// actually uses one of these properties.
+class StyleRareNonInheritedData : public RefCounted<StyleRareNonInheritedData> {
+public:
+ static PassRefPtr<StyleRareNonInheritedData> create() { return adoptRef(new StyleRareNonInheritedData); }
+ PassRefPtr<StyleRareNonInheritedData> copy() const { return adoptRef(new StyleRareNonInheritedData(*this)); }
+ ~StyleRareNonInheritedData();
+
+#if ENABLE(XBL)
+ bool bindingsEquivalent(const StyleRareNonInheritedData&) const;
+#endif
+
+ bool operator==(const StyleRareNonInheritedData&) const;
+ bool operator!=(const StyleRareNonInheritedData& o) const { return !(*this == o); }
+
+ bool shadowDataEquivalent(const StyleRareNonInheritedData& o) const;
+ bool reflectionDataEquivalent(const StyleRareNonInheritedData& o) const;
+ bool animationDataEquivalent(const StyleRareNonInheritedData&) const;
+ bool transitionDataEquivalent(const StyleRareNonInheritedData&) const;
+
+ int lineClamp; // An Apple extension.
+#if ENABLE(DASHBOARD_SUPPORT)
+ Vector<StyleDashboardRegion> m_dashboardRegions;
+#endif
+ float opacity; // Whether or not we're transparent.
+
+ DataRef<StyleFlexibleBoxData> flexibleBox; // Flexible box properties
+ DataRef<StyleMarqueeData> marquee; // Marquee properties
+ DataRef<StyleMultiColData> m_multiCol; // CSS3 multicol properties
+ DataRef<StyleTransformData> m_transform; // Transform properties (rotate, scale, skew, etc.)
+
+ OwnPtr<ContentData> m_content;
+ OwnPtr<CounterDirectiveMap> m_counterDirectives;
+
+ unsigned userDrag : 2; // EUserDrag
+ bool textOverflow : 1; // Whether or not lines that spill out should be truncated with "..."
+ unsigned marginTopCollapse : 2; // EMarginCollapse
+ unsigned marginBottomCollapse : 2; // EMarginCollapse
+ unsigned matchNearestMailBlockquoteColor : 1; // EMatchNearestMailBlockquoteColor, FIXME: This property needs to be eliminated. It should never have been added.
+ unsigned m_appearance : 6; // EAppearance
+ unsigned m_borderFit : 1; // EBorderFit
+ OwnPtr<ShadowData> m_boxShadow; // For box-shadow decorations.
+
+ RefPtr<StyleReflection> m_boxReflect;
+
+ OwnPtr<AnimationList> m_animations;
+ OwnPtr<AnimationList> m_transitions;
+
+ FillLayer m_mask;
+ NinePieceImage m_maskBoxImage;
+
+#if ENABLE(XBL)
+ OwnPtr<BindingURI> bindingURI; // The XBL binding URI list.
+#endif
+
+private:
+ StyleRareNonInheritedData();
+ StyleRareNonInheritedData(const StyleRareNonInheritedData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleRareNonInheritedData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleReflection.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleReflection.h
new file mode 100644
index 0000000..455d1b7
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleReflection.h
@@ -0,0 +1,70 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleReflection_h
+#define StyleReflection_h
+
+#include "CSSReflectionDirection.h"
+#include "Length.h"
+#include "NinePieceImage.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class StyleReflection : public RefCounted<StyleReflection> {
+public:
+ static PassRefPtr<StyleReflection> create()
+ {
+ return adoptRef(new StyleReflection);
+ }
+
+ bool operator==(const StyleReflection& o) const
+ {
+ return m_direction == o.m_direction && m_offset == o.m_offset && m_mask == o.m_mask;
+ }
+ bool operator!=(const StyleReflection& o) const { return !(*this == o); }
+
+ CSSReflectionDirection direction() const { return m_direction; }
+ Length offset() const { return m_offset; }
+ const NinePieceImage& mask() const { return m_mask; }
+
+ void setDirection(CSSReflectionDirection dir) { m_direction = dir; }
+ void setOffset(const Length& l) { m_offset = l; }
+ void setMask(const NinePieceImage& image) { m_mask = image; }
+
+private:
+ StyleReflection()
+ : m_direction(ReflectionBelow)
+ , m_offset(0, Fixed)
+ {
+ }
+
+ CSSReflectionDirection m_direction;
+ Length m_offset;
+ NinePieceImage m_mask;
+};
+
+} // namespace WebCore
+
+#endif // StyleReflection_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleSurroundData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleSurroundData.cpp
new file mode 100644
index 0000000..8d5e79c
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleSurroundData.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleSurroundData.h"
+
+namespace WebCore {
+
+StyleSurroundData::StyleSurroundData()
+ : margin(Fixed)
+ , padding(Fixed)
+{
+}
+
+StyleSurroundData::StyleSurroundData(const StyleSurroundData& o)
+ : RefCounted<StyleSurroundData>()
+ , offset(o.offset)
+ , margin(o.margin)
+ , padding(o.padding)
+ , border(o.border)
+{
+}
+
+bool StyleSurroundData::operator==(const StyleSurroundData& o) const
+{
+ return offset == o.offset && margin == o.margin && padding == o.padding && border == o.border;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleSurroundData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleSurroundData.h
new file mode 100644
index 0000000..b8f21e4
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleSurroundData.h
@@ -0,0 +1,58 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleSurroundData_h
+#define StyleSurroundData_h
+
+#include "BorderData.h"
+#include "LengthBox.h"
+#include <wtf/RefCounted.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class StyleSurroundData : public RefCounted<StyleSurroundData> {
+public:
+ static PassRefPtr<StyleSurroundData> create() { return adoptRef(new StyleSurroundData); }
+ PassRefPtr<StyleSurroundData> copy() const { return adoptRef(new StyleSurroundData(*this)); }
+
+ bool operator==(const StyleSurroundData& o) const;
+ bool operator!=(const StyleSurroundData& o) const
+ {
+ return !(*this == o);
+ }
+
+ LengthBox offset;
+ LengthBox margin;
+ LengthBox padding;
+ BorderData border;
+
+private:
+ StyleSurroundData();
+ StyleSurroundData(const StyleSurroundData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleSurroundData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.cpp
new file mode 100644
index 0000000..de20e77
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleTransformData.h"
+
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+StyleTransformData::StyleTransformData()
+ : m_operations(RenderStyle::initialTransform())
+ , m_x(RenderStyle::initialTransformOriginX())
+ , m_y(RenderStyle::initialTransformOriginY())
+{
+}
+
+StyleTransformData::StyleTransformData(const StyleTransformData& o)
+ : RefCounted<StyleTransformData>()
+ , m_operations(o.m_operations)
+ , m_x(o.m_x)
+ , m_y(o.m_y)
+{
+}
+
+bool StyleTransformData::operator==(const StyleTransformData& o) const
+{
+ return m_x == o.m_x && m_y == o.m_y && m_operations == o.m_operations;
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.h
new file mode 100644
index 0000000..157e600
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleTransformData.h
@@ -0,0 +1,57 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleTransformData_h
+#define StyleTransformData_h
+
+#include "Length.h"
+#include "TransformOperations.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class StyleTransformData : public RefCounted<StyleTransformData> {
+public:
+ static PassRefPtr<StyleTransformData> create() { return adoptRef(new StyleTransformData); }
+ PassRefPtr<StyleTransformData> copy() const { return adoptRef(new StyleTransformData(*this)); }
+
+ bool operator==(const StyleTransformData& o) const;
+ bool operator!=(const StyleTransformData& o) const
+ {
+ return !(*this == o);
+ }
+
+ TransformOperations m_operations;
+ Length m_x;
+ Length m_y;
+
+private:
+ StyleTransformData();
+ StyleTransformData(const StyleTransformData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleTransformData_h
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleVisualData.cpp b/src/3rdparty/webkit/WebCore/rendering/style/StyleVisualData.cpp
new file mode 100644
index 0000000..91690cf
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleVisualData.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "StyleVisualData.h"
+
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+StyleVisualData::StyleVisualData()
+ : hasClip(false)
+ , textDecoration(RenderStyle::initialTextDecoration())
+ , counterIncrement(0)
+ , counterReset(0)
+ , m_zoom(RenderStyle::initialZoom())
+{
+}
+
+StyleVisualData::~StyleVisualData()
+{
+}
+
+StyleVisualData::StyleVisualData(const StyleVisualData& o)
+ : RefCounted<StyleVisualData>()
+ , clip(o.clip)
+ , hasClip(o.hasClip)
+ , textDecoration(o.textDecoration)
+ , counterIncrement(o.counterIncrement)
+ , counterReset(o.counterReset)
+ , m_zoom(RenderStyle::initialZoom())
+{
+}
+
+} // namespace WebCore
diff --git a/src/3rdparty/webkit/WebCore/rendering/style/StyleVisualData.h b/src/3rdparty/webkit/WebCore/rendering/style/StyleVisualData.h
new file mode 100644
index 0000000..613ef2f
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/rendering/style/StyleVisualData.h
@@ -0,0 +1,67 @@
+/*
+ * 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) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * 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 StyleVisualData_h
+#define StyleVisualData_h
+
+#include "LengthBox.h"
+#include <wtf/RefCounted.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class StyleVisualData : public RefCounted<StyleVisualData> {
+public:
+ static PassRefPtr<StyleVisualData> create() { return adoptRef(new StyleVisualData); }
+ PassRefPtr<StyleVisualData> copy() const { return adoptRef(new StyleVisualData(*this)); }
+ ~StyleVisualData();
+
+ bool operator==(const StyleVisualData& o) const
+ {
+ return ( clip == o.clip &&
+ hasClip == o.hasClip &&
+ counterIncrement == o.counterIncrement &&
+ counterReset == o.counterReset &&
+ textDecoration == o.textDecoration &&
+ m_zoom == o.m_zoom);
+ }
+ bool operator!=(const StyleVisualData& o) const { return !(*this == o); }
+
+ LengthBox clip;
+ bool hasClip : 1;
+ unsigned textDecoration : 4; // Text decorations defined *only* by this element.
+
+ short counterIncrement; // ok, so these are not visual mode specific
+ short counterReset; // can't go to inherited, since these are not inherited
+
+ float m_zoom;
+
+private:
+ StyleVisualData();
+ StyleVisualData(const StyleVisualData&);
+};
+
+} // namespace WebCore
+
+#endif // StyleVisualData_h