summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/SimpleLineLayoutCoverage.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/SimpleLineLayoutCoverage.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/rendering/SimpleLineLayoutCoverage.cpp')
-rw-r--r--Source/WebCore/rendering/SimpleLineLayoutCoverage.cpp357
1 files changed, 357 insertions, 0 deletions
diff --git a/Source/WebCore/rendering/SimpleLineLayoutCoverage.cpp b/Source/WebCore/rendering/SimpleLineLayoutCoverage.cpp
new file mode 100644
index 000000000..ba462af1a
--- /dev/null
+++ b/Source/WebCore/rendering/SimpleLineLayoutCoverage.cpp
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2017 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 INC. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 "SimpleLineLayoutCoverage.h"
+
+#include "Logging.h"
+#include "RenderBlockFlow.h"
+#include "RenderChildIterator.h"
+#include "RenderStyle.h"
+#include "RenderView.h"
+#include "Settings.h"
+#include "SimpleLineLayout.h"
+#include "TextStream.h"
+
+namespace WebCore {
+namespace SimpleLineLayout {
+
+#ifndef NDEBUG
+static void printReason(AvoidanceReason reason, TextStream& stream)
+{
+ switch (reason) {
+ case FlowIsInsideRegion:
+ stream << "flow is inside region";
+ break;
+ case FlowHasHorizonalWritingMode:
+ stream << "horizontal writing mode";
+ break;
+ case FlowHasOutline:
+ stream << "outline";
+ break;
+ case FlowIsRuby:
+ stream << "ruby";
+ break;
+ case FlowHasHangingPunctuation:
+ stream << "hanging punctuation";
+ break;
+ case FlowIsPaginated:
+ stream << "paginated";
+ break;
+ case FlowHasTextOverflow:
+ stream << "text-overflow";
+ break;
+ case FlowIsDepricatedFlexBox:
+ stream << "depricatedFlexBox";
+ break;
+ case FlowParentIsPlaceholderElement:
+ stream << "placeholder element";
+ break;
+ case FlowParentIsTextAreaWithWrapping:
+ stream << "wrapping textarea";
+ break;
+ case FlowHasNonSupportedChild:
+ stream << "nested renderers";
+ break;
+ case FlowHasUnsupportedFloat:
+ stream << "complicated float";
+ break;
+ case FlowHasUnsupportedUnderlineDecoration:
+ stream << "text-underline-position: under";
+ break;
+ case FlowHasJustifiedNonLatinText:
+ stream << "text-align: justify with non-latin text";
+ break;
+ case FlowHasOverflowNotVisible:
+ stream << "overflow: hidden | scroll | auto";
+ break;
+ case FlowHasWebKitNBSPMode:
+ stream << "-webkit-nbsp-mode: space";
+ break;
+ case FlowIsNotLTR:
+ stream << "dir is not LTR";
+ break;
+ case FlowHasLineBoxContainProperty:
+ stream << "line-box-contain value indicates variable line height";
+ break;
+ case FlowIsNotTopToBottom:
+ stream << "non top-to-bottom flow";
+ break;
+ case FlowHasLineBreak:
+ stream << "line-break property";
+ break;
+ case FlowHasNonNormalUnicodeBiDi:
+ stream << "non-normal Unicode bidi";
+ break;
+ case FlowHasRTLOrdering:
+ stream << "-webkit-rtl-ordering";
+ break;
+ case FlowHasLineAlignEdges:
+ stream << "-webkit-line-align edges";
+ break;
+ case FlowHasLineSnap:
+ stream << "-webkit-line-snap property";
+ break;
+ case FlowHasTextEmphasisFillOrMark:
+ stream << "text-emphasis (fill/mark)";
+ break;
+ case FlowHasPseudoFirstLine:
+ stream << "first-line";
+ break;
+ case FlowHasPseudoFirstLetter:
+ stream << "first-letter";
+ break;
+ case FlowHasTextCombine:
+ stream << "text combine";
+ break;
+ case FlowHasTextFillBox:
+ stream << "background-color (text-fill)";
+ break;
+ case FlowHasBorderFitLines:
+ stream << "-webkit-border-fit";
+ break;
+ case FlowHasNonAutoLineBreak:
+ stream << "line-break is not auto";
+ break;
+ case FlowHasNonAutoTrailingWord:
+ stream << "-apple-trailing-word is not auto";
+ break;
+ case FlowHasSVGFont:
+ stream << "SVG font";
+ break;
+ case FlowTextHasSoftHyphen:
+ stream << "soft hyphen character";
+ break;
+ case FlowTextHasDirectionCharacter:
+ stream << "direction character";
+ break;
+ case FlowIsMissingPrimaryFont:
+ stream << "missing primary font";
+ break;
+ case FlowPrimaryFontIsInsufficient:
+ stream << "missing glyph or glyph needs another font";
+ break;
+ case FlowTextIsCombineText:
+ stream << "text is combine";
+ break;
+ case FlowTextIsRenderCounter:
+ stream << "unsupported RenderCounter";
+ break;
+ case FlowTextIsRenderQuote:
+ stream << "unsupported RenderQuote";
+ break;
+ case FlowTextIsTextFragment:
+ stream << "unsupported TextFragment";
+ break;
+ case FlowTextIsSVGInlineText:
+ stream << "unsupported SVGInlineText";
+ break;
+ case FlowHasComplexFontCodePath:
+ stream << "text with complex font codepath";
+ break;
+ case FlowHasTextShadow:
+ stream << "text-shadow";
+ break;
+ case FlowChildIsSelected:
+ stream << "selected content";
+ break;
+ case FlowFontHasOverflowGlyph:
+ stream << "-webkit-line-box-contain: glyphs with overflowing text.";
+ break;
+ case FlowTextHasSurrogatePair:
+ stream << "surrogate pair";
+ break;
+ case FlowTextIsEmpty:
+ case FlowHasNoChild:
+ case FlowHasNoParent:
+ case FeatureIsDisabled:
+ default:
+ break;
+ }
+}
+
+static void printReasons(AvoidanceReasonFlags reasons, TextStream& stream)
+{
+ bool first = true;
+ for (auto reasonItem = EndOfReasons >> 1; reasonItem != NoReason; reasonItem >>= 1) {
+ if (!(reasons & reasonItem))
+ continue;
+ stream << (first ? " " : ", ");
+ first = false;
+ printReason(reasonItem, stream);
+ }
+}
+
+static void printTextForSubtree(const RenderObject& renderer, unsigned& charactersLeft, TextStream& stream)
+{
+ if (!charactersLeft)
+ return;
+ if (is<RenderText>(renderer)) {
+ String text = downcast<RenderText>(renderer).text();
+ text = text.stripWhiteSpace();
+ unsigned len = std::min(charactersLeft, text.length());
+ stream << text.left(len);
+ charactersLeft -= len;
+ return;
+ }
+ if (!is<RenderElement>(renderer))
+ return;
+ for (const auto* child = downcast<RenderElement>(renderer).firstChild(); child; child = child->nextSibling())
+ printTextForSubtree(*child, charactersLeft, stream);
+}
+
+static unsigned textLengthForSubtree(const RenderObject& renderer)
+{
+ if (is<RenderText>(renderer))
+ return downcast<RenderText>(renderer).textLength();
+ if (!is<RenderElement>(renderer))
+ return 0;
+ unsigned textLength = 0;
+ for (const auto* child = downcast<RenderElement>(renderer).firstChild(); child; child = child->nextSibling())
+ textLength += textLengthForSubtree(*child);
+ return textLength;
+}
+
+static void collectNonEmptyLeafRenderBlockFlows(const RenderObject& renderer, HashSet<const RenderBlockFlow*>& leafRenderers)
+{
+ if (is<RenderText>(renderer)) {
+ if (!downcast<RenderText>(renderer).textLength())
+ return;
+ // Find RenderBlockFlow ancestor.
+ for (const auto* current = renderer.parent(); current; current = current->parent()) {
+ if (!is<RenderBlockFlow>(current))
+ continue;
+ leafRenderers.add(downcast<RenderBlockFlow>(current));
+ break;
+ }
+ return;
+ }
+ if (!is<RenderElement>(renderer))
+ return;
+ for (const auto* child = downcast<RenderElement>(renderer).firstChild(); child; child = child->nextSibling())
+ collectNonEmptyLeafRenderBlockFlows(*child, leafRenderers);
+}
+
+static void collectNonEmptyLeafRenderBlockFlowsForCurrentPage(HashSet<const RenderBlockFlow*>& leafRenderers)
+{
+ for (const auto* document : Document::allDocuments()) {
+ if (!document->renderView() || document->pageCacheState() != Document::NotInPageCache)
+ continue;
+ if (!document->isHTMLDocument() && !document->isXHTMLDocument())
+ continue;
+ collectNonEmptyLeafRenderBlockFlows(*document->renderView(), leafRenderers);
+ }
+}
+
+void toggleSimpleLineLayout()
+{
+ for (auto* document : Document::allDocuments()) {
+ auto& settings = document->mutableSettings();
+ settings.setSimpleLineLayoutEnabled(!settings.simpleLineLayoutEnabled());
+ }
+}
+
+void printSimpleLineLayoutBlockList()
+{
+ HashSet<const RenderBlockFlow*> leafRenderers;
+ collectNonEmptyLeafRenderBlockFlowsForCurrentPage(leafRenderers);
+ if (!leafRenderers.size()) {
+ WTFLogAlways("No text found in this document\n");
+ return;
+ }
+ TextStream stream;
+ stream << "---------------------------------------------------\n";
+ for (const auto* flow : leafRenderers) {
+ auto reason = canUseForWithReason(*flow, IncludeReasons::All);
+ if (reason == NoReason)
+ continue;
+ unsigned printedLength = 30;
+ stream << "\"";
+ printTextForSubtree(*flow, printedLength, stream);
+ for (;printedLength > 0; --printedLength)
+ stream << " ";
+ stream << "\"(" << textLengthForSubtree(*flow) << "):";
+ printReasons(reason, stream);
+ stream << "\n";
+ }
+ stream << "---------------------------------------------------\n";
+ WTFLogAlways("%s", stream.release().utf8().data());
+}
+
+void printSimpleLineLayoutCoverage()
+{
+ HashSet<const RenderBlockFlow*> leafRenderers;
+ collectNonEmptyLeafRenderBlockFlowsForCurrentPage(leafRenderers);
+ if (!leafRenderers.size()) {
+ WTFLogAlways("No text found in this document\n");
+ return;
+ }
+ TextStream stream;
+ HashMap<AvoidanceReason, unsigned> flowStatistics;
+ unsigned textLength = 0;
+ unsigned unsupportedTextLength = 0;
+ unsigned numberOfUnsupportedLeafBlocks = 0;
+ unsigned supportedButForcedToLineLayoutTextLength = 0;
+ unsigned numberOfSupportedButForcedToLineLayoutLeafBlocks = 0;
+ for (const auto* flow : leafRenderers) {
+ auto flowLength = textLengthForSubtree(*flow);
+ textLength += flowLength;
+ auto reasons = canUseForWithReason(*flow, IncludeReasons::All);
+ if (reasons == NoReason) {
+ if (flow->lineLayoutPath() == RenderBlockFlow::ForceLineBoxesPath) {
+ supportedButForcedToLineLayoutTextLength += flowLength;
+ ++numberOfSupportedButForcedToLineLayoutLeafBlocks;
+ }
+ continue;
+ }
+ ++numberOfUnsupportedLeafBlocks;
+ unsupportedTextLength += flowLength;
+ for (auto reasonItem = EndOfReasons >> 1; reasonItem != NoReason; reasonItem >>= 1) {
+ if (!(reasons & reasonItem))
+ continue;
+ auto result = flowStatistics.add(reasonItem, flowLength);
+ if (!result.isNewEntry)
+ result.iterator->value += flowLength;
+ }
+ }
+ stream << "---------------------------------------------------\n";
+ stream << "Number of blocks: total(" << leafRenderers.size() << ") non-simple(" << numberOfUnsupportedLeafBlocks << ")\nContent length: total(" <<
+ textLength << ") non-simple(" << unsupportedTextLength << ")\n";
+ for (const auto reasonEntry : flowStatistics) {
+ printReason(reasonEntry.key, stream);
+ stream << ": " << (float)reasonEntry.value / (float)textLength * 100 << "%\n";
+ }
+ if (supportedButForcedToLineLayoutTextLength) {
+ stream << "Simple line layout potential coverage: " << (float)(textLength - unsupportedTextLength) / (float)textLength * 100 << "%\n\n";
+ stream << "Simple line layout actual coverage: " << (float)(textLength - unsupportedTextLength - supportedButForcedToLineLayoutTextLength) / (float)textLength * 100 << "%\nForced line layout blocks: " << numberOfSupportedButForcedToLineLayoutLeafBlocks << " content length: " << supportedButForcedToLineLayoutTextLength << "(" << (float)supportedButForcedToLineLayoutTextLength / (float)textLength * 100 << "%)";
+ } else
+ stream << "Simple line layout coverage: " << (float)(textLength - unsupportedTextLength) / (float)textLength * 100 << "%";
+ stream << "\n---------------------------------------------------\n";
+ WTFLogAlways("%s", stream.release().utf8().data());
+}
+#endif
+
+}
+}