static bool definesTextLengthWithSpacing(const InlineFlowBox* start)
{
    SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromLayoutObject(&start->layoutObject());
    return textContentElement
        && textContentElement->lengthAdjust()->currentValue()->enumValue() == SVGLengthAdjustSpacing
        && textContentElement->textLengthIsSpecifiedByUser();
}
JSValue jsSVGTextContentElementStyle(ExecState* exec, const Identifier&, const PropertySlot& slot)
{
    JSSVGTextContentElement* castedThis = static_cast<JSSVGTextContentElement*>(asObject(slot.slotBase()));
    UNUSED_PARAM(exec);
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThis->impl());
    return toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->style()));
}
  void
  SVGTextPathElement::glTextTraverse(svgl::Context * svglContext, svgl::GLInfo* glinfo, svgl::TextInfo* textinfo)
  {
    _textinfo = textinfo;
    buildBezier(svglContext, glinfo, textinfo);

    for(dom::Node *n = getFirstChild(); n; n=n->getNextSibling()) {
      _currentPCDATA = 0;
      dom::Text * pcdata = dynamic_cast<dom::Text*>(n);
      if(pcdata) {
	_currentPCDATA = pcdata;
	//SVGTransformable::glTraverse(svglContext, glinfo);
	SVGStylable::glTraverse(svglContext, glinfo, false, true);
      }
      else {
	SVGTextContentElement *e = dynamic_cast<SVGTextContentElement*>(n);
	if(e) {
	  //std::cerr << "text may not be at the right place since transforms are not traversed" __FL__;
	  e->glTextTraverse(svglContext, glinfo, _textinfo);
	  //textinfo->dx = textinfo->distanceIterator->x;
	  //textinfo->dy = textinfo->distanceIterator->y;
	}
      }
    }

    delete _textinfo->distanceIterator;
    _textinfo->distanceIterator=0;

  }
JSValue jsSVGTextContentElementXmlspace(ExecState* exec, const Identifier&, const PropertySlot& slot)
{
    JSSVGTextContentElement* castedThis = static_cast<JSSVGTextContentElement*>(asObject(slot.slotBase()));
    UNUSED_PARAM(exec);
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThis->impl());
    return jsString(exec, imp->xmlspace());
}
JSValue jsSVGTextContentElementExternalResourcesRequired(ExecState* exec, const Identifier&, const PropertySlot& slot)
{
    JSSVGTextContentElement* castedThis = static_cast<JSSVGTextContentElement*>(asObject(slot.slotBase()));
    UNUSED_PARAM(exec);
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThis->impl());
    RefPtr<SVGAnimatedBoolean> obj = imp->externalResourcesRequiredAnimated();
    return toJS(exec, castedThis->globalObject(), obj.get(), imp);
}
JSValue jsSVGTextContentElementClassName(ExecState* exec, const Identifier&, const PropertySlot& slot)
{
    JSSVGTextContentElement* castedThis = static_cast<JSSVGTextContentElement*>(asObject(slot.slotBase()));
    UNUSED_PARAM(exec);
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThis->impl());
    RefPtr<SVGAnimatedString> obj = imp->classNameAnimated();
    return toJS(exec, castedThis->globalObject(), obj.get(), imp);
}
JSValue* jsSVGTextContentElementPrototypeFunctionGetComputedTextLength(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
    if (!thisValue->isObject(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(thisValue);
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());


    JSC::JSValue* result = jsNumber(exec, imp->getComputedTextLength());
    return result;
}
JSValue JSC_HOST_CALL jsSVGTextContentElementPrototypeFunctionGetComputedTextLength(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
    UNUSED_PARAM(args);
    if (!thisValue.inherits(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(asObject(thisValue));
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());


    JSC::JSValue result = jsNumber(exec, imp->getComputedTextLength());
    return result;
}
JSValue* jsSVGTextContentElementPrototypeFunctionGetPresentationAttribute(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
    if (!thisValue->isObject(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(thisValue);
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());
    const UString& name = args.at(exec, 0)->toString(exec);


    JSC::JSValue* result = toJS(exec, WTF::getPtr(imp->getPresentationAttribute(name)));
    return result;
}
JSValue* jsSVGTextContentElementPrototypeFunctionHasExtension(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
    if (!thisValue->isObject(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(thisValue);
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());
    const UString& extension = args.at(exec, 0)->toString(exec);


    JSC::JSValue* result = jsBoolean(imp->hasExtension(extension));
    return result;
}
JSValue* jsSVGTextContentElementPrototypeFunctionGetCharNumAtPosition(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
    if (!thisValue->isObject(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(thisValue);
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());
    FloatPoint point = toSVGPoint(args.at(exec, 0));


    JSC::JSValue* result = jsNumber(exec, imp->getCharNumAtPosition(point));
    return result;
}
JSValue JSC_HOST_CALL jsSVGTextContentElementPrototypeFunctionHasExtension(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
    UNUSED_PARAM(args);
    if (!thisValue.inherits(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(asObject(thisValue));
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());
    const UString& extension = args.at(0).toString(exec);


    JSC::JSValue result = jsBoolean(imp->hasExtension(extension));
    return result;
}
JSValue JSC_HOST_CALL jsSVGTextContentElementPrototypeFunctionGetPresentationAttribute(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
    UNUSED_PARAM(args);
    if (!thisValue.inherits(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(asObject(thisValue));
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());
    const UString& name = args.at(0).toString(exec);


    JSC::JSValue result = toJS(exec, castedThisObj->globalObject(), WTF::getPtr(imp->getPresentationAttribute(name)));
    return result;
}
JSValue* jsSVGTextContentElementPrototypeFunctionSelectSubString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
    if (!thisValue->isObject(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(thisValue);
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());
    ExceptionCode ec = 0;
    unsigned offset = args.at(exec, 0)->toInt32(exec);
    unsigned length = args.at(exec, 1)->toInt32(exec);

    imp->selectSubString(offset, length, ec);
    setDOMException(exec, ec);
    return jsUndefined();
}
JSValue* jsSVGTextContentElementPrototypeFunctionGetRotationOfChar(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
    if (!thisValue->isObject(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(thisValue);
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());
    ExceptionCode ec = 0;
    unsigned offset = args.at(exec, 0)->toInt32(exec);


    JSC::JSValue* result = jsNumber(exec, imp->getRotationOfChar(offset, ec));
    setDOMException(exec, ec);
    return result;
}
void JSSVGTextContentElement::putValueProperty(ExecState* exec, int token, JSValue* value)
{
    switch (token) {
    case XmllangAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        imp->setXmllang(value->toString(exec));
        break;
    }
    case XmlspaceAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        imp->setXmlspace(value->toString(exec));
        break;
    }
    }
}
Example #17
0
  void
  SVGTRefElement::glTextTraverse(svgl::Context * svglContext, svgl::GLInfo* glinfo, svgl::TextInfo* textinfo)
  {
    for(dom::Node *n = getFirstChild(); n; n=n->getNextSibling()) {
      dom::Text * pcdata = dynamic_cast<dom::Text*>(n);
      if(pcdata) {
	glTextTraversePCDATA(svglContext, glinfo, textinfo, pcdata );
      }
      else {
	SVGTextContentElement *e = dynamic_cast<SVGTextContentElement*>(n);
	if(e) {
	  e->glTextTraverse(svglContext, glinfo, textinfo);
	}
      }
    }
  }
JSValue JSC_HOST_CALL jsSVGTextContentElementPrototypeFunctionGetRotationOfChar(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
    UNUSED_PARAM(args);
    if (!thisValue.inherits(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(asObject(thisValue));
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());
    ExceptionCode ec = 0;
    int offset = args.at(0).toInt32(exec);
    if (offset < 0) {
        setDOMException(exec, INDEX_SIZE_ERR);
        return jsUndefined();
    }


    JSC::JSValue result = jsNumber(exec, imp->getRotationOfChar(offset, ec));
    setDOMException(exec, ec);
    return result;
}
JSValue JSC_HOST_CALL jsSVGTextContentElementPrototypeFunctionSelectSubString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
    UNUSED_PARAM(args);
    if (!thisValue.inherits(&JSSVGTextContentElement::s_info))
        return throwError(exec, TypeError);
    JSSVGTextContentElement* castedThisObj = static_cast<JSSVGTextContentElement*>(asObject(thisValue));
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(castedThisObj->impl());
    ExceptionCode ec = 0;
    int offset = args.at(0).toInt32(exec);
    if (offset < 0) {
        setDOMException(exec, INDEX_SIZE_ERR);
        return jsUndefined();
    }
    int length = args.at(1).toInt32(exec);
    if (length < 0) {
        setDOMException(exec, INDEX_SIZE_ERR);
        return jsUndefined();
    }

    imp->selectSubString(offset, length, ec);
    setDOMException(exec, ec);
    return jsUndefined();
}
void setJSSVGTextContentElementXmlspace(ExecState* exec, JSObject* thisObject, JSValue value)
{
    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(static_cast<JSSVGTextContentElement*>(thisObject)->impl());
    imp->setXmlspace(value.toString(exec));
}
JSValue* JSSVGTextContentElement::getValueProperty(ExecState* exec, int token) const
{
    switch (token) {
    case TextLengthAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        RefPtr<SVGAnimatedLength> obj = imp->textLengthAnimated();
        return toJS(exec, obj.get(), imp);
    }
    case LengthAdjustAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        RefPtr<SVGAnimatedEnumeration> obj = imp->lengthAdjustAnimated();
        return toJS(exec, obj.get(), imp);
    }
    case RequiredFeaturesAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        return toJS(exec, WTF::getPtr(imp->requiredFeatures()), imp);
    }
    case RequiredExtensionsAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        return toJS(exec, WTF::getPtr(imp->requiredExtensions()), imp);
    }
    case SystemLanguageAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        return toJS(exec, WTF::getPtr(imp->systemLanguage()), imp);
    }
    case XmllangAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        return jsString(exec, imp->xmllang());
    }
    case XmlspaceAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        return jsString(exec, imp->xmlspace());
    }
    case ExternalResourcesRequiredAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        RefPtr<SVGAnimatedBoolean> obj = imp->externalResourcesRequiredAnimated();
        return toJS(exec, obj.get(), imp);
    }
    case ClassNameAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        RefPtr<SVGAnimatedString> obj = imp->classNameAnimated();
        return toJS(exec, obj.get(), imp);
    }
    case StyleAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());
        return toJS(exec, WTF::getPtr(imp->style()));
    }
    case ConstructorAttrNum:
        return getConstructor(exec);
    }
    return 0;
}
JSValue* JSSVGTextContentElementPrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
    if (!thisObj->inherits(&JSSVGTextContentElement::info))
      return throwError(exec, TypeError);

    SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(static_cast<JSSVGTextContentElement*>(thisObj)->impl());

    switch (id) {
    case JSSVGTextContentElement::GetNumberOfCharsFuncNum: {


        KJS::JSValue* result = jsNumber(imp->getNumberOfChars());
        return result;
    }
    case JSSVGTextContentElement::GetComputedTextLengthFuncNum: {


        KJS::JSValue* result = jsNumber(imp->getComputedTextLength());
        return result;
    }
    case JSSVGTextContentElement::GetSubStringLengthFuncNum: {
        ExceptionCode ec = 0;
        bool offsetOk;
        unsigned offset = args[0]->toInt32(exec, offsetOk);
        if (!offsetOk) {
            setDOMException(exec, TYPE_MISMATCH_ERR);
            return jsUndefined();
        }
        bool lengthOk;
        unsigned length = args[1]->toInt32(exec, lengthOk);
        if (!lengthOk) {
            setDOMException(exec, TYPE_MISMATCH_ERR);
            return jsUndefined();
        }


        KJS::JSValue* result = jsNumber(imp->getSubStringLength(offset, length, ec));
        setDOMException(exec, ec);
        return result;
    }
    case JSSVGTextContentElement::GetStartPositionOfCharFuncNum: {
        ExceptionCode ec = 0;
        bool offsetOk;
        unsigned offset = args[0]->toInt32(exec, offsetOk);
        if (!offsetOk) {
            setDOMException(exec, TYPE_MISMATCH_ERR);
            return jsUndefined();
        }


        KJS::JSValue* result = toJS(exec, new JSSVGPODTypeWrapper<FloatPoint>(imp->getStartPositionOfChar(offset, ec)));
        setDOMException(exec, ec);
        return result;
    }
    case JSSVGTextContentElement::GetEndPositionOfCharFuncNum: {
        ExceptionCode ec = 0;
        bool offsetOk;
        unsigned offset = args[0]->toInt32(exec, offsetOk);
        if (!offsetOk) {
            setDOMException(exec, TYPE_MISMATCH_ERR);
            return jsUndefined();
        }


        KJS::JSValue* result = toJS(exec, new JSSVGPODTypeWrapper<FloatPoint>(imp->getEndPositionOfChar(offset, ec)));
        setDOMException(exec, ec);
        return result;
    }
    case JSSVGTextContentElement::GetExtentOfCharFuncNum: {
        ExceptionCode ec = 0;
        bool offsetOk;
        unsigned offset = args[0]->toInt32(exec, offsetOk);
        if (!offsetOk) {
            setDOMException(exec, TYPE_MISMATCH_ERR);
            return jsUndefined();
        }


        KJS::JSValue* result = toJS(exec, new JSSVGPODTypeWrapper<FloatRect>(imp->getExtentOfChar(offset, ec)));
        setDOMException(exec, ec);
        return result;
    }
    case JSSVGTextContentElement::GetRotationOfCharFuncNum: {
        ExceptionCode ec = 0;
        bool offsetOk;
        unsigned offset = args[0]->toInt32(exec, offsetOk);
        if (!offsetOk) {
            setDOMException(exec, TYPE_MISMATCH_ERR);
            return jsUndefined();
        }


        KJS::JSValue* result = jsNumber(imp->getRotationOfChar(offset, ec));
        setDOMException(exec, ec);
        return result;
    }
    case JSSVGTextContentElement::GetCharNumAtPositionFuncNum: {
        FloatPoint point = toSVGPoint(args[0]);


        KJS::JSValue* result = jsNumber(imp->getCharNumAtPosition(point));
        return result;
    }
    case JSSVGTextContentElement::SelectSubStringFuncNum: {
        ExceptionCode ec = 0;
        bool offsetOk;
        unsigned offset = args[0]->toInt32(exec, offsetOk);
        if (!offsetOk) {
            setDOMException(exec, TYPE_MISMATCH_ERR);
            return jsUndefined();
        }
        bool lengthOk;
        unsigned length = args[1]->toInt32(exec, lengthOk);
        if (!lengthOk) {
            setDOMException(exec, TYPE_MISMATCH_ERR);
            return jsUndefined();
        }

        imp->selectSubString(offset, length, ec);
        setDOMException(exec, ec);
        return jsUndefined();
    }
    case JSSVGTextContentElement::HasExtensionFuncNum: {
        String extension = args[0]->toString(exec);


        KJS::JSValue* result = jsBoolean(imp->hasExtension(extension));
        return result;
    }
    }
    return 0;
}
void SVGTextChunkLayoutInfo::recursiveBuildTextChunks(InlineFlowBox* start)
{
#if DEBUG_CHUNK_BUILDING > 1
    fprintf(stderr, " -> buildTextChunks(start=%p)\n", start);
#endif

    for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) {
        if (curr->renderer()->isText()) {
            InlineTextBox* textBox = static_cast<InlineTextBox*>(curr);

            unsigned length = textBox->len();
            ASSERT(length > 0);

#if DEBUG_CHUNK_BUILDING > 1
            fprintf(stderr, " -> Handle inline text box (%p) with %i characters (start: %i, end: %i), handlingTextPath=%i\n",
                            textBox, length, textBox->start(), textBox->end(), (int) m_handlingTextPath);
#endif

            RenderText* text = textBox->textRenderer();
            ASSERT(text);
            ASSERT(text->node());

            SVGTextContentElement* textContent = 0;
            Node* node = text->node()->parent();
            while (node && node->isSVGElement() && !textContent) {
                if (static_cast<SVGElement*>(node)->isTextContent())
                    textContent = static_cast<SVGTextContentElement*>(node);
                else
                    node = node->parentNode();
            }
            ASSERT(textContent);

            // Start new character range for the first chunk
            bool isFirstCharacter = m_svgTextChunks.isEmpty() && m_chunk.start == m_charsIt && m_chunk.start == m_chunk.end;
            if (isFirstCharacter) {
                ASSERT(m_chunk.boxes.isEmpty());
                m_chunk.boxes.append(SVGInlineBoxCharacterRange());
            } else
                ASSERT(!m_chunk.boxes.isEmpty());

            // Walk string to find out new chunk positions, if existent
            for (unsigned i = 0; i < length; ++i) {
                ASSERT(m_charsIt != m_charsEnd);

                SVGInlineBoxCharacterRange& range = m_chunk.boxes.last();
                if (range.isOpen()) {
                    range.box = curr;
                    range.startOffset = !i ? 0 : i - 1;

#if DEBUG_CHUNK_BUILDING > 1
                    fprintf(stderr, " | -> Range is open! box=%p, startOffset=%i\n", range.box, range.startOffset);
#endif
                }

                // If a new (or the first) chunk has been started, record it's text-anchor and writing mode.
                if (m_assignChunkProperties) {
                    m_assignChunkProperties = false;

                    m_chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle());
                    m_chunk.isTextPath = m_handlingTextPath;
                    m_chunk.anchor = text->style()->svgStyle()->textAnchor();
                    m_chunk.textLength = textContent->textLength().value(textContent);
                    m_chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();

#if DEBUG_CHUNK_BUILDING > 1
                    fprintf(stderr, " | -> Assign chunk properties, isVerticalText=%i, anchor=%i\n", m_chunk.isVerticalText, m_chunk.anchor);
#endif
                }

                if (i > 0 && !isFirstCharacter && m_charsIt->newTextChunk) {
                    // Close mid chunk & character range
                    ASSERT(!range.isOpen());
                    ASSERT(!range.isClosed());

                    range.endOffset = i;
                    closeTextChunk();

#if DEBUG_CHUNK_BUILDING > 1
                    fprintf(stderr, " | -> Close mid-text chunk, at endOffset: %i and starting new mid chunk!\n", range.endOffset);
#endif
    
                    // Prepare for next chunk, if we're not at the end
                    startTextChunk();
                    if (i + 1 == length) {
#if DEBUG_CHUNK_BUILDING > 1
                        fprintf(stderr, " | -> Record last chunk of inline text box!\n");
#endif

                        startTextChunk();
                        SVGInlineBoxCharacterRange& range = m_chunk.boxes.last();

                        m_assignChunkProperties = false;
                        m_chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle());
                        m_chunk.isTextPath = m_handlingTextPath;
                        m_chunk.anchor = text->style()->svgStyle()->textAnchor();
                        m_chunk.textLength = textContent->textLength().value(textContent);
                        m_chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust();

                        range.box = curr;
                        range.startOffset = i;

                        ASSERT(!range.isOpen());
                        ASSERT(!range.isClosed());
                    }
                }

                // This should only hold true for the first character of the first chunk
                if (isFirstCharacter)
                    isFirstCharacter = false;
    
                ++m_charsIt;
            }

#if DEBUG_CHUNK_BUILDING > 1    
            fprintf(stderr, " -> Finished inline text box!\n");
#endif

            SVGInlineBoxCharacterRange& range = m_chunk.boxes.last();
            if (!range.isOpen() && !range.isClosed()) {
#if DEBUG_CHUNK_BUILDING > 1
                fprintf(stderr, " -> Last range not closed - closing with endOffset: %i\n", length);
#endif

                // Current text chunk is not yet closed. Finish the current range, but don't start a new chunk.
                range.endOffset = length;

                if (m_charsIt != m_charsEnd) {
#if DEBUG_CHUNK_BUILDING > 1
                    fprintf(stderr, " -> Not at last character yet!\n");
#endif

                    // If we're not at the end of the last box to be processed, and if the next
                    // character starts a new chunk, then close the current chunk and start a new one.
                    if (m_charsIt->newTextChunk) {
#if DEBUG_CHUNK_BUILDING > 1
                        fprintf(stderr, " -> Next character starts new chunk! Closing current chunk, and starting a new one...\n");
#endif

                        closeTextChunk();
                        startTextChunk();
                    } else {
                        // Just start a new character range
                        m_chunk.boxes.append(SVGInlineBoxCharacterRange());

#if DEBUG_CHUNK_BUILDING > 1
                        fprintf(stderr, " -> Next character does NOT start a new chunk! Starting new character range...\n");
#endif
                    }
                } else {
#if DEBUG_CHUNK_BUILDING > 1
                    fprintf(stderr, " -> Closing final chunk! Finished processing!\n");
#endif

                    // Close final chunk, once we're at the end of the last box
                    closeTextChunk();
                }
            }
        } else {
            ASSERT(curr->isInlineFlowBox());
            InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr);

            // Skip generated content.
            if (!flowBox->renderer()->node())
                continue;

            bool isTextPath = flowBox->renderer()->node()->hasTagName(SVGNames::textPathTag);

#if DEBUG_CHUNK_BUILDING > 1
            fprintf(stderr, " -> Handle inline flow box (%p), isTextPath=%i\n", flowBox, (int) isTextPath);
#endif

            if (isTextPath)
                m_handlingTextPath = true;

            recursiveBuildTextChunks(flowBox);

            if (isTextPath)
                m_handlingTextPath = false;
        }
    }

#if DEBUG_CHUNK_BUILDING > 1
    fprintf(stderr, " <- buildTextChunks(start=%p)\n", start);
#endif
}
JSValue* JSSVGTextContentElement::getValueProperty(ExecState* exec, int token) const
{
    switch (token) {
    case TextLengthAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());

        ASSERT(exec && exec->dynamicInterpreter());

        RefPtr<SVGAnimatedLength> obj = imp->textLengthAnimated();
        Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame();
        if (activeFrame) {
            SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0);
            if (extensions) {
                if (extensions->hasGenericContext<SVGAnimatedLength>(obj.get()))
                    ASSERT(extensions->genericContext<SVGAnimatedLength>(obj.get()) == imp);
                else
                    extensions->setGenericContext<SVGAnimatedLength>(obj.get(), imp);
            }
        }

        return toJS(exec, obj.get());
    }
    case LengthAdjustAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());

        ASSERT(exec && exec->dynamicInterpreter());

        RefPtr<SVGAnimatedEnumeration> obj = imp->lengthAdjustAnimated();
        Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame();
        if (activeFrame) {
            SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0);
            if (extensions) {
                if (extensions->hasGenericContext<SVGAnimatedEnumeration>(obj.get()))
                    ASSERT(extensions->genericContext<SVGAnimatedEnumeration>(obj.get()) == imp);
                else
                    extensions->setGenericContext<SVGAnimatedEnumeration>(obj.get(), imp);
            }
        }

        return toJS(exec, obj.get());
    }
    case RequiredFeaturesAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());

        return toJS(exec, WTF::getPtr(imp->requiredFeatures()));
    }
    case RequiredExtensionsAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());

        return toJS(exec, WTF::getPtr(imp->requiredExtensions()));
    }
    case SystemLanguageAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());

        return toJS(exec, WTF::getPtr(imp->systemLanguage()));
    }
    case XmllangAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());

        return jsString(imp->xmllang());
    }
    case XmlspaceAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());

        return jsString(imp->xmlspace());
    }
    case ExternalResourcesRequiredAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());

        ASSERT(exec && exec->dynamicInterpreter());

        RefPtr<SVGAnimatedBoolean> obj = imp->externalResourcesRequiredAnimated();
        Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame();
        if (activeFrame) {
            SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0);
            if (extensions) {
                if (extensions->hasGenericContext<SVGAnimatedBoolean>(obj.get()))
                    ASSERT(extensions->genericContext<SVGAnimatedBoolean>(obj.get()) == imp);
                else
                    extensions->setGenericContext<SVGAnimatedBoolean>(obj.get(), imp);
            }
        }

        return toJS(exec, obj.get());
    }
    case ClassNameAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());

        ASSERT(exec && exec->dynamicInterpreter());

        RefPtr<SVGAnimatedString> obj = imp->classNameAnimated();
        Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame();
        if (activeFrame) {
            SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0);
            if (extensions) {
                if (extensions->hasGenericContext<SVGAnimatedString>(obj.get()))
                    ASSERT(extensions->genericContext<SVGAnimatedString>(obj.get()) == imp);
                else
                    extensions->setGenericContext<SVGAnimatedString>(obj.get(), imp);
            }
        }

        return toJS(exec, obj.get());
    }
    case StyleAttrNum: {
        SVGTextContentElement* imp = static_cast<SVGTextContentElement*>(impl());

        return toJS(exec, WTF::getPtr(imp->style()));
    }
    }
    return 0;
}