Home | History | Annotate | Download | only in properties
      1 /*
      2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  */
     19 
     20 #include "config.h"
     21 #include "core/svg/properties/SVGPathSegListPropertyTearOff.h"
     22 
     23 #include "SVGNames.h"
     24 #include "core/dom/ExceptionCode.h"
     25 #include "core/svg/SVGPathElement.h"
     26 #include "core/svg/SVGPathSegWithContext.h"
     27 #include "core/svg/properties/SVGAnimatedPathSegListPropertyTearOff.h"
     28 
     29 namespace WebCore {
     30 
     31 void SVGPathSegListPropertyTearOff::clearContextAndRoles()
     32 {
     33     ASSERT(m_values);
     34     unsigned size = m_values->size();
     35     for (unsigned i = 0; i < size; ++i) {
     36         ListItemType item = m_values->at(i);
     37         static_cast<SVGPathSegWithContext*>(item.get())->setContextAndRole(0, PathSegUndefinedRole);
     38     }
     39 }
     40 
     41 void SVGPathSegListPropertyTearOff::clear(ExceptionState& exceptionState)
     42 {
     43     ASSERT(m_values);
     44     if (m_values->isEmpty())
     45         return;
     46 
     47     clearContextAndRoles();
     48     SVGPathSegListPropertyTearOff::Base::clearValues(exceptionState);
     49 }
     50 
     51 SVGPathSegListPropertyTearOff::PassListItemType SVGPathSegListPropertyTearOff::getItem(unsigned index, ExceptionState& exceptionState)
     52 {
     53     ListItemType returnedItem = Base::getItemValues(index, exceptionState);
     54     if (returnedItem) {
     55         ASSERT(static_cast<SVGPathSegWithContext*>(returnedItem.get())->contextElement() == contextElement());
     56         ASSERT(static_cast<SVGPathSegWithContext*>(returnedItem.get())->role() == m_pathSegRole);
     57     }
     58     return returnedItem.release();
     59 }
     60 
     61 SVGPathSegListPropertyTearOff::PassListItemType SVGPathSegListPropertyTearOff::replaceItem(PassListItemType passNewItem, unsigned index, ExceptionState& exceptionState)
     62 {
     63     // Not specified, but FF/Opera do it this way, and it's just sane.
     64     if (!passNewItem) {
     65         exceptionState.throwUninformativeAndGenericTypeError();
     66         return 0;
     67     }
     68 
     69     if (index < m_values->size()) {
     70         ListItemType replacedItem = m_values->at(index);
     71         ASSERT(replacedItem);
     72         static_cast<SVGPathSegWithContext*>(replacedItem.get())->setContextAndRole(0, PathSegUndefinedRole);
     73     }
     74 
     75     ListItemType newItem = passNewItem;
     76     return Base::replaceItemValues(newItem, index, exceptionState);
     77 }
     78 
     79 SVGPathSegListPropertyTearOff::PassListItemType SVGPathSegListPropertyTearOff::removeItem(unsigned index, ExceptionState& exceptionState)
     80 {
     81     SVGPathSegListPropertyTearOff::ListItemType removedItem = SVGPathSegListPropertyTearOff::Base::removeItemValues(index, exceptionState);
     82     if (removedItem)
     83         static_cast<SVGPathSegWithContext*>(removedItem.get())->setContextAndRole(0, PathSegUndefinedRole);
     84     return removedItem.release();
     85 }
     86 
     87 SVGPathElement* SVGPathSegListPropertyTearOff::contextElement() const
     88 {
     89     SVGElement* contextElement = m_animatedProperty->contextElement();
     90     ASSERT(contextElement);
     91     return toSVGPathElement(contextElement);
     92 }
     93 
     94 bool SVGPathSegListPropertyTearOff::processIncomingListItemValue(const ListItemType& newItem, unsigned* indexToModify)
     95 {
     96     SVGPathSegWithContext* newItemWithContext = static_cast<SVGPathSegWithContext*>(newItem.get());
     97     SVGAnimatedProperty* animatedPropertyOfItem = newItemWithContext->animatedProperty();
     98 
     99     // Alter the role, after calling animatedProperty(), as that may influence the returned animated property.
    100     newItemWithContext->setContextAndRole(contextElement(), m_pathSegRole);
    101 
    102     if (!animatedPropertyOfItem)
    103         return true;
    104 
    105     // newItem belongs to a SVGPathElement, but its associated SVGAnimatedProperty is not an animated list tear off.
    106     // (for example: "pathElement.pathSegList.appendItem(pathElement.createSVGPathSegClosepath())")
    107     if (!animatedPropertyOfItem->isAnimatedListTearOff())
    108         return true;
    109 
    110     // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
    111     // 'newItem' is already living in another list. If it's not our list, synchronize the other lists wrappers after the removal.
    112     bool livesInOtherList = animatedPropertyOfItem != m_animatedProperty;
    113     SVGAnimatedPathSegListPropertyTearOff* propertyTearOff = static_cast<SVGAnimatedPathSegListPropertyTearOff*>(animatedPropertyOfItem);
    114     int indexToRemove = propertyTearOff->findItem(newItem.get());
    115     ASSERT(indexToRemove != -1);
    116 
    117     // Do not remove newItem if already in this list at the target index.
    118     if (!livesInOtherList && indexToModify && static_cast<unsigned>(indexToRemove) == *indexToModify)
    119         return false;
    120 
    121     propertyTearOff->removeItemFromList(indexToRemove, livesInOtherList);
    122 
    123     if (!indexToModify)
    124         return true;
    125 
    126     // If the item lived in our list, adjust the insertion index.
    127     if (!livesInOtherList) {
    128         unsigned& index = *indexToModify;
    129         // Spec: If the item is already in this list, note that the index of the item to (replace|insert before) is before the removal of the item.
    130         if (static_cast<unsigned>(indexToRemove) < index)
    131             --index;
    132     }
    133 
    134     return true;
    135 }
    136 
    137 }
    138