summaryrefslogtreecommitdiffstats
path: root/ksvg/impl/SVGLengthImpl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ksvg/impl/SVGLengthImpl.cc')
-rw-r--r--ksvg/impl/SVGLengthImpl.cc510
1 files changed, 510 insertions, 0 deletions
diff --git a/ksvg/impl/SVGLengthImpl.cc b/ksvg/impl/SVGLengthImpl.cc
new file mode 100644
index 00000000..46529022
--- /dev/null
+++ b/ksvg/impl/SVGLengthImpl.cc
@@ -0,0 +1,510 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ 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 <kdebug.h>
+
+#include <qfont.h>
+#include <qregexp.h>
+#include <qwidget.h>
+#include <qpaintdevicemetrics.h>
+
+#include "SVGLength.h"
+
+#include "SVGRectImpl.h"
+#include "SVGLengthImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGStringListImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedRectImpl.h"
+#include "svgpathparser.h"
+
+#include "KSVGCanvas.h"
+
+using namespace KSVG;
+
+#include "SVGLengthImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_cacheimpl.h"
+
+// keep track of textual description of the unit type
+QString UnitText[] =
+{
+ "", "", "%", "em", "ex", "px", "cm", "mm", "in", "pt", "pc"
+};
+
+SVGLengthImpl::SVGLengthImpl(LengthMode mode, SVGElementImpl *context) : DOM::DomShared(), m_mode(mode), m_context(context)
+{
+ KSVG_EMPTY_FLAGS
+
+ m_unitType = SVG_LENGTHTYPE_UNKNOWN;
+ m_value = 0;
+ m_valueInSpecifiedUnits = 0;
+ m_bboxContext = 0;
+}
+
+SVGLengthImpl::SVGLengthImpl(const SVGLengthImpl &other) : DOM::DomShared()
+{
+ (*this) = other;
+}
+
+SVGLengthImpl::~SVGLengthImpl()
+{
+}
+
+double SVGLengthImpl::dpi()
+{
+ if(m_context && m_context->ownerDoc())
+ {
+ if(m_mode == LENGTHMODE_WIDTH)
+ return 25.4 * m_context->ownerDoc()->screenPixelsPerMillimeterX();
+ else if(m_mode == LENGTHMODE_HEIGHT)
+ return 25.4 * m_context->ownerDoc()->screenPixelsPerMillimeterY();
+ else if(m_mode == LENGTHMODE_OTHER)
+ return 25.4 * m_context->ownerDoc()->screenPixelsPerMillimeterX();
+ }
+ return 90.0;
+}
+
+SVGLengthImpl &SVGLengthImpl::operator=(const SVGLengthImpl &other)
+{
+ m_unitType = other.m_unitType;
+ m_value = other.m_value;
+ m_valueInSpecifiedUnits = other.m_valueInSpecifiedUnits;
+ m_bboxContext = other.m_bboxContext;
+ m_mode = other.m_mode;
+ m_context = other.m_context;
+
+ return *this;
+}
+
+unsigned short SVGLengthImpl::unitType() const
+{
+ return m_unitType;
+}
+
+void SVGLengthImpl::setValue(float value)
+{
+ m_value = value;
+ getValFromPx();
+}
+
+float SVGLengthImpl::value()
+{
+ if(m_unitType == SVG_LENGTHTYPE_PERCENTAGE)
+ {
+ float value = m_valueInSpecifiedUnits / 100.0;
+ SVGRectImpl *bbox = 0;
+ if(m_bboxContext && (bbox = m_bboxContext->getBBox()))
+ {
+ float result = 0;
+ if(m_mode == LENGTHMODE_WIDTH)
+ result = value * bbox->width();
+ else if(m_mode == LENGTHMODE_HEIGHT)
+ result = value * bbox->height();
+ else if(m_mode == LENGTHMODE_OTHER)
+ result = value * sqrt(pow(bbox->width(), 2) + pow(bbox->height(), 2)) / sqrt(2.0);
+
+ bbox->deref();
+ return result;
+ }
+ else
+ return percentageOfViewport();
+ }
+ else
+ return m_value;
+}
+
+void SVGLengthImpl::setValueInSpecifiedUnits(float valueInSpecifiedUnits)
+{
+ m_valueInSpecifiedUnits = valueInSpecifiedUnits;
+ convertNumToPx();
+}
+
+float SVGLengthImpl::valueInSpecifiedUnits() const
+{
+ return m_valueInSpecifiedUnits;
+}
+
+void SVGLengthImpl::setValueAsString(const DOM::DOMString &valueAsString)
+{
+ convertStringToPx(valueAsString.string());
+}
+
+DOM::DOMString SVGLengthImpl::valueAsString() const
+{
+ DOM::DOMString valueAsString = QString::number(m_valueInSpecifiedUnits);
+ valueAsString += UnitText[m_unitType];
+ return valueAsString;
+}
+
+void SVGLengthImpl::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits)
+{
+ m_valueInSpecifiedUnits = valueInSpecifiedUnits;
+ m_unitType = unitType;
+ convertNumToPx();
+}
+
+void SVGLengthImpl::convertToSpecifiedUnits(unsigned short unitType)
+{
+ m_unitType = unitType;
+ getValFromPx();
+}
+
+SVGLengthImpl::operator float()
+{
+ return valueInSpecifiedUnits();
+}
+
+bool SVGLengthImpl::getValFromPx()
+{
+ if(m_unitType == SVG_LENGTHTYPE_UNKNOWN)
+ return false;
+
+ switch(m_unitType)
+ {
+ // case SVG_LENGTHTYPE_PERCENTAGE: TODO
+ // case SVG_LENGTHTYPE_EMS: TODO
+ // case SVG_LENGTHTYPE_EXS: TODO
+ //break;
+ case SVG_LENGTHTYPE_PX:
+ m_valueInSpecifiedUnits = m_value;
+ break;
+ case SVG_LENGTHTYPE_CM:
+ m_valueInSpecifiedUnits = m_value / dpi() * 2.54;
+ break;
+ case SVG_LENGTHTYPE_MM:
+ m_valueInSpecifiedUnits = m_value / dpi() * 25.4;
+ break;
+ case SVG_LENGTHTYPE_IN:
+ m_valueInSpecifiedUnits = m_value / dpi();
+ break;
+ case SVG_LENGTHTYPE_PT:
+ m_valueInSpecifiedUnits = m_value / dpi() * 72.0;
+ break;
+ case SVG_LENGTHTYPE_PC:
+ m_valueInSpecifiedUnits = m_value / dpi() * 6.0;
+ break;
+ };
+ return true;
+}
+
+void SVGLengthImpl::convertStringToPx(QString s)
+{
+ if(s.isEmpty())
+ return;
+
+ double convNum = 0;
+ const char *start = s.latin1();
+ const char *end = getNumber(start, convNum);
+ m_valueInSpecifiedUnits = convNum;
+
+ if(uint(end - start) < s.length())
+ {
+ if(s.endsWith(UnitText[SVG_LENGTHTYPE_PX]))
+ m_unitType = SVG_LENGTHTYPE_PX;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_CM]))
+ m_unitType = SVG_LENGTHTYPE_CM;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_PC]))
+ m_unitType = SVG_LENGTHTYPE_PC;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_MM]))
+ m_unitType = SVG_LENGTHTYPE_MM;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_IN]))
+ m_unitType = SVG_LENGTHTYPE_IN;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_PT]))
+ m_unitType = SVG_LENGTHTYPE_PT;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_PERCENTAGE]))
+ m_unitType = SVG_LENGTHTYPE_PERCENTAGE;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_EMS]))
+ m_unitType = SVG_LENGTHTYPE_EMS;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_EXS]))
+ m_unitType = SVG_LENGTHTYPE_EXS;
+ else if(s.isEmpty())
+ m_unitType = SVG_LENGTHTYPE_NUMBER;
+ else
+ m_unitType = SVG_LENGTHTYPE_UNKNOWN;
+ }
+ else
+ m_unitType = SVG_LENGTHTYPE_PX;
+ convertNumToPx();
+}
+
+void SVGLengthImpl::convertNumToPx()
+{
+ switch(m_unitType)
+ {
+ case SVG_LENGTHTYPE_PX:
+ m_value = m_valueInSpecifiedUnits;
+ break;
+ case SVG_LENGTHTYPE_CM:
+ m_value = (m_valueInSpecifiedUnits / 2.54) * dpi();
+ break;
+ case SVG_LENGTHTYPE_MM:
+ m_value = (m_valueInSpecifiedUnits / 25.4) * dpi();
+ break;
+ case SVG_LENGTHTYPE_IN:
+ m_value = m_valueInSpecifiedUnits * dpi();
+ break;
+ case SVG_LENGTHTYPE_PT:
+ m_value = (m_valueInSpecifiedUnits / 72.0) * dpi();
+ break;
+ case SVG_LENGTHTYPE_PC:
+ m_value = (m_valueInSpecifiedUnits / 6.0) * dpi();
+ break;
+ case SVG_LENGTHTYPE_EMS: // Be careful here, always recheck coords-units-BE-01.svg after touching (Niko)
+ case SVG_LENGTHTYPE_EXS:
+ if(m_context)
+ {
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(m_context);
+ if(!style)
+ break;
+
+ bool sizeLocal = (style->getFontSize() != -1);
+ bool familyLocal = (style->getFontFamily() && style->getFontFamily()->getFirst());
+
+ SVGStylableImpl *parentStyle = 0;
+ if((!sizeLocal || !familyLocal) && m_context)
+ parentStyle = dynamic_cast<SVGStylableImpl *>(m_context->ownerDoc()->getElementFromHandle(m_context->parentNode().handle()));
+
+ // Look up font-size in a SAFE way, because at this place
+ // processStyle() has NOT yet been called, so we need
+ // a different solution (Niko)
+ QString useFont = "Arial";
+ double useSize = 12;
+
+ if(sizeLocal)
+ useSize = style->getFontSize();
+ else if(parentStyle && parentStyle->getFontSize() != -1)
+ useSize = parentStyle->getFontSize();
+
+ if(familyLocal)
+ useFont = style->getFontFamily()->getFirst()->string();
+ else if(parentStyle && parentStyle->getFontFamily() && parentStyle->getFontFamily()->getFirst())
+ useFont = parentStyle->getFontFamily()->getFirst()->string();
+
+ if(m_unitType == SVG_LENGTHTYPE_EMS)
+ m_value = m_valueInSpecifiedUnits * useSize;
+ else
+ {
+ // Easiest way, use qfont (Niko)
+ QFont font(useFont);
+ font.setPixelSize(static_cast<int>(useSize));
+
+ QFontMetrics fm(font);
+ m_value = m_valueInSpecifiedUnits * fm.boundingRect('x').height();
+ }
+ }
+ break;
+ };
+}
+
+void SVGLengthImpl::convertPercentageToFloat(const QString &perc, float &result)
+{
+ // TODO : more error checking ?
+ if(perc.endsWith("%"))
+ result = perc.left(perc.length() - 1).toFloat() / 100.0;
+ else
+ result = perc.toFloat();
+}
+
+QString SVGLengthImpl::convertValToPercentage(const QString &val, float benchmark)
+{
+ if(val.endsWith("%"))
+ return val;
+
+ QString result;
+ float temp = val.toFloat();
+
+ temp = (temp / benchmark) * 100.0;
+ result.setNum(temp);
+ result.append("%");
+
+ return result;
+}
+
+SVGElementImpl *SVGLengthImpl::context() const
+{
+ return m_context;
+}
+
+void SVGLengthImpl::setContext(SVGElementImpl *context)
+{
+ m_context = context;
+}
+
+void SVGLengthImpl::setBBoxContext(SVGShapeImpl *bbox)
+{
+ m_bboxContext = bbox;
+ convertNumToPx();
+}
+
+float SVGLengthImpl::percentageOfViewport()
+{
+ float width = 0, height = 0;
+ float value = m_valueInSpecifiedUnits / 100.0;
+ if(m_context->viewportElement())
+ {
+ SVGSVGElementImpl *svg = dynamic_cast<SVGSVGElementImpl *>(m_context->viewportElement());
+ if(svg)
+ {
+ // Calculate against viewBox, otherwise svg width/height
+ width = svg->viewBox()->baseVal()->width();
+ if(width == 0)
+ width = svg->width()->baseVal()->value();
+ height = svg->viewBox()->baseVal()->height();
+ if(height == 0)
+ height = svg->height()->baseVal()->value();
+ }
+
+ if(m_mode == LENGTHMODE_WIDTH)
+ return value * width;
+ else if(m_mode == LENGTHMODE_HEIGHT)
+ return value * height;
+ else if(m_mode == LENGTHMODE_OTHER)
+ return value * sqrt(pow(width, 2) + pow(height, 2)) / sqrt(2.0);
+ }
+ else if(m_context == m_context->ownerDoc()->rootElement())
+ {
+ if(!m_context->ownerDoc()->canvas()) // Happens when parsing <svg width="100%"> with printnodetest
+ return 0.0;
+
+ QPaintDeviceMetrics metrics(m_context->ownerDoc()->canvas()->drawWindow());
+
+ if(m_mode == LENGTHMODE_WIDTH)
+ return value * metrics.width();
+ else if(m_mode == LENGTHMODE_HEIGHT)
+ return value * metrics.height();
+ else if(m_mode == LENGTHMODE_OTHER)
+ return value * sqrt(pow(metrics.width(), 2) + pow(metrics.height(), 2)) / sqrt(2.0);
+ }
+
+ return 0;
+}
+
+// Ecma stuff
+//
+/*
+@namespace KSVG
+@begin SVGLengthImpl::s_hashTable 5
+ unitType SVGLengthImpl::UnitType DontDelete|ReadOnly
+ value SVGLengthImpl::Value DontDelete
+ valueAsString SVGLengthImpl::ValueAsString DontDelete
+ valueInSpecifiedUnits SVGLengthImpl::ValueInSpecifiedUnits DontDelete
+@end
+@namespace KSVG
+@begin SVGLengthImplProto::s_hashTable 3
+ newValueSpecifiedUnits SVGLengthImpl::NewValueSpecifiedUnits DontDelete|Function 2
+ convertToSpecifiedUnits SVGLengthImpl::ConvertToSpecifiedUnits DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGLength", SVGLengthImplProto, SVGLengthImplProtoFunc)
+
+Value SVGLengthImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case UnitType:
+ return Number(unitType());
+ case Value:
+ return Number(m_value);
+ case ValueAsString:
+ return String(valueAsString().string());
+ case ValueInSpecifiedUnits:
+ return Number(valueInSpecifiedUnits());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return KJS::Undefined();
+ }
+}
+
+void SVGLengthImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case Value:
+ setValue(value.toNumber(exec));
+ SVGHelperImpl::updateItem(exec, *m_context);
+ break;
+ case ValueAsString:
+ setValueAsString(value.toString(exec).string());
+ SVGHelperImpl::updateItem(exec, *m_context);
+ break;
+ case ValueInSpecifiedUnits:
+ setValueInSpecifiedUnits(value.toNumber(exec));
+ SVGHelperImpl::updateItem(exec, *m_context);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+Value SVGLengthImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGLengthImpl)
+
+ switch(id)
+ {
+ case SVGLengthImpl::NewValueSpecifiedUnits:
+ obj->newValueSpecifiedUnits(static_cast<unsigned short>(args[0].toNumber(exec)), args[1].toNumber(exec));
+ SVGHelperImpl::updateItem(exec, *obj->context());
+ return Undefined();
+ case SVGLengthImpl::ConvertToSpecifiedUnits:
+ obj->convertToSpecifiedUnits(static_cast<unsigned short>(args[0].toNumber(exec)));
+ SVGHelperImpl::updateItem(exec, *obj->context());
+ return Undefined();
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+/*
+@namespace KSVG
+@begin SVGLengthImplConstructor::s_hashTable 11
+ SVG_LENGTHTYPE_UNKNOWN KSVG::SVG_LENGTHTYPE_UNKNOWN DontDelete|ReadOnly
+ SVG_LENGTHTYPE_NUMBER KSVG::SVG_LENGTHTYPE_NUMBER DontDelete|ReadOnly
+ SVG_LENGTHTYPE_PERCENTAGE KSVG::SVG_LENGTHTYPE_PERCENTAGE DontDelete|ReadOnly
+ SVG_LENGTHTYPE_EMS KSVG::SVG_LENGTHTYPE_EMS DontDelete|ReadOnly
+ SVG_LENGTHTYPE_EXS KSVG::SVG_LENGTHTYPE_EXS DontDelete|ReadOnly
+ SVG_LENGTHTYPE_PX KSVG::SVG_LENGTHTYPE_PX DontDelete|ReadOnly
+ SVG_LENGTHTYPE_CM KSVG::SVG_LENGTHTYPE_CM DontDelete|ReadOnly
+ SVG_LENGTHTYPE_MM KSVG::SVG_LENGTHTYPE_MM DontDelete|ReadOnly
+ SVG_LENGTHTYPE_PT KSVG::SVG_LENGTHTYPE_PT DontDelete|ReadOnly
+ SVG_LENGTHTYPE_PC KSVG::SVG_LENGTHTYPE_PC DontDelete|ReadOnly
+@end
+*/
+
+Value SVGLengthImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGLengthImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGLengthImplConstructor>(exec, "[[svglength.constructor]]");
+}
+
+// vim:ts=4:noet