Bug 1330236 - Compute SVG getNumberOfChars() quicker in simple cases. r=longsonr+218550

MozReview-Commit-ID: FgwR9dxTefx

--HG--
extra : rebase_source : 5b1ba3aa727cdd278a4b40c24231ca446b8bc45d
This commit is contained in:
Cameron McCormack 2017-01-17 13:45:43 +08:00
Родитель 740cebbff8
Коммит 4f17cad8f0
4 изменённых файлов: 130 добавлений и 13 удалений

Просмотреть файл

@ -5,9 +5,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/SVGTextContentElement.h"
#include "nsISVGPoint.h"
#include "SVGTextFrame.h"
#include "mozilla/dom/SVGIRect.h"
#include "nsBidiUtils.h"
#include "nsISVGPoint.h"
#include "nsTextFragment.h"
#include "nsTextFrameUtils.h"
#include "nsTextNode.h"
#include "SVGTextFrame.h"
namespace mozilla {
namespace dom {
@ -32,14 +37,18 @@ SVGTextFrame*
SVGTextContentElement::GetSVGTextFrame()
{
nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
while (frame) {
SVGTextFrame* textFrame = do_QueryFrame(frame);
if (textFrame) {
return textFrame;
}
frame = frame->GetParent();
}
return nullptr;
nsIFrame* textFrame =
nsLayoutUtils::GetClosestFrameOfType(frame, nsGkAtoms::svgTextFrame);
return static_cast<SVGTextFrame*>(textFrame);
}
SVGTextFrame*
SVGTextContentElement::GetSVGTextFrameForNonLayoutDependentQuery()
{
nsIFrame* frame = GetPrimaryFrame(FlushType::Frames);
nsIFrame* textFrame =
nsLayoutUtils::GetClosestFrameOfType(frame, nsGkAtoms::svgTextFrame);
return static_cast<SVGTextFrame*>(textFrame);
}
already_AddRefed<SVGAnimatedLength>
@ -56,9 +65,62 @@ SVGTextContentElement::LengthAdjust()
//----------------------------------------------------------------------
template<typename T>
static bool
FragmentHasSkippableCharacter(const T* aBuffer, uint32_t aLength)
{
for (uint32_t i = 0; i < aLength; i++) {
if (nsTextFrameUtils::IsSkippableCharacterForTransformText(aBuffer[i])) {
return true;
}
}
return false;
}
Maybe<int32_t>
SVGTextContentElement::GetNonLayoutDependentNumberOfChars()
{
SVGTextFrame* frame = GetSVGTextFrameForNonLayoutDependentQuery();
if (!frame || frame != GetPrimaryFrame()) {
// Only support this fast path on <text>, not child <tspan>s, etc.
return Some(0);
}
uint32_t num = 0;
for (nsINode* n = Element::GetFirstChild(); n; n = n->GetNextSibling()) {
if (!n->IsNodeOfType(nsINode::eTEXT)) {
return Nothing();
}
const nsTextFragment* text = static_cast<nsTextNode*>(n)->GetText();
uint32_t length = text->GetLength();
if (text->Is2b()) {
if (FragmentHasSkippableCharacter(text->Get2b(), length)) {
return Nothing();
}
} else {
auto buffer = reinterpret_cast<const uint8_t*>(text->Get1b());
if (FragmentHasSkippableCharacter(buffer, length)) {
return Nothing();
}
}
num += length;
}
return Some(num);
}
int32_t
SVGTextContentElement::GetNumberOfChars()
{
Maybe<int32_t> num = GetNonLayoutDependentNumberOfChars();
if (num) {
return *num;
}
SVGTextFrame* textFrame = GetSVGTextFrame();
return textFrame ? textFrame->GetNumberOfChars(this) : 0;
}

Просмотреть файл

@ -52,6 +52,8 @@ protected:
{}
SVGTextFrame* GetSVGTextFrame();
SVGTextFrame* GetSVGTextFrameForNonLayoutDependentQuery();
mozilla::Maybe<int32_t> GetNonLayoutDependentNumberOfChars();
enum { LENGTHADJUST };
virtual nsSVGEnum* EnumAttributes() = 0;

Просмотреть файл

@ -56,6 +56,36 @@ IsSpaceOrTabOrSegmentBreak(char16_t aCh)
return IsSpaceOrTab(aCh) || IsSegmentBreak(aCh);
}
template<typename CharT>
/* static */ bool
nsTextFrameUtils::IsSkippableCharacterForTransformText(CharT aChar)
{
return aChar == ' ' ||
aChar == '\t' ||
aChar == '\n' ||
aChar == CH_SHY ||
(aChar > 0xFF && IsBidiControl(aChar));
}
#ifdef DEBUG
template<typename CharT>
static void AssertSkippedExpectedChars(const CharT* aText,
const gfxSkipChars& aSkipChars,
int32_t aSkipCharsOffset)
{
gfxSkipCharsIterator it(aSkipChars);
it.AdvanceOriginal(aSkipCharsOffset);
while (it.GetOriginalOffset() < it.GetOriginalEnd()) {
CharT ch = aText[it.GetOriginalOffset() - aSkipCharsOffset];
MOZ_ASSERT(!it.IsOriginalCharSkipped() ||
nsTextFrameUtils::IsSkippableCharacterForTransformText(ch),
"skipped unexpected character; need to update "
"IsSkippableCharacterForTransformText?");
it.AdvanceOriginal(1);
}
}
#endif
template<class CharT>
static CharT*
TransformWhiteSpaces(const CharT* aText, uint32_t aLength,
@ -183,6 +213,9 @@ nsTextFrameUtils::TransformText(const CharT* aText, uint32_t aLength,
{
uint32_t flags = 0;
CharT* outputStart = aOutput;
#ifdef DEBUG
int32_t skipCharsOffset = aSkipChars->GetOriginalCharCount();
#endif
bool lastCharArabic = false;
if (aCompression == COMPRESS_NONE ||
@ -303,12 +336,18 @@ nsTextFrameUtils::TransformText(const CharT* aText, uint32_t aLength,
flags |= TEXT_WAS_TRANSFORMED;
}
*aAnalysisFlags = flags;
#ifdef DEBUG
AssertSkippedExpectedChars(aText, *aSkipChars, skipCharsOffset);
#endif
return aOutput;
}
/*
* NOTE: This template is part of public API of nsTextFrameUtils, while
* its function body is not available in the header. It may stop working
* (fail to resolve symbol in link time) once its callsites are moved to a
* NOTE: The TransformText and IsSkippableCharacterForTransformText template
* functions are part of the public API of nsTextFrameUtils, while
* their function bodies are not available in the header. They may stop working
* (fail to resolve symbol in link time) once their callsites are moved to a
* different translation unit (e.g. a different unified source file).
* Explicit instantiating this function template with `uint8_t` and `char16_t`
* could prevent us from the potential risk.
@ -327,6 +366,10 @@ nsTextFrameUtils::TransformText(const char16_t* aText, uint32_t aLength,
uint8_t* aIncomingFlags,
gfxSkipChars* aSkipChars,
uint32_t* aAnalysisFlags);
template bool
nsTextFrameUtils::IsSkippableCharacterForTransformText(uint8_t aChar);
template bool
nsTextFrameUtils::IsSkippableCharacterForTransformText(char16_t aChar);
uint32_t
nsTextFrameUtils::ComputeApproximateLengthWithWhitespaceCompression(

Просмотреть файл

@ -121,6 +121,16 @@ public:
gfxSkipChars* aSkipChars,
uint32_t* aAnalysisFlags);
/**
* Returns whether aChar is a character that nsTextFrameUtils::TransformText
* might mark as skipped. This is used by
* SVGTextContentElement::GetNumberOfChars to know whether reflowing frames,
* so that we have the results of TransformText, is required, or whether we
* can use a fast path instead.
*/
template<class CharT>
static bool IsSkippableCharacterForTransformText(CharT aChar);
static void
AppendLineBreakOffset(nsTArray<uint32_t>* aArray, uint32_t aOffset)
{