summaryrefslogtreecommitdiffstats
path: root/third_party/WebKit/Source/web/WebFrameContentDumper.cpp
blob: c28d1fc6b208da451b2aa6c1d5fdfee9094e1314 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "public/web/WebFrameContentDumper.h"

#include "core/editing/EphemeralRange.h"
#include "core/editing/iterators/TextIterator.h"
#include "core/editing/serializers/Serialization.h"
#include "core/frame/LocalFrame.h"
#include "core/layout/LayoutPart.h"
#include "core/layout/LayoutTreeAsText.h"
#include "core/layout/LayoutView.h"
#include "public/web/WebDocument.h"
#include "public/web/WebLocalFrame.h"
#include "web/WebLocalFrameImpl.h"
#include "wtf/text/WTFString.h"

namespace blink {

static void frameContentAsPlainText(size_t maxChars, LocalFrame* frame, StringBuilder& output)
{
    Document* document = frame->document();
    if (!document)
        return;

    if (!frame->view())
        return;

    // Select the document body.
    if (document->body()) {
        const EphemeralRange range = EphemeralRange::rangeOfContents(*document->body());

        // The text iterator will walk nodes giving us text. This is similar to
        // the plainText() function in core/editing/TextIterator.h, but we implement the maximum
        // size and also copy the results directly into a wstring, avoiding the
        // string conversion.
        for (TextIterator it(range.startPosition(), range.endPosition()); !it.atEnd(); it.advance()) {
            it.text().appendTextToStringBuilder(output, 0, maxChars - output.length());
            if (output.length() >= maxChars)
                return; // Filled up the buffer.
        }
    }

    // The separator between frames when the frames are converted to plain text.
    const LChar frameSeparator[] = { '\n', '\n' };
    const size_t frameSeparatorLength = WTF_ARRAY_LENGTH(frameSeparator);

    // Recursively walk the children.
    const FrameTree& frameTree = frame->tree();
    for (Frame* curChild = frameTree.firstChild(); curChild; curChild = curChild->tree().nextSibling()) {
        if (!curChild->isLocalFrame())
            continue;
        LocalFrame* curLocalChild = toLocalFrame(curChild);
        // Ignore the text of non-visible frames.
        LayoutView* contentLayoutObject = curLocalChild->contentLayoutObject();
        LayoutPart* ownerLayoutObject = curLocalChild->ownerLayoutObject();
        if (!contentLayoutObject || !contentLayoutObject->size().width() || !contentLayoutObject->size().height()
            || (contentLayoutObject->location().x() + contentLayoutObject->size().width() <= 0) || (contentLayoutObject->location().y() + contentLayoutObject->size().height() <= 0)
            || (ownerLayoutObject && ownerLayoutObject->style() && ownerLayoutObject->style()->visibility() != VISIBLE)) {
            continue;
        }

        // Make sure the frame separator won't fill up the buffer, and give up if
        // it will. The danger is if the separator will make the buffer longer than
        // maxChars. This will cause the computation above:
        //   maxChars - output->size()
        // to be a negative number which will crash when the subframe is added.
        if (output.length() >= maxChars - frameSeparatorLength)
            return;

        output.append(frameSeparator, frameSeparatorLength);
        frameContentAsPlainText(maxChars, curLocalChild, output);
        if (output.length() >= maxChars)
            return; // Filled up the buffer.
    }
}

WebString WebFrameContentDumper::dumpFrameTreeAsText(WebLocalFrame* frame, size_t maxChars)
{
    if (!frame)
        return WebString();
    StringBuilder text;
    frameContentAsPlainText(maxChars, toWebLocalFrameImpl(frame)->frame(), text);
    return text.toString();
}

WebString WebFrameContentDumper::dumpAsMarkup(WebLocalFrame* frame)
{
    if (!frame)
        return WebString();
    return createMarkup(toWebLocalFrameImpl(frame)->frame()->document());
}

WebString WebFrameContentDumper::dumpLayoutTreeAsText(WebLocalFrame* frame, LayoutAsTextControls toShow)
{
    if (!frame)
        return WebString();
    LayoutAsTextBehavior behavior = LayoutAsTextShowAllLayers;

    if (toShow & LayoutAsTextWithLineTrees)
        behavior |= LayoutAsTextShowLineTrees;

    if (toShow & LayoutAsTextDebug)
        behavior |= LayoutAsTextShowCompositedLayers | LayoutAsTextShowAddresses | LayoutAsTextShowIDAndClass | LayoutAsTextShowLayerNesting;

    if (toShow & LayoutAsTextPrinting)
        behavior |= LayoutAsTextPrintingMode;

    return externalRepresentation(toWebLocalFrameImpl(frame)->frame(), behavior);
}
}