1 /* 2 * Copyright (C) 1997 Martin Jones (mjones (at) kde.org) 3 * (C) 1997 Torben Weis (weis (at) kde.org) 4 * (C) 1998 Waldo Bastian (bastian (at) kde.org) 5 * (C) 1999 Lars Knoll (knoll (at) kde.org) 6 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 7 * Copyright (C) 2003, 2004, 2005, 2006, 2009, 2010 Apple Inc. All rights reserved. 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Library General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Library General Public License for more details. 18 * 19 * You should have received a copy of the GNU Library General Public License 20 * along with this library; see the file COPYING.LIB. If not, write to 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 * Boston, MA 02110-1301, USA. 23 */ 24 25 #ifndef RenderTable_h 26 #define RenderTable_h 27 28 #include "core/CSSPropertyNames.h" 29 #include "core/rendering/RenderBlock.h" 30 #include "core/rendering/style/CollapsedBorderValue.h" 31 #include "wtf/Vector.h" 32 33 namespace blink { 34 35 class RenderTableCol; 36 class RenderTableCaption; 37 class RenderTableCell; 38 class RenderTableSection; 39 class TableLayout; 40 41 enum SkipEmptySectionsValue { DoNotSkipEmptySections, SkipEmptySections }; 42 43 class RenderTable FINAL : public RenderBlock { 44 public: 45 explicit RenderTable(Element*); 46 virtual ~RenderTable(); 47 48 // Per CSS 3 writing-mode: "The first and second values of the 'border-spacing' property represent spacing between columns 49 // and rows respectively, not necessarily the horizontal and vertical spacing respectively". 50 int hBorderSpacing() const { return m_hSpacing; } 51 int vBorderSpacing() const { return m_vSpacing; } 52 53 bool collapseBorders() const { return style()->borderCollapse(); } 54 55 virtual int borderStart() const OVERRIDE { return m_borderStart; } 56 virtual int borderEnd() const OVERRIDE { return m_borderEnd; } 57 virtual int borderBefore() const OVERRIDE; 58 virtual int borderAfter() const OVERRIDE; 59 60 virtual int borderLeft() const OVERRIDE 61 { 62 if (style()->isHorizontalWritingMode()) 63 return style()->isLeftToRightDirection() ? borderStart() : borderEnd(); 64 return style()->isFlippedBlocksWritingMode() ? borderAfter() : borderBefore(); 65 } 66 67 virtual int borderRight() const OVERRIDE 68 { 69 if (style()->isHorizontalWritingMode()) 70 return style()->isLeftToRightDirection() ? borderEnd() : borderStart(); 71 return style()->isFlippedBlocksWritingMode() ? borderBefore() : borderAfter(); 72 } 73 74 virtual int borderTop() const OVERRIDE 75 { 76 if (style()->isHorizontalWritingMode()) 77 return style()->isFlippedBlocksWritingMode() ? borderAfter() : borderBefore(); 78 return style()->isLeftToRightDirection() ? borderStart() : borderEnd(); 79 } 80 81 virtual int borderBottom() const OVERRIDE 82 { 83 if (style()->isHorizontalWritingMode()) 84 return style()->isFlippedBlocksWritingMode() ? borderBefore() : borderAfter(); 85 return style()->isLeftToRightDirection() ? borderEnd() : borderStart(); 86 } 87 88 Color bgColor() const { return resolveColor(CSSPropertyBackgroundColor); } 89 90 int outerBorderBefore() const; 91 int outerBorderAfter() const; 92 int outerBorderStart() const; 93 int outerBorderEnd() const; 94 95 int outerBorderLeft() const 96 { 97 if (style()->isHorizontalWritingMode()) 98 return style()->isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd(); 99 return style()->isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore(); 100 } 101 102 int outerBorderRight() const 103 { 104 if (style()->isHorizontalWritingMode()) 105 return style()->isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart(); 106 return style()->isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter(); 107 } 108 109 int outerBorderTop() const 110 { 111 if (style()->isHorizontalWritingMode()) 112 return style()->isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore(); 113 return style()->isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd(); 114 } 115 116 int outerBorderBottom() const 117 { 118 if (style()->isHorizontalWritingMode()) 119 return style()->isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter(); 120 return style()->isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart(); 121 } 122 123 int calcBorderStart() const; 124 int calcBorderEnd() const; 125 void recalcBordersInRowDirection(); 126 127 virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; 128 129 struct ColumnStruct { 130 explicit ColumnStruct(unsigned initialSpan = 1) 131 : span(initialSpan) 132 { 133 } 134 135 unsigned span; 136 }; 137 138 void forceSectionsRecalc() 139 { 140 setNeedsSectionRecalc(); 141 recalcSections(); 142 } 143 144 const Vector<ColumnStruct>& columns() const { return m_columns; } 145 const Vector<int>& columnPositions() const { return m_columnPos; } 146 void setColumnPosition(unsigned index, int position) 147 { 148 // Note that if our horizontal border-spacing changed, our position will change but not 149 // our column's width. In practice, horizontal border-spacing won't change often. 150 m_columnLogicalWidthChanged |= m_columnPos[index] != position; 151 m_columnPos[index] = position; 152 } 153 154 RenderTableSection* header() const { return m_head; } 155 RenderTableSection* footer() const { return m_foot; } 156 RenderTableSection* firstBody() const { return m_firstBody; } 157 158 // This function returns 0 if the table has no section. 159 RenderTableSection* topSection() const; 160 RenderTableSection* bottomSection() const; 161 162 // This function returns 0 if the table has no non-empty sections. 163 RenderTableSection* topNonEmptySection() const; 164 165 unsigned lastColumnIndex() const { return numEffCols() - 1; } 166 167 void splitColumn(unsigned position, unsigned firstSpan); 168 void appendColumn(unsigned span); 169 unsigned numEffCols() const { return m_columns.size(); } 170 unsigned spanOfEffCol(unsigned effCol) const { return m_columns[effCol].span; } 171 172 unsigned colToEffCol(unsigned column) const 173 { 174 if (!m_hasCellColspanThatDeterminesTableWidth) 175 return column; 176 177 unsigned effColumn = 0; 178 unsigned numColumns = numEffCols(); 179 for (unsigned c = 0; effColumn < numColumns && c + m_columns[effColumn].span - 1 < column; ++effColumn) 180 c += m_columns[effColumn].span; 181 return effColumn; 182 } 183 184 unsigned effColToCol(unsigned effCol) const 185 { 186 if (!m_hasCellColspanThatDeterminesTableWidth) 187 return effCol; 188 189 unsigned c = 0; 190 for (unsigned i = 0; i < effCol; i++) 191 c += m_columns[i].span; 192 return c; 193 } 194 195 LayoutUnit borderSpacingInRowDirection() const 196 { 197 if (unsigned effectiveColumnCount = numEffCols()) 198 return static_cast<LayoutUnit>(effectiveColumnCount + 1) * hBorderSpacing(); 199 200 return 0; 201 } 202 203 // Override paddingStart/End to return pixel values to match behavor of RenderTableCell. 204 virtual LayoutUnit paddingEnd() const OVERRIDE { return static_cast<int>(RenderBlock::paddingEnd()); } 205 virtual LayoutUnit paddingStart() const OVERRIDE { return static_cast<int>(RenderBlock::paddingStart()); } 206 207 LayoutUnit bordersPaddingAndSpacingInRowDirection() const 208 { 209 // 'border-spacing' only applies to separate borders (see 17.6.1 The separated borders model). 210 return borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : (paddingStart() + paddingEnd() + borderSpacingInRowDirection())); 211 } 212 213 // Return the first column or column-group. 214 RenderTableCol* firstColumn() const; 215 216 RenderTableCol* colElement(unsigned col, bool* startEdge = 0, bool* endEdge = 0) const 217 { 218 // The common case is to not have columns, make that case fast. 219 if (!m_hasColElements) 220 return 0; 221 return slowColElement(col, startEdge, endEdge); 222 } 223 224 bool needsSectionRecalc() const { return m_needsSectionRecalc; } 225 void setNeedsSectionRecalc() 226 { 227 if (documentBeingDestroyed()) 228 return; 229 m_needsSectionRecalc = true; 230 setNeedsLayoutAndFullPaintInvalidation(); 231 } 232 233 RenderTableSection* sectionAbove(const RenderTableSection*, SkipEmptySectionsValue = DoNotSkipEmptySections) const; 234 RenderTableSection* sectionBelow(const RenderTableSection*, SkipEmptySectionsValue = DoNotSkipEmptySections) const; 235 236 RenderTableCell* cellAbove(const RenderTableCell*) const; 237 RenderTableCell* cellBelow(const RenderTableCell*) const; 238 RenderTableCell* cellBefore(const RenderTableCell*) const; 239 RenderTableCell* cellAfter(const RenderTableCell*) const; 240 241 typedef Vector<CollapsedBorderValue> CollapsedBorderValues; 242 void invalidateCollapsedBorders() 243 { 244 m_collapsedBordersValid = false; 245 m_collapsedBorders.clear(); 246 } 247 248 // FIXME: This method should be moved into TablePainter. 249 const CollapsedBorderValue* currentBorderValue() const { return m_currentBorder; } 250 void setCurrentBorderValue(const CollapsedBorderValue* val) { m_currentBorder = val; } 251 252 bool hasSections() const { return m_head || m_foot || m_firstBody; } 253 254 void recalcSectionsIfNeeded() const 255 { 256 if (m_needsSectionRecalc) 257 recalcSections(); 258 } 259 260 static RenderTable* createAnonymousWithParentRenderer(const RenderObject*); 261 virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE 262 { 263 return createAnonymousWithParentRenderer(parent); 264 } 265 266 const BorderValue& tableStartBorderAdjoiningCell(const RenderTableCell*) const; 267 const BorderValue& tableEndBorderAdjoiningCell(const RenderTableCell*) const; 268 269 void addCaption(const RenderTableCaption*); 270 void removeCaption(const RenderTableCaption*); 271 void addColumn(const RenderTableCol*); 272 void removeColumn(const RenderTableCol*); 273 274 // FIXME: this method should be moved into TablePainter. 275 virtual void paintBoxDecorationBackground(PaintInfo&, const LayoutPoint&) OVERRIDE; 276 277 virtual void paintMask(PaintInfo&, const LayoutPoint&) OVERRIDE; 278 279 const CollapsedBorderValues& collapsedBorders() { return m_collapsedBorders; } 280 void subtractCaptionRect(LayoutRect&) const; 281 void recalcCollapsedBorders(); 282 283 protected: 284 virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; 285 virtual void simplifiedNormalFlowLayout() OVERRIDE; 286 287 private: 288 virtual const char* renderName() const OVERRIDE { return "RenderTable"; } 289 290 virtual bool isTable() const OVERRIDE { return true; } 291 292 virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; 293 virtual void paintObject(PaintInfo&, const LayoutPoint&) OVERRIDE; 294 virtual void layout() OVERRIDE; 295 virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const OVERRIDE; 296 virtual void computePreferredLogicalWidths() OVERRIDE; 297 virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; 298 299 virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; 300 virtual int firstLineBoxBaseline() const OVERRIDE; 301 virtual int inlineBlockBaseline(LineDirectionMode) const OVERRIDE; 302 303 RenderTableCol* slowColElement(unsigned col, bool* startEdge, bool* endEdge) const; 304 305 void updateColumnCache() const; 306 void invalidateCachedColumns(); 307 308 virtual void updateLogicalWidth() OVERRIDE; 309 310 LayoutUnit convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth); 311 LayoutUnit convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight); 312 313 virtual LayoutRect overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) OVERRIDE; 314 315 virtual void addOverflowFromChildren() OVERRIDE; 316 317 void recalcSections() const; 318 void layoutCaption(RenderTableCaption*); 319 320 void distributeExtraLogicalHeight(int extraLogicalHeight); 321 322 mutable Vector<int> m_columnPos; 323 mutable Vector<ColumnStruct> m_columns; 324 mutable Vector<RenderTableCaption*> m_captions; 325 mutable Vector<RenderTableCol*> m_columnRenderers; 326 327 mutable RenderTableSection* m_head; 328 mutable RenderTableSection* m_foot; 329 mutable RenderTableSection* m_firstBody; 330 331 OwnPtr<TableLayout> m_tableLayout; 332 333 CollapsedBorderValues m_collapsedBorders; 334 const CollapsedBorderValue* m_currentBorder; 335 bool m_collapsedBordersValid : 1; 336 337 mutable bool m_hasColElements : 1; 338 mutable bool m_needsSectionRecalc : 1; 339 340 bool m_columnLogicalWidthChanged : 1; 341 mutable bool m_columnRenderersValid: 1; 342 mutable bool m_hasCellColspanThatDeterminesTableWidth : 1; 343 bool hasCellColspanThatDeterminesTableWidth() const 344 { 345 for (unsigned c = 0; c < numEffCols(); c++) { 346 if (m_columns[c].span > 1) 347 return true; 348 } 349 return false; 350 } 351 352 short m_hSpacing; 353 short m_vSpacing; 354 int m_borderStart; 355 int m_borderEnd; 356 }; 357 358 inline RenderTableSection* RenderTable::topSection() const 359 { 360 ASSERT(!needsSectionRecalc()); 361 if (m_head) 362 return m_head; 363 if (m_firstBody) 364 return m_firstBody; 365 return m_foot; 366 } 367 368 DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderTable, isTable()); 369 370 } // namespace blink 371 372 #endif // RenderTable_h 373