static bool planCounter(LayoutObject& object, const AtomicString& identifier, bool& isReset, int& value) { // Real text nodes don't have their own style so they can't have counters. // We can't even look at their styles or we'll see extra resets and increments! if (object.isText() && !object.isBR()) return false; Node* generatingNode = object.generatingNode(); // We must have a generating node or else we cannot have a counter. if (!generatingNode) return false; const ComputedStyle& style = object.styleRef(); switch (style.styleType()) { case NOPSEUDO: // Sometimes nodes have more then one layoutObject. Only the first one gets the counter // LayoutTests/http/tests/css/counter-crash.html if (generatingNode->layoutObject() != &object) return false; break; case BEFORE: case AFTER: break; default: return false; // Counters are forbidden from all other pseudo elements. } const CounterDirectives directives = style.getCounterDirectives(identifier); if (directives.isDefined()) { value = directives.combinedValue(); isReset = directives.isReset(); return true; } if (identifier == "list-item") { if (object.isListItem()) { if (toLayoutListItem(object).hasExplicitValue()) { value = toLayoutListItem(object).explicitValue(); isReset = true; return true; } value = 1; isReset = false; return true; } if (Node* e = object.node()) { if (isHTMLOListElement(*e)) { value = toHTMLOListElement(e)->start(); isReset = true; return true; } if (isHTMLUListElement(*e) || isHTMLMenuElement(*e) || isHTMLDirectoryElement(*e)) { value = 0; isReset = true; return true; } } } return false; }
static bool blockIsRowOfLinks(const LayoutBlock* block) { // A "row of links" is a block for which: // 1. It does not contain non-link text elements longer than 3 characters // 2. It contains a minimum of 3 inline links and all links should // have the same specified font size. // 3. It should not contain <br> elements. // 4. It should contain only inline elements unless they are containers, // children of link elements or children of sub-containers. int linkCount = 0; LayoutObject* layoutObject = block->firstChild(); float matchingFontSize = -1; while (layoutObject) { if (!isPotentialClusterRoot(layoutObject)) { if (layoutObject->isText() && toLayoutText(layoutObject)->text().stripWhiteSpace().length() > 3) return false; if (!layoutObject->isInline() || layoutObject->isBR()) return false; } if (layoutObject->style()->isLink()) { linkCount++; if (matchingFontSize < 0) matchingFontSize = layoutObject->style()->specifiedFontSize(); else if (matchingFontSize != layoutObject->style()->specifiedFontSize()) return false; // Skip traversing descendants of the link. layoutObject = layoutObject->nextInPreOrderAfterChildren(block); continue; } layoutObject = layoutObject->nextInPreOrder(block); } return (linkCount >= 3); }
Position VisiblePosition::rightVisuallyDistinctCandidate() const { Position p = m_deepPosition; if (p.isNull()) return Position(); Position downstreamStart = mostForwardCaretPosition(p); TextDirection primaryDirection = primaryDirectionOf(*p.anchorNode()); while (true) { InlineBoxPosition boxPosition = computeInlineBoxPosition(p, m_affinity, primaryDirection); InlineBox* box = boxPosition.inlineBox; int offset = boxPosition.offsetInBox; if (!box) return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); LayoutObject* layoutObject = &box->layoutObject(); while (true) { if ((layoutObject->isReplaced() || layoutObject->isBR()) && offset == box->caretLeftmostOffset()) return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); if (!layoutObject->node()) { box = box->nextLeafChild(); if (!box) return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); layoutObject = &box->layoutObject(); offset = box->caretLeftmostOffset(); continue; } offset = box->isLeftToRightDirection() ? layoutObject->nextOffset(offset) : layoutObject->previousOffset(offset); int caretMinOffset = box->caretMinOffset(); int caretMaxOffset = box->caretMaxOffset(); if (offset > caretMinOffset && offset < caretMaxOffset) break; if (box->isLeftToRightDirection() ? offset > caretMaxOffset : offset < caretMinOffset) { // Overshot to the right. InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak(); if (!nextBox) { Position positionOnRight = primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); if (positionOnRight.isNull()) return Position(); InlineBox* boxOnRight = computeInlineBoxPosition(positionOnRight, m_affinity, primaryDirection).inlineBox; if (boxOnRight && boxOnRight->root() == box->root()) return Position(); return positionOnRight; } // Reposition at the other logical position corresponding to our edge's visual position and go for another round. box = nextBox; layoutObject = &box->layoutObject(); offset = nextBox->caretLeftmostOffset(); continue; } ASSERT(offset == box->caretRightmostOffset()); unsigned char level = box->bidiLevel(); InlineBox* nextBox = box->nextLeafChild(); if (box->direction() == primaryDirection) { if (!nextBox) { InlineBox* logicalEnd = 0; if (primaryDirection == LTR ? box->root().getLogicalEndBoxWithNode(logicalEnd) : box->root().getLogicalStartBoxWithNode(logicalEnd)) { box = logicalEnd; layoutObject = &box->layoutObject(); offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset(); } break; } if (nextBox->bidiLevel() >= level) break; level = nextBox->bidiLevel(); InlineBox* prevBox = box; do { prevBox = prevBox->prevLeafChild(); } while (prevBox && prevBox->bidiLevel() > level); if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA break; // For example, abc 123 ^ CBA or 123 ^ CBA abc box = nextBox; layoutObject = &box->layoutObject(); offset = box->caretLeftmostOffset(); if (box->direction() == primaryDirection) break; continue; } while (nextBox && !nextBox->layoutObject().node()) nextBox = nextBox->nextLeafChild(); if (nextBox) { box = nextBox; layoutObject = &box->layoutObject(); offset = box->caretLeftmostOffset(); if (box->bidiLevel() > level) { do { nextBox = nextBox->nextLeafChild(); } while (nextBox && nextBox->bidiLevel() > level); if (!nextBox || nextBox->bidiLevel() < level) continue; } } else { // Trailing edge of a secondary run. Set to the leading edge of the entire run. while (true) { while (InlineBox* prevBox = box->prevLeafChild()) { if (prevBox->bidiLevel() < level) break; box = prevBox; } if (box->bidiLevel() == level) break; level = box->bidiLevel(); while (InlineBox* nextBox = box->nextLeafChild()) { if (nextBox->bidiLevel() < level) break; box = nextBox; } if (box->bidiLevel() == level) break; level = box->bidiLevel(); } layoutObject = &box->layoutObject(); offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset(); } break; } p = Position::editingPositionOf(layoutObject->node(), offset); if ((isVisuallyEquivalentCandidate(p) && mostForwardCaretPosition(p) != downstreamStart) || p.atStartOfTree() || p.atEndOfTree()) return p; ASSERT(p != m_deepPosition); } }
Position VisiblePosition::leftVisuallyDistinctCandidate() const { Position p = m_deepPosition; if (p.isNull()) return Position(); Position downstreamStart = p.downstream(); TextDirection primaryDirection = p.primaryDirection(); while (true) { InlineBox* box; int offset; p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset); if (!box) return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition); LayoutObject* layoutObject = &box->layoutObject(); while (true) { if ((layoutObject->isReplaced() || layoutObject->isBR()) && offset == box->caretRightmostOffset()) return box->isLeftToRightDirection() ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition); if (!layoutObject->node()) { box = box->prevLeafChild(); if (!box) return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition); layoutObject = &box->layoutObject(); offset = box->caretRightmostOffset(); continue; } offset = box->isLeftToRightDirection() ? layoutObject->previousOffset(offset) : layoutObject->nextOffset(offset); int caretMinOffset = box->caretMinOffset(); int caretMaxOffset = box->caretMaxOffset(); if (offset > caretMinOffset && offset < caretMaxOffset) break; if (box->isLeftToRightDirection() ? offset < caretMinOffset : offset > caretMaxOffset) { // Overshot to the left. InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak(); if (!prevBox) { Position positionOnLeft = primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition); if (positionOnLeft.isNull()) return Position(); InlineBox* boxOnLeft; int offsetOnLeft; positionOnLeft.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnLeft, offsetOnLeft); if (boxOnLeft && boxOnLeft->root() == box->root()) return Position(); return positionOnLeft; } // Reposition at the other logical position corresponding to our edge's visual position and go for another round. box = prevBox; layoutObject = &box->layoutObject(); offset = prevBox->caretRightmostOffset(); continue; } ASSERT(offset == box->caretLeftmostOffset()); unsigned char level = box->bidiLevel(); InlineBox* prevBox = box->prevLeafChild(); if (box->direction() == primaryDirection) { if (!prevBox) { InlineBox* logicalStart = 0; if (primaryDirection == LTR ? box->root().getLogicalStartBoxWithNode(logicalStart) : box->root().getLogicalEndBoxWithNode(logicalStart)) { box = logicalStart; layoutObject = &box->layoutObject(); offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset(); } break; } if (prevBox->bidiLevel() >= level) break; level = prevBox->bidiLevel(); InlineBox* nextBox = box; do { nextBox = nextBox->nextLeafChild(); } while (nextBox && nextBox->bidiLevel() > level); if (nextBox && nextBox->bidiLevel() == level) break; box = prevBox; layoutObject = &box->layoutObject(); offset = box->caretRightmostOffset(); if (box->direction() == primaryDirection) break; continue; } while (prevBox && !prevBox->layoutObject().node()) prevBox = prevBox->prevLeafChild(); if (prevBox) { box = prevBox; layoutObject = &box->layoutObject(); offset = box->caretRightmostOffset(); if (box->bidiLevel() > level) { do { prevBox = prevBox->prevLeafChild(); } while (prevBox && prevBox->bidiLevel() > level); if (!prevBox || prevBox->bidiLevel() < level) continue; } } else { // Trailing edge of a secondary run. Set to the leading edge of the entire run. while (true) { while (InlineBox* nextBox = box->nextLeafChild()) { if (nextBox->bidiLevel() < level) break; box = nextBox; } if (box->bidiLevel() == level) break; level = box->bidiLevel(); while (InlineBox* prevBox = box->prevLeafChild()) { if (prevBox->bidiLevel() < level) break; box = prevBox; } if (box->bidiLevel() == level) break; level = box->bidiLevel(); } layoutObject = &box->layoutObject(); offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset(); } break; } p = createLegacyEditingPosition(layoutObject->node(), offset); if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree()) return p; ASSERT(p != m_deepPosition); } }