Bug 1484092 - part 1: Make HTMLEditor::GetElementOrParentByTagName() use nsAtom for the tag name r=m_kato

HTMLElementOrParentByTagName() is the last user of IsLinkTag(const nsAString&)
and IsNamedAnchorTag(const nsAString&).  For making their maintenance easier,
let's make GetElementOrParentByTagName() take const nsAtom& for tag name.

GetElementOrParentByTagName() has two functions, one is looking for an element
starting from a node.  The other is, if the start node is nullptr, it retrieves
anchor node of Selection as start node.  Therefore, this patch splits the
first part to GetElementOrParentByTagNameInternal().  Then, creates its
wrapper which retrieves anchor of Selection automatically,
GetElementOrParentByTagNameAtSelection().

Additionally, this patch makes all internal callers of HTMLEditor use
GetElementOrParentByTagNameInternal() or
GetElementOrParentByTagNameAtSelection() directly.  Then, public method,
GetElementOrParentByTagName() is called only by outer classes.

Note that some callers use both GetElementOrParentByTagNameInternal()
and GetElementOrParentByTagNameAtSelection() since they don't check whether
setting node is nullptr.  They may be bug of them.  We should investigate
the API callers later.

Differential Revision: https://phabricator.services.mozilla.com/D3584

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2018-08-17 10:04:42 +00:00
Родитель e89e01ef69
Коммит a8b7670d10
6 изменённых файлов: 394 добавлений и 205 удалений

Просмотреть файл

@ -289,7 +289,9 @@ HTMLEditor::DeleteRefToAnonymousNode(ManualNACPtr aContent,
NS_IMETHODIMP
HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
{
NS_ENSURE_ARG_POINTER(aSelection);
if (NS_WARN_IF(!aSelection)) {
return NS_ERROR_INVALID_ARG;
}
// early way out if all contextual UI extensions are disabled
NS_ENSURE_TRUE(mIsObjectResizingEnabled ||
@ -326,7 +328,8 @@ HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
if (mIsObjectResizingEnabled || mIsInlineTableEditingEnabled) {
// Resizing or Inline Table Editing is enabled, we need to check if the
// selection is contained in a table cell
cellElement = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
cellElement =
GetElementOrParentByTagNameAtSelection(*aSelection, *nsGkAtoms::td);
}
if (mIsObjectResizingEnabled && cellElement) {

Просмотреть файл

@ -88,24 +88,12 @@ GetLowerCaseNameAtom(const nsAString& aTagName)
}
// Some utilities to handle overloading of "A" tag for link and named anchor.
static bool
IsLinkTag(const nsString& s)
{
return s.EqualsIgnoreCase("href");
}
static bool
IsLinkTag(const nsAtom& aTagName)
{
return aTagName.Equals(NS_LITERAL_STRING("href"));
}
static bool
IsNamedAnchorTag(const nsString& s)
{
return s.EqualsIgnoreCase("anchor") || s.EqualsIgnoreCase("namedanchor");
}
static bool
IsNamedAnchorTag(const nsAtom& aTagName)
{
@ -1106,24 +1094,38 @@ HTMLEditor::TabInTable(bool inIsShift,
NS_ENSURE_TRUE(outHandled, NS_ERROR_NULL_POINTER);
*outHandled = false;
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
// Do nothing if we didn't find a table cell.
return NS_OK;
}
// Find enclosing table cell from selection (cell may be selected element)
nsCOMPtr<Element> cellElement =
GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
// Do nothing -- we didn't find a table cell
NS_ENSURE_TRUE(cellElement, NS_OK);
Element* cellElement =
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
if (NS_WARN_IF(!cellElement)) {
// Do nothing if we didn't find a table cell.
return NS_OK;
}
// find enclosing table
nsCOMPtr<Element> table = GetEnclosingTable(cellElement);
NS_ENSURE_TRUE(table, NS_OK);
RefPtr<Element> table = GetEnclosingTable(cellElement);
if (NS_WARN_IF(!table)) {
return NS_OK;
}
// advance to next cell
// first create an iterator over the table
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
nsresult rv = iter->Init(table);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// position iter at block
rv = iter->PositionAt(cellElement);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsINode> node;
do {
@ -2527,84 +2529,93 @@ HTMLEditor::Align(const nsAString& aAlignType)
return rules->DidDoAction(selection, subActionInfo, rv);
}
already_AddRefed<Element>
HTMLEditor::GetElementOrParentByTagName(const nsAString& aTagName,
Element*
HTMLEditor::GetElementOrParentByTagName(const nsAtom& aTagName,
nsINode* aNode)
{
MOZ_ASSERT(!aTagName.IsEmpty());
MOZ_ASSERT(&aTagName != nsGkAtoms::_empty);
nsCOMPtr<nsINode> node = aNode;
if (!node) {
// If no node supplied, get it from anchor node of current selection
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
return nullptr;
}
const EditorDOMPoint atAnchor(selection->AnchorRef());
if (NS_WARN_IF(!atAnchor.IsSet())) {
return nullptr;
}
// Try to get the actual selected node
if (atAnchor.GetContainer()->HasChildNodes() &&
atAnchor.GetContainerAsContent()) {
node = atAnchor.GetChild();
}
// Anchor node is probably a text node - just use that
if (!node) {
node = atAnchor.GetContainer();
}
if (aNode) {
return GetElementOrParentByTagNameInternal(aTagName, *aNode);
}
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
return nullptr;
}
return GetElementOrParentByTagNameAtSelection(*selection, aTagName);
}
nsCOMPtr<Element> current;
if (node->IsElement()) {
current = node->AsElement();
} else if (node->GetParentElement()) {
current = node->GetParentElement();
} else {
// Neither aNode nor its parent is an element, so no ancestor is
MOZ_ASSERT(!node->GetParentNode() ||
!node->GetParentNode()->GetParentNode());
Element*
HTMLEditor::GetElementOrParentByTagNameAtSelection(Selection& aSelection,
const nsAtom& aTagName)
{
MOZ_ASSERT(&aTagName != nsGkAtoms::_empty);
// If no node supplied, get it from anchor node of current selection
const EditorRawDOMPoint atAnchor(aSelection.AnchorRef());
if (NS_WARN_IF(!atAnchor.IsSet())) {
return nullptr;
}
nsAutoString tagName(aTagName);
ToLowerCase(tagName);
bool getLink = IsLinkTag(tagName);
bool getNamedAnchor = IsNamedAnchorTag(tagName);
if (getLink || getNamedAnchor) {
tagName.Assign('a');
// Try to get the actual selected node
nsCOMPtr<nsINode> node;
if (atAnchor.GetContainer()->HasChildNodes() &&
atAnchor.GetContainerAsContent()) {
node = atAnchor.GetChild();
}
bool findTableCell = tagName.EqualsLiteral("td");
bool findList = tagName.EqualsLiteral("list");
for (; current; current = current->GetParentElement()) {
// Test if we have a link (an anchor with href set)
if ((getLink && HTMLEditUtils::IsLink(current)) ||
(getNamedAnchor && HTMLEditUtils::IsNamedAnchor(current))) {
return current.forget();
// Anchor node is probably a text node - just use that
if (!node) {
node = atAnchor.GetContainer();
if (NS_WARN_IF(!node)) {
return nullptr;
}
if (findList) {
}
return GetElementOrParentByTagNameInternal(aTagName, *node);
}
Element*
HTMLEditor::GetElementOrParentByTagNameInternal(const nsAtom& aTagName,
nsINode& aNode)
{
MOZ_ASSERT(&aTagName != nsGkAtoms::_empty);
Element* currentElement =
aNode.IsElement() ? aNode.AsElement() : aNode.GetParentElement();
if (NS_WARN_IF(!currentElement)) {
// Neither aNode nor its parent is an element, so no ancestor is
MOZ_ASSERT(!aNode.GetParentNode() ||
!aNode.GetParentNode()->GetParentNode());
return nullptr;
}
bool getLink = IsLinkTag(aTagName);
bool getNamedAnchor = IsNamedAnchorTag(aTagName);
const nsAtom& tagName = getLink || getNamedAnchor ? *nsGkAtoms::a : aTagName;
for (; currentElement; currentElement = currentElement->GetParentElement()) {
// Test if we have a link (an anchor with href set)
if ((getLink && HTMLEditUtils::IsLink(currentElement)) ||
(getNamedAnchor && HTMLEditUtils::IsNamedAnchor(currentElement))) {
return currentElement;
}
if (&tagName == nsGkAtoms::list_) {
// Match "ol", "ul", or "dl" for lists
if (HTMLEditUtils::IsList(current)) {
return current.forget();
if (HTMLEditUtils::IsList(currentElement)) {
return currentElement;
}
} else if (findTableCell) {
} else if (&tagName == nsGkAtoms::td) {
// Table cells are another special case: match either "td" or "th"
if (HTMLEditUtils::IsTableCell(current)) {
return current.forget();
if (HTMLEditUtils::IsTableCell(currentElement)) {
return currentElement;
}
} else if (current->NodeName().Equals(tagName,
nsCaseInsensitiveStringComparator())) {
return current.forget();
} else if (&tagName == currentElement->NodeInfo()->NameAtom()) {
return currentElement;
}
// Stop searching if parent is a body tag. Note: Originally used IsRoot to
// stop at table cells, but that's too messy when you are trying to find
// the parent table
if (current->GetParentElement() &&
current->GetParentElement()->IsHTMLElement(nsGkAtoms::body)) {
if (currentElement->GetParentElement() &&
currentElement->GetParentElement()->IsHTMLElement(nsGkAtoms::body)) {
break;
}
}
@ -2617,15 +2628,20 @@ HTMLEditor::GetElementOrParentByTagName(const nsAString& aTagName,
nsINode* aNode,
Element** aReturn)
{
NS_ENSURE_TRUE(!aTagName.IsEmpty(), NS_ERROR_NULL_POINTER);
NS_ENSURE_TRUE(aReturn, NS_ERROR_NULL_POINTER);
if (NS_WARN_IF(aTagName.IsEmpty()) ||
NS_WARN_IF(!aReturn)) {
return NS_ERROR_INVALID_ARG;
}
RefPtr<Element> parent = GetElementOrParentByTagName(aTagName, aNode);
RefPtr<nsAtom> tagName = GetLowerCaseNameAtom(aTagName);
if (NS_WARN_IF(!tagName) || NS_WARN_IF(tagName == nsGkAtoms::_empty)) {
return NS_ERROR_INVALID_ARG;
}
RefPtr<Element> parent = GetElementOrParentByTagName(*tagName, aNode);
if (!parent) {
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
parent.forget(aReturn);
return NS_OK;
}
@ -2707,22 +2723,22 @@ HTMLEditor::GetSelectedElement(Selection& aSelection,
const RangeBoundary& focus = aSelection.FocusRef();
// Link node must be the same for both ends of selection
if (anchor.IsSet()) {
RefPtr<Element> parentLinkOfAnchor =
GetElementOrParentByTagName(NS_LITERAL_STRING("href"),
anchor.Container());
Element* parentLinkOfAnchor =
GetElementOrParentByTagNameInternal(*nsGkAtoms::href,
*anchor.Container());
// XXX: ERROR_HANDLING can parentLinkOfAnchor be null?
if (parentLinkOfAnchor) {
if (aSelection.IsCollapsed()) {
// We have just a caret in the link.
return parentLinkOfAnchor.forget();
return do_AddRef(parentLinkOfAnchor);
}
if (focus.IsSet()) {
// Link node must be the same for both ends of selection.
RefPtr<Element> parentLinkOfFocus =
GetElementOrParentByTagName(NS_LITERAL_STRING("href"),
focus.Container());
Element* parentLinkOfFocus =
GetElementOrParentByTagNameInternal(*nsGkAtoms::href,
*focus.Container());
if (parentLinkOfFocus == parentLinkOfAnchor) {
return parentLinkOfAnchor.forget();
return do_AddRef(parentLinkOfAnchor);
}
}
} else if (anchor.GetChildAtOffset() && focus.GetChildAtOffset()) {

Просмотреть файл

@ -322,8 +322,28 @@ public:
*/
nsresult DoInlineTableEditingAction(const Element& aUIAnonymousElement);
already_AddRefed<Element>
GetElementOrParentByTagName(const nsAString& aTagName, nsINode* aNode);
/**
* GetElementOrParentByTagName() looks for an element node whose name matches
* aTagName from aNode or anchor node of Selection to <body> element.
*
* @param aTagName The tag name which you want to look for.
* Must not be nsGkAtoms::_empty.
* If nsGkAtoms::list, the result may be <ul>, <ol> or
* <dl> element.
* If nsGkAtoms::td, the result may be <td> or <th>.
* If nsGkAtoms::href, the result may be <a> element
* which has "href" attribute with non-empty value.
* If nsGkAtoms::anchor or atom of "namedanchor", the
* result may be <a> which has "name" attribute with
* non-empty value.
* @param aNode If non-nullptr, this starts to look for the result
* from it. Otherwise, i.e., nullptr, starts from
* anchor node of Selection.
* @return If an element which matches aTagName, returns
* an Element. Otherwise, nullptr.
*/
Element*
GetElementOrParentByTagName(const nsAtom& aTagName, nsINode* aNode);
/**
* Get an active editor's editing host in DOM window. If this editor isn't
@ -814,6 +834,50 @@ protected: // Shouldn't be used by friend classes
nsresult CollapseSelectionAfter(Selection& aSelection,
Element& aElement);
/**
* GetElementOrParentByTagNameAtSelection() looks for an element node whose
* name matches aTagName from anchor node of Selection to <body> element.
*
* @param aSelection The Selection for this editor.
* @param aTagName The tag name which you want to look for.
* Must not be nsGkAtoms::_empty.
* If nsGkAtoms::list, the result may be <ul>, <ol> or
* <dl> element.
* If nsGkAtoms::td, the result may be <td> or <th>.
* If nsGkAtoms::href, the result may be <a> element
* which has "href" attribute with non-empty value.
* If nsGkAtoms::anchor or atom of "namedanchor", the
* result may be <a> which has "name" attribute with
* non-empty value.
* @return If an element which matches aTagName, returns
* an Element. Otherwise, nullptr.
*/
Element*
GetElementOrParentByTagNameAtSelection(Selection& aSelection,
const nsAtom& aTagName);
/**
* GetElementOrParentByTagNameInternal() looks for an element node whose
* name matches aTagName from aNode to <body> element.
*
* @param aTagName The tag name which you want to look for.
* Must not be nsGkAtoms::_empty.
* If nsGkAtoms::list, the result may be <ul>, <ol> or
* <dl> element.
* If nsGkAtoms::td, the result may be <td> or <th>.
* If nsGkAtoms::href, the result may be <a> element
* which has "href" attribute with non-empty value.
* If nsGkAtoms::anchor or atom of "namedanchor", the
* result may be <a> which has "name" attribute with
* non-empty value.
* @param aNode Start node to look for the element.
* @return If an element which matches aTagName, returns
* an Element. Otherwise, nullptr.
*/
Element*
GetElementOrParentByTagNameInternal(const nsAtom& aTagName,
nsINode& aNode);
/**
* GetSelectedElement() returns an element node which is in first range of
* aSelection. The rule is a little bit complicated and the rules do not

Просмотреть файл

@ -142,9 +142,8 @@ HTMLEditorEventListener::MouseDown(MouseEvent* aMouseEvent)
selection->Collapse(parent, offset);
} else {
// Get enclosing link if in text so we can select the link
RefPtr<Element> linkElement =
htmlEditor->GetElementOrParentByTagName(NS_LITERAL_STRING("href"),
node);
Element* linkElement =
htmlEditor->GetElementOrParentByTagName(*nsGkAtoms::href, node);
if (linkElement) {
element = linkElement;
}

Просмотреть файл

@ -224,16 +224,17 @@ NS_IMETHODIMP
HTMLEditor::GetFirstRow(Element* aTableElement,
nsINode** aRowNode)
{
NS_ENSURE_TRUE(aRowNode, NS_ERROR_NULL_POINTER);
if (NS_WARN_IF(!aTableElement) || NS_WARN_IF(!aRowNode)) {
return NS_ERROR_INVALID_ARG;
}
*aRowNode = nullptr;
nsCOMPtr<nsINode> tableElement = aTableElement;
NS_ENSURE_TRUE(tableElement, NS_ERROR_NULL_POINTER);
tableElement = GetElementOrParentByTagName(NS_LITERAL_STRING("table"),
tableElement);
NS_ENSURE_TRUE(tableElement, NS_ERROR_NULL_POINTER);
Element* tableElement =
GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aTableElement);
if (NS_WARN_IF(!tableElement)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIContent> tableChild = tableElement->GetFirstChild();
while (tableChild) {
@ -602,19 +603,20 @@ HTMLEditor::InsertTableRow(int32_t aNumber,
}
if (cellsInRow > 0) {
NS_NAMED_LITERAL_STRING(trStr, "tr");
if (!cellForRowParent) {
if (NS_WARN_IF(!cellForRowParent)) {
return NS_ERROR_FAILURE;
}
Element* parentRow =
GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cellForRowParent);
if (NS_WARN_IF(!parentRow)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<Element> parentRow =
GetElementOrParentByTagName(trStr, cellForRowParent);
NS_ENSURE_TRUE(parentRow, NS_ERROR_NULL_POINTER);
// The row parent and offset where we will insert new row
nsCOMPtr<nsINode> parentOfRow = parentRow->GetParentNode();
NS_ENSURE_TRUE(parentOfRow, NS_ERROR_NULL_POINTER);
if (NS_WARN_IF(!parentOfRow)) {
return NS_ERROR_FAILURE;
}
int32_t newRowOffset = parentOfRow->ComputeIndexOf(parentRow);
// Adjust for when adding past the end
@ -851,12 +853,16 @@ HTMLEditor::DeleteTableCell(int32_t aNumber)
&startRowIndex, &startColIndex);
NS_ENSURE_SUCCESS(rv, rv);
// Don't fail if no cell found
NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
if (NS_WARN_IF(!cell)) {
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
if (GetNumberOfCellsInRow(table, startRowIndex) == 1) {
RefPtr<Element> parentRow =
GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cell);
NS_ENSURE_TRUE(parentRow, NS_ERROR_NULL_POINTER);
Element* parentRow =
GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cell);
if (NS_WARN_IF(!parentRow)) {
return NS_ERROR_FAILURE;
}
// We should delete the row instead,
// but first check if its the only row left
@ -1087,10 +1093,10 @@ HTMLEditor::DeleteColumn(Element* aTable,
// Delete the cell
if (GetNumberOfCellsInRow(aTable, rowIndex) == 1) {
// Only 1 cell in row - delete the row
RefPtr<Element> parentRow =
GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cell);
if (!parentRow) {
return NS_ERROR_NULL_POINTER;
Element* parentRow =
GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cell);
if (NS_WARN_IF(!parentRow)) {
return NS_ERROR_FAILURE;
}
// But first check if its the only row left
@ -1304,12 +1310,13 @@ HTMLEditor::DeleteRow(Element* aTable,
} while (cell);
// Things are messed up if we didn't find a cell in the row!
NS_ENSURE_TRUE(cellInDeleteRow, NS_ERROR_FAILURE);
if (NS_WARN_IF(!cellInDeleteRow)) {
return NS_ERROR_FAILURE;
}
// Delete the entire row
RefPtr<Element> parentRow =
GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cellInDeleteRow);
GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cellInDeleteRow);
if (parentRow) {
rv = DeleteNodeWithTransaction(*parentRow);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -1332,10 +1339,15 @@ HTMLEditor::DeleteRow(Element* aTable,
NS_IMETHODIMP
HTMLEditor::SelectTable()
{
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_OK; // Don't fail if we didn't find a table.
}
RefPtr<Element> table =
GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr);
// Don't fail if we didn't find a table
NS_ENSURE_TRUE(table, NS_OK);
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
if (NS_WARN_IF(!table)) {
return NS_OK; // Don't fail if we didn't find a table.
}
nsresult rv = ClearSelection();
if (NS_FAILED(rv)) {
@ -1347,9 +1359,15 @@ HTMLEditor::SelectTable()
NS_IMETHODIMP
HTMLEditor::SelectTableCell()
{
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> cell =
GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
if (NS_WARN_IF(!cell)) {
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
nsresult rv = ClearSelection();
if (NS_FAILED(rv)) {
@ -1362,17 +1380,26 @@ NS_IMETHODIMP
HTMLEditor::SelectBlockOfCells(Element* aStartCell,
Element* aEndCell)
{
NS_ENSURE_TRUE(aStartCell && aEndCell, NS_ERROR_NULL_POINTER);
if (NS_WARN_IF(!aStartCell) || NS_WARN_IF(!aEndCell)) {
return NS_ERROR_INVALID_ARG;
}
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
NS_NAMED_LITERAL_STRING(tableStr, "table");
RefPtr<Element> table = GetElementOrParentByTagName(tableStr, aStartCell);
NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
RefPtr<Element> table =
GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aStartCell);
if (NS_WARN_IF(!table)) {
return NS_ERROR_FAILURE;
}
RefPtr<Element> endTable = GetElementOrParentByTagName(tableStr, aEndCell);
NS_ENSURE_TRUE(endTable, NS_ERROR_FAILURE);
RefPtr<Element> endTable =
GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aEndCell);
if (NS_WARN_IF(!endTable)) {
return NS_ERROR_FAILURE;
}
// We can only select a block if within the same table,
// so do nothing if not within one table
@ -1457,28 +1484,30 @@ HTMLEditor::SelectBlockOfCells(Element* aStartCell,
NS_IMETHODIMP
HTMLEditor::SelectAllTableCells()
{
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> cell =
GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
// Don't fail if we didn't find a cell
NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
if (NS_WARN_IF(!cell)) {
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> startCell = cell;
// Get parent table
RefPtr<Element> table =
GetElementOrParentByTagName(NS_LITERAL_STRING("table"), cell);
if (!table) {
return NS_ERROR_NULL_POINTER;
GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *cell);
if (NS_WARN_IF(!table)) {
return NS_ERROR_FAILURE;
}
int32_t rowCount, colCount;
nsresult rv = GetTableSize(table, &rowCount, &colCount);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
// Suppress nsISelectionListener notification
// until all selection changes are finished
SelectionBatcher selectionBatcher(selection);
@ -1522,19 +1551,25 @@ HTMLEditor::SelectAllTableCells()
NS_IMETHODIMP
HTMLEditor::SelectTableRow()
{
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> cell =
GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
if (NS_WARN_IF(!cell)) {
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
// Don't fail if we didn't find a cell
NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
RefPtr<Element> startCell = cell;
// Get table and location of cell:
RefPtr<Selection> selection;
RefPtr<Element> table;
int32_t startRowIndex, startColIndex;
nsresult rv = GetCellContext(getter_AddRefs(selection),
nsresult rv = GetCellContext(nullptr,
getter_AddRefs(table),
getter_AddRefs(cell),
nullptr, nullptr,
@ -1590,20 +1625,25 @@ HTMLEditor::SelectTableRow()
NS_IMETHODIMP
HTMLEditor::SelectTableColumn()
{
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> cell =
GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
// Don't fail if we didn't find a cell
NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
if (NS_WARN_IF(!cell)) {
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> startCell = cell;
// Get location of cell:
RefPtr<Selection> selection;
RefPtr<Element> table;
int32_t startRowIndex, startColIndex;
nsresult rv = GetCellContext(getter_AddRefs(selection),
nsresult rv = GetCellContext(nullptr,
getter_AddRefs(table),
getter_AddRefs(cell),
nullptr, nullptr,
@ -2469,13 +2509,18 @@ NS_IMETHODIMP
HTMLEditor::NormalizeTable(Element* aTable)
{
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
RefPtr<Element> table =
GetElementOrParentByTagName(NS_LITERAL_STRING("table"),
aTable);
// Don't fail if we didn't find a table
NS_ENSURE_TRUE(table, NS_OK);
aTable ?
GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aTable) :
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
if (NS_WARN_IF(!table)) {
// Don't fail if we didn't find a table.
return NS_OK;
}
int32_t rowCount, colCount, rowIndex, colIndex;
nsresult rv = GetTableSize(table, &rowCount, &colCount);
@ -2561,11 +2606,19 @@ HTMLEditor::GetCellIndexes(Element* aCell,
*aColIndex=0; // initialize out params
NS_ENSURE_ARG_POINTER(aColIndex);
*aRowIndex=0;
RefPtr<Element> cell; // Needs to stay alive while we're using
// aCell, since it may be keeping it alive.
// Needs to stay alive while we're using aCell, since it may be keeping it
// alive.
// XXX Looks like it's safe to use raw pointer here. However, layout code
// change won't be handled by editor developers so that it must be safe
// to keep using RefPtr here.
RefPtr<Element> cell;
if (!aCell) {
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
// Get the selected cell or the cell enclosing the selection anchor
cell = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
cell = GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::td);
if (!cell) {
return NS_ERROR_FAILURE;
}
@ -2632,12 +2685,31 @@ HTMLEditor::GetTableSize(Element* aTable,
*aRowCount = 0;
*aColCount = 0;
// Get the selected talbe or the table enclosing the selection anchor
RefPtr<Element> table =
GetElementOrParentByTagName(NS_LITERAL_STRING("table"), aTable);
NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
// XXX Looks like it's safe to use raw pointer here. However, layout code
// change won't be handled by editor developers so that it must be safe
// to keep using RefPtr here.
RefPtr<Element> table;
if (aTable) {
table = GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aTable);
if (NS_WARN_IF(!table)) {
return NS_ERROR_FAILURE;
}
} else {
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
table =
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
if (NS_WARN_IF(!table)) {
return NS_ERROR_FAILURE;
}
}
nsTableWrapperFrame* tableFrame = do_QueryFrame(table->GetPrimaryFrame());
NS_ENSURE_TRUE(tableFrame, NS_ERROR_FAILURE);
if (NS_WARN_IF(!tableFrame)) {
return NS_ERROR_FAILURE;
}
*aRowCount = tableFrame->GetRowCount();
*aColCount = tableFrame->GetColCount();
@ -2677,10 +2749,19 @@ HTMLEditor::GetCellDataAt(Element* aTable,
*aCell = nullptr;
RefPtr<Element> table; // needs to live while we use aTable
// needs to live while we use aTable
// XXX Really? Looks like it's safe to use raw pointer here.
// However, layout code change won't be handled by editor developers
// so that it must be safe to keep using RefPtr here.
RefPtr<Element> table;
if (!aTable) {
// Get the selected table or the table enclosing the selection anchor
table = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr);
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
// Get the selected table or the table enclosing the selection anchor.
table =
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
if (!table) {
return NS_ERROR_FAILURE;
}
@ -2719,11 +2800,22 @@ HTMLEditor::GetCellAt(Element* aTable,
NS_ENSURE_ARG_POINTER(aCell);
*aCell = nullptr;
RefPtr<Element> table; // Needs to live as long as we use aTable
// Needs to live as long as we use aTable
// XXX Really? Looks like it's safe to use raw pointer here.
// However, layout code change won't be handled by editor developers
// so that it must be safe to keep using RefPtr here.
RefPtr<Element> table;
if (!aTable) {
// Get the selected table or the table enclosing the selection anchor
table = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), nullptr);
NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
// Get the selected table or the table enclosing the selection anchor.
table =
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
if (NS_WARN_IF(!table)) {
return NS_ERROR_FAILURE;
}
aTable = table;
}
@ -2791,7 +2883,9 @@ HTMLEditor::GetCellContext(Selection** aSelection,
}
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
if (aSelection) {
*aSelection = selection.get();
@ -2829,6 +2923,7 @@ HTMLEditor::GetCellContext(Selection** aSelection,
}
// We found a cell
MOZ_ASSERT(cellOrTableElement);
cell = cellOrTableElement;
}
if (aCell) {
@ -2837,9 +2932,11 @@ HTMLEditor::GetCellContext(Selection** aSelection,
}
// Get containing table
table = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), cell);
// Cell must be in a table, so fail if not found
NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
table = GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *cell);
if (NS_WARN_IF(!table)) {
// Cell must be in a table, so fail if not found
return NS_ERROR_FAILURE;
}
if (aTable) {
table.forget(aTable);
}
@ -3157,13 +3254,11 @@ HTMLEditor::GetSelectedOrParentTableElement(nsAString& aTagName,
getter_AddRefs(tableOrCellElement));
NS_ENSURE_SUCCESS(rv, rv);
NS_NAMED_LITERAL_STRING(tdName, "td");
if (tableOrCellElement) {
// Each cell is in its own selection range,
// so count signals multiple-cell selection
*aSelectedCount = selection->RangeCount();
aTagName = tdName;
aTagName = NS_LITERAL_STRING("td");
} else {
nsCOMPtr<nsINode> anchorNode = selection->GetAnchorNode();
if (NS_WARN_IF(!anchorNode)) {
@ -3176,7 +3271,7 @@ HTMLEditor::GetSelectedOrParentTableElement(nsAString& aTagName,
if (selectedNode) {
if (selectedNode->IsHTMLElement(nsGkAtoms::td)) {
tableOrCellElement = selectedNode->AsElement();
aTagName = tdName;
aTagName = NS_LITERAL_STRING("td");
// Each cell is in its own selection range,
// so count signals multiple-cell selection
*aSelectedCount = selection->RangeCount();
@ -3193,9 +3288,10 @@ HTMLEditor::GetSelectedOrParentTableElement(nsAString& aTagName,
}
if (!tableOrCellElement) {
// Didn't find a table element -- find a cell parent
tableOrCellElement = GetElementOrParentByTagName(tdName, anchorNode);
tableOrCellElement =
GetElementOrParentByTagNameInternal(*nsGkAtoms::td, *anchorNode);
if (tableOrCellElement) {
aTagName = tdName;
aTagName = NS_LITERAL_STRING("td");
}
}
}
@ -3214,8 +3310,20 @@ HTMLEditor::GetSelectedCellsType(Element* aElement,
// Be sure we have a table element
// (if aElement is null, this uses selection's anchor node)
RefPtr<Element> table =
GetElementOrParentByTagName(NS_LITERAL_STRING("table"), aElement);
RefPtr<Element> table;
if (aElement) {
table = GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aElement);
} else {
RefPtr<Selection> selection = GetSelection();
if (NS_WARN_IF(!selection)) {
// If there is no Selection, the following GetTableSize() will return
// nullptr if we set first argument to nullptr. So, let's return error
// in this case.
return NS_ERROR_FAILURE;
}
table =
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
}
// table might be null at this point, but if so GetTableSize will fail.
int32_t rowCount, colCount;

Просмотреть файл

@ -302,24 +302,23 @@ interface nsIHTMLEditor : nsISupports
void align(in AString aAlign);
/**
* Return the input node or a parent matching the given aTagName,
* starting the search at the supplied node.
* An example of use is for testing if a node is in a table cell
* given a selection anchor node.
* GetElementOrParentByTagName() looks for an element node whose name matches
* aTagName from aNode or anchor node of Selection to <body> element.
*
* @param aTagName The HTML tagname
* Special input values:
* Use "href" to get a link node
* (an "A" tag with the "href" attribute set)
* Use "anchor" or "namedanchor" to get a named anchor node
* (an "A" tag with the "name" attribute set)
* Use "list" to get an OL, UL, or DL list node
* Use "td" to get either a TD or TH cell node
*
* @param aNode The node in the document to start the search.
* If it is null, the anchor node of the current selection is used.
* @return NS_EDITOR_ELEMENT_NOT_FOUND if an element is not found
* (passes NS_SUCCEEDED macro)
* @param aTagName The tag name which you want to look for.
* Must not be empty string.
* If "list", the result may be <ul>, <ol> or <dl>
* element.
* If "td", the result may be <td> or <th>.
* If "href", the result may be <a> element
* which has "href" attribute with non-empty value.
* If "anchor" or "namedanchor", the result may be <a>
* which has "name" attribute with non-empty value.
* @param aNode If non-null, this starts to look for the result
* from it. Otherwise, i.e., null, starts from
* anchor node of Selection.
* @return If an element which matches aTagName, returns
* an Element. Otherwise, nullptr.
*/
Element getElementOrParentByTagName(in AString aTagName,
in Node aNode);