📄 applystylecommand.cpp
字号:
Node *prevNode = text->previousSibling(); ASSERT(prevNode); Node *startNode = start.node() == end.node() ? prevNode : start.node(); ASSERT(startNode); updateStartEnd(Position(startNode, start.offset()), Position(prevNode, caretMaxOffset(prevNode))); return true; } return false;}bool ApplyStyleCommand::splitTextElementAtStartIfNeeded(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()); splitTextNodeContainingElement(text, start.offset()); updateStartEnd(Position(start.node()->parentNode(), start.node()->nodeIndex()), Position(end.node(), end.offset() - endOffsetAdjustment)); return true; } return false;}bool ApplyStyleCommand::splitTextElementAtEndIfNeeded(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()); splitTextNodeContainingElement(text, end.offset()); Node *prevNode = text->parent()->previousSibling()->lastChild(); ASSERT(prevNode); Node *startNode = start.node() == end.node() ? prevNode : start.node(); ASSERT(startNode); updateStartEnd(Position(startNode, start.offset()), Position(prevNode->parent(), prevNode->nodeIndex() + 1)); return true; } return false;}static bool areIdenticalElements(Node *first, Node *second){ // check that tag name and all attribute names and values are identical if (!first->isElementNode()) return false; if (!second->isElementNode()) return false; Element *firstElement = static_cast<Element *>(first); Element *secondElement = static_cast<Element *>(second); if (!firstElement->tagQName().matches(secondElement->tagQName())) return false; NamedAttrMap *firstMap = firstElement->attributes(); NamedAttrMap *secondMap = secondElement->attributes(); unsigned firstLength = firstMap->length(); if (firstLength != secondMap->length()) return false; for (unsigned i = 0; i < firstLength; i++) { Attribute *attribute = firstMap->attributeItem(i); Attribute *secondAttribute = secondMap->getAttributeItem(attribute->name()); if (!secondAttribute || attribute->value() != secondAttribute->value()) return false; } return true;}bool ApplyStyleCommand::mergeStartWithPreviousIfIdentical(const Position &start, const Position &end){ Node *startNode = start.node(); int startOffset = start.offset(); if (isAtomicNode(start.node())) { if (start.offset() != 0) return false; // note: prior siblings could be unrendered elements. it's silly to miss the // merge opportunity just for that. if (start.node()->previousSibling()) return false; startNode = start.node()->parent(); startOffset = 0; } if (!startNode->isElementNode()) return false; if (startOffset != 0) return false; Node *previousSibling = startNode->previousSibling(); if (previousSibling && areIdenticalElements(startNode, previousSibling)) { Element *previousElement = static_cast<Element *>(previousSibling); Element *element = static_cast<Element *>(startNode); Node *startChild = element->firstChild(); ASSERT(startChild); mergeIdenticalElements(previousElement, element); int startOffsetAdjustment = startChild->nodeIndex(); int endOffsetAdjustment = startNode == end.node() ? startOffsetAdjustment : 0; updateStartEnd(Position(startNode, startOffsetAdjustment), Position(end.node(), end.offset() + endOffsetAdjustment)); return true; } return false;}bool ApplyStyleCommand::mergeEndWithNextIfIdentical(const Position &start, const Position &end){ Node *endNode = end.node(); int endOffset = end.offset(); if (isAtomicNode(endNode)) { if (endOffset < caretMaxOffset(endNode)) return false; unsigned parentLastOffset = end.node()->parent()->childNodes()->length() - 1; if (end.node()->nextSibling()) return false; endNode = end.node()->parent(); endOffset = parentLastOffset; } if (!endNode->isElementNode() || endNode->hasTagName(brTag)) return false; Node *nextSibling = endNode->nextSibling(); if (nextSibling && areIdenticalElements(endNode, nextSibling)) { Element *nextElement = static_cast<Element *>(nextSibling); Element *element = static_cast<Element *>(endNode); Node *nextChild = nextElement->firstChild(); mergeIdenticalElements(element, nextElement); Node *startNode = start.node() == endNode ? nextElement : start.node(); ASSERT(startNode); int endOffset = nextChild ? nextChild->nodeIndex() : nextElement->childNodes()->length(); updateStartEnd(Position(startNode, start.offset()), Position(nextElement, endOffset)); return true; } return false;}void ApplyStyleCommand::surroundNodeRangeWithElement(Node* startNode, Node* endNode, PassRefPtr<Element> elementToInsert){ ASSERT(startNode); ASSERT(endNode); ASSERT(elementToInsert); RefPtr<Element> element = elementToInsert; insertNodeBefore(element, startNode); Node* node = startNode; while (1) { Node* next = node->traverseNextNode(); if (node->childNodeCount() == 0 && node->renderer() && node->renderer()->isInline()) { removeNode(node); appendNode(node, element); } if (node == endNode) break; node = next; } // FIXME: We should probably call updateStartEnd if the start or end was in the node // range so that the endingSelection() is canonicalized. See the comments at the end of // VisibleSelection::validate().}void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange, HTMLElement* block){ // Do not check for legacy styles here. Those styles, like <B> and <I>, only apply for // inline content. if (!block) return; String cssText = styleChange.cssStyle(); CSSMutableStyleDeclaration* decl = block->inlineStyleDecl(); if (decl) cssText += decl->cssText(); setNodeAttribute(block, styleAttr, cssText);}static bool fontColorChangesComputedStyle(RenderStyle* computedStyle, StyleChange styleChange){ if (styleChange.applyFontColor()) { if (Color(styleChange.fontColor()) != computedStyle->color()) return true; } return false;}static bool fontSizeChangesComputedStyle(RenderStyle* computedStyle, StyleChange styleChange){ if (styleChange.applyFontSize()) { if (styleChange.fontSize().toInt() != computedStyle->fontSize()) return true; } return false;}static bool fontFaceChangesComputedStyle(RenderStyle* computedStyle, StyleChange styleChange){ if (styleChange.applyFontFace()) { if (computedStyle->fontDescription().family().family().string() != styleChange.fontFace()) return true; } return false;}void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style, Node *startNode, Node *endNode){ if (m_removeOnly) return; StyleChange styleChange(style, Position(startNode, 0)); // // Font tags need to go outside of CSS so that CSS font sizes override leagcy font sizes. // if (styleChange.applyFontColor() || styleChange.applyFontFace() || styleChange.applyFontSize()) { RefPtr<Element> fontElement = createFontElement(document()); RenderStyle* computedStyle = startNode->computedStyle(); // We only want to insert a font element if it will end up changing the style of the // text somehow. Otherwise it will be a garbage node that will create problems for us // most notably when we apply a blockquote style for a message reply. if (fontColorChangesComputedStyle(computedStyle, styleChange) || fontFaceChangesComputedStyle(computedStyle, styleChange) || fontSizeChangesComputedStyle(computedStyle, styleChange)) { if (styleChange.applyFontColor()) fontElement->setAttribute(colorAttr, styleChange.fontColor()); if (styleChange.applyFontFace()) fontElement->setAttribute(faceAttr, styleChange.fontFace()); if (styleChange.applyFontSize()) fontElement->setAttribute(sizeAttr, styleChange.fontSize()); surroundNodeRangeWithElement(startNode, endNode, fontElement.get()); } } if (styleChange.cssStyle().length() > 0) { RefPtr<Element> styleElement = createStyleSpanElement(document()); styleElement->setAttribute(styleAttr, styleChange.cssStyle()); surroundNodeRangeWithElement(startNode, endNode, styleElement.release()); } if (styleChange.applyBold()) surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(document(), bTag)); if (styleChange.applyItalic()) surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(document(), iTag)); if (styleChange.applySubscript()) surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(document(), subTag)); else if (styleChange.applySuperscript()) surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(document(), supTag)); if (m_styledInlineElement) surroundNodeRangeWithElement(startNode, endNode, m_styledInlineElement->cloneElement());}float ApplyStyleCommand::computedFontSize(const Node *node){ if (!node) return 0; Position pos(const_cast<Node *>(node), 0); RefPtr<CSSComputedStyleDeclaration> computedStyle = pos.computedStyle(); if (!computedStyle) return 0; RefPtr<CSSPrimitiveValue> value = static_pointer_cast<CSSPrimitiveValue>(computedStyle->getPropertyCSSValue(CSSPropertyFontSize)); if (!value) return 0; return value->getFloatValue(CSSPrimitiveValue::CSS_PX);}void ApplyStyleCommand::joinChildTextNodes(Node *node, const Position &start, const Position &end){ if (!node) return; Position newStart = start; Position newEnd = end; Node *child = node->firstChild(); while (child) { Node *next = child->nextSibling(); if (child->isTextNode() && next && next->isTextNode()) { Text *childText = static_cast<Text *>(child); Text *nextText = static_cast<Text *>(next); if (next == start.node()) newStart = Position(childText, childText->length() + start.offset()); if (next == end.node()) newEnd = Position(childText, childText->length() + end.offset()); String textToMove = nextText->data(); insertTextIntoNode(childText, childText->length(), textToMove); removeNode(next); // don't move child node pointer. it may want to merge with more text nodes. } else { child = child->nextSibling(); } } updateStartEnd(newStart, newEnd);}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -