blob: 7e255936c37ca227be29872c94b2c7fd4c8b5b8b [file] [log] [blame]
/*
* Copyright (C) 2007, 2010 Rob Buis <buis@kde.org>
*
* 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/svg/svg_view_spec.h"
#include "third_party/blink/renderer/core/svg/svg_parser_utilities.h"
#include "third_party/blink/renderer/core/svg/svg_preserve_aspect_ratio.h"
#include "third_party/blink/renderer/core/svg/svg_rect.h"
#include "third_party/blink/renderer/core/svg/svg_transform_list.h"
#include "third_party/blink/renderer/core/svg/svg_view_element.h"
#include "third_party/blink/renderer/platform/wtf/text/parsing_utilities.h"
namespace blink {
SVGViewSpec::SVGViewSpec() : zoom_and_pan_(kSVGZoomAndPanUnknown) {}
void SVGViewSpec::Trace(Visitor* visitor) {
visitor->Trace(view_box_);
visitor->Trace(preserve_aspect_ratio_);
visitor->Trace(transform_);
}
SVGViewSpec* SVGViewSpec::CreateFromFragment(const String& fragment) {
SVGViewSpec* view_spec = MakeGarbageCollected<SVGViewSpec>();
if (!view_spec->ParseViewSpec(fragment))
return nullptr;
return view_spec;
}
SVGViewSpec* SVGViewSpec::CreateForViewElement(const SVGViewElement& view) {
SVGViewSpec* view_spec = MakeGarbageCollected<SVGViewSpec>();
if (view.HasValidViewBox())
view_spec->view_box_ = view.viewBox()->CurrentValue()->Clone();
if (view.preserveAspectRatio()->IsSpecified()) {
view_spec->preserve_aspect_ratio_ =
view.preserveAspectRatio()->CurrentValue()->Clone();
}
if (view.hasAttribute(svg_names::kZoomAndPanAttr))
view_spec->zoom_and_pan_ = view.zoomAndPan();
return view_spec;
}
bool SVGViewSpec::ParseViewSpec(const String& spec) {
if (spec.IsEmpty())
return false;
if (spec.Is8Bit()) {
const LChar* ptr = spec.Characters8();
const LChar* end = ptr + spec.length();
return ParseViewSpecInternal(ptr, end);
}
const UChar* ptr = spec.Characters16();
const UChar* end = ptr + spec.length();
return ParseViewSpecInternal(ptr, end);
}
namespace {
enum ViewSpecFunctionType {
kUnknown,
kPreserveAspectRatio,
kTransform,
kViewBox,
kViewTarget,
kZoomAndPan,
};
template <typename CharType>
static ViewSpecFunctionType ScanViewSpecFunction(const CharType*& ptr,
const CharType* end) {
DCHECK_LT(ptr, end);
switch (*ptr) {
case 'v':
if (SkipToken(ptr, end, "viewBox"))
return kViewBox;
if (SkipToken(ptr, end, "viewTarget"))
return kViewTarget;
break;
case 'z':
if (SkipToken(ptr, end, "zoomAndPan"))
return kZoomAndPan;
break;
case 'p':
if (SkipToken(ptr, end, "preserveAspectRatio"))
return kPreserveAspectRatio;
break;
case 't':
if (SkipToken(ptr, end, "transform"))
return kTransform;
break;
}
return kUnknown;
}
} // namespace
template <typename CharType>
bool SVGViewSpec::ParseViewSpecInternal(const CharType* ptr,
const CharType* end) {
if (!SkipToken(ptr, end, "svgView"))
return false;
if (!SkipExactly<CharType>(ptr, end, '('))
return false;
while (ptr < end && *ptr != ')') {
ViewSpecFunctionType function_type = ScanViewSpecFunction(ptr, end);
if (function_type == kUnknown)
return false;
if (!SkipExactly<CharType>(ptr, end, '('))
return false;
switch (function_type) {
case kViewBox: {
float x = 0.0f;
float y = 0.0f;
float width = 0.0f;
float height = 0.0f;
if (!(ParseNumber(ptr, end, x) && ParseNumber(ptr, end, y) &&
ParseNumber(ptr, end, width) &&
ParseNumber(ptr, end, height, kDisallowWhitespace)))
return false;
view_box_ = SVGRect::Create(FloatRect(x, y, width, height));
break;
}
case kViewTarget: {
// Ignore arguments.
SkipUntil<CharType>(ptr, end, ')');
break;
}
case kZoomAndPan:
zoom_and_pan_ = SVGZoomAndPan::Parse(ptr, end);
if (zoom_and_pan_ == kSVGZoomAndPanUnknown)
return false;
break;
case kPreserveAspectRatio:
preserve_aspect_ratio_ = SVGPreserveAspectRatio::Create();
if (!preserve_aspect_ratio_->Parse(ptr, end, false))
return false;
break;
case kTransform:
transform_ = SVGTransformList::Create();
transform_->Parse(ptr, end);
break;
default:
NOTREACHED();
break;
}
if (!SkipExactly<CharType>(ptr, end, ')'))
return false;
SkipExactly<CharType>(ptr, end, ';');
}
return SkipExactly<CharType>(ptr, end, ')');
}
} // namespace blink