1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2007 David Smith (catfish.man (at) gmail.com) 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 */ 23 24 #include "config.h" 25 #include "core/rendering/FloatingObjects.h" 26 27 #include "core/rendering/RenderBlockFlow.h" 28 #include "core/rendering/RenderBox.h" 29 #include "core/rendering/RenderView.h" 30 31 using namespace std; 32 using namespace WTF; 33 34 namespace WebCore { 35 36 struct SameSizeAsFloatingObject { 37 void* pointers[2]; 38 LayoutRect rect; 39 int paginationStrut; 40 uint32_t bitfields : 8; 41 }; 42 43 COMPILE_ASSERT(sizeof(FloatingObject) == sizeof(SameSizeAsFloatingObject), FloatingObject_should_stay_small); 44 45 FloatingObject::FloatingObject(RenderBox* renderer) 46 : m_renderer(renderer) 47 , m_originatingLine(0) 48 , m_paginationStrut(0) 49 , m_shouldPaint(true) 50 , m_isDescendant(false) 51 , m_isPlaced(false) 52 #ifndef NDEBUG 53 , m_isInPlacedTree(false) 54 #endif 55 { 56 EFloat type = renderer->style()->floating(); 57 ASSERT(type != NoFloat); 58 if (type == LeftFloat) 59 m_type = FloatLeft; 60 else if (type == RightFloat) 61 m_type = FloatRight; 62 } 63 64 FloatingObject::FloatingObject(RenderBox* renderer, Type type, const LayoutRect& frameRect, bool shouldPaint, bool isDescendant) 65 : m_renderer(renderer) 66 , m_originatingLine(0) 67 , m_frameRect(frameRect) 68 , m_paginationStrut(0) 69 , m_type(type) 70 , m_shouldPaint(shouldPaint) 71 , m_isDescendant(isDescendant) 72 , m_isPlaced(true) 73 #ifndef NDEBUG 74 , m_isInPlacedTree(false) 75 #endif 76 { 77 } 78 79 PassOwnPtr<FloatingObject> FloatingObject::create(RenderBox* renderer) 80 { 81 OwnPtr<FloatingObject> newObj = adoptPtr(new FloatingObject(renderer)); 82 newObj->setShouldPaint(!renderer->hasSelfPaintingLayer()); // If a layer exists, the float will paint itself. Otherwise someone else will. 83 newObj->setIsDescendant(true); 84 85 return newObj.release(); 86 } 87 88 PassOwnPtr<FloatingObject> FloatingObject::copyToNewContainer(LayoutSize offset, bool shouldPaint, bool isDescendant) const 89 { 90 return adoptPtr(new FloatingObject(renderer(), type(), LayoutRect(frameRect().location() - offset, frameRect().size()), shouldPaint, isDescendant)); 91 } 92 93 PassOwnPtr<FloatingObject> FloatingObject::unsafeClone() const 94 { 95 OwnPtr<FloatingObject> cloneObject = adoptPtr(new FloatingObject(renderer(), type(), m_frameRect, m_shouldPaint, m_isDescendant)); 96 cloneObject->m_paginationStrut = m_paginationStrut; 97 cloneObject->m_isPlaced = m_isPlaced; 98 return cloneObject.release(); 99 } 100 101 template <FloatingObject::Type FloatTypeValue> 102 class ComputeFloatOffsetAdapter { 103 public: 104 typedef FloatingObjectInterval IntervalType; 105 106 ComputeFloatOffsetAdapter(const RenderBlockFlow* renderer, int lineTop, int lineBottom, LayoutUnit offset) 107 : m_renderer(renderer) 108 , m_lineTop(lineTop) 109 , m_lineBottom(lineBottom) 110 , m_offset(offset) 111 , m_outermostFloat(0) 112 { 113 } 114 115 virtual ~ComputeFloatOffsetAdapter() { } 116 117 int lowValue() const { return m_lineTop; } 118 int highValue() const { return m_lineBottom; } 119 void collectIfNeeded(const IntervalType&); 120 121 LayoutUnit offset() const { return m_offset; } 122 123 protected: 124 virtual bool updateOffsetIfNeeded(const FloatingObject*) = 0; 125 126 const RenderBlockFlow* m_renderer; 127 int m_lineTop; 128 int m_lineBottom; 129 LayoutUnit m_offset; 130 const FloatingObject* m_outermostFloat; 131 }; 132 133 template <FloatingObject::Type FloatTypeValue> 134 class ComputeFloatOffsetForFloatLayoutAdapter : public ComputeFloatOffsetAdapter<FloatTypeValue> { 135 public: 136 ComputeFloatOffsetForFloatLayoutAdapter(const RenderBlockFlow* renderer, LayoutUnit lineTop, LayoutUnit lineBottom, LayoutUnit offset) 137 : ComputeFloatOffsetAdapter<FloatTypeValue>(renderer, lineTop, lineBottom, offset) 138 { 139 } 140 141 virtual ~ComputeFloatOffsetForFloatLayoutAdapter() { } 142 143 LayoutUnit heightRemaining() const; 144 145 protected: 146 virtual bool updateOffsetIfNeeded(const FloatingObject*) OVERRIDE FINAL; 147 }; 148 149 template <FloatingObject::Type FloatTypeValue> 150 class ComputeFloatOffsetForLineLayoutAdapter : public ComputeFloatOffsetAdapter<FloatTypeValue> { 151 public: 152 ComputeFloatOffsetForLineLayoutAdapter(const RenderBlockFlow* renderer, LayoutUnit lineTop, LayoutUnit lineBottom, LayoutUnit offset) 153 : ComputeFloatOffsetAdapter<FloatTypeValue>(renderer, lineTop, lineBottom, offset) 154 { 155 } 156 157 virtual ~ComputeFloatOffsetForLineLayoutAdapter() { } 158 159 protected: 160 virtual bool updateOffsetIfNeeded(const FloatingObject*) OVERRIDE FINAL; 161 }; 162 163 164 FloatingObjects::~FloatingObjects() 165 { 166 } 167 void FloatingObjects::clearLineBoxTreePointers() 168 { 169 // Clear references to originating lines, since the lines are being deleted 170 FloatingObjectSetIterator end = m_set.end(); 171 for (FloatingObjectSetIterator it = m_set.begin(); it != end; ++it) { 172 ASSERT(!((*it)->originatingLine()) || (*it)->originatingLine()->renderer() == m_renderer); 173 (*it)->setOriginatingLine(0); 174 } 175 } 176 177 FloatingObjects::FloatingObjects(const RenderBlockFlow* renderer, bool horizontalWritingMode) 178 : m_placedFloatsTree(UninitializedTree) 179 , m_leftObjectsCount(0) 180 , m_rightObjectsCount(0) 181 , m_horizontalWritingMode(horizontalWritingMode) 182 , m_renderer(renderer) 183 , m_cachedHorizontalWritingMode(false) 184 { 185 } 186 187 void FloatingObjects::clear() 188 { 189 m_set.clear(); 190 m_placedFloatsTree.clear(); 191 m_leftObjectsCount = 0; 192 m_rightObjectsCount = 0; 193 markLowestFloatLogicalBottomCacheAsDirty(); 194 } 195 196 LayoutUnit FloatingObjects::lowestFloatLogicalBottom(FloatingObject::Type floatType) 197 { 198 bool isInHorizontalWritingMode = m_horizontalWritingMode; 199 if (floatType != FloatingObject::FloatLeftRight) { 200 if (hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, floatType)) 201 return getCachedlowestFloatLogicalBottom(floatType); 202 } else { 203 if (hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, FloatingObject::FloatLeft) && hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, FloatingObject::FloatRight)) { 204 return max(getCachedlowestFloatLogicalBottom(FloatingObject::FloatLeft), 205 getCachedlowestFloatLogicalBottom(FloatingObject::FloatRight)); 206 } 207 } 208 209 LayoutUnit lowestFloatBottom = 0; 210 const FloatingObjectSet& floatingObjectSet = set(); 211 FloatingObjectSetIterator end = floatingObjectSet.end(); 212 if (floatType == FloatingObject::FloatLeftRight) { 213 LayoutUnit lowestFloatBottomLeft = 0; 214 LayoutUnit lowestFloatBottomRight = 0; 215 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 216 FloatingObject* floatingObject = it->get(); 217 if (floatingObject->isPlaced()) { 218 FloatingObject::Type curType = floatingObject->type(); 219 LayoutUnit curFloatLogicalBottom = m_renderer->logicalBottomForFloat(floatingObject); 220 if (curType & FloatingObject::FloatLeft) 221 lowestFloatBottomLeft = max(lowestFloatBottomLeft, curFloatLogicalBottom); 222 if (curType & FloatingObject::FloatRight) 223 lowestFloatBottomRight = max(lowestFloatBottomRight, curFloatLogicalBottom); 224 } 225 } 226 lowestFloatBottom = max(lowestFloatBottomLeft, lowestFloatBottomRight); 227 setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, FloatingObject::FloatLeft, lowestFloatBottomLeft); 228 setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, FloatingObject::FloatRight, lowestFloatBottomRight); 229 } else { 230 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 231 FloatingObject* floatingObject = it->get(); 232 if (floatingObject->isPlaced() && floatingObject->type() == floatType) 233 lowestFloatBottom = max(lowestFloatBottom, m_renderer->logicalBottomForFloat(floatingObject)); 234 } 235 setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, floatType, lowestFloatBottom); 236 } 237 238 return lowestFloatBottom; 239 } 240 241 bool FloatingObjects::hasLowestFloatLogicalBottomCached(bool isHorizontal, FloatingObject::Type type) const 242 { 243 int floatIndex = static_cast<int>(type) - 1; 244 ASSERT(floatIndex < static_cast<int>(sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue))); 245 ASSERT(floatIndex >= 0); 246 return (m_cachedHorizontalWritingMode == isHorizontal && !m_lowestFloatBottomCache[floatIndex].dirty); 247 } 248 249 LayoutUnit FloatingObjects::getCachedlowestFloatLogicalBottom(FloatingObject::Type type) const 250 { 251 int floatIndex = static_cast<int>(type) - 1; 252 ASSERT(floatIndex < static_cast<int>(sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue))); 253 ASSERT(floatIndex >= 0); 254 return m_lowestFloatBottomCache[floatIndex].value; 255 } 256 257 void FloatingObjects::setCachedLowestFloatLogicalBottom(bool isHorizontal, FloatingObject::Type type, LayoutUnit value) 258 { 259 int floatIndex = static_cast<int>(type) - 1; 260 ASSERT(floatIndex < static_cast<int>(sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue))); 261 ASSERT(floatIndex >= 0); 262 m_cachedHorizontalWritingMode = isHorizontal; 263 m_lowestFloatBottomCache[floatIndex].value = value; 264 m_lowestFloatBottomCache[floatIndex].dirty = false; 265 } 266 267 void FloatingObjects::markLowestFloatLogicalBottomCacheAsDirty() 268 { 269 for (size_t i = 0; i < sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue); ++i) 270 m_lowestFloatBottomCache[i].dirty = true; 271 } 272 273 void FloatingObjects::moveAllToFloatInfoMap(RendererToFloatInfoMap& map) 274 { 275 while (!m_set.isEmpty()) { 276 OwnPtr<FloatingObject> floatingObject = m_set.takeFirst(); 277 RenderBox* renderer = floatingObject->renderer(); 278 map.add(renderer, floatingObject.release()); 279 } 280 clear(); 281 } 282 283 inline void FloatingObjects::increaseObjectsCount(FloatingObject::Type type) 284 { 285 if (type == FloatingObject::FloatLeft) 286 m_leftObjectsCount++; 287 else 288 m_rightObjectsCount++; 289 } 290 291 inline void FloatingObjects::decreaseObjectsCount(FloatingObject::Type type) 292 { 293 if (type == FloatingObject::FloatLeft) 294 m_leftObjectsCount--; 295 else 296 m_rightObjectsCount--; 297 } 298 299 inline FloatingObjectInterval FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject) 300 { 301 if (m_horizontalWritingMode) 302 return FloatingObjectInterval(floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxY(), floatingObject); 303 return FloatingObjectInterval(floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject); 304 } 305 306 void FloatingObjects::addPlacedObject(FloatingObject* floatingObject) 307 { 308 ASSERT(!floatingObject->isInPlacedTree()); 309 310 floatingObject->setIsPlaced(true); 311 if (m_placedFloatsTree.isInitialized()) 312 m_placedFloatsTree.add(intervalForFloatingObject(floatingObject)); 313 314 #ifndef NDEBUG 315 floatingObject->setIsInPlacedTree(true); 316 #endif 317 markLowestFloatLogicalBottomCacheAsDirty(); 318 } 319 320 void FloatingObjects::removePlacedObject(FloatingObject* floatingObject) 321 { 322 ASSERT(floatingObject->isPlaced() && floatingObject->isInPlacedTree()); 323 324 if (m_placedFloatsTree.isInitialized()) { 325 bool removed = m_placedFloatsTree.remove(intervalForFloatingObject(floatingObject)); 326 ASSERT_UNUSED(removed, removed); 327 } 328 329 floatingObject->setIsPlaced(false); 330 #ifndef NDEBUG 331 floatingObject->setIsInPlacedTree(false); 332 #endif 333 markLowestFloatLogicalBottomCacheAsDirty(); 334 } 335 336 FloatingObject* FloatingObjects::add(PassOwnPtr<FloatingObject> floatingObject) 337 { 338 FloatingObject* newObject = floatingObject.leakPtr(); 339 increaseObjectsCount(newObject->type()); 340 m_set.add(adoptPtr(newObject)); 341 if (newObject->isPlaced()) 342 addPlacedObject(newObject); 343 markLowestFloatLogicalBottomCacheAsDirty(); 344 return newObject; 345 } 346 347 void FloatingObjects::remove(FloatingObject* toBeRemoved) 348 { 349 decreaseObjectsCount(toBeRemoved->type()); 350 OwnPtr<FloatingObject> floatingObject = m_set.take(toBeRemoved); 351 ASSERT(floatingObject->isPlaced() || !floatingObject->isInPlacedTree()); 352 if (floatingObject->isPlaced()) 353 removePlacedObject(floatingObject.get()); 354 markLowestFloatLogicalBottomCacheAsDirty(); 355 ASSERT(!floatingObject->originatingLine()); 356 } 357 358 void FloatingObjects::computePlacedFloatsTree() 359 { 360 ASSERT(!m_placedFloatsTree.isInitialized()); 361 if (m_set.isEmpty()) 362 return; 363 m_placedFloatsTree.initIfNeeded(m_renderer->view()->intervalArena()); 364 FloatingObjectSetIterator it = m_set.begin(); 365 FloatingObjectSetIterator end = m_set.end(); 366 for (; it != end; ++it) { 367 FloatingObject* floatingObject = it->get(); 368 if (floatingObject->isPlaced()) 369 m_placedFloatsTree.add(intervalForFloatingObject(floatingObject)); 370 } 371 } 372 373 LayoutUnit FloatingObjects::logicalLeftOffsetForPositioningFloat(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit *heightRemaining) 374 { 375 int logicalTopAsInt = roundToInt(logicalTop); 376 ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatLeft> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset); 377 placedFloatsTree().allOverlapsWithAdapter(adapter); 378 379 if (heightRemaining) 380 *heightRemaining = adapter.heightRemaining(); 381 382 return adapter.offset(); 383 } 384 385 LayoutUnit FloatingObjects::logicalRightOffsetForPositioningFloat(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit *heightRemaining) 386 { 387 int logicalTopAsInt = roundToInt(logicalTop); 388 ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatRight> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset); 389 placedFloatsTree().allOverlapsWithAdapter(adapter); 390 391 if (heightRemaining) 392 *heightRemaining = adapter.heightRemaining(); 393 394 return min(fixedOffset, adapter.offset()); 395 } 396 397 LayoutUnit FloatingObjects::logicalLeftOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight) 398 { 399 ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatLeft> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset); 400 placedFloatsTree().allOverlapsWithAdapter(adapter); 401 402 return adapter.offset(); 403 } 404 405 LayoutUnit FloatingObjects::logicalRightOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight) 406 { 407 ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatRight> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset); 408 placedFloatsTree().allOverlapsWithAdapter(adapter); 409 410 return min(fixedOffset, adapter.offset()); 411 } 412 413 FloatingObjects::FloatBottomCachedValue::FloatBottomCachedValue() 414 : value(0) 415 , dirty(true) 416 { 417 } 418 419 inline static bool rangesIntersect(int floatTop, int floatBottom, int objectTop, int objectBottom) 420 { 421 if (objectTop >= floatBottom || objectBottom < floatTop) 422 return false; 423 424 // The top of the object overlaps the float 425 if (objectTop >= floatTop) 426 return true; 427 428 // The object encloses the float 429 if (objectTop < floatTop && objectBottom > floatBottom) 430 return true; 431 432 // The bottom of the object overlaps the float 433 if (objectBottom > objectTop && objectBottom > floatTop && objectBottom <= floatBottom) 434 return true; 435 436 return false; 437 } 438 439 template<> 440 inline bool ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject* floatingObject) 441 { 442 LayoutUnit logicalRight = m_renderer->logicalRightForFloat(floatingObject); 443 if (logicalRight > m_offset) { 444 m_offset = logicalRight; 445 return true; 446 } 447 return false; 448 } 449 450 template<> 451 inline bool ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject* floatingObject) 452 { 453 LayoutUnit logicalLeft = m_renderer->logicalLeftForFloat(floatingObject); 454 if (logicalLeft < m_offset) { 455 m_offset = logicalLeft; 456 return true; 457 } 458 return false; 459 } 460 461 template <FloatingObject::Type FloatTypeValue> 462 LayoutUnit ComputeFloatOffsetForFloatLayoutAdapter<FloatTypeValue>::heightRemaining() const 463 { 464 return this->m_outermostFloat ? this->m_renderer->logicalBottomForFloat(this->m_outermostFloat) - this->m_lineTop : LayoutUnit(1); 465 } 466 467 template <FloatingObject::Type FloatTypeValue> 468 inline void ComputeFloatOffsetAdapter<FloatTypeValue>::collectIfNeeded(const IntervalType& interval) 469 { 470 const FloatingObject* floatingObject = interval.data(); 471 if (floatingObject->type() != FloatTypeValue || !rangesIntersect(interval.low(), interval.high(), m_lineTop, m_lineBottom)) 472 return; 473 474 // Make sure the float hasn't changed since it was added to the placed floats tree. 475 ASSERT(floatingObject->isPlaced()); 476 ASSERT(interval.low() == m_renderer->pixelSnappedLogicalTopForFloat(floatingObject)); 477 ASSERT(interval.high() == m_renderer->pixelSnappedLogicalBottomForFloat(floatingObject)); 478 479 bool floatIsNewExtreme = updateOffsetIfNeeded(floatingObject); 480 if (floatIsNewExtreme) 481 m_outermostFloat = floatingObject; 482 } 483 484 static inline ShapeOutsideInfo* shapeInfoForFloat(const FloatingObject& floatingObject, const RenderBlockFlow& containingBlock, LayoutUnit lineTop, LayoutUnit lineBottom) 485 { 486 if (ShapeOutsideInfo* shapeOutside = floatingObject.renderer()->shapeOutsideInfo()) { 487 shapeOutside->updateDeltasForContainingBlockLine(containingBlock, floatingObject, lineTop, lineBottom - lineTop); 488 return shapeOutside; 489 } 490 491 return 0; 492 } 493 494 template<> 495 inline bool ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject* floatingObject) 496 { 497 ASSERT(floatingObject); 498 LayoutUnit logicalRight = m_renderer->logicalRightForFloat(floatingObject); 499 if (ShapeOutsideInfo* shapeOutside = shapeInfoForFloat(*floatingObject, *m_renderer, m_lineTop, m_lineBottom)) { 500 if (!shapeOutside->lineOverlapsShape()) 501 return false; 502 503 logicalRight += shapeOutside->rightMarginBoxDelta(); 504 } 505 if (logicalRight > m_offset) { 506 m_offset = logicalRight; 507 return true; 508 } 509 510 return false; 511 } 512 513 template<> 514 inline bool ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject* floatingObject) 515 { 516 ASSERT(floatingObject); 517 LayoutUnit logicalLeft = m_renderer->logicalLeftForFloat(floatingObject); 518 if (ShapeOutsideInfo* shapeOutside = shapeInfoForFloat(*floatingObject, *m_renderer, m_lineTop, m_lineBottom)) { 519 if (!shapeOutside->lineOverlapsShape()) 520 return false; 521 522 logicalLeft += shapeOutside->leftMarginBoxDelta(); 523 } 524 if (logicalLeft < m_offset) { 525 m_offset = logicalLeft; 526 return true; 527 } 528 529 return false; 530 } 531 532 #ifndef NDEBUG 533 // These helpers are only used by the PODIntervalTree for debugging purposes. 534 String ValueToString<int>::string(const int value) 535 { 536 return String::number(value); 537 } 538 539 String ValueToString<FloatingObject*>::string(const FloatingObject* floatingObject) 540 { 541 return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject->frameRect().pixelSnappedMaxY()); 542 } 543 #endif 544 545 546 } // namespace WebCore 547