blob: f5842370cc06cf74d64f7e3edaf33f66e7a2b31e [file] [log] [blame]
/*
* Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org>
* Copyright (C) Research In Motion Limited 2009-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/svg/layout_svg_resource_marker.h"
#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/layout/svg/svg_marker_data.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/svg/svg_animated_angle.h"
#include "third_party/blink/renderer/core/svg/svg_animated_length.h"
#include "third_party/blink/renderer/core/svg/svg_animated_rect.h"
namespace blink {
LayoutSVGResourceMarker::LayoutSVGResourceMarker(SVGMarkerElement* node)
: LayoutSVGResourceContainer(node),
needs_transform_update_(true),
is_in_layout_(false) {}
LayoutSVGResourceMarker::~LayoutSVGResourceMarker() = default;
void LayoutSVGResourceMarker::UpdateLayout() {
NOT_DESTROYED();
DCHECK(NeedsLayout());
if (is_in_layout_)
return;
base::AutoReset<bool> in_layout_change(&is_in_layout_, true);
// LayoutSVGHiddenContainer overrides UpdateLayout(). We need the
// LayoutSVGContainer behavior for calculating local transformations and paint
// invalidation.
LayoutSVGContainer::UpdateLayout();
ClearInvalidationMask();
}
void LayoutSVGResourceMarker::RemoveAllClientsFromCache() {
NOT_DESTROYED();
MarkAllClientsForInvalidation(kLayoutInvalidation | kBoundariesInvalidation);
}
FloatRect LayoutSVGResourceMarker::MarkerBoundaries(
const AffineTransform& marker_transformation) const {
NOT_DESTROYED();
FloatRect coordinates = LayoutSVGContainer::VisualRectInLocalSVGCoordinates();
// Map visual rect into parent coordinate space, in which the marker
// boundaries have to be evaluated.
coordinates = LocalToSVGParentTransform().MapRect(coordinates);
return marker_transformation.MapRect(coordinates);
}
FloatPoint LayoutSVGResourceMarker::ReferencePoint() const {
NOT_DESTROYED();
auto* marker = To<SVGMarkerElement>(GetElement());
DCHECK(marker);
SVGLengthContext length_context(marker);
return FloatPoint(marker->refX()->CurrentValue()->Value(length_context),
marker->refY()->CurrentValue()->Value(length_context));
}
float LayoutSVGResourceMarker::Angle() const {
NOT_DESTROYED();
return To<SVGMarkerElement>(GetElement())
->orientAngle()
->CurrentValue()
->Value();
}
SVGMarkerUnitsType LayoutSVGResourceMarker::MarkerUnits() const {
NOT_DESTROYED();
return To<SVGMarkerElement>(GetElement())->markerUnits()->CurrentEnumValue();
}
SVGMarkerOrientType LayoutSVGResourceMarker::OrientType() const {
NOT_DESTROYED();
return To<SVGMarkerElement>(GetElement())->orientType()->CurrentEnumValue();
}
AffineTransform LayoutSVGResourceMarker::MarkerTransformation(
const MarkerPosition& position,
float stroke_width) const {
NOT_DESTROYED();
// Apply scaling according to markerUnits ('strokeWidth' or 'userSpaceOnUse'.)
float marker_scale =
MarkerUnits() == kSVGMarkerUnitsStrokeWidth ? stroke_width : 1;
double computed_angle = position.angle;
SVGMarkerOrientType orient_type = OrientType();
if (orient_type == kSVGMarkerOrientAngle) {
computed_angle = Angle();
} else if (position.type == kStartMarker &&
orient_type == kSVGMarkerOrientAutoStartReverse) {
computed_angle += 180;
}
AffineTransform transform;
transform.Translate(position.origin.X(), position.origin.Y());
transform.Rotate(computed_angle);
transform.Scale(marker_scale);
// The reference point (refX, refY) is in the coordinate space of the marker's
// contents so we include the value in each marker's transform.
FloatPoint mapped_reference_point =
LocalToSVGParentTransform().MapPoint(ReferencePoint());
transform.Translate(-mapped_reference_point.X(), -mapped_reference_point.Y());
return transform;
}
bool LayoutSVGResourceMarker::ShouldPaint() const {
NOT_DESTROYED();
// An empty viewBox disables rendering.
auto* marker = To<SVGMarkerElement>(GetElement());
DCHECK(marker);
return !marker->viewBox()->IsSpecified() ||
!marker->viewBox()->CurrentValue()->IsValid() ||
!marker->viewBox()->CurrentValue()->Value().IsEmpty();
}
void LayoutSVGResourceMarker::SetNeedsTransformUpdate() {
NOT_DESTROYED();
// The transform paint property relies on the SVG transform being up-to-date
// (see: PaintPropertyTreeBuilder::updateTransformForNonRootSVG).
SetNeedsPaintPropertyUpdate();
needs_transform_update_ = true;
}
SVGTransformChange LayoutSVGResourceMarker::CalculateLocalTransform(
bool bounds_changed) {
NOT_DESTROYED();
if (!needs_transform_update_)
return SVGTransformChange::kNone;
auto* marker = To<SVGMarkerElement>(GetElement());
DCHECK(marker);
SVGLengthContext length_context(marker);
float width = marker->markerWidth()->CurrentValue()->Value(length_context);
float height = marker->markerHeight()->CurrentValue()->Value(length_context);
viewport_size_ = FloatSize(width, height);
SVGTransformChangeDetector change_detector(local_to_parent_transform_);
local_to_parent_transform_ = marker->ViewBoxToViewTransform(viewport_size_);
needs_transform_update_ = false;
return change_detector.ComputeChange(local_to_parent_transform_);
}
} // namespace blink