1 /** 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 2000 Simon Hausmann <hausmann (at) kde.org> 4 * (C) 2000 Stefan Schimanski (1Stein (at) gmx.de) 5 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 * 22 */ 23 24 #include "config.h" 25 #include "core/rendering/RenderFrameSet.h" 26 27 #include "core/dom/Document.h" 28 #include "core/events/MouseEvent.h" 29 #include "core/events/ThreadLocalEventNames.h" 30 #include "core/html/HTMLDimension.h" 31 #include "core/html/HTMLFrameSetElement.h" 32 #include "core/page/EventHandler.h" 33 #include "core/frame/Frame.h" 34 #include "core/rendering/GraphicsContextAnnotator.h" 35 #include "core/rendering/LayoutRectRecorder.h" 36 #include "core/rendering/PaintInfo.h" 37 #include "core/rendering/RenderFrame.h" 38 #include "core/rendering/RenderView.h" 39 #include "platform/Cursor.h" 40 #include "platform/graphics/GraphicsContext.h" 41 42 namespace WebCore { 43 44 RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet) 45 : RenderBox(frameSet) 46 , m_isResizing(false) 47 , m_isChildResizing(false) 48 { 49 setInline(false); 50 } 51 52 RenderFrameSet::~RenderFrameSet() 53 { 54 } 55 56 RenderFrameSet::GridAxis::GridAxis() 57 : m_splitBeingResized(noSplit) 58 { 59 } 60 61 inline HTMLFrameSetElement* RenderFrameSet::frameSet() const 62 { 63 return toHTMLFrameSetElement(node()); 64 } 65 66 static Color borderStartEdgeColor() 67 { 68 return Color(170, 170, 170); 69 } 70 71 static Color borderEndEdgeColor() 72 { 73 return Color::black; 74 } 75 76 static Color borderFillColor() 77 { 78 return Color(208, 208, 208); 79 } 80 81 void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect& borderRect) 82 { 83 if (!paintInfo.rect.intersects(borderRect)) 84 return; 85 86 // FIXME: We should do something clever when borders from distinct framesets meet at a join. 87 88 // Fill first. 89 GraphicsContext* context = paintInfo.context; 90 context->fillRect(borderRect, frameSet()->hasBorderColor() ? resolveColor(CSSPropertyBorderLeftColor) : borderFillColor()); 91 92 // Now stroke the edges but only if we have enough room to paint both edges with a little 93 // bit of the fill color showing through. 94 if (borderRect.width() >= 3) { 95 context->fillRect(IntRect(borderRect.location(), IntSize(1, height())), borderStartEdgeColor()); 96 context->fillRect(IntRect(IntPoint(borderRect.maxX() - 1, borderRect.y()), IntSize(1, height())), borderEndEdgeColor()); 97 } 98 } 99 100 void RenderFrameSet::paintRowBorder(const PaintInfo& paintInfo, const IntRect& borderRect) 101 { 102 if (!paintInfo.rect.intersects(borderRect)) 103 return; 104 105 // FIXME: We should do something clever when borders from distinct framesets meet at a join. 106 107 // Fill first. 108 GraphicsContext* context = paintInfo.context; 109 context->fillRect(borderRect, frameSet()->hasBorderColor() ? resolveColor(CSSPropertyBorderLeftColor) : borderFillColor()); 110 111 // Now stroke the edges but only if we have enough room to paint both edges with a little 112 // bit of the fill color showing through. 113 if (borderRect.height() >= 3) { 114 context->fillRect(IntRect(borderRect.location(), IntSize(width(), 1)), borderStartEdgeColor()); 115 context->fillRect(IntRect(IntPoint(borderRect.x(), borderRect.maxY() - 1), IntSize(width(), 1)), borderEndEdgeColor()); 116 } 117 } 118 119 void RenderFrameSet::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 120 { 121 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); 122 123 if (paintInfo.phase != PaintPhaseForeground) 124 return; 125 126 RenderObject* child = firstChild(); 127 if (!child) 128 return; 129 130 LayoutPoint adjustedPaintOffset = paintOffset + location(); 131 132 size_t rows = m_rows.m_sizes.size(); 133 size_t cols = m_cols.m_sizes.size(); 134 LayoutUnit borderThickness = frameSet()->border(); 135 136 LayoutUnit yPos = 0; 137 for (size_t r = 0; r < rows; r++) { 138 LayoutUnit xPos = 0; 139 for (size_t c = 0; c < cols; c++) { 140 child->paint(paintInfo, adjustedPaintOffset); 141 xPos += m_cols.m_sizes[c]; 142 if (borderThickness && m_cols.m_allowBorder[c + 1]) { 143 paintColumnBorder(paintInfo, pixelSnappedIntRect(LayoutRect(adjustedPaintOffset.x() + xPos, adjustedPaintOffset.y() + yPos, borderThickness, height()))); 144 xPos += borderThickness; 145 } 146 child = child->nextSibling(); 147 if (!child) 148 return; 149 } 150 yPos += m_rows.m_sizes[r]; 151 if (borderThickness && m_rows.m_allowBorder[r + 1]) { 152 paintRowBorder(paintInfo, pixelSnappedIntRect(LayoutRect(adjustedPaintOffset.x(), adjustedPaintOffset.y() + yPos, width(), borderThickness))); 153 yPos += borderThickness; 154 } 155 } 156 } 157 158 void RenderFrameSet::GridAxis::resize(int size) 159 { 160 m_sizes.resize(size); 161 m_deltas.resize(size); 162 m_deltas.fill(0); 163 164 // To track edges for resizability and borders, we need to be (size + 1). This is because a parent frameset 165 // may ask us for information about our left/top/right/bottom edges in order to make its own decisions about 166 // what to do. We are capable of tainting that parent frameset's borders, so we have to cache this info. 167 m_preventResize.resize(size + 1); 168 m_allowBorder.resize(size + 1); 169 } 170 171 void RenderFrameSet::layOutAxis(GridAxis& axis, const Vector<HTMLDimension>& grid, int availableLen) 172 { 173 availableLen = max(availableLen, 0); 174 175 int* gridLayout = axis.m_sizes.data(); 176 177 if (grid.isEmpty()) { 178 gridLayout[0] = availableLen; 179 return; 180 } 181 182 int gridLen = axis.m_sizes.size(); 183 ASSERT(gridLen); 184 185 int totalRelative = 0; 186 int totalFixed = 0; 187 int totalPercent = 0; 188 int countRelative = 0; 189 int countFixed = 0; 190 int countPercent = 0; 191 192 // First we need to investigate how many columns of each type we have and 193 // how much space these columns are going to require. 194 for (int i = 0; i < gridLen; ++i) { 195 // Count the total length of all of the fixed columns/rows -> totalFixed 196 // Count the number of columns/rows which are fixed -> countFixed 197 if (grid[i].isAbsolute()) { 198 gridLayout[i] = max<int>(grid[i].value(), 0); 199 totalFixed += gridLayout[i]; 200 countFixed++; 201 } 202 203 // Count the total percentage of all of the percentage columns/rows -> totalPercent 204 // Count the number of columns/rows which are percentages -> countPercent 205 if (grid[i].isPercentage()) { 206 gridLayout[i] = max<int>(grid[i].value() * availableLen / 100., 0); 207 totalPercent += gridLayout[i]; 208 countPercent++; 209 } 210 211 // Count the total relative of all the relative columns/rows -> totalRelative 212 // Count the number of columns/rows which are relative -> countRelative 213 if (grid[i].isRelative()) { 214 totalRelative += max<int>(grid[i].value(), 1); 215 countRelative++; 216 } 217 } 218 219 int remainingLen = availableLen; 220 221 // Fixed columns/rows are our first priority. If there is not enough space to fit all fixed 222 // columns/rows we need to proportionally adjust their size. 223 if (totalFixed > remainingLen) { 224 int remainingFixed = remainingLen; 225 226 for (int i = 0; i < gridLen; ++i) { 227 if (grid[i].isAbsolute()) { 228 gridLayout[i] = (gridLayout[i] * remainingFixed) / totalFixed; 229 remainingLen -= gridLayout[i]; 230 } 231 } 232 } else 233 remainingLen -= totalFixed; 234 235 // Percentage columns/rows are our second priority. Divide the remaining space proportionally 236 // over all percentage columns/rows. IMPORTANT: the size of each column/row is not relative 237 // to 100%, but to the total percentage. For example, if there are three columns, each of 75%, 238 // and the available space is 300px, each column will become 100px in width. 239 if (totalPercent > remainingLen) { 240 int remainingPercent = remainingLen; 241 242 for (int i = 0; i < gridLen; ++i) { 243 if (grid[i].isPercentage()) { 244 gridLayout[i] = (gridLayout[i] * remainingPercent) / totalPercent; 245 remainingLen -= gridLayout[i]; 246 } 247 } 248 } else 249 remainingLen -= totalPercent; 250 251 // Relative columns/rows are our last priority. Divide the remaining space proportionally 252 // over all relative columns/rows. IMPORTANT: the relative value of 0* is treated as 1*. 253 if (countRelative) { 254 int lastRelative = 0; 255 int remainingRelative = remainingLen; 256 257 for (int i = 0; i < gridLen; ++i) { 258 if (grid[i].isRelative()) { 259 gridLayout[i] = (max(grid[i].value(), 1.) * remainingRelative) / totalRelative; 260 remainingLen -= gridLayout[i]; 261 lastRelative = i; 262 } 263 } 264 265 // If we could not evenly distribute the available space of all of the relative 266 // columns/rows, the remainder will be added to the last column/row. 267 // For example: if we have a space of 100px and three columns (*,*,*), the remainder will 268 // be 1px and will be added to the last column: 33px, 33px, 34px. 269 if (remainingLen) { 270 gridLayout[lastRelative] += remainingLen; 271 remainingLen = 0; 272 } 273 } 274 275 // If we still have some left over space we need to divide it over the already existing 276 // columns/rows 277 if (remainingLen) { 278 // Our first priority is to spread if over the percentage columns. The remaining 279 // space is spread evenly, for example: if we have a space of 100px, the columns 280 // definition of 25%,25% used to result in two columns of 25px. After this the 281 // columns will each be 50px in width. 282 if (countPercent && totalPercent) { 283 int remainingPercent = remainingLen; 284 int changePercent = 0; 285 286 for (int i = 0; i < gridLen; ++i) { 287 if (grid[i].isPercentage()) { 288 changePercent = (remainingPercent * gridLayout[i]) / totalPercent; 289 gridLayout[i] += changePercent; 290 remainingLen -= changePercent; 291 } 292 } 293 } else if (totalFixed) { 294 // Our last priority is to spread the remaining space over the fixed columns. 295 // For example if we have 100px of space and two column of each 40px, both 296 // columns will become exactly 50px. 297 int remainingFixed = remainingLen; 298 int changeFixed = 0; 299 300 for (int i = 0; i < gridLen; ++i) { 301 if (grid[i].isAbsolute()) { 302 changeFixed = (remainingFixed * gridLayout[i]) / totalFixed; 303 gridLayout[i] += changeFixed; 304 remainingLen -= changeFixed; 305 } 306 } 307 } 308 } 309 310 // If we still have some left over space we probably ended up with a remainder of 311 // a division. We cannot spread it evenly anymore. If we have any percentage 312 // columns/rows simply spread the remainder equally over all available percentage columns, 313 // regardless of their size. 314 if (remainingLen && countPercent) { 315 int remainingPercent = remainingLen; 316 int changePercent = 0; 317 318 for (int i = 0; i < gridLen; ++i) { 319 if (grid[i].isPercentage()) { 320 changePercent = remainingPercent / countPercent; 321 gridLayout[i] += changePercent; 322 remainingLen -= changePercent; 323 } 324 } 325 } else if (remainingLen && countFixed) { 326 // If we don't have any percentage columns/rows we only have 327 // fixed columns. Spread the remainder equally over all fixed 328 // columns/rows. 329 int remainingFixed = remainingLen; 330 int changeFixed = 0; 331 332 for (int i = 0; i < gridLen; ++i) { 333 if (grid[i].isAbsolute()) { 334 changeFixed = remainingFixed / countFixed; 335 gridLayout[i] += changeFixed; 336 remainingLen -= changeFixed; 337 } 338 } 339 } 340 341 // Still some left over. Add it to the last column, because it is impossible 342 // spread it evenly or equally. 343 if (remainingLen) 344 gridLayout[gridLen - 1] += remainingLen; 345 346 // now we have the final layout, distribute the delta over it 347 bool worked = true; 348 int* gridDelta = axis.m_deltas.data(); 349 for (int i = 0; i < gridLen; ++i) { 350 if (gridLayout[i] && gridLayout[i] + gridDelta[i] <= 0) 351 worked = false; 352 gridLayout[i] += gridDelta[i]; 353 } 354 // if the deltas broke something, undo them 355 if (!worked) { 356 for (int i = 0; i < gridLen; ++i) 357 gridLayout[i] -= gridDelta[i]; 358 axis.m_deltas.fill(0); 359 } 360 } 361 362 void RenderFrameSet::notifyFrameEdgeInfoChanged() 363 { 364 if (needsLayout()) 365 return; 366 // FIXME: We should only recompute the edge info with respect to the frame that changed 367 // and its adjacent frame(s) instead of recomputing the edge info for the entire frameset. 368 computeEdgeInfo(); 369 } 370 371 void RenderFrameSet::fillFromEdgeInfo(const FrameEdgeInfo& edgeInfo, int r, int c) 372 { 373 if (edgeInfo.allowBorder(LeftFrameEdge)) 374 m_cols.m_allowBorder[c] = true; 375 if (edgeInfo.allowBorder(RightFrameEdge)) 376 m_cols.m_allowBorder[c + 1] = true; 377 if (edgeInfo.preventResize(LeftFrameEdge)) 378 m_cols.m_preventResize[c] = true; 379 if (edgeInfo.preventResize(RightFrameEdge)) 380 m_cols.m_preventResize[c + 1] = true; 381 382 if (edgeInfo.allowBorder(TopFrameEdge)) 383 m_rows.m_allowBorder[r] = true; 384 if (edgeInfo.allowBorder(BottomFrameEdge)) 385 m_rows.m_allowBorder[r + 1] = true; 386 if (edgeInfo.preventResize(TopFrameEdge)) 387 m_rows.m_preventResize[r] = true; 388 if (edgeInfo.preventResize(BottomFrameEdge)) 389 m_rows.m_preventResize[r + 1] = true; 390 } 391 392 void RenderFrameSet::computeEdgeInfo() 393 { 394 m_rows.m_preventResize.fill(frameSet()->noResize()); 395 m_rows.m_allowBorder.fill(false); 396 m_cols.m_preventResize.fill(frameSet()->noResize()); 397 m_cols.m_allowBorder.fill(false); 398 399 RenderObject* child = firstChild(); 400 if (!child) 401 return; 402 403 size_t rows = m_rows.m_sizes.size(); 404 size_t cols = m_cols.m_sizes.size(); 405 for (size_t r = 0; r < rows; ++r) { 406 for (size_t c = 0; c < cols; ++c) { 407 FrameEdgeInfo edgeInfo; 408 if (child->isFrameSet()) 409 edgeInfo = toRenderFrameSet(child)->edgeInfo(); 410 else 411 edgeInfo = toRenderFrame(child)->edgeInfo(); 412 fillFromEdgeInfo(edgeInfo, r, c); 413 child = child->nextSibling(); 414 if (!child) 415 return; 416 } 417 } 418 } 419 420 FrameEdgeInfo RenderFrameSet::edgeInfo() const 421 { 422 FrameEdgeInfo result(frameSet()->noResize(), true); 423 424 int rows = frameSet()->totalRows(); 425 int cols = frameSet()->totalCols(); 426 if (rows && cols) { 427 result.setPreventResize(LeftFrameEdge, m_cols.m_preventResize[0]); 428 result.setAllowBorder(LeftFrameEdge, m_cols.m_allowBorder[0]); 429 result.setPreventResize(RightFrameEdge, m_cols.m_preventResize[cols]); 430 result.setAllowBorder(RightFrameEdge, m_cols.m_allowBorder[cols]); 431 result.setPreventResize(TopFrameEdge, m_rows.m_preventResize[0]); 432 result.setAllowBorder(TopFrameEdge, m_rows.m_allowBorder[0]); 433 result.setPreventResize(BottomFrameEdge, m_rows.m_preventResize[rows]); 434 result.setAllowBorder(BottomFrameEdge, m_rows.m_allowBorder[rows]); 435 } 436 437 return result; 438 } 439 440 void RenderFrameSet::layout() 441 { 442 ASSERT(needsLayout()); 443 444 LayoutRectRecorder recorder(*this); 445 bool doFullRepaint = !RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && selfNeedsLayout() && checkForRepaintDuringLayout(); 446 LayoutRect oldBounds; 447 RenderLayerModelObject* repaintContainer = 0; 448 if (doFullRepaint) { 449 repaintContainer = containerForRepaint(); 450 oldBounds = clippedOverflowRectForRepaint(repaintContainer); 451 } 452 453 if (!parent()->isFrameSet() && !document().printing()) { 454 setWidth(view()->viewWidth()); 455 setHeight(view()->viewHeight()); 456 } 457 458 unsigned cols = frameSet()->totalCols(); 459 unsigned rows = frameSet()->totalRows(); 460 461 if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) { 462 m_rows.resize(rows); 463 m_cols.resize(cols); 464 } 465 466 LayoutUnit borderThickness = frameSet()->border(); 467 layOutAxis(m_rows, frameSet()->rowLengths(), height() - (rows - 1) * borderThickness); 468 layOutAxis(m_cols, frameSet()->colLengths(), width() - (cols - 1) * borderThickness); 469 470 positionFrames(); 471 472 RenderBox::layout(); 473 474 computeEdgeInfo(); 475 476 updateLayerTransform(); 477 478 if (doFullRepaint) { 479 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds)); 480 LayoutRect newBounds = clippedOverflowRectForRepaint(repaintContainer); 481 if (newBounds != oldBounds) 482 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds)); 483 } 484 485 clearNeedsLayout(); 486 } 487 488 static void clearNeedsLayoutOnHiddenFrames(RenderBox* frame) 489 { 490 for (; frame; frame = frame->nextSiblingBox()) { 491 frame->setWidth(0); 492 frame->setHeight(0); 493 frame->clearNeedsLayout(); 494 clearNeedsLayoutOnHiddenFrames(frame->firstChildBox()); 495 } 496 } 497 498 void RenderFrameSet::positionFrames() 499 { 500 RenderBox* child = firstChildBox(); 501 if (!child) 502 return; 503 504 int rows = frameSet()->totalRows(); 505 int cols = frameSet()->totalCols(); 506 507 int yPos = 0; 508 int borderThickness = frameSet()->border(); 509 for (int r = 0; r < rows; r++) { 510 int xPos = 0; 511 int height = m_rows.m_sizes[r]; 512 for (int c = 0; c < cols; c++) { 513 child->setLocation(IntPoint(xPos, yPos)); 514 int width = m_cols.m_sizes[c]; 515 516 // has to be resized and itself resize its contents 517 if (width != child->width() || height != child->height()) { 518 child->setWidth(width); 519 child->setHeight(height); 520 child->setNeedsLayout(); 521 child->layout(); 522 } 523 524 xPos += width + borderThickness; 525 526 child = child->nextSiblingBox(); 527 if (!child) 528 return; 529 } 530 yPos += height + borderThickness; 531 } 532 533 // All the remaining frames are hidden to avoid ugly spurious unflowed frames. 534 clearNeedsLayoutOnHiddenFrames(child); 535 } 536 537 void RenderFrameSet::startResizing(GridAxis& axis, int position) 538 { 539 int split = hitTestSplit(axis, position); 540 if (split == noSplit || axis.m_preventResize[split]) { 541 axis.m_splitBeingResized = noSplit; 542 return; 543 } 544 axis.m_splitBeingResized = split; 545 axis.m_splitResizeOffset = position - splitPosition(axis, split); 546 } 547 548 void RenderFrameSet::continueResizing(GridAxis& axis, int position) 549 { 550 if (needsLayout()) 551 return; 552 if (axis.m_splitBeingResized == noSplit) 553 return; 554 int currentSplitPosition = splitPosition(axis, axis.m_splitBeingResized); 555 int delta = (position - currentSplitPosition) - axis.m_splitResizeOffset; 556 if (!delta) 557 return; 558 axis.m_deltas[axis.m_splitBeingResized - 1] += delta; 559 axis.m_deltas[axis.m_splitBeingResized] -= delta; 560 setNeedsLayout(); 561 } 562 563 bool RenderFrameSet::userResize(MouseEvent* evt) 564 { 565 if (!m_isResizing) { 566 if (needsLayout()) 567 return false; 568 if (evt->type() == EventTypeNames::mousedown && evt->button() == LeftButton) { 569 FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms); 570 startResizing(m_cols, localPos.x()); 571 startResizing(m_rows, localPos.y()); 572 if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) { 573 setIsResizing(true); 574 return true; 575 } 576 } 577 } else { 578 if (evt->type() == EventTypeNames::mousemove || (evt->type() == EventTypeNames::mouseup && evt->button() == LeftButton)) { 579 FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms); 580 continueResizing(m_cols, localPos.x()); 581 continueResizing(m_rows, localPos.y()); 582 if (evt->type() == EventTypeNames::mouseup && evt->button() == LeftButton) { 583 setIsResizing(false); 584 return true; 585 } 586 } 587 } 588 589 return false; 590 } 591 592 void RenderFrameSet::setIsResizing(bool isResizing) 593 { 594 m_isResizing = isResizing; 595 for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { 596 if (ancestor->isFrameSet()) 597 toRenderFrameSet(ancestor)->m_isChildResizing = isResizing; 598 } 599 if (Frame* frame = this->frame()) 600 frame->eventHandler().setResizingFrameSet(isResizing ? frameSet() : 0); 601 } 602 603 bool RenderFrameSet::isResizingRow() const 604 { 605 return m_isResizing && m_rows.m_splitBeingResized != noSplit; 606 } 607 608 bool RenderFrameSet::isResizingColumn() const 609 { 610 return m_isResizing && m_cols.m_splitBeingResized != noSplit; 611 } 612 613 bool RenderFrameSet::canResizeRow(const IntPoint& p) const 614 { 615 int r = hitTestSplit(m_rows, p.y()); 616 return r != noSplit && !m_rows.m_preventResize[r]; 617 } 618 619 bool RenderFrameSet::canResizeColumn(const IntPoint& p) const 620 { 621 int c = hitTestSplit(m_cols, p.x()); 622 return c != noSplit && !m_cols.m_preventResize[c]; 623 } 624 625 int RenderFrameSet::splitPosition(const GridAxis& axis, int split) const 626 { 627 if (needsLayout()) 628 return 0; 629 630 int borderThickness = frameSet()->border(); 631 632 int size = axis.m_sizes.size(); 633 if (!size) 634 return 0; 635 636 int position = 0; 637 for (int i = 0; i < split && i < size; ++i) 638 position += axis.m_sizes[i] + borderThickness; 639 return position - borderThickness; 640 } 641 642 int RenderFrameSet::hitTestSplit(const GridAxis& axis, int position) const 643 { 644 if (needsLayout()) 645 return noSplit; 646 647 int borderThickness = frameSet()->border(); 648 if (borderThickness <= 0) 649 return noSplit; 650 651 size_t size = axis.m_sizes.size(); 652 if (!size) 653 return noSplit; 654 655 int splitPosition = axis.m_sizes[0]; 656 for (size_t i = 1; i < size; ++i) { 657 if (position >= splitPosition && position < splitPosition + borderThickness) 658 return i; 659 splitPosition += borderThickness + axis.m_sizes[i]; 660 } 661 return noSplit; 662 } 663 664 bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle*) const 665 { 666 return child->isFrame() || child->isFrameSet(); 667 } 668 669 CursorDirective RenderFrameSet::getCursor(const LayoutPoint& point, Cursor& cursor) const 670 { 671 IntPoint roundedPoint = roundedIntPoint(point); 672 if (canResizeRow(roundedPoint)) { 673 cursor = rowResizeCursor(); 674 return SetCursor; 675 } 676 if (canResizeColumn(roundedPoint)) { 677 cursor = columnResizeCursor(); 678 return SetCursor; 679 } 680 return RenderBox::getCursor(point, cursor); 681 } 682 683 } // namespace WebCore 684