blob: 3db8f737b5f489803048df9106523c7e9f0dfe6e [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2007 David Smith (catfish.man@gmail.com)
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
* All rights reserved.
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* 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 "third_party/blink/renderer/core/layout/floating_objects.h"
#include <algorithm>
#include <memory>
#include <utility>
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
namespace blink {
struct SameSizeAsFloatingObject {
void* pointers[2];
LayoutRect rect;
uint32_t bitfields : 8;
};
static_assert(sizeof(FloatingObject) == sizeof(SameSizeAsFloatingObject),
"FloatingObject should stay small");
FloatingObject::FloatingObject(LayoutBox* layout_object, Type type)
: layout_object_(layout_object),
originating_line_(nullptr),
type_(type),
should_paint_(true),
is_descendant_(false),
is_placed_(false),
is_lowest_non_overhanging_float_in_child_(false)
#if DCHECK_IS_ON()
,
is_in_placed_tree_(false),
has_geometry_(false)
#endif
{
}
FloatingObject::FloatingObject(LayoutBox* layout_object,
Type type,
const LayoutRect& frame_rect,
bool should_paint,
bool is_descendant,
bool is_lowest_non_overhanging_float_in_child)
: layout_object_(layout_object),
originating_line_(nullptr),
frame_rect_(frame_rect),
type_(type),
should_paint_(should_paint),
is_descendant_(is_descendant),
is_placed_(true),
is_lowest_non_overhanging_float_in_child_(
is_lowest_non_overhanging_float_in_child)
#if DCHECK_IS_ON()
,
is_in_placed_tree_(false),
has_geometry_(false)
#endif
{
}
std::unique_ptr<FloatingObject> FloatingObject::Create(LayoutBox* layout_object,
Type type) {
std::unique_ptr<FloatingObject> new_obj =
base::WrapUnique(new FloatingObject(layout_object, type));
// If a layer exists, the float will paint itself. Otherwise someone else
// will.
new_obj->SetShouldPaint(!layout_object->HasSelfPaintingLayer());
new_obj->SetIsDescendant(true);
// We set SelfPaintingStatusChanged in case we get to the next compositing
// update and still haven't decided who should paint the float. If we've
// decided that the current float owner can paint it that step is unnecessary,
// so we can clear it now.
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
new_obj->ShouldPaint() && layout_object->Layer() &&
layout_object->Layer()->SelfPaintingStatusChanged())
layout_object->Layer()->ClearSelfPaintingStatusChanged();
return new_obj;
}
std::unique_ptr<FloatingObject> FloatingObject::CopyToNewContainer(
LayoutSize offset,
bool should_paint,
bool is_descendant) const {
return base::WrapUnique(new FloatingObject(
GetLayoutObject(), GetType(),
LayoutRect(FrameRect().Location() - offset, FrameRect().Size()),
should_paint, is_descendant, IsLowestNonOverhangingFloatInChild()));
}
std::unique_ptr<FloatingObject> FloatingObject::UnsafeClone() const {
std::unique_ptr<FloatingObject> clone_object = base::WrapUnique(
new FloatingObject(GetLayoutObject(), GetType(), frame_rect_,
should_paint_, is_descendant_, false));
clone_object->is_placed_ = is_placed_;
#if DCHECK_IS_ON()
clone_object->has_geometry_ = has_geometry_;
#endif
return clone_object;
}
template <FloatingObject::Type FloatTypeValue>
class ComputeFloatOffsetAdapter {
public:
typedef FloatingObjectInterval IntervalType;
ComputeFloatOffsetAdapter(const LayoutBlockFlow* layout_object,
LayoutUnit line_top,
LayoutUnit line_bottom,
LayoutUnit offset)
: layout_object_(layout_object),
line_top_(line_top),
line_bottom_(line_bottom),
offset_(offset),
outermost_float_(nullptr) {}
virtual ~ComputeFloatOffsetAdapter() = default;
LayoutUnit LowValue() const { return line_top_; }
LayoutUnit HighValue() const { return line_bottom_; }
void CollectIfNeeded(const IntervalType&);
LayoutUnit Offset() const { return offset_; }
protected:
virtual bool UpdateOffsetIfNeeded(const FloatingObject&) = 0;
const LayoutBlockFlow* layout_object_;
LayoutUnit line_top_;
LayoutUnit line_bottom_;
LayoutUnit offset_;
const FloatingObject* outermost_float_;
};
template <FloatingObject::Type FloatTypeValue>
class ComputeFloatOffsetForFloatLayoutAdapter
: public ComputeFloatOffsetAdapter<FloatTypeValue> {
public:
ComputeFloatOffsetForFloatLayoutAdapter(const LayoutBlockFlow* layout_object,
LayoutUnit line_top,
LayoutUnit line_bottom,
LayoutUnit offset)
: ComputeFloatOffsetAdapter<FloatTypeValue>(layout_object,
line_top,
line_bottom,
offset) {}
~ComputeFloatOffsetForFloatLayoutAdapter() override = default;
LayoutUnit HeightRemaining() const;
protected:
bool UpdateOffsetIfNeeded(const FloatingObject&) final;
};
template <FloatingObject::Type FloatTypeValue>
class ComputeFloatOffsetForLineLayoutAdapter
: public ComputeFloatOffsetAdapter<FloatTypeValue> {
public:
ComputeFloatOffsetForLineLayoutAdapter(const LayoutBlockFlow* layout_object,
LayoutUnit line_top,
LayoutUnit line_bottom,
LayoutUnit offset)
: ComputeFloatOffsetAdapter<FloatTypeValue>(layout_object,
line_top,
line_bottom,
offset) {}
~ComputeFloatOffsetForLineLayoutAdapter() override = default;
protected:
bool UpdateOffsetIfNeeded(const FloatingObject&) final;
};
class FindNextFloatLogicalBottomAdapter {
public:
typedef FloatingObjectInterval IntervalType;
FindNextFloatLogicalBottomAdapter(const LayoutBlockFlow& renderer,
LayoutUnit below_logical_height)
: layout_object_(renderer),
below_logical_height_(below_logical_height),
above_logical_height_(LayoutUnit::Max()),
next_logical_bottom_(),
next_shape_logical_bottom_() {}
LayoutUnit LowValue() const { return below_logical_height_; }
LayoutUnit HighValue() const { return above_logical_height_; }
void CollectIfNeeded(const IntervalType&);
LayoutUnit NextLogicalBottom() { return next_logical_bottom_; }
LayoutUnit NextShapeLogicalBottom() { return next_shape_logical_bottom_; }
private:
const LayoutBlockFlow& layout_object_;
LayoutUnit below_logical_height_;
LayoutUnit above_logical_height_;
LayoutUnit next_logical_bottom_;
LayoutUnit next_shape_logical_bottom_;
};
inline static bool RangesIntersect(LayoutUnit float_top,
LayoutUnit float_bottom,
LayoutUnit object_top,
LayoutUnit object_bottom) {
if (object_top >= float_bottom || object_bottom < float_top)
return false;
// The top of the object overlaps the float
if (object_top >= float_top)
return true;
// The object encloses the float
if (object_top < float_top && object_bottom > float_bottom)
return true;
// The bottom of the object overlaps the float
if (object_bottom > object_top && object_bottom > float_top &&
object_bottom <= float_bottom)
return true;
return false;
}
inline void FindNextFloatLogicalBottomAdapter::CollectIfNeeded(
const IntervalType& interval) {
const FloatingObject& floating_object = *(interval.Data());
if (!RangesIntersect(interval.Low(), interval.High(), below_logical_height_,
above_logical_height_))
return;
// All the objects returned from the tree should be already placed.
DCHECK(floating_object.IsPlaced());
DCHECK(RangesIntersect(layout_object_.LogicalTopForFloat(floating_object),
layout_object_.LogicalBottomForFloat(floating_object),
below_logical_height_, above_logical_height_));
LayoutUnit float_bottom =
layout_object_.LogicalBottomForFloat(floating_object);
if (ShapeOutsideInfo* shape_outside =
floating_object.GetLayoutObject()->GetShapeOutsideInfo()) {
LayoutUnit shape_bottom =
layout_object_.LogicalTopForFloat(floating_object) +
layout_object_.MarginBeforeForChild(
*floating_object.GetLayoutObject()) +
shape_outside->ShapeLogicalBottom();
// Use the shapeBottom unless it extends outside of the margin box, in which
// case it is clipped.
next_shape_logical_bottom_ = next_shape_logical_bottom_
? std::min(shape_bottom, float_bottom)
: shape_bottom;
} else {
next_shape_logical_bottom_ =
next_shape_logical_bottom_
? std::min(next_shape_logical_bottom_, float_bottom)
: float_bottom;
}
next_logical_bottom_ = next_logical_bottom_
? std::min(next_logical_bottom_, float_bottom)
: float_bottom;
}
LayoutUnit FloatingObjects::FindNextFloatLogicalBottomBelow(
LayoutUnit logical_height) {
FindNextFloatLogicalBottomAdapter adapter(*layout_object_, logical_height);
PlacedFloatsTree().AllOverlapsWithAdapter(adapter);
return adapter.NextShapeLogicalBottom();
}
LayoutUnit FloatingObjects::FindNextFloatLogicalBottomBelowForBlock(
LayoutUnit logical_height) {
FindNextFloatLogicalBottomAdapter adapter(*layout_object_, logical_height);
PlacedFloatsTree().AllOverlapsWithAdapter(adapter);
return adapter.NextLogicalBottom();
}
FloatingObjects::~FloatingObjects() = default;
void FloatingObjects::ClearLineBoxTreePointers() {
// Clear references to originating lines, since the lines are being deleted
FloatingObjectSetIterator end = set_.end();
for (FloatingObjectSetIterator it = set_.begin(); it != end; ++it) {
DCHECK(
!((*it)->OriginatingLine()) ||
(*it)->OriginatingLine()->GetLineLayoutItem().IsEqual(layout_object_));
(*it)->SetOriginatingLine(nullptr);
}
}
FloatingObjects::FloatingObjects(const LayoutBlockFlow* layout_object,
bool horizontal_writing_mode)
: placed_floats_tree_(WTF::kUninitializedTree),
left_objects_count_(0),
right_objects_count_(0),
horizontal_writing_mode_(horizontal_writing_mode),
layout_object_(layout_object),
cached_horizontal_writing_mode_(false) {}
void FloatingObjects::Clear() {
set_.clear();
placed_floats_tree_.Clear();
left_objects_count_ = 0;
right_objects_count_ = 0;
MarkLowestFloatLogicalBottomCacheAsDirty();
}
LayoutUnit FloatingObjects::LowestFloatLogicalBottom(
FloatingObject::Type float_type) {
bool is_in_horizontal_writing_mode = horizontal_writing_mode_;
if (float_type != FloatingObject::kFloatLeftRight) {
if (HasLowestFloatLogicalBottomCached(is_in_horizontal_writing_mode,
float_type))
return GetCachedlowestFloatLogicalBottom(float_type);
} else {
if (HasLowestFloatLogicalBottomCached(is_in_horizontal_writing_mode,
FloatingObject::kFloatLeft) &&
HasLowestFloatLogicalBottomCached(is_in_horizontal_writing_mode,
FloatingObject::kFloatRight)) {
return std::max(
GetCachedlowestFloatLogicalBottom(FloatingObject::kFloatLeft),
GetCachedlowestFloatLogicalBottom(FloatingObject::kFloatRight));
}
}
LayoutUnit lowest_float_bottom;
const FloatingObjectSet& floating_object_set = Set();
FloatingObjectSetIterator end = floating_object_set.end();
if (float_type == FloatingObject::kFloatLeftRight) {
FloatingObject* lowest_floating_object_left = nullptr;
FloatingObject* lowest_floating_object_right = nullptr;
LayoutUnit lowest_float_bottom_left;
LayoutUnit lowest_float_bottom_right;
for (FloatingObjectSetIterator it = floating_object_set.begin(); it != end;
++it) {
FloatingObject& floating_object = *it->get();
if (floating_object.IsPlaced()) {
FloatingObject::Type cur_type = floating_object.GetType();
LayoutUnit cur_float_logical_bottom =
layout_object_->LogicalBottomForFloat(floating_object);
if (cur_type & FloatingObject::kFloatLeft &&
cur_float_logical_bottom > lowest_float_bottom_left) {
lowest_float_bottom_left = cur_float_logical_bottom;
lowest_floating_object_left = &floating_object;
}
if (cur_type & FloatingObject::kFloatRight &&
cur_float_logical_bottom > lowest_float_bottom_right) {
lowest_float_bottom_right = cur_float_logical_bottom;
lowest_floating_object_right = &floating_object;
}
}
}
lowest_float_bottom =
std::max(lowest_float_bottom_left, lowest_float_bottom_right);
SetCachedLowestFloatLogicalBottom(is_in_horizontal_writing_mode,
FloatingObject::kFloatLeft,
lowest_floating_object_left);
SetCachedLowestFloatLogicalBottom(is_in_horizontal_writing_mode,
FloatingObject::kFloatRight,
lowest_floating_object_right);
} else {
FloatingObject* lowest_floating_object = nullptr;
for (FloatingObjectSetIterator it = floating_object_set.begin(); it != end;
++it) {
FloatingObject& floating_object = *it->get();
if (floating_object.IsPlaced() &&
floating_object.GetType() == float_type) {
if (layout_object_->LogicalBottomForFloat(floating_object) >
lowest_float_bottom) {
lowest_floating_object = &floating_object;
lowest_float_bottom =
layout_object_->LogicalBottomForFloat(floating_object);
}
}
}
SetCachedLowestFloatLogicalBottom(is_in_horizontal_writing_mode, float_type,
lowest_floating_object);
}
return lowest_float_bottom;
}
bool FloatingObjects::HasLowestFloatLogicalBottomCached(
bool is_horizontal,
FloatingObject::Type type) const {
int float_index = static_cast<int>(type) - 1;
DCHECK_LT(float_index, static_cast<int>(sizeof(lowest_float_bottom_cache_) /
sizeof(FloatBottomCachedValue)));
DCHECK_GE(float_index, 0);
return (cached_horizontal_writing_mode_ == is_horizontal &&
!lowest_float_bottom_cache_[float_index].dirty);
}
LayoutUnit FloatingObjects::GetCachedlowestFloatLogicalBottom(
FloatingObject::Type type) const {
int float_index = static_cast<int>(type) - 1;
DCHECK_LT(float_index, static_cast<int>(sizeof(lowest_float_bottom_cache_) /
sizeof(FloatBottomCachedValue)));
DCHECK_GE(float_index, 0);
if (!lowest_float_bottom_cache_[float_index].floating_object)
return LayoutUnit();
return layout_object_->LogicalBottomForFloat(
*lowest_float_bottom_cache_[float_index].floating_object);
}
void FloatingObjects::SetCachedLowestFloatLogicalBottom(
bool is_horizontal,
FloatingObject::Type type,
FloatingObject* floating_object) {
int float_index = static_cast<int>(type) - 1;
DCHECK_LT(float_index, static_cast<int>(sizeof(lowest_float_bottom_cache_) /
sizeof(FloatBottomCachedValue)));
DCHECK_GE(float_index, 0);
cached_horizontal_writing_mode_ = is_horizontal;
lowest_float_bottom_cache_[float_index].floating_object = floating_object;
lowest_float_bottom_cache_[float_index].dirty = false;
}
FloatingObject* FloatingObjects::LowestFloatingObject() const {
bool is_in_horizontal_writing_mode = horizontal_writing_mode_;
if (!HasLowestFloatLogicalBottomCached(is_in_horizontal_writing_mode,
FloatingObject::kFloatLeft) &&
!HasLowestFloatLogicalBottomCached(is_in_horizontal_writing_mode,
FloatingObject::kFloatRight))
return nullptr;
FloatingObject* lowest_left_object =
lowest_float_bottom_cache_[0].floating_object;
FloatingObject* lowest_right_object =
lowest_float_bottom_cache_[1].floating_object;
LayoutUnit lowest_float_bottom_left =
lowest_left_object
? layout_object_->LogicalBottomForFloat(*lowest_left_object)
: LayoutUnit();
LayoutUnit lowest_float_bottom_right =
lowest_right_object
? layout_object_->LogicalBottomForFloat(*lowest_right_object)
: LayoutUnit();
if (lowest_float_bottom_left > lowest_float_bottom_right)
return lowest_left_object;
return lowest_right_object;
}
void FloatingObjects::MarkLowestFloatLogicalBottomCacheAsDirty() {
for (size_t i = 0;
i < sizeof(lowest_float_bottom_cache_) / sizeof(FloatBottomCachedValue);
++i)
lowest_float_bottom_cache_[i].dirty = true;
}
void FloatingObjects::MoveAllToFloatInfoMap(LayoutBoxToFloatInfoMap& map) {
while (!set_.IsEmpty()) {
std::unique_ptr<FloatingObject> floating_object = set_.TakeFirst();
LayoutBox* layout_object = floating_object->GetLayoutObject();
map.insert(layout_object, std::move(floating_object));
}
Clear();
}
inline void FloatingObjects::IncreaseObjectsCount(FloatingObject::Type type) {
if (type == FloatingObject::kFloatLeft)
left_objects_count_++;
else
right_objects_count_++;
}
inline void FloatingObjects::DecreaseObjectsCount(FloatingObject::Type type) {
if (type == FloatingObject::kFloatLeft)
left_objects_count_--;
else
right_objects_count_--;
}
inline FloatingObjectInterval FloatingObjects::IntervalForFloatingObject(
FloatingObject& floating_object) {
if (horizontal_writing_mode_)
return FloatingObjectInterval(floating_object.FrameRect().Y(),
floating_object.FrameRect().MaxY(),
&floating_object);
return FloatingObjectInterval(floating_object.FrameRect().X(),
floating_object.FrameRect().MaxX(),
&floating_object);
}
void FloatingObjects::AddPlacedObject(FloatingObject& floating_object) {
DCHECK(!layout_object_->IsLayoutNGMixin());
DCHECK(!floating_object.IsInPlacedTree());
floating_object.SetIsPlaced(true);
if (placed_floats_tree_.IsInitialized())
placed_floats_tree_.Add(IntervalForFloatingObject(floating_object));
#if DCHECK_IS_ON()
floating_object.SetIsInPlacedTree(true);
#endif
MarkLowestFloatLogicalBottomCacheAsDirty();
}
void FloatingObjects::RemovePlacedObject(FloatingObject& floating_object) {
DCHECK(!layout_object_->IsLayoutNGMixin());
DCHECK(floating_object.IsPlaced());
DCHECK(floating_object.IsInPlacedTree());
if (placed_floats_tree_.IsInitialized()) {
bool removed =
placed_floats_tree_.Remove(IntervalForFloatingObject(floating_object));
DCHECK(removed);
}
floating_object.SetIsPlaced(false);
#if DCHECK_IS_ON()
floating_object.SetIsInPlacedTree(false);
#endif
MarkLowestFloatLogicalBottomCacheAsDirty();
}
FloatingObject* FloatingObjects::Add(
std::unique_ptr<FloatingObject> floating_object) {
FloatingObject* new_object = floating_object.release();
IncreaseObjectsCount(new_object->GetType());
set_.insert(base::WrapUnique(new_object));
if (new_object->IsPlaced())
AddPlacedObject(*new_object);
MarkLowestFloatLogicalBottomCacheAsDirty();
return new_object;
}
void FloatingObjects::Remove(FloatingObject* to_be_removed) {
DecreaseObjectsCount(to_be_removed->GetType());
std::unique_ptr<FloatingObject> floating_object = set_.Take(to_be_removed);
DCHECK(floating_object->IsPlaced() || !floating_object->IsInPlacedTree());
if (floating_object->IsPlaced())
RemovePlacedObject(*floating_object);
MarkLowestFloatLogicalBottomCacheAsDirty();
DCHECK(!floating_object->OriginatingLine());
}
void FloatingObjects::ComputePlacedFloatsTree() {
DCHECK(!placed_floats_tree_.IsInitialized());
if (set_.IsEmpty())
return;
placed_floats_tree_.InitIfNeeded(layout_object_->View()->GetIntervalArena());
FloatingObjectSetIterator it = set_.begin();
FloatingObjectSetIterator end = set_.end();
for (; it != end; ++it) {
FloatingObject& floating_object = *it->get();
if (floating_object.IsPlaced())
placed_floats_tree_.Add(IntervalForFloatingObject(floating_object));
}
}
LayoutUnit FloatingObjects::LogicalLeftOffsetForPositioningFloat(
LayoutUnit fixed_offset,
LayoutUnit logical_top,
LayoutUnit* height_remaining) {
ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::kFloatLeft> adapter(
layout_object_, logical_top, logical_top, fixed_offset);
PlacedFloatsTree().AllOverlapsWithAdapter(adapter);
if (height_remaining)
*height_remaining = adapter.HeightRemaining();
return adapter.Offset();
}
LayoutUnit FloatingObjects::LogicalRightOffsetForPositioningFloat(
LayoutUnit fixed_offset,
LayoutUnit logical_top,
LayoutUnit* height_remaining) {
ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::kFloatRight> adapter(
layout_object_, logical_top, logical_top, fixed_offset);
PlacedFloatsTree().AllOverlapsWithAdapter(adapter);
if (height_remaining)
*height_remaining = adapter.HeightRemaining();
return std::min(fixed_offset, adapter.Offset());
}
LayoutUnit FloatingObjects::LogicalLeftOffset(LayoutUnit fixed_offset,
LayoutUnit logical_top,
LayoutUnit logical_height) {
ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::kFloatLeft> adapter(
layout_object_, logical_top, logical_top + logical_height, fixed_offset);
PlacedFloatsTree().AllOverlapsWithAdapter(adapter);
return adapter.Offset();
}
LayoutUnit FloatingObjects::LogicalRightOffset(LayoutUnit fixed_offset,
LayoutUnit logical_top,
LayoutUnit logical_height) {
ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::kFloatRight> adapter(
layout_object_, logical_top, logical_top + logical_height, fixed_offset);
PlacedFloatsTree().AllOverlapsWithAdapter(adapter);
return std::min(fixed_offset, adapter.Offset());
}
LayoutUnit FloatingObjects::LogicalLeftOffsetForAvoidingFloats(
LayoutUnit fixed_offset,
LayoutUnit logical_top,
LayoutUnit logical_height) {
ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::kFloatLeft> adapter(
layout_object_, logical_top, logical_top + logical_height, fixed_offset);
PlacedFloatsTree().AllOverlapsWithAdapter(adapter);
return adapter.Offset();
}
LayoutUnit FloatingObjects::LogicalRightOffsetForAvoidingFloats(
LayoutUnit fixed_offset,
LayoutUnit logical_top,
LayoutUnit logical_height) {
ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::kFloatRight> adapter(
layout_object_, logical_top, logical_top + logical_height, fixed_offset);
PlacedFloatsTree().AllOverlapsWithAdapter(adapter);
return std::min(fixed_offset, adapter.Offset());
}
FloatingObjects::FloatBottomCachedValue::FloatBottomCachedValue()
: floating_object(nullptr), dirty(true) {}
template <>
inline bool ComputeFloatOffsetForFloatLayoutAdapter<
FloatingObject::kFloatLeft>::UpdateOffsetIfNeeded(const FloatingObject&
floating_object) {
LayoutUnit logical_right =
layout_object_->LogicalRightForFloat(floating_object);
if (logical_right > offset_) {
offset_ = logical_right;
return true;
}
return false;
}
template <>
inline bool ComputeFloatOffsetForFloatLayoutAdapter<
FloatingObject::kFloatRight>::UpdateOffsetIfNeeded(const FloatingObject&
floating_object) {
LayoutUnit logical_left =
layout_object_->LogicalLeftForFloat(floating_object);
if (logical_left < offset_) {
offset_ = logical_left;
return true;
}
return false;
}
template <FloatingObject::Type FloatTypeValue>
LayoutUnit ComputeFloatOffsetForFloatLayoutAdapter<
FloatTypeValue>::HeightRemaining() const {
return this->outermost_float_ ? this->layout_object_->LogicalBottomForFloat(
*this->outermost_float_) -
this->line_top_
: LayoutUnit(1);
}
template <FloatingObject::Type FloatTypeValue>
DISABLE_CFI_PERF inline void
ComputeFloatOffsetAdapter<FloatTypeValue>::CollectIfNeeded(
const IntervalType& interval) {
const FloatingObject& floating_object = *(interval.Data());
if (floating_object.GetType() != FloatTypeValue ||
!RangesIntersect(interval.Low(), interval.High(), line_top_,
line_bottom_))
return;
// Make sure the float hasn't changed since it was added to the placed floats
// tree.
DCHECK(floating_object.IsPlaced());
DCHECK_EQ(interval.Low(),
layout_object_->LogicalTopForFloat(floating_object));
DCHECK_EQ(interval.High(),
layout_object_->LogicalBottomForFloat(floating_object));
bool float_is_new_extreme = UpdateOffsetIfNeeded(floating_object);
if (float_is_new_extreme)
outermost_float_ = &floating_object;
}
template <>
inline bool ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::kFloatLeft>::
UpdateOffsetIfNeeded(const FloatingObject& floating_object) {
LayoutUnit logical_right =
layout_object_->LogicalRightForFloat(floating_object);
if (ShapeOutsideInfo* shape_outside =
floating_object.GetLayoutObject()->GetShapeOutsideInfo()) {
ShapeOutsideDeltas shape_deltas =
shape_outside->ComputeDeltasForContainingBlockLine(
LineLayoutBlockFlow(const_cast<LayoutBlockFlow*>(layout_object_)),
floating_object, line_top_, line_bottom_ - line_top_);
if (!shape_deltas.LineOverlapsShape())
return false;
logical_right += shape_deltas.RightMarginBoxDelta();
}
if (logical_right > offset_) {
offset_ = logical_right;
return true;
}
return false;
}
template <>
inline bool ComputeFloatOffsetForLineLayoutAdapter<
FloatingObject::kFloatRight>::UpdateOffsetIfNeeded(const FloatingObject&
floating_object) {
LayoutUnit logical_left =
layout_object_->LogicalLeftForFloat(floating_object);
if (ShapeOutsideInfo* shape_outside =
floating_object.GetLayoutObject()->GetShapeOutsideInfo()) {
ShapeOutsideDeltas shape_deltas =
shape_outside->ComputeDeltasForContainingBlockLine(
LineLayoutBlockFlow(const_cast<LayoutBlockFlow*>(layout_object_)),
floating_object, line_top_, line_bottom_ - line_top_);
if (!shape_deltas.LineOverlapsShape())
return false;
logical_left += shape_deltas.LeftMarginBoxDelta();
}
if (logical_left < offset_) {
offset_ = logical_left;
return true;
}
return false;
}
} // namespace blink
namespace WTF {
#ifndef NDEBUG
// These helpers are only used by the PODIntervalTree for debugging purposes.
String ValueToString<blink::LayoutUnit>::ToString(
const blink::LayoutUnit value) {
return String::Number(value.ToFloat());
}
String ValueToString<blink::FloatingObject*>::ToString(
const blink::FloatingObject* floating_object) {
return String::Format("%p (%gx%g %gx%g)", floating_object,
floating_object->FrameRect().X().ToFloat(),
floating_object->FrameRect().Y().ToFloat(),
floating_object->FrameRect().MaxX().ToFloat(),
floating_object->FrameRect().MaxY().ToFloat());
}
#endif
} // namespace WTF