📄 rendertreeastext.cpp
字号:
/* * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "RenderTreeAsText.h"#include "CharacterNames.h"#include "Document.h"#include "Frame.h"#include "FrameView.h"#include "HTMLElement.h"#include "HTMLNames.h"#include "InlineTextBox.h"#include "RenderBR.h"#include "RenderInline.h"#include "RenderListMarker.h"#include "RenderTableCell.h"#include "RenderView.h"#include "RenderWidget.h"#include "SelectionController.h"#include "TextStream.h"#include <wtf/Vector.h>#if ENABLE(SVG)#include "RenderSVGRoot.h"#include "RenderSVGContainer.h"#include "RenderSVGInlineText.h"#include "RenderSVGText.h"#include "SVGRenderTreeAsText.h"#endifnamespace WebCore {using namespace HTMLNames;static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const IntRect& paintDirtyRect, int indent = 0);#if !ENABLE(SVG)static TextStream &operator<<(TextStream& ts, const IntRect& r){ return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height();}#endifstatic void writeIndent(TextStream& ts, int indent){ for (int i = 0; i != indent; ++i) ts << " ";}static void printBorderStyle(TextStream& ts, const EBorderStyle borderStyle){ switch (borderStyle) { case BNONE: ts << "none"; break; case BHIDDEN: ts << "hidden"; break; case INSET: ts << "inset"; break; case GROOVE: ts << "groove"; break; case RIDGE: ts << "ridge"; break; case OUTSET: ts << "outset"; break; case DOTTED: ts << "dotted"; break; case DASHED: ts << "dashed"; break; case SOLID: ts << "solid"; break; case DOUBLE: ts << "double"; break; } ts << " ";}static String getTagName(Node* n){ if (n->isDocumentNode()) return ""; if (n->isCommentNode()) return "COMMENT"; return n->nodeName();}static bool isEmptyOrUnstyledAppleStyleSpan(const Node* node){ if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag)) return false; const HTMLElement* elem = static_cast<const HTMLElement*>(node); if (elem->getAttribute(classAttr) != "Apple-style-span") return false; if (!node->hasChildNodes()) return true; CSSMutableStyleDeclaration* inlineStyleDecl = elem->inlineStyleDecl(); return (!inlineStyleDecl || inlineStyleDecl->length() == 0);}String quoteAndEscapeNonPrintables(const String& s){ Vector<UChar> result; result.append('"'); for (unsigned i = 0; i != s.length(); ++i) { UChar c = s[i]; if (c == '\\') { result.append('\\'); result.append('\\'); } else if (c == '"') { result.append('\\'); result.append('"'); } else if (c == '\n' || c == noBreakSpace) result.append(' '); else { if (c >= 0x20 && c < 0x7F) result.append(c); else { unsigned u = c; String hex = String::format("\\x{%X}", u); unsigned len = hex.length(); for (unsigned i = 0; i < len; ++i) result.append(hex[i]); } } } result.append('"'); return String::adopt(result);}static TextStream &operator<<(TextStream& ts, const RenderObject& o){ ts << o.renderName(); if (o.style() && o.style()->zIndex()) ts << " zI: " << o.style()->zIndex(); if (o.node()) { String tagName = getTagName(o.node()); if (!tagName.isEmpty()) { ts << " {" << tagName << "}"; // flag empty or unstyled AppleStyleSpan because we never // want to leave them in the DOM if (isEmptyOrUnstyledAppleStyleSpan(o.node())) ts << " *empty or unstyled AppleStyleSpan*"; } } bool adjustForTableCells = o.containingBlock()->isTableCell(); IntRect r; if (o.isText()) { // FIXME: Would be better to dump the bounding box x and y rather than the first run's x and y, but that would involve updating // many test results. const RenderText& text = *toRenderText(&o); IntRect linesBox = text.linesBoundingBox(); r = IntRect(text.firstRunX(), text.firstRunY(), linesBox.width(), linesBox.height()); if (adjustForTableCells && !text.firstTextBox()) adjustForTableCells = false; } else if (o.isRenderInline()) { // FIXME: Would be better not to just dump 0, 0 as the x and y here. const RenderInline& inlineFlow = *toRenderInline(&o); r = IntRect(0, 0, inlineFlow.linesBoundingBox().width(), inlineFlow.linesBoundingBox().height()); adjustForTableCells = false; } else if (o.isTableCell()) { // FIXME: Deliberately dump the "inner" box of table cells, since that is what current results reflect. We'd like // to clean up the results to dump both the outer box and the intrinsic padding so that both bits of information are // captured by the results. const RenderTableCell& cell = static_cast<const RenderTableCell&>(o); r = IntRect(cell.x(), cell.y() + cell.intrinsicPaddingTop(), cell.width(), cell.height() - cell.intrinsicPaddingTop() - cell.intrinsicPaddingBottom()); } else if (o.isBox()) r = toRenderBox(&o)->frameRect(); // FIXME: Temporary in order to ensure compatibility with existing layout test results. if (adjustForTableCells) r.move(0, -static_cast<RenderTableCell*>(o.containingBlock())->intrinsicPaddingTop()); ts << " " << r; if (!(o.isText() && !o.isBR())) { if (o.parent() && (o.parent()->style()->color() != o.style()->color())) ts << " [color=" << o.style()->color().name() << "]"; if (o.parent() && (o.parent()->style()->backgroundColor() != o.style()->backgroundColor()) && o.style()->backgroundColor().isValid() && o.style()->backgroundColor().rgb()) // Do not dump invalid or transparent backgrounds, since that is the default. ts << " [bgcolor=" << o.style()->backgroundColor().name() << "]"; if (o.parent() && (o.parent()->style()->textFillColor() != o.style()->textFillColor()) && o.style()->textFillColor().isValid() && o.style()->textFillColor() != o.style()->color() && o.style()->textFillColor().rgb()) ts << " [textFillColor=" << o.style()->textFillColor().name() << "]"; if (o.parent() && (o.parent()->style()->textStrokeColor() != o.style()->textStrokeColor()) && o.style()->textStrokeColor().isValid() && o.style()->textStrokeColor() != o.style()->color() && o.style()->textStrokeColor().rgb()) ts << " [textStrokeColor=" << o.style()->textStrokeColor().name() << "]"; if (o.parent() && (o.parent()->style()->textStrokeWidth() != o.style()->textStrokeWidth()) && o.style()->textStrokeWidth() > 0) ts << " [textStrokeWidth=" << o.style()->textStrokeWidth() << "]"; if (!o.isBoxModelObject()) return ts; const RenderBoxModelObject& box = *toRenderBoxModelObject(&o); if (box.borderTop() || box.borderRight() || box.borderBottom() || box.borderLeft()) { ts << " [border:"; BorderValue prevBorder; if (o.style()->borderTop() != prevBorder) { prevBorder = o.style()->borderTop(); if (!box.borderTop()) ts << " none"; else { ts << " (" << box.borderTop() << "px "; printBorderStyle(ts, o.style()->borderTopStyle()); Color col = o.style()->borderTopColor(); if (!col.isValid()) col = o.style()->color(); ts << col.name() << ")"; } } if (o.style()->borderRight() != prevBorder) { prevBorder = o.style()->borderRight(); if (!box.borderRight()) ts << " none"; else { ts << " (" << box.borderRight() << "px "; printBorderStyle(ts, o.style()->borderRightStyle()); Color col = o.style()->borderRightColor(); if (!col.isValid()) col = o.style()->color(); ts << col.name() << ")"; } } if (o.style()->borderBottom() != prevBorder) { prevBorder = box.style()->borderBottom();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -