RenderGeometryMap.cpp [plain text]
#include "config.h"
#include "RenderGeometryMap.h"
#include "RenderFlowThread.h"
#include "RenderLayer.h"
#include "RenderView.h"
#include "TransformState.h"
#include <wtf/TemporaryChange.h>
namespace WebCore {
RenderGeometryMap::RenderGeometryMap(MapCoordinatesFlags flags)
: m_insertionPosition(notFound)
, m_nonUniformStepsCount(0)
, m_transformedStepsCount(0)
, m_fixedStepsCount(0)
, m_mapCoordinatesFlags(flags)
{
}
RenderGeometryMap::~RenderGeometryMap()
{
}
void RenderGeometryMap::mapToContainer(TransformState& transformState, const RenderLayerModelObject* container) const
{
if (hasNonUniformStep()) {
m_mapping.last().m_renderer->mapLocalToContainer(container, transformState, ApplyContainerFlip | m_mapCoordinatesFlags);
transformState.flatten();
return;
}
bool inFixed = false;
#if !ASSERT_DISABLED
bool foundContainer = !container || (m_mapping.size() && m_mapping[0].m_renderer == container);
#endif
for (int i = m_mapping.size() - 1; i >= 0; --i) {
const RenderGeometryMapStep& currentStep = m_mapping[i];
if (i > 0 && currentStep.m_renderer == container) {
#if !ASSERT_DISABLED
foundContainer = true;
#endif
break;
}
if (i && currentStep.m_hasTransform && !currentStep.m_isFixedPosition)
inFixed = false;
else if (currentStep.m_isFixedPosition)
inFixed = true;
if (!i) {
if (!container && currentStep.m_transform)
transformState.applyTransform(*currentStep.m_transform.get());
if (inFixed)
transformState.move(currentStep.m_offset.width(), currentStep.m_offset.height());
} else {
TransformState::TransformAccumulation accumulate = currentStep.m_accumulatingTransform ? TransformState::AccumulateTransform : TransformState::FlattenTransform;
if (currentStep.m_transform)
transformState.applyTransform(*currentStep.m_transform.get(), accumulate);
else
transformState.move(currentStep.m_offset.width(), currentStep.m_offset.height(), accumulate);
}
}
ASSERT(foundContainer);
transformState.flatten();
}
FloatPoint RenderGeometryMap::mapToContainer(const FloatPoint& p, const RenderLayerModelObject* container) const
{
FloatPoint result;
#if !ASSERT_DISABLED
FloatPoint rendererMappedResult = m_mapping.last().m_renderer->localToAbsolute(p, m_mapCoordinatesFlags);
#endif
if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer))) {
result = p + roundedIntSize(m_accumulatedOffset);
ASSERT(roundedIntPoint(LayoutPoint(rendererMappedResult)) == result);
} else {
TransformState transformState(TransformState::ApplyTransformDirection, p);
mapToContainer(transformState, container);
result = transformState.lastPlanarPoint();
ASSERT(areEssentiallyEqual(rendererMappedResult, result));
}
return result;
}
FloatQuad RenderGeometryMap::mapToContainer(const FloatRect& rect, const RenderLayerModelObject* container) const
{
FloatQuad result;
if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer))) {
result = rect;
result.move(m_accumulatedOffset);
} else {
TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect);
mapToContainer(transformState, container);
result = transformState.lastPlanarQuad();
}
return result;
}
void RenderGeometryMap::pushMappingsToAncestor(const RenderObject* renderer, const RenderLayerModelObject* ancestorRenderer)
{
TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
do {
renderer = renderer->pushMappingToContainer(ancestorRenderer, *this);
} while (renderer && renderer != ancestorRenderer);
ASSERT(m_mapping.isEmpty() || m_mapping[0].m_renderer->isRenderView());
}
static bool canMapBetweenRenderersViaLayers(const RenderLayerModelObject& renderer, const RenderLayerModelObject& ancestor)
{
for (const RenderElement* current = &renderer; ; current = current->parent()) {
const RenderStyle& style = current->style();
if (style.position() == FixedPosition || style.isFlippedBlocksWritingMode())
return false;
if (current->hasTransformRelatedProperty() && (current->style().hasTransform() || current->style().hasPerspective()))
return false;
if (current->isRenderFlowThread())
return false;
if (current->isSVGRoot())
return false;
if (current == &ancestor)
break;
}
return true;
}
void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, bool respectTransforms)
{
MapCoordinatesFlags newFlags = respectTransforms ? m_mapCoordinatesFlags : m_mapCoordinatesFlags & ~UseTransforms;
TemporaryChange<MapCoordinatesFlags> flagsChange(m_mapCoordinatesFlags, newFlags);
const RenderLayerModelObject& renderer = layer->renderer();
bool canConvertInLayerTree = ancestorLayer ? canMapBetweenRenderersViaLayers(layer->renderer(), ancestorLayer->renderer()) : false;
if (canConvertInLayerTree) {
LayoutSize layerOffset = layer->offsetFromAncestor(ancestorLayer);
if (!m_mapping.size()) {
ASSERT(ancestorLayer->renderer().isRenderView());
pushMappingsToAncestor(&ancestorLayer->renderer(), nullptr);
}
TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
push(&renderer, layerOffset, true, false, false, false);
return;
}
const RenderLayerModelObject* ancestorRenderer = ancestorLayer ? &ancestorLayer->renderer() : nullptr;
pushMappingsToAncestor(&renderer, ancestorRenderer);
}
void RenderGeometryMap::push(const RenderObject* renderer, const LayoutSize& offsetFromContainer, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform)
{
ASSERT(m_insertionPosition != notFound);
m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));
RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
step.m_offset = offsetFromContainer;
stepInserted(step);
}
void RenderGeometryMap::push(const RenderObject* renderer, const TransformationMatrix& t, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform)
{
ASSERT(m_insertionPosition != notFound);
m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));
RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
if (!t.isIntegerTranslation())
step.m_transform = std::make_unique<TransformationMatrix>(t);
else
step.m_offset = LayoutSize(t.e(), t.f());
stepInserted(step);
}
void RenderGeometryMap::pushView(const RenderView* view, const LayoutSize& scrollOffset, const TransformationMatrix* t)
{
ASSERT(m_insertionPosition != notFound);
ASSERT(!m_insertionPosition);
m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(view, false, false, false, t));
RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
step.m_offset = scrollOffset;
if (t)
step.m_transform = std::make_unique<TransformationMatrix>(*t);
stepInserted(step);
}
void RenderGeometryMap::pushRenderFlowThread(const RenderFlowThread* flowThread)
{
m_mapping.append(RenderGeometryMapStep(flowThread, false, false, false, false));
stepInserted(m_mapping.last());
}
void RenderGeometryMap::popMappingsToAncestor(const RenderLayerModelObject* ancestorRenderer)
{
ASSERT(m_mapping.size());
while (m_mapping.size() && m_mapping.last().m_renderer != ancestorRenderer) {
stepRemoved(m_mapping.last());
m_mapping.removeLast();
}
}
void RenderGeometryMap::popMappingsToAncestor(const RenderLayer* ancestorLayer)
{
const RenderLayerModelObject* ancestorRenderer = ancestorLayer ? &ancestorLayer->renderer() : 0;
popMappingsToAncestor(ancestorRenderer);
}
void RenderGeometryMap::stepInserted(const RenderGeometryMapStep& step)
{
if (!step.m_renderer->isRenderView())
m_accumulatedOffset += step.m_offset;
if (step.m_isNonUniform)
++m_nonUniformStepsCount;
if (step.m_transform)
++m_transformedStepsCount;
if (step.m_isFixedPosition)
++m_fixedStepsCount;
}
void RenderGeometryMap::stepRemoved(const RenderGeometryMapStep& step)
{
if (!step.m_renderer->isRenderView())
m_accumulatedOffset -= step.m_offset;
if (step.m_isNonUniform) {
ASSERT(m_nonUniformStepsCount);
--m_nonUniformStepsCount;
}
if (step.m_transform) {
ASSERT(m_transformedStepsCount);
--m_transformedStepsCount;
}
if (step.m_isFixedPosition) {
ASSERT(m_fixedStepsCount);
--m_fixedStepsCount;
}
}
}