mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Remove all code relating to shadow trees, insertion points, shadow boundaries, traversing composed trees, distribution, template documents, custom elements, registering elements, element registries, element factories, shadow roots, etc. Remove the following features from the IDLs and from the binding generators: CustomElementCallbacks, Reflect*, EventHandler. Remove the CSS custom pseudo-element concept, since we no longer have a UA style sheet worth talking about, no longer have shadow trees or custom elements, no longer use pseudo-elements, and generally therefore don't use this code at all.
468 lines
17 KiB
C++
468 lines
17 KiB
C++
/*
|
|
* 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 "sky/engine/core/rendering/RenderTreeAsText.h"
|
|
|
|
#include "sky/engine/core/css/StylePropertySet.h"
|
|
#include "sky/engine/core/dom/Document.h"
|
|
#include "sky/engine/core/frame/FrameView.h"
|
|
#include "sky/engine/core/frame/LocalFrame.h"
|
|
#include "sky/engine/core/html/HTMLElement.h"
|
|
#include "sky/engine/core/rendering/InlineTextBox.h"
|
|
#include "sky/engine/core/rendering/RenderInline.h"
|
|
#include "sky/engine/core/rendering/RenderLayer.h"
|
|
#include "sky/engine/core/rendering/RenderView.h"
|
|
#include "sky/engine/wtf/HexNumber.h"
|
|
#include "sky/engine/wtf/Vector.h"
|
|
#include "sky/engine/wtf/unicode/CharacterNames.h"
|
|
|
|
namespace blink {
|
|
|
|
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 bool isEmptyOrUnstyledAppleStyleSpan(const Node* node)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
String quoteAndEscapeNonPrintables(const String& s)
|
|
{
|
|
StringBuilder 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 {
|
|
result.append('\\');
|
|
result.append('x');
|
|
result.append('{');
|
|
appendUnsignedAsHex(c, result);
|
|
result.append('}');
|
|
}
|
|
}
|
|
}
|
|
result.append('"');
|
|
return result.toString();
|
|
}
|
|
|
|
void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, RenderAsTextBehavior behavior)
|
|
{
|
|
ts << o.renderName();
|
|
|
|
if (behavior & RenderAsTextShowAddresses)
|
|
ts << " " << static_cast<const void*>(&o);
|
|
|
|
if (o.style() && o.style()->zIndex())
|
|
ts << " zI: " << o.style()->zIndex();
|
|
|
|
if (o.node()) {
|
|
String tagName = o.node()->nodeName();
|
|
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*";
|
|
}
|
|
}
|
|
|
|
LayoutRect 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());
|
|
} 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());
|
|
} else if (o.isBox())
|
|
r = toRenderBox(&o)->frameRect();
|
|
|
|
ts << " " << r;
|
|
|
|
if (!o.isText()) {
|
|
if (o.parent()) {
|
|
Color color = o.resolveColor(CSSPropertyColor);
|
|
if (o.parent()->resolveColor(CSSPropertyColor) != color)
|
|
ts << " [color=" << color.nameForRenderTreeAsText() << "]";
|
|
|
|
// Do not dump invalid or transparent backgrounds, since that is the default.
|
|
Color backgroundColor = o.resolveColor(CSSPropertyBackgroundColor);
|
|
if (o.parent()->resolveColor(CSSPropertyBackgroundColor) != backgroundColor
|
|
&& backgroundColor.rgb())
|
|
ts << " [bgcolor=" << backgroundColor.nameForRenderTreeAsText() << "]";
|
|
|
|
Color textFillColor = o.resolveColor(CSSPropertyWebkitTextFillColor);
|
|
if (o.parent()->resolveColor(CSSPropertyWebkitTextFillColor) != textFillColor
|
|
&& textFillColor != color && textFillColor.rgb())
|
|
ts << " [textFillColor=" << textFillColor.nameForRenderTreeAsText() << "]";
|
|
|
|
Color textStrokeColor = o.resolveColor(CSSPropertyWebkitTextStrokeColor);
|
|
if (o.parent()->resolveColor(CSSPropertyWebkitTextStrokeColor) != textStrokeColor
|
|
&& textStrokeColor != color && textStrokeColor.rgb())
|
|
ts << " [textStrokeColor=" << textStrokeColor.nameForRenderTreeAsText() << "]";
|
|
|
|
if (o.parent()->style()->textStrokeWidth() != o.style()->textStrokeWidth() && o.style()->textStrokeWidth() > 0)
|
|
ts << " [textStrokeWidth=" << o.style()->textStrokeWidth() << "]";
|
|
}
|
|
|
|
if (!o.isBoxModelObject())
|
|
return;
|
|
|
|
const RenderBoxModelObject& box = toRenderBoxModelObject(o);
|
|
if (box.borderTop() || box.borderRight() || box.borderBottom() || box.borderLeft()) {
|
|
ts << " [border:";
|
|
|
|
BorderValue prevBorder = o.style()->borderTop();
|
|
if (!box.borderTop())
|
|
ts << " none";
|
|
else {
|
|
ts << " (" << box.borderTop() << "px ";
|
|
printBorderStyle(ts, o.style()->borderTopStyle());
|
|
Color col = o.resolveColor(CSSPropertyBorderTopColor);
|
|
ts << col.nameForRenderTreeAsText() << ")";
|
|
}
|
|
|
|
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.resolveColor(CSSPropertyBorderRightColor);
|
|
ts << col.nameForRenderTreeAsText() << ")";
|
|
}
|
|
}
|
|
|
|
if (o.style()->borderBottom() != prevBorder) {
|
|
prevBorder = box.style()->borderBottom();
|
|
if (!box.borderBottom())
|
|
ts << " none";
|
|
else {
|
|
ts << " (" << box.borderBottom() << "px ";
|
|
printBorderStyle(ts, o.style()->borderBottomStyle());
|
|
Color col = o.resolveColor(CSSPropertyBorderBottomColor);
|
|
ts << col.nameForRenderTreeAsText() << ")";
|
|
}
|
|
}
|
|
|
|
if (o.style()->borderLeft() != prevBorder) {
|
|
prevBorder = o.style()->borderLeft();
|
|
if (!box.borderLeft())
|
|
ts << " none";
|
|
else {
|
|
ts << " (" << box.borderLeft() << "px ";
|
|
printBorderStyle(ts, o.style()->borderLeftStyle());
|
|
Color col = o.resolveColor(CSSPropertyBorderLeftColor);
|
|
ts << col.nameForRenderTreeAsText() << ")";
|
|
}
|
|
}
|
|
|
|
ts << "]";
|
|
}
|
|
}
|
|
|
|
if (behavior & RenderAsTextShowIDAndClass) {
|
|
Node* node = o.node();
|
|
if (node && node->isElementNode()) {
|
|
Element& element = toElement(*node);
|
|
if (element.hasID())
|
|
ts << " id=\"" + element.getIdAttribute() + "\"";
|
|
|
|
if (element.hasClass()) {
|
|
ts << " class=\"";
|
|
for (size_t i = 0; i < element.classNames().size(); ++i) {
|
|
if (i > 0)
|
|
ts << " ";
|
|
ts << element.classNames()[i];
|
|
}
|
|
ts << "\"";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (behavior & RenderAsTextShowLayoutState) {
|
|
bool needsLayout = o.selfNeedsLayout() || o.needsPositionedMovementLayout() || o.posChildNeedsLayout() || o.normalChildNeedsLayout();
|
|
if (needsLayout)
|
|
ts << " (needs layout:";
|
|
|
|
bool havePrevious = false;
|
|
if (o.selfNeedsLayout()) {
|
|
ts << " self";
|
|
havePrevious = true;
|
|
}
|
|
|
|
if (o.needsPositionedMovementLayout()) {
|
|
if (havePrevious)
|
|
ts << ",";
|
|
havePrevious = true;
|
|
ts << " positioned movement";
|
|
}
|
|
|
|
if (o.normalChildNeedsLayout()) {
|
|
if (havePrevious)
|
|
ts << ",";
|
|
havePrevious = true;
|
|
ts << " child";
|
|
}
|
|
|
|
if (o.posChildNeedsLayout()) {
|
|
if (havePrevious)
|
|
ts << ",";
|
|
ts << " positioned child";
|
|
}
|
|
|
|
if (needsLayout)
|
|
ts << ")";
|
|
}
|
|
}
|
|
|
|
static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBox& run)
|
|
{
|
|
// FIXME: For now use an "enclosingIntRect" model for x, y and logicalWidth, although this makes it harder
|
|
// to detect any changes caused by the conversion to floating point. :(
|
|
int x = run.x();
|
|
int y = run.y();
|
|
int logicalWidth = ceilf(run.left() + run.logicalWidth()) - x;
|
|
|
|
ts << "text run at (" << x << "," << y << ") width " << logicalWidth;
|
|
if (!run.isLeftToRightDirection() || run.dirOverride()) {
|
|
ts << (!run.isLeftToRightDirection() ? " RTL" : " LTR");
|
|
if (run.dirOverride())
|
|
ts << " override";
|
|
}
|
|
ts << ": "
|
|
<< quoteAndEscapeNonPrintables(String(o.text()).substring(run.start(), run.len()));
|
|
if (run.hasHyphen())
|
|
ts << " + hyphen string " << quoteAndEscapeNonPrintables(o.style()->hyphenString());
|
|
ts << "\n";
|
|
}
|
|
|
|
void write(TextStream& ts, const RenderObject& o, int indent, RenderAsTextBehavior behavior)
|
|
{
|
|
writeIndent(ts, indent);
|
|
|
|
RenderTreeAsText::writeRenderObject(ts, o, behavior);
|
|
ts << "\n";
|
|
|
|
if (o.isText()) {
|
|
const RenderText& text = toRenderText(o);
|
|
for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) {
|
|
writeIndent(ts, indent + 1);
|
|
writeTextRun(ts, text, *box);
|
|
}
|
|
}
|
|
|
|
for (RenderObject* child = o.slowFirstChild(); child; child = child->nextSibling()) {
|
|
if (child->hasLayer())
|
|
continue;
|
|
write(ts, *child, indent + 1, behavior);
|
|
}
|
|
}
|
|
|
|
static void write(TextStream& ts, RenderLayer& l,
|
|
const LayoutRect& layerBounds, const LayoutRect& backgroundClipRect,
|
|
int indent = 0, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal)
|
|
{
|
|
IntRect adjustedLayoutBounds = pixelSnappedIntRect(layerBounds);
|
|
IntRect adjustedBackgroundClipRect = pixelSnappedIntRect(backgroundClipRect);
|
|
|
|
writeIndent(ts, indent);
|
|
|
|
ts << "layer ";
|
|
|
|
if (behavior & RenderAsTextShowAddresses)
|
|
ts << static_cast<const void*>(&l) << " ";
|
|
|
|
ts << adjustedLayoutBounds;
|
|
|
|
if (!adjustedLayoutBounds.isEmpty()) {
|
|
if (!adjustedBackgroundClipRect.contains(adjustedLayoutBounds))
|
|
ts << " backgroundClip " << adjustedBackgroundClipRect;
|
|
}
|
|
|
|
ts << "\n";
|
|
write(ts, *l.renderer(), indent + 1, behavior);
|
|
}
|
|
|
|
void RenderTreeAsText::writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLayer* layer,
|
|
const LayoutRect& paintRect, int indent, RenderAsTextBehavior behavior)
|
|
{
|
|
// FIXME: Apply overflow to the root layer to not break every test. Complete hack. Sigh.
|
|
LayoutRect paintDirtyRect(paintRect);
|
|
if (rootLayer == layer) {
|
|
paintDirtyRect.setWidth(max<LayoutUnit>(paintDirtyRect.width(), rootLayer->renderer()->layoutOverflowRect().maxX()));
|
|
paintDirtyRect.setHeight(max<LayoutUnit>(paintDirtyRect.height(), rootLayer->renderer()->layoutOverflowRect().maxY()));
|
|
}
|
|
|
|
// Calculate the clip rects we should use.
|
|
LayoutRect layerBounds;
|
|
ClipRect damageRect;
|
|
layer->clipper().calculateRects(ClipRectsContext(rootLayer, UncachedClipRects), paintDirtyRect, layerBounds, damageRect);
|
|
|
|
// FIXME: Apply overflow to the root layer to not break every test. Complete hack. Sigh.
|
|
if (rootLayer == layer)
|
|
layerBounds.setSize(layer->size().expandedTo(pixelSnappedIntSize(layer->renderer()->maxLayoutOverflow(), LayoutPoint(0, 0))));
|
|
|
|
// Ensure our lists are up-to-date.
|
|
layer->stackingNode()->updateLayerListsIfNeeded();
|
|
|
|
bool shouldPaint = (behavior & RenderAsTextShowAllLayers) ? true : layer->intersectsDamageRect(layerBounds, damageRect.rect(), rootLayer);
|
|
|
|
if (shouldPaint)
|
|
write(ts, *layer, layerBounds, damageRect.rect(), indent, behavior);
|
|
|
|
if (Vector<RenderLayerStackingNode*>* normalFlowList = layer->stackingNode()->normalFlowList()) {
|
|
int currIndent = indent;
|
|
if (behavior & RenderAsTextShowLayerNesting) {
|
|
writeIndent(ts, indent);
|
|
ts << " normal flow list(" << normalFlowList->size() << ")\n";
|
|
++currIndent;
|
|
}
|
|
for (unsigned i = 0; i != normalFlowList->size(); ++i)
|
|
writeLayers(ts, rootLayer, normalFlowList->at(i)->layer(), paintDirtyRect, currIndent, behavior);
|
|
}
|
|
|
|
if (Vector<RenderLayerStackingNode*>* posList = layer->stackingNode()->zOrderList()) {
|
|
int currIndent = indent;
|
|
if (behavior & RenderAsTextShowLayerNesting) {
|
|
writeIndent(ts, indent);
|
|
ts << " positive z-order list(" << posList->size() << ")\n";
|
|
++currIndent;
|
|
}
|
|
for (unsigned i = 0; i != posList->size(); ++i)
|
|
writeLayers(ts, rootLayer, posList->at(i)->layer(), paintDirtyRect, currIndent, behavior);
|
|
}
|
|
}
|
|
|
|
String nodePositionAsStringForTesting(Node* node)
|
|
{
|
|
StringBuilder result;
|
|
|
|
Node* parent;
|
|
for (Node* n = node; n; n = parent) {
|
|
parent = n->parentNode();
|
|
if (n != node)
|
|
result.appendLiteral(" of ");
|
|
if (parent) {
|
|
result.appendLiteral("child ");
|
|
result.appendNumber(n->nodeIndex());
|
|
result.appendLiteral(" {");
|
|
result.append(n->nodeName());
|
|
result.append('}');
|
|
} else
|
|
result.appendLiteral("document");
|
|
}
|
|
|
|
return result.toString();
|
|
}
|
|
|
|
static String externalRepresentation(RenderBox* renderer, RenderAsTextBehavior behavior)
|
|
{
|
|
TextStream ts;
|
|
if (!renderer->hasLayer())
|
|
return ts.release();
|
|
|
|
RenderLayer* layer = renderer->layer();
|
|
RenderTreeAsText::writeLayers(ts, layer, layer, layer->rect(), 0, behavior);
|
|
return ts.release();
|
|
}
|
|
|
|
String externalRepresentation(LocalFrame* frame, RenderAsTextBehavior behavior)
|
|
{
|
|
if (!(behavior & RenderAsTextDontUpdateLayout))
|
|
frame->document()->updateLayout();
|
|
|
|
RenderObject* renderer = frame->contentRenderer();
|
|
if (!renderer || !renderer->isBox())
|
|
return String();
|
|
|
|
return externalRepresentation(toRenderBox(renderer), behavior);
|
|
}
|
|
|
|
String externalRepresentation(Element* element, RenderAsTextBehavior behavior)
|
|
{
|
|
// Doesn't support printing mode.
|
|
if (!(behavior & RenderAsTextDontUpdateLayout))
|
|
element->document().updateLayout();
|
|
|
|
RenderObject* renderer = element->renderer();
|
|
if (!renderer || !renderer->isBox())
|
|
return String();
|
|
|
|
return externalRepresentation(toRenderBox(renderer), behavior | RenderAsTextShowAllLayers);
|
|
}
|
|
|
|
} // namespace blink
|