blob: 99e63978ef707bc270daaf8e94219cb5c3fb3b96 [file] [log] [blame]
/*
* 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.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_FRAGMENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_FRAGMENT_H_
#include "third_party/blink/renderer/core/layout/line/glyph_overflow.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
// A SVGTextFragment describes a text fragment of a LayoutSVGInlineText which
// can be laid out at once.
struct SVGTextFragment {
DISALLOW_NEW();
SVGTextFragment()
: character_offset(0),
metrics_list_offset(0),
length(0),
is_text_on_path(false),
is_vertical(false),
x(0),
y(0),
width(0),
height(0),
length_adjust_scale(1),
length_adjust_bias(0) {}
enum TransformType {
kTransformRespectingTextLength,
kTransformIgnoringTextLength
};
FloatRect BoundingBox(float baseline) const {
FloatRect fragment_rect(x, y - baseline, width, height);
if (!IsTransformed())
return fragment_rect;
return BuildNormalFragmentTransform().MapRect(fragment_rect);
}
FloatRect OverflowBoundingBox(float baseline) const {
FloatRect fragment_rect(
x - glyph_overflow.left, y - baseline - glyph_overflow.top,
width + glyph_overflow.left + glyph_overflow.right,
height + glyph_overflow.top + glyph_overflow.bottom);
if (!IsTransformed())
return fragment_rect;
return BuildNormalFragmentTransform().MapRect(fragment_rect);
}
FloatQuad BoundingQuad(float baseline) const {
FloatQuad fragment_quad(FloatRect(x, y - baseline, width, height));
if (!IsTransformed())
return fragment_quad;
return BuildNormalFragmentTransform().MapQuad(fragment_quad);
}
AffineTransform BuildFragmentTransform(
TransformType type = kTransformRespectingTextLength) const {
if (type == kTransformIgnoringTextLength) {
AffineTransform result = transform;
TransformAroundOrigin(result);
return result;
}
return BuildNormalFragmentTransform();
}
bool AffectedByTextLength() const { return length_adjust_scale != 1; }
bool IsTransformed() const {
return AffectedByTextLength() || !transform.IsIdentity();
}
// The first laid out character starts at LayoutSVGInlineText::characters() +
// characterOffset.
unsigned character_offset;
unsigned metrics_list_offset;
unsigned length : 30;
unsigned is_text_on_path : 1;
unsigned is_vertical : 1;
float x;
float y;
float width;
float height;
GlyphOverflow glyph_overflow;
// Includes rotation/glyph-orientation-(horizontal|vertical) transforms, as
// well as orientation related shifts
// (see SVGTextLayoutEngine, which builds this transformation).
AffineTransform transform;
// Contains lengthAdjust related transformations, which are not allowed to
// influence the SVGTextQuery code.
float length_adjust_scale;
float length_adjust_bias;
private:
AffineTransform BuildNormalFragmentTransform() const {
if (is_text_on_path)
return BuildTransformForTextOnPath();
return BuildTransformForTextOnLine();
}
void TransformAroundOrigin(AffineTransform& result) const {
// Returns (translate(x, y) * result) * translate(-x, -y).
result.SetE(result.E() + x);
result.SetF(result.F() + y);
result.Translate(-x, -y);
}
AffineTransform BuildTransformForTextOnPath() const {
// For text-on-path layout, multiply the transform with the
// lengthAdjustTransform before orienting the resulting transform.
// T(x,y) * M(transform) * M(lengthAdjust) * T(-x,-y)
AffineTransform result = !AffectedByTextLength()
? transform
: transform * LengthAdjustTransform();
if (!result.IsIdentity())
TransformAroundOrigin(result);
return result;
}
AffineTransform LengthAdjustTransform() const {
AffineTransform result;
if (!AffectedByTextLength())
return result;
// Load a transform assuming horizontal direction, then swap if vertical.
result.SetMatrix(length_adjust_scale, 0, 0, 1, length_adjust_bias, 0);
if (is_vertical) {
result.SetD(result.A());
result.SetA(1);
result.SetF(result.E());
result.SetE(0);
}
return result;
}
AffineTransform BuildTransformForTextOnLine() const {
// For text-on-line layout, orient the transform first, then multiply
// the lengthAdjustTransform with the oriented transform.
// M(lengthAdjust) * T(x,y) * M(transform) * T(-x,-y)
if (transform.IsIdentity())
return LengthAdjustTransform();
AffineTransform result = transform;
TransformAroundOrigin(result);
result.PreMultiply(LengthAdjustTransform());
return result;
}
};
} // namespace blink
#endif