#include "config.h"
#if SVG_SUPPORT
#include "IntRect.h"
#include <kcanvas/RenderPath.h>
#include "KCanvasRenderingStyle.h"
#include "ksvg.h"
#include "svgpathparser.h"
#include "SVGLength.h"
#include "SVGElement.h"
#include "SVGSVGElement.h"
#include "SVGAnimatedRect.h"
#include "SVGAnimatedLength.h"
#include <math.h>
using namespace WebCore;
using namespace std;
static const char* UnitText[] =
{
"", "",
"%", "em",
"ex", "px",
"cm", "mm",
"in", "pt",
"pc"
};
SVGLength::SVGLength(const SVGStyledElement *context, LengthMode mode, const SVGElement *viewport)
: Shared<SVGLength>()
, m_value(0)
, m_valueInSpecifiedUnits(0)
, m_mode(mode)
, m_bboxRelative(false)
, m_unitType(SVG_LENGTHTYPE_UNKNOWN)
, m_requiresLayout(false)
, m_context(context)
, m_viewportElement(viewport)
{
}
SVGLength::~SVGLength()
{
}
unsigned short SVGLength::unitType() const
{
return m_unitType;
}
void SVGLength::setValue(float value)
{
m_value = value;
updateValueInSpecifiedUnits();
}
float SVGLength::value() const
{
if (m_requiresLayout)
const_cast<SVGLength*>(this)->updateValue(false);
if (m_unitType != SVG_LENGTHTYPE_PERCENTAGE)
return m_value;
float value = m_valueInSpecifiedUnits / 100.0;
if (m_bboxRelative)
return value;
return SVGHelper::PercentageOfViewport(value, m_context ? m_context->viewportElement() : m_viewportElement, static_cast<LengthMode>(m_mode));
}
void SVGLength::setValueInSpecifiedUnits(float valueInSpecifiedUnits)
{
m_valueInSpecifiedUnits = valueInSpecifiedUnits;
updateValue();
}
float SVGLength::valueInSpecifiedUnits() const
{
return m_valueInSpecifiedUnits;
}
void SVGLength::setValueAsString(const String& s)
{
if(s.isEmpty())
return;
DeprecatedString valueAsQString = s.deprecatedString();
double convertedNumber = 0;
const char *start = valueAsQString.latin1();
const char *end = parseCoord(start, convertedNumber);
m_valueInSpecifiedUnits = convertedNumber;
unsigned int diff = end - start;
if (diff < valueAsQString.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;
updateValue();
}
String SVGLength::valueAsString() const
{
return String::number(m_valueInSpecifiedUnits) + UnitText[m_unitType];
}
void SVGLength::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits)
{
m_valueInSpecifiedUnits = valueInSpecifiedUnits;
m_unitType = unitType;
updateValue();
}
void SVGLength::convertToSpecifiedUnits(unsigned short unitType)
{
m_unitType = unitType;
updateValueInSpecifiedUnits();
}
double SVGLength::dpi() const
{
return 90.0;
}
void SVGLength::updateValue(bool notify)
{
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:
case SVG_LENGTHTYPE_EXS:
if (m_context && m_context->renderer()) {
RenderStyle *style = m_context->renderer()->style();
float useSize = style->fontSize();
ASSERT(useSize > 0);
if (m_unitType == SVG_LENGTHTYPE_EMS)
m_value = m_valueInSpecifiedUnits * useSize;
else {
float xHeight = style->font().xHeight();
m_value = m_valueInSpecifiedUnits * ceil(xHeight);
}
m_requiresLayout = false;
} else {
m_requiresLayout = true;
}
break;
}
if (notify && m_context)
m_context->notifyAttributeChange();
}
bool SVGLength::updateValueInSpecifiedUnits(bool notify)
{
if(m_unitType == SVG_LENGTHTYPE_UNKNOWN)
return false;
switch(m_unitType)
{
case SVG_LENGTHTYPE_PERCENTAGE:
return false;
case SVG_LENGTHTYPE_EMS:
return false;
case SVG_LENGTHTYPE_EXS:
return false;
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;
};
if (notify && m_context)
m_context->notifyAttributeChange();
return true;
}
bool SVGLength::bboxRelative() const
{
return m_bboxRelative;
}
void SVGLength::setBboxRelative(bool relative)
{
m_bboxRelative = relative;
}
const SVGStyledElement *SVGLength::context() const
{
return m_context;
}
void SVGLength::setContext(const SVGStyledElement *context)
{
m_context = context;
}
#endif // SVG_SUPPORT