?? htmlediting.cpp
字號:
return;
}
// Get the adjustment amount out of the style.
CSSValueImpl *value = style->getPropertyCSSValue(CSS_PROP__KHTML_FONT_SIZE_DELTA);
if (!value)
return;
value->ref();
float adjustment = NoFontDelta;
if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) {
CSSPrimitiveValueImpl *primitiveValue = static_cast<CSSPrimitiveValueImpl *>(value);
if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_PX) {
// Only PX handled now. If we handle more types in the future, perhaps
// a switch statement here would be more appropriate.
adjustment = primitiveValue->getFloatValue(CSSPrimitiveValue::CSS_PX);
}
}
style->removeProperty(CSS_PROP__KHTML_FONT_SIZE_DELTA);
value->deref();
if (adjustment == NoFontDelta)
return;
// Adjust to the positions we want to use for applying style.
Selection selection = endingSelection();
Position start(selection.start().downstream(StayInBlock));
Position end(selection.end().upstream(StayInBlock));
if (RangeImpl::compareBoundaryPoints(end, start) < 0) {
Position swap = start;
start = end;
end = swap;
}
// Join up any adjacent text nodes.
if (start.node()->isTextNode()) {
joinChildTextNodes(start.node()->parentNode(), start, end);
selection = endingSelection();
start = selection.start();
end = selection.end();
}
if (end.node()->isTextNode() && start.node()->parentNode() != end.node()->parentNode()) {
joinChildTextNodes(end.node()->parentNode(), start, end);
selection = endingSelection();
start = selection.start();
end = selection.end();
}
// Split the start text nodes if needed to apply style.
bool splitStart = splitTextAtStartIfNeeded(start, end);
if (splitStart) {
start = endingSelection().start();
end = endingSelection().end();
}
bool splitEnd = splitTextAtEndIfNeeded(start, end);
if (splitEnd) {
start = endingSelection().start();
end = endingSelection().end();
}
NodeImpl *beyondEnd = end.node()->traverseNextNode(); // Calculate loop end point.
start = start.upstream(StayInBlock); // Move upstream to ensure we do not add redundant spans.
NodeImpl *startNode = start.node();
if (startNode->isTextNode() && start.offset() >= startNode->caretMaxOffset()) // Move out of text node if range does not include its characters.
startNode = startNode->traverseNextNode();
// Store away font size before making any changes to the document.
// This ensures that changes to one node won't effect another.
QMap<const NodeImpl *,float> startingFontSizes;
for (const NodeImpl *node = startNode; node != beyondEnd; node = node->traverseNextNode())
startingFontSizes.insert(node, computedFontSize(node));
// These spans were added by us. If empty after font size changes, they can be removed.
QPtrList<NodeImpl> emptySpans;
NodeImpl *lastStyledNode = 0;
for (NodeImpl *node = startNode; node != beyondEnd; node = node->traverseNextNode()) {
HTMLElementImpl *elem = 0;
if (node->isHTMLElement()) {
// Only work on fully selected nodes.
if (!nodeFullySelected(node, start, end))
continue;
elem = static_cast<HTMLElementImpl *>(node);
}
else if (node->isTextNode() && node->parentNode() != lastStyledNode) {
// Last styled node was not parent node of this text node, but we wish to style this
// text node. To make this possible, add a style span to surround this text node.
elem = static_cast<HTMLElementImpl *>(createStyleSpanElement(document()));
insertNodeBefore(elem, node);
surroundNodeRangeWithElement(node, node, elem);
}
else {
// Only handle HTML elements and text nodes.
continue;
}
lastStyledNode = node;
CSSMutableStyleDeclarationImpl *inlineStyleDecl = elem->getInlineStyleDecl();
float currentFontSize = computedFontSize(node);
float desiredFontSize = kMax(MinimumFontSize, startingFontSizes[node] + adjustment);
if (inlineStyleDecl->getPropertyCSSValue(CSS_PROP_FONT_SIZE)) {
inlineStyleDecl->removeProperty(CSS_PROP_FONT_SIZE, true);
currentFontSize = computedFontSize(node);
}
if (currentFontSize != desiredFontSize) {
QString desiredFontSizeString = QString::number(desiredFontSize);
desiredFontSizeString += "px";
inlineStyleDecl->setProperty(CSS_PROP_FONT_SIZE, desiredFontSizeString, false, false);
setNodeAttribute(elem, ATTR_STYLE, inlineStyleDecl->cssText());
}
if (inlineStyleDecl->length() == 0) {
removeNodeAttribute(elem, ATTR_STYLE);
if (isEmptyStyleSpan(elem))
emptySpans.append(elem);
}
}
for (QPtrListIterator<NodeImpl> it(emptySpans); it.current(); ++it)
removeNodePreservingChildren(it.current());
}
#undef NoFontDelta
#undef MinimumFontSize
void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclarationImpl *style)
{
// adjust to the positions we want to use for applying style
Position start(endingSelection().start().downstream(StayInBlock).equivalentRangeCompliantPosition());
Position end(endingSelection().end().upstream(StayInBlock));
if (RangeImpl::compareBoundaryPoints(end, start) < 0) {
Position swap = start;
start = end;
end = swap;
}
// update document layout once before removing styles
// so that we avoid the expense of updating before each and every call
// to check a computed style
document()->updateLayout();
// split the start node and containing element if the selection starts inside of it
bool splitStart = splitTextElementAtStartIfNeeded(start, end);
if (splitStart) {
start = endingSelection().start();
end = endingSelection().end();
}
// split the end node and containing element if the selection ends inside of it
bool splitEnd = splitTextElementAtEndIfNeeded(start, end);
start = endingSelection().start();
end = endingSelection().end();
// Remove style from the selection.
// Use the upstream position of the start for removing style.
// This will ensure we remove all traces of the relevant styles from the selection
// and prevent us from adding redundant ones, as described in:
// <rdar://problem/3724344> Bolding and unbolding creates extraneous tags
removeInlineStyle(style, start.upstream(StayInBlock), end);
start = endingSelection().start();
end = endingSelection().end();
if (splitStart) {
bool mergedStart = mergeStartWithPreviousIfIdentical(start, end);
if (mergedStart) {
start = endingSelection().start();
end = endingSelection().end();
}
}
if (splitEnd) {
mergeEndWithNextIfIdentical(start, end);
start = endingSelection().start();
end = endingSelection().end();
}
// update document layout once before running the rest of the function
// so that we avoid the expense of updating before each and every call
// to check a computed style
document()->updateLayout();
if (start.node() == end.node()) {
// simple case...start and end are the same node
addInlineStyleIfNeeded(style, start.node(), end.node());
}
else {
NodeImpl *node = start.node();
if (start.offset() >= start.node()->caretMaxOffset())
node = node->traverseNextNode();
while (1) {
if (node->childNodeCount() == 0 && node->renderer() && node->renderer()->isInline()) {
NodeImpl *runStart = node;
while (1) {
NodeImpl *next = node->traverseNextNode();
// Break if node is the end node, or if the next node does not fit in with
// the current group.
if (node == end.node() ||
runStart->parentNode() != next->parentNode() ||
(next->isHTMLElement() && next->id() != ID_BR) ||
(next->renderer() && !next->renderer()->isInline()))
break;
node = next;
}
// Now apply style to the run we found.
addInlineStyleIfNeeded(style, runStart, node);
}
if (node == end.node())
break;
node = node->traverseNextNode();
}
}
if (splitStart || splitEnd) {
cleanUpEmptyStyleSpans(start, end);
}
}
//------------------------------------------------------------------------------------------
// ApplyStyleCommand: style-removal helpers
bool ApplyStyleCommand::isHTMLStyleNode(CSSMutableStyleDeclarationImpl *style, HTMLElementImpl *elem)
{
QValueListConstIterator<CSSProperty> end;
for (QValueListConstIterator<CSSProperty> it = style->valuesIterator(); it != end; ++it) {
switch ((*it).id()) {
case CSS_PROP_FONT_WEIGHT:
if (elem->id() == ID_B)
return true;
break;
case CSS_PROP_FONT_STYLE:
if (elem->id() == ID_I)
return true;
}
}
return false;
}
void ApplyStyleCommand::removeHTMLStyleNode(HTMLElementImpl *elem)
{
// This node can be removed.
// EDIT FIXME: This does not handle the case where the node
// has attributes. But how often do people add attributes to <B> tags?
// Not so often I think.
ASSERT(elem);
removeNodePreservingChildren(elem);
}
void ApplyStyleCommand::removeHTMLFontStyle(CSSMutableStyleDeclarationImpl *style, HTMLElementImpl *elem)
{
ASSERT(style);
ASSERT(elem);
if (elem->id() != ID_FONT)
return;
int exceptionCode = 0;
QValueListConstIterator<CSSProperty> end;
for (QValueListConstIterator<CSSProperty> it = style->valuesIterator(); it != end; ++it) {
switch ((*it).id()) {
case CSS_PROP_COLOR:
elem->removeAttribute(ATTR_COLOR, exceptionCode);
ASSERT(exceptionCode == 0);
break;
case CSS_PROP_FONT_FAMILY:
elem->removeAttribute(ATTR_FACE, exceptionCode);
ASSERT(exceptionCode == 0);
break;
case CSS_PROP_FONT_SIZE:
elem->removeAttribute(ATTR_SIZE, exceptionCode);
ASSERT(exceptionCode == 0);
break;
}
}
if (isEmptyFontTag(elem))
removeNodePreservingChildren(elem);
}
void ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclarationImpl *style, HTMLElementImpl *elem)
{
ASSERT(style);
ASSERT(elem);
CSSMutableStyleDeclarationImpl *decl = elem->inlineStyleDecl();
if (!decl)
return;
QValueListConstIterator<CSSProperty> end;
for (QValueListConstIterator<CSSProperty> it = style->valuesIterator(); it != end; ++it) {
int propertyID = (*it).id();
CSSValueImpl *value = decl->getPropertyCSSValue(propertyID);
if (value) {
value->ref();
removeCSSProperty(decl, propertyID);
value->deref();
}
}
if (isEmptyStyleSpan(elem))
removeNodePreservingChildren(elem);
}
void ApplyStyleCommand::removeBlockStyle(CSSMutableStyleDeclarationImpl *style, const Position &start, const Position &end)
{
ASSERT(start.isNotNull());
ASSERT(end.isNotNull());
ASSERT(start.node()->inDocument());
ASSERT(end.node()->inDocument());
ASSERT(RangeImpl::compareBoundaryPoints(start, end) <= 0);
}
static bool hasTextDecorationProperty(NodeImpl *node)
{
if (!node->isElementNode())
return false;
ElementImpl *element = static_cast<ElementImpl *>(node);
CSSComputedStyleDeclarationImpl style(element);
CSSValueImpl *value = style.getPropertyCSSValue(CSS_PROP_TEXT_DECORATION, DoNotUpdateLayout);
if (value) {
value->ref();
DOMString valueText(value->cssText());
value->deref();
if (strcasecmp(valueText,"none") != 0)
return true;
}
return false;
}
static NodeImpl* highestAncestorWithTextDecoration(NodeImpl *node)
{
NodeImpl *result = NULL;
for (NodeImpl *n = node; n; n = n->parentNode()) {
if (hasTextDecorationProperty(n))
result = n;
}
return result;
}
CSSMutableStyleDeclarationImpl *ApplyStyleCommand::extractTextDecorationStyle(NodeImpl *node)
{
ASSERT(node);
ASSERT(node->isElementNode());
// non-html elements not handled yet
if (!node->isHTMLElement())
return 0;
HTMLElementImpl *element = static_cast<HTMLElementImpl *>(node);
CSSMutableStyleDeclarationImpl *style = element->inlineStyleDecl();
if (!style)
return 0;
style->ref();
int properties[1] = { CSS_PROP_TEXT_DECORATION };
CSSMutableStyleDeclarationImpl *textDecorationStyle = style->copyPropertiesInSet(properties, 1);
CSSValueImpl *property = style->getPropertyCSSValue(CSS_PROP_TEXT_DECORATION);
if (property && strcasecmp(property->cssText(), "none") != 0) {
removeCSSProperty(style, CSS_PROP_TEXT_DECORATION);
}
style->deref();
return textDecorationStyle;
}
CSSMutableStyleDeclarationImpl *ApplyStyleCommand::extractAndNegateTextDecorationStyle(NodeImpl *node)
{
ASSERT(node);
ASSERT(node->isElementNode());
// non-html elements not handled yet
if (!node->isHTMLElement())
return 0;
HTMLElementImpl *element = static_cast<HTMLElementImpl *>(node);
CSSComputedStyleDeclarationImpl *computedStyle = new CSSComputedStyleDeclarationImpl(element);
ASSERT(computedStyle);
computedStyle->ref();
int properties[1] = { CSS_PROP_TEXT_DECORATION };
CSSMutableStyleDeclarationImpl *textDecorationStyle = computedStyle->copyPropertiesInSet(properties, 1);
CSSValueImpl *property = computedStyle->getPropertyCSSValue(CSS_PROP_TEXT_DECORATION);
if (property && strcasecmp(property->cssText(), "none") != 0) {
property->ref();
CSSMutableStyleDecla
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -