dom/html/HTMLTableRowElement.cpp
author Masayuki Nakano <masayuki@d-toybox.com>
Fri, 19 May 2017 17:49:41 +0900
changeset 407399 b75c111837a802ceb953dba50a3c5a193d53ca22
parent 390922 9b78f38eef9ea01642807a95b0f28660d9a99d58
child 416428 6a629adbb62a299d7208373d1c6f375149d2afdb
permissions -rw-r--r--
Bug 1339543 part 4 Change nsIWidget::ExecuteNativeKeyBinding() to nsIWidget::GetEditCommands() which just retrieves edit commands for the type r=smaug Now, nsIWidget::ExecuteNativeKeyBinding() isn't used by anybody for executing edit commands. Instead, they need array of edit commands for the key combination. So, the method should be renamed to GetEditCommands() and just return edit commands as an array. MozReview-Commit-ID: 4G0B1lJ8Lbe

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/dom/HTMLTableRowElement.h"
#include "mozilla/dom/HTMLTableElement.h"
#include "mozilla/GenericSpecifiedValuesInlines.h"
#include "nsMappedAttributes.h"
#include "nsAttrValueInlines.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/HTMLTableRowElementBinding.h"
#include "nsContentList.h"
#include "nsContentUtils.h"

NS_IMPL_NS_NEW_HTML_ELEMENT(TableRow)

namespace mozilla {
namespace dom {

HTMLTableRowElement::~HTMLTableRowElement()
{
}

JSObject*
HTMLTableRowElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
  return HTMLTableRowElementBinding::Wrap(aCx, this, aGivenProto);
}

NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLTableRowElement)

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLTableRowElement,
                                                  nsGenericHTMLElement)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCells)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_ADDREF_INHERITED(HTMLTableRowElement, Element)
NS_IMPL_RELEASE_INHERITED(HTMLTableRowElement, Element)

// QueryInterface implementation for HTMLTableRowElement
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLTableRowElement)
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)


NS_IMPL_ELEMENT_CLONE(HTMLTableRowElement)


// protected method
HTMLTableSectionElement*
HTMLTableRowElement::GetSection() const
{
  nsIContent* parent = GetParent();
  if (parent &&
      parent->IsAnyOfHTMLElements(nsGkAtoms::thead,
                                  nsGkAtoms::tbody,
                                  nsGkAtoms::tfoot)) {
    return static_cast<HTMLTableSectionElement*>(parent);
  }
  return nullptr;
}

// protected method
HTMLTableElement*
HTMLTableRowElement::GetTable() const
{
  nsIContent* parent = GetParent();
  if (!parent) {
    return nullptr;
  }

  // We may not be in a section
  HTMLTableElement* table = HTMLTableElement::FromContent(parent);
  if (table) {
    return table;
  }

  return HTMLTableElement::FromContentOrNull(parent->GetParent());
}

int32_t
HTMLTableRowElement::RowIndex() const
{
  HTMLTableElement* table = GetTable();
  if (!table) {
    return -1;
  }

  nsIHTMLCollection* rows = table->Rows();

  uint32_t numRows = rows->Length();

  for (uint32_t i = 0; i < numRows; i++) {
    if (rows->GetElementAt(i) == this) {
      return i;
    }
  }

  return -1;
}

int32_t
HTMLTableRowElement::SectionRowIndex() const
{
  HTMLTableSectionElement* section = GetSection();
  if (!section) {
    return -1;
  }

  nsCOMPtr<nsIHTMLCollection> coll = section->Rows();
  uint32_t numRows = coll->Length();
  for (uint32_t i = 0; i < numRows; i++) {
    if (coll->GetElementAt(i) == this) {
      return i;
    }
  }

  return -1;
}

static bool
IsCell(Element *aElement, int32_t aNamespaceID,
       nsIAtom* aAtom, void *aData)
{
  return aElement->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th);
}

nsIHTMLCollection*
HTMLTableRowElement::Cells()
{
  if (!mCells) {
    mCells = new nsContentList(this,
                               IsCell,
                               nullptr, // destroy func
                               nullptr, // closure data
                               false,
                               nullptr,
                               kNameSpaceID_XHTML,
                               false);
  }

  return mCells;
}

already_AddRefed<nsGenericHTMLElement>
HTMLTableRowElement::InsertCell(int32_t aIndex,
                                ErrorResult& aError)
{
  if (aIndex < -1) {
    aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    return nullptr;
  }

  // Make sure mCells is initialized.
  nsIHTMLCollection* cells = Cells();

  NS_ASSERTION(mCells, "How did that happen?");

  nsCOMPtr<nsINode> nextSibling;
  // -1 means append, so should use null nextSibling
  if (aIndex != -1) {
    nextSibling = cells->Item(aIndex);
    // Check whether we're inserting past end of list.  We want to avoid doing
    // this unless we really have to, since this has to walk all our kids.  If
    // we have a nextSibling, we're clearly not past end of list.
    if (!nextSibling) {
      uint32_t cellCount = cells->Length();
      if (aIndex > int32_t(cellCount)) {
        aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
        return nullptr;
      }
    }
  }

  // create the cell
  RefPtr<mozilla::dom::NodeInfo> nodeInfo;
  nsContentUtils::QNameChanged(mNodeInfo, nsGkAtoms::td,
                               getter_AddRefs(nodeInfo));

  RefPtr<nsGenericHTMLElement> cell =
    NS_NewHTMLTableCellElement(nodeInfo.forget());
  if (!cell) {
    aError.Throw(NS_ERROR_OUT_OF_MEMORY);
    return nullptr;
  }

  nsINode::InsertBefore(*cell, nextSibling, aError);

  return cell.forget();
}

void
HTMLTableRowElement::DeleteCell(int32_t aValue, ErrorResult& aError)
{
  if (aValue < -1) {
    aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    return;
  }

  nsIHTMLCollection* cells = Cells();

  uint32_t refIndex;
  if (aValue == -1) {
    refIndex = cells->Length();
    if (refIndex == 0) {
      return;
    }

    --refIndex;
  }
  else {
    refIndex = (uint32_t)aValue;
  }

  nsCOMPtr<nsINode> cell = cells->Item(refIndex);
  if (!cell) {
    aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    return;
  }

  nsINode::RemoveChild(*cell, aError);
}

bool
HTMLTableRowElement::ParseAttribute(int32_t aNamespaceID,
                                    nsIAtom* aAttribute,
                                    const nsAString& aValue,
                                    nsAttrValue& aResult)
{
  /*
   * ignore these attributes, stored simply as strings
   *
   * ch
   */

  if (aNamespaceID == kNameSpaceID_None) {
    if (aAttribute == nsGkAtoms::charoff) {
      return aResult.ParseIntWithBounds(aValue, 0);
    }
    if (aAttribute == nsGkAtoms::height) {
      return aResult.ParseSpecialIntValue(aValue);
    }
    if (aAttribute == nsGkAtoms::width) {
      return aResult.ParseSpecialIntValue(aValue);
    }
    if (aAttribute == nsGkAtoms::align) {
      return ParseTableCellHAlignValue(aValue, aResult);
    }
    if (aAttribute == nsGkAtoms::bgcolor) {
      return aResult.ParseColor(aValue);
    }
    if (aAttribute == nsGkAtoms::valign) {
      return ParseTableVAlignValue(aValue, aResult);
    }
  }

  return nsGenericHTMLElement::ParseBackgroundAttribute(aNamespaceID,
                                                        aAttribute, aValue,
                                                        aResult) ||
         nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                              aResult);
}

void
HTMLTableRowElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                           GenericSpecifiedValues* aData)
{
  nsGenericHTMLElement::MapHeightAttributeInto(aAttributes, aData);
  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
  nsGenericHTMLElement::MapVAlignAttributeInto(aAttributes, aData);
  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
}

NS_IMETHODIMP_(bool)
HTMLTableRowElement::IsAttributeMapped(const nsIAtom* aAttribute) const
{
  static const MappedAttributeEntry attributes[] = {
    { &nsGkAtoms::align },
    { &nsGkAtoms::valign }, 
    { &nsGkAtoms::height },
    { nullptr }
  };

  static const MappedAttributeEntry* const map[] = {
    attributes,
    sCommonAttributeMap,
    sBackgroundAttributeMap,
  };

  return FindAttributeDependence(aAttribute, map);
}

nsMapRuleToAttributesFunc
HTMLTableRowElement::GetAttributeMappingFunction() const
{
  return &MapAttributesIntoRule;
}

} // namespace dom
} // namespace mozilla