📄 applystylecommand.cpp
字号:
CSSMutableStyleDeclaration::const_iterator end = style->end(); for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) { switch ((*it).id()) { case CSSPropertyColor: removeNodeAttribute(elem, colorAttr); break; case CSSPropertyFontFamily: removeNodeAttribute(elem, faceAttr); break; case CSSPropertyFontSize: removeNodeAttribute(elem, sizeAttr); break; } } if (isEmptyFontTag(elem)) removeNodePreservingChildren(elem);}void ApplyStyleCommand::removeHTMLBidiEmbeddingStyle(CSSMutableStyleDeclaration *style, HTMLElement *elem){ ASSERT(style); ASSERT(elem); if (!elem->hasAttribute(dirAttr)) return; if (!style->getPropertyCSSValue(CSSPropertyUnicodeBidi) && !style->getPropertyCSSValue(CSSPropertyDirection)) return; removeNodeAttribute(elem, dirAttr); // FIXME: should this be isSpanWithoutAttributesOrUnstyleStyleSpan? Need a test. if (isUnstyledStyleSpan(elem)) removeNodePreservingChildren(elem);}void ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclaration* style, HTMLElement* elem){ ASSERT(style); ASSERT(elem); CSSMutableStyleDeclaration* decl = elem->inlineStyleDecl(); if (!decl) return; CSSMutableStyleDeclaration::const_iterator end = style->end(); for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) { CSSPropertyID propertyID = static_cast<CSSPropertyID>((*it).id()); RefPtr<CSSValue> value = decl->getPropertyCSSValue(propertyID); if (value && (propertyID != CSSPropertyWhiteSpace || !isTabSpanNode(elem))) { removeCSSProperty(decl, propertyID); if (propertyID == CSSPropertyUnicodeBidi && !decl->getPropertyValue(CSSPropertyDirection).isEmpty()) removeCSSProperty(decl, CSSPropertyDirection); } } // No need to serialize <foo style=""> if we just removed the last css property if (decl->length() == 0) removeNodeAttribute(elem, styleAttr); if (isSpanWithoutAttributesOrUnstyleStyleSpan(elem)) removeNodePreservingChildren(elem);}static bool hasTextDecorationProperty(Node *node){ if (!node->isElementNode()) return false; RefPtr<CSSValue> value = computedStyle(node)->getPropertyCSSValue(CSSPropertyTextDecoration, DoNotUpdateLayout); return value && !equalIgnoringCase(value->cssText(), "none");}static Node* highestAncestorWithTextDecoration(Node *node){ Node *result = NULL; for (Node *n = node; n; n = n->parentNode()) { if (hasTextDecorationProperty(n)) result = n; } return result;}PassRefPtr<CSSMutableStyleDeclaration> ApplyStyleCommand::extractTextDecorationStyle(Node* node){ ASSERT(node); ASSERT(node->isElementNode()); // non-html elements not handled yet if (!node->isHTMLElement()) return 0; HTMLElement *element = static_cast<HTMLElement *>(node); RefPtr<CSSMutableStyleDeclaration> style = element->inlineStyleDecl(); if (!style) return 0; int properties[1] = { CSSPropertyTextDecoration }; RefPtr<CSSMutableStyleDeclaration> textDecorationStyle = style->copyPropertiesInSet(properties, 1); RefPtr<CSSValue> property = style->getPropertyCSSValue(CSSPropertyTextDecoration); if (property && !equalIgnoringCase(property->cssText(), "none")) removeCSSProperty(style.get(), CSSPropertyTextDecoration); return textDecorationStyle.release();}PassRefPtr<CSSMutableStyleDeclaration> ApplyStyleCommand::extractAndNegateTextDecorationStyle(Node* node){ ASSERT(node); ASSERT(node->isElementNode()); // non-html elements not handled yet if (!node->isHTMLElement()) return 0; RefPtr<CSSComputedStyleDeclaration> nodeStyle = computedStyle(node); ASSERT(nodeStyle); int properties[1] = { CSSPropertyTextDecoration }; RefPtr<CSSMutableStyleDeclaration> textDecorationStyle = nodeStyle->copyPropertiesInSet(properties, 1); RefPtr<CSSValue> property = nodeStyle->getPropertyCSSValue(CSSPropertyTextDecoration); if (property && !equalIgnoringCase(property->cssText(), "none")) { RefPtr<CSSMutableStyleDeclaration> newStyle = textDecorationStyle->copy(); newStyle->setProperty(CSSPropertyTextDecoration, "none"); applyTextDecorationStyle(node, newStyle.get()); } return textDecorationStyle.release();}void ApplyStyleCommand::applyTextDecorationStyle(Node *node, CSSMutableStyleDeclaration *style){ ASSERT(node); if (!style || !style->cssText().length()) return; if (node->isTextNode()) { RefPtr<HTMLElement> styleSpan = createStyleSpanElement(document()); surroundNodeRangeWithElement(node, node, styleSpan.get()); node = styleSpan.get(); } if (!node->isElementNode()) return; HTMLElement *element = static_cast<HTMLElement *>(node); StyleChange styleChange(style, Position(element, 0)); if (styleChange.cssStyle().length() > 0) { String cssText = styleChange.cssStyle(); CSSMutableStyleDeclaration *decl = element->inlineStyleDecl(); if (decl) cssText += decl->cssText(); setNodeAttribute(element, styleAttr, cssText); }}void ApplyStyleCommand::pushDownTextDecorationStyleAroundNode(Node* node, bool force){ Node *highestAncestor = highestAncestorWithTextDecoration(node); if (highestAncestor) { Node *nextCurrent; Node *nextChild; for (Node *current = highestAncestor; current != node; current = nextCurrent) { ASSERT(current); nextCurrent = NULL; RefPtr<CSSMutableStyleDeclaration> decoration = force ? extractAndNegateTextDecorationStyle(current) : extractTextDecorationStyle(current); for (Node *child = current->firstChild(); child; child = nextChild) { nextChild = child->nextSibling(); if (node == child) { nextCurrent = child; } else if (node->isDescendantOf(child)) { applyTextDecorationStyle(child, decoration.get()); nextCurrent = child; } else { applyTextDecorationStyle(child, decoration.get()); } } } }}void ApplyStyleCommand::pushDownTextDecorationStyleAtBoundaries(const Position &start, const Position &end){ // We need to work in two passes. First we push down any inline // styles that set text decoration. Then we look for any remaining // styles (caused by stylesheets) and explicitly negate text // decoration while pushing down. pushDownTextDecorationStyleAroundNode(start.node(), false); updateLayout(); pushDownTextDecorationStyleAroundNode(start.node(), true); pushDownTextDecorationStyleAroundNode(end.node(), false); updateLayout(); pushDownTextDecorationStyleAroundNode(end.node(), true);}static int maxRangeOffset(Node *n){ if (n->offsetInCharacters()) return n->maxCharacterOffset(); if (n->isElementNode()) return n->childNodeCount(); return 1;}void ApplyStyleCommand::removeInlineStyle(PassRefPtr<CSSMutableStyleDeclaration> style, const Position &start, const Position &end){ ASSERT(start.isNotNull()); ASSERT(end.isNotNull()); ASSERT(start.node()->inDocument()); ASSERT(end.node()->inDocument()); ASSERT(Range::compareBoundaryPoints(start, end) <= 0); RefPtr<CSSValue> textDecorationSpecialProperty = style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect); if (textDecorationSpecialProperty) { pushDownTextDecorationStyleAtBoundaries(start.downstream(), end.upstream()); style = style->copy(); style->setProperty(CSSPropertyTextDecoration, textDecorationSpecialProperty->cssText(), style->getPropertyPriority(CSSPropertyWebkitTextDecorationsInEffect)); } // The s and e variables store the positions used to set the ending selection after style removal // takes place. This will help callers to recognize when either the start node or the end node // are removed from the document during the work of this function. Position s = start; Position e = end; Node *node = start.node(); while (node) { Node *next = node->traverseNextNode(); if (node->isHTMLElement() && nodeFullySelected(node, start, end)) { HTMLElement *elem = static_cast<HTMLElement *>(node); Node *prev = elem->traversePreviousNodePostOrder(); Node *next = elem->traverseNextNode(); if (m_styledInlineElement && elem->hasTagName(m_styledInlineElement->tagQName())) removeNodePreservingChildren(elem); if (isHTMLStyleNode(style.get(), elem)) removeHTMLStyleNode(elem); else { removeHTMLFontStyle(style.get(), elem); removeHTMLBidiEmbeddingStyle(style.get(), elem); removeCSSStyle(style.get(), elem); } if (!elem->inDocument()) { if (s.node() == elem) { // Since elem must have been fully selected, and it is at the start // of the selection, it is clear we can set the new s offset to 0. ASSERT(s.offset() <= caretMinOffset(s.node())); s = Position(next, 0); } if (e.node() == elem) { // Since elem must have been fully selected, and it is at the end // of the selection, it is clear we can set the new e offset to // the max range offset of prev. ASSERT(e.offset() >= maxRangeOffset(e.node())); e = Position(prev, maxRangeOffset(prev)); } } } if (node == end.node()) break; node = next; } ASSERT(s.node()->inDocument()); ASSERT(e.node()->inDocument()); updateStartEnd(s, e);}bool ApplyStyleCommand::nodeFullySelected(Node *node, const Position &start, const Position &end) const{ ASSERT(node); ASSERT(node->isElementNode()); Position pos = Position(node, node->childNodeCount()).upstream(); return Range::compareBoundaryPoints(node, 0, start.node(), start.offset()) >= 0 && Range::compareBoundaryPoints(pos, end) <= 0;}bool ApplyStyleCommand::nodeFullyUnselected(Node *node, const Position &start, const Position &end) const{ ASSERT(node); ASSERT(node->isElementNode()); Position pos = Position(node, node->childNodeCount()).upstream(); bool isFullyBeforeStart = Range::compareBoundaryPoints(pos, start) < 0; bool isFullyAfterEnd = Range::compareBoundaryPoints(node, 0, end.node(), end.offset()) > 0; return isFullyBeforeStart || isFullyAfterEnd;}bool ApplyStyleCommand::splitTextAtStartIfNeeded(const Position &start, const Position &end){ if (start.node()->isTextNode() && start.offset() > caretMinOffset(start.node()) && start.offset() < caretMaxOffset(start.node())) { int endOffsetAdjustment = start.node() == end.node() ? start.offset() : 0; Text *text = static_cast<Text *>(start.node()); splitTextNode(text, start.offset()); updateStartEnd(Position(start.node(), 0), Position(end.node(), end.offset() - endOffsetAdjustment)); return true; } return false;}bool ApplyStyleCommand::splitTextAtEndIfNeeded(const Position &start, const Position &end){ if (end.node()->isTextNode() && end.offset() > caretMinOffset(end.node()) && end.offset() < caretMaxOffset(end.node())) { Text *text = static_cast<Text *>(end.node()); splitTextNode(text, end.offset());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -