This commit is contained in:
Kyle Huey 2011-10-31 14:13:23 -04:00
Родитель 1e94cbe0aa d538650f49
Коммит a94e57306e
30 изменённых файлов: 286 добавлений и 80 удалений

22
gfx/skia/new-aa.patch Normal file
Просмотреть файл

@ -0,0 +1,22 @@
diff --git a/gfx/skia/src/core/SkScan_AntiPath.cpp b/gfx/skia/src/core/SkScan_AntiPath.cpp
--- a/gfx/skia/src/core/SkScan_AntiPath.cpp
+++ b/gfx/skia/src/core/SkScan_AntiPath.cpp
@@ -26,17 +26,17 @@
this is often faster for large objects with big spans
NEW_AA is a set of code-changes to try to make both paths produce identical
results. Its not quite there yet, though the remaining differences may be
in the subsequent blits, and not in the different masks/runs...
*/
//#define FORCE_SUPERMASK
//#define FORCE_RLE
-//#define SK_SUPPORT_NEW_AA
+#define SK_SUPPORT_NEW_AA
///////////////////////////////////////////////////////////////////////////////
class BaseSuperBlitter : public SkBlitter {
public:
BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
const SkRegion& clip);

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

@ -0,0 +1,25 @@
diff --git a/gfx/skia/src/effects/SkGradientShader.cpp b/gfx/skia/src/effects/SkGradientShader.cpp
--- a/gfx/skia/src/effects/SkGradientShader.cpp
+++ b/gfx/skia/src/effects/SkGradientShader.cpp
@@ -1652,17 +1652,20 @@ public:
}
return kRadial2_GradientType;
}
virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, int count) {
SkASSERT(count > 0);
// Zero difference between radii: fill with transparent black.
- if (fDiffRadius == 0) {
+ // TODO: Is removing this actually correct? Two circles with the
+ // same radius, but different centers doesn't sound like it
+ // should be cleared
+ if (fDiffRadius == 0 && fCenter1 == fCenter2) {
sk_bzero(dstC, count * sizeof(*dstC));
return;
}
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
TileProc proc = fTileProc;
const SkPMColor* SK_RESTRICT cache = this->getCache32();
SkScalar foura = fA * 4;

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

@ -31,7 +31,7 @@
*/
//#define FORCE_SUPERMASK
//#define FORCE_RLE
//#define SK_SUPPORT_NEW_AA
#define SK_SUPPORT_NEW_AA
///////////////////////////////////////////////////////////////////////////////

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

@ -1657,7 +1657,10 @@ public:
SkASSERT(count > 0);
// Zero difference between radii: fill with transparent black.
if (fDiffRadius == 0) {
// TODO: Is removing this actually correct? Two circles with the
// same radius, but different centers doesn't sound like it
// should be cleared
if (fDiffRadius == 0 && fCenter1 == fCenter2) {
sk_bzero(dstC, count * sizeof(*dstC));
return;
}

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

@ -99,3 +99,7 @@ patch -p3 < arm-opts.patch
patch -p3 < fix-gradient-clamp.patch
# Bug 687189 - Implement SkPaint::getPosTextPath.
patch -p3 < getpostextpath.patch
# Bug 688365 - Enable Skia 'New AA' mode.
patch -p3 < new-aa.patch
# Bug 688366 - Fix Skia marking radial gradients with the same radius as invalid.
patch -p3 < radial-gradients.patch

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

@ -77,6 +77,21 @@ PreparePatternForUntiledDrawing(gfxPattern* aPattern,
// the surface type.
switch (currentTarget->GetType()) {
// The printing surfaces don't natively support or need
// EXTEND_PAD for padding the edges. Using EXTEND_PAD this way
// is suboptimal as it will result in the printing surface
// creating a new image for each fill operation. The pattern
// will be painted to the image to pad out the pattern, then
// the new image will be used as the source. This increases
// printing time and memory use, and prevents the use of mime
// data from cairo_surface_set_mime_data(). Bug 691061.
case gfxASurface::SurfaceTypePDF:
case gfxASurface::SurfaceTypePS:
case gfxASurface::SurfaceTypeWin32Printing:
aPattern->SetExtend(gfxPattern::EXTEND_NONE);
aPattern->SetFilter(aDefaultFilter);
break;
#ifdef MOZ_X11
case gfxASurface::SurfaceTypeXlib:
{

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

@ -295,8 +295,13 @@ class HashTable : private AllocPolicy
uint64 mutationCount;
#endif
static const unsigned sMinSizeLog2 = 4;
/* The default initial capacity is 16, but you can ask for as small as 4. */
static const unsigned sMinSizeLog2 = 2;
static const unsigned sMinSize = 1 << sMinSizeLog2;
static const unsigned sDefaultInitSizeLog2 = 4;
public:
static const unsigned sDefaultInitSize = 1 << sDefaultInitSizeLog2;
private:
static const unsigned sMaxInit = JS_BIT(23);
static const unsigned sMaxCapacity = JS_BIT(24);
static const unsigned sHashBits = tl::BitSize<HashNumber>::result;
@ -986,7 +991,7 @@ class HashMap
* init after constructing a HashMap and check the return value.
*/
HashMap(AllocPolicy a = AllocPolicy()) : impl(a) {}
bool init(uint32 len = 0) { return impl.init(len); }
bool init(uint32 len = Impl::sDefaultInitSize) { return impl.init(len); }
bool initialized() const { return impl.initialized(); }
/*
@ -1214,7 +1219,7 @@ class HashSet
* init after constructing a HashSet and check the return value.
*/
HashSet(AllocPolicy a = AllocPolicy()) : impl(a) {}
bool init(uint32 len = 0) { return impl.init(len); }
bool init(uint32 len = Impl::sDefaultInitSize) { return impl.init(len); }
bool initialized() const { return impl.initialized(); }
/*

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

@ -2705,7 +2705,6 @@ dnl Configure JIT support
case "$target" in
i?86-*)
ENABLE_TRACEJIT=1
NANOJIT_ARCH=i386
ENABLE_METHODJIT=1
ENABLE_MONOIC=1
@ -2715,7 +2714,6 @@ i?86-*)
AC_DEFINE(JS_NUNBOX32)
;;
x86_64*-*)
ENABLE_TRACEJIT=1
NANOJIT_ARCH=X64
ENABLE_METHODJIT=1
ENABLE_MONOIC=1
@ -2725,7 +2723,6 @@ x86_64*-*)
AC_DEFINE(JS_PUNBOX64)
;;
arm*-*)
ENABLE_TRACEJIT=1
NANOJIT_ARCH=ARM
ENABLE_METHODJIT=1
ENABLE_MONOIC=1
@ -2735,7 +2732,6 @@ arm*-*)
AC_DEFINE(JS_NUNBOX32)
;;
sparc*-*)
ENABLE_TRACEJIT=1
NANOJIT_ARCH=Sparc
ENABLE_METHODJIT=1
ENABLE_MONOIC=1
@ -2758,9 +2754,10 @@ MOZ_ARG_DISABLE_BOOL(polyic,
[ --disable-polyic Disable use of PICs by JIT compiler],
ENABLE_POLYIC= )
MOZ_ARG_DISABLE_BOOL(tracejit,
[ --disable-tracejit Disable tracing JIT support],
ENABLE_TRACEJIT=)
MOZ_ARG_ENABLE_BOOL(tracejit,
[ --enable-tracejit Enable tracing JIT support],
ENABLE_TRACEJIT=1,
ENABLE_TRACEJIT= )
MOZ_ARG_ENABLE_BOOL(methodjit-spew,
[ --enable-methodjit-spew Enable method JIT spew support],

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

@ -2482,13 +2482,6 @@ gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
*coords[index] = NSAppUnitsToFloatPixels(coord.GetCoordValue(), aFactor);
}
}
/**
* An offset of (0,0) results in the perspective-origin being at the centre of the element,
* so include a shift of the centre point to (0,0).
*/
result.x -= NSAppUnitsToFloatPixels(boundingRect.width, aFactor)/2;
result.y -= NSAppUnitsToFloatPixels(boundingRect.height, aFactor)/2;
return result;
}
@ -2551,7 +2544,10 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
perspective._34 =
-1.0 / NSAppUnitsToFloatPixels(parentDisp->mChildPerspective.GetCoordValue(),
aFactor);
result = result * nsLayoutUtils::ChangeMatrixBasis(toPerspectiveOrigin, perspective);
/* At the point when perspective is applied, we have been translated to the transform origin.
* The translation to the perspective origin is the difference between these values.
*/
result = result * nsLayoutUtils::ChangeMatrixBasis(toPerspectiveOrigin - toMozOrigin, perspective);
}
if (aFrame->Preserves3D() && nsLayoutUtils::Are3DTransformsEnabled()) {

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

@ -35,3 +35,5 @@ fails == preserve3d-1a.html preserve3d-1-ref.html
== sorting-2a.html sorting-2-ref.html
# Parallel planes, same z depth (shouldn't be sorted!)
== sorting-2b.html sorting-2-ref.html
# Different, but equivalent (for the given transform) transform origins
== rotatex-transformorigin-1a.html rotatex-transformorigin-1-ref.html

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

@ -0,0 +1,11 @@
<html>
<head>
</head>
<body>
<div style="-moz-perspective: 1000px;">
<div style="-moz-transform: rotatex(45deg); -moz-transform-origin: top right; width: 100px; height: 100px;">
Test Text
</div>
</div>
</body>
</html>

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

@ -0,0 +1,11 @@
<html>
<head>
</head>
<body>
<div style="-moz-perspective: 1000px;">
<div style="-moz-transform: rotatex(45deg); -moz-transform-origin: top left; width: 100px; height: 100px;">
Test Text
</div>
</div>
</body>
</html>

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

@ -81,7 +81,7 @@ _BROWSER_FILES = \
browser_preferences_text.js \
browser_preferences_fulltoggle.js \
browser_rect.js \
browser_rememberPassword.js \
$(info browser_rememberPassword.js is disabled because it is random orange on XUL fennec (bug 698387)) \
browser_scroll.js \
browser_scroll.html \
browser_scrollbar.js \
@ -89,8 +89,8 @@ _BROWSER_FILES = \
browser_select.js \
browser_sessionstore.js \
browser_tabs.js \
browser_tapping.js \
browser_tap_content.html \
$(info browser_tapping.js is disabled because it is random orange on XUL fennec (bug 698387)) \
$(info browser_tap_content.html is disabled because it is random orange on XUL fennec (bug 698387)) \
browser_tapping_edit.js \
browser_tap_contentedit.html \
browser_test.js \

2
netwerk/cache/nsCacheService.cpp поставляемый
Просмотреть файл

@ -74,6 +74,7 @@
#include <math.h> // for log()
#include "mozilla/Util.h" // for DebugOnly
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
#include "mozilla/FunctionTimer.h"
@ -1764,6 +1765,7 @@ nsCacheService::ActivateEntry(nsCacheRequest * request,
nsCacheEntry *
nsCacheService::SearchCacheDevices(nsCString * key, nsCacheStoragePolicy policy, bool *collision)
{
Telemetry::AutoTimer<Telemetry::CACHE_DEVICE_SEARCH> timer;
nsCacheEntry * entry = nsnull;
CACHE_LOG_DEBUG(("mMemoryDevice: 0x%p\n", mMemoryDevice));

1
netwerk/cache/nsDiskCacheDevice.cpp поставляемый
Просмотреть файл

@ -503,6 +503,7 @@ nsDiskCacheDevice::GetDeviceID()
nsCacheEntry *
nsDiskCacheDevice::FindEntry(nsCString * key, bool *collision)
{
Telemetry::AutoTimer<Telemetry::CACHE_DISK_SEARCH> timer;
if (!Initialized()) return nsnull; // NS_ERROR_NOT_INITIALIZED
nsDiskCacheRecord record;
nsDiskCacheBinding * binding = nsnull;

2
netwerk/cache/nsDiskCacheDeviceSQL.cpp поставляемый
Просмотреть файл

@ -68,6 +68,7 @@
#include "nsISeekableStream.h"
#include "mozilla/FunctionTimer.h"
#include "mozilla/Telemetry.h"
using namespace mozilla;
@ -1340,6 +1341,7 @@ nsOfflineCacheDevice::GetDeviceID()
nsCacheEntry *
nsOfflineCacheDevice::FindEntry(nsCString *fullKey, bool *collision)
{
mozilla::Telemetry::AutoTimer<mozilla::Telemetry::CACHE_OFFLINE_SEARCH> timer;
LOG(("nsOfflineCacheDevice::FindEntry [key=%s]\n", fullKey->get()));
// SELECT * FROM moz_cache WHERE key = ?

2
netwerk/cache/nsMemoryCacheDevice.cpp поставляемый
Просмотреть файл

@ -48,6 +48,7 @@
#include "nsCRT.h"
#include "nsCache.h"
#include "nsReadableUtils.h"
#include "mozilla/Telemetry.h"
// The memory cache implements the "LRU-SP" caching algorithm
// described in "LRU-SP: A Size-Adjusted and Popularity-Aware LRU Replacement
@ -146,6 +147,7 @@ nsMemoryCacheDevice::GetDeviceID()
nsCacheEntry *
nsMemoryCacheDevice::FindEntry(nsCString * key, bool *collision)
{
mozilla::Telemetry::AutoTimer<mozilla::Telemetry::CACHE_MEMORY_SEARCH> timer;
nsCacheEntry * entry = mMemCacheEntries.GetEntry(key);
if (!entry) return nsnull;

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

@ -367,7 +367,7 @@ nsFileChannel::OpenContentStream(bool async, nsIInputStream **result,
SetContentType(NS_LITERAL_CSTRING(APPLICATION_OCTET_STREAM));
} else {
nsCAutoString contentType;
nsresult rv = MakeFileInputStream(file, stream, contentType);
rv = MakeFileInputStream(file, stream, contentType);
if (NS_FAILED(rv))
return rv;

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

@ -77,6 +77,13 @@ nsHtml5OwningUTF16Buffer::FalliblyCreate(PRInt32 aLength)
return newObj.forget();
}
void
nsHtml5OwningUTF16Buffer::Swap(nsHtml5OwningUTF16Buffer* aOther)
{
nsHtml5UTF16Buffer::Swap(aOther);
}
// Not using macros for AddRef and Release in order to be able to refcount on
// and create on different threads.

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

@ -75,6 +75,11 @@ class nsHtml5OwningUTF16Buffer : public nsHtml5UTF16Buffer
static already_AddRefed<nsHtml5OwningUTF16Buffer>
FalliblyCreate(PRInt32 aLength);
/**
* Swap start, end and buffer fields with another object.
*/
void Swap(nsHtml5OwningUTF16Buffer* aOther);
nsrefcnt AddRef();
nsrefcnt Release();
private:

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

@ -287,25 +287,112 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
NS_ASSERTION(!mStreamParser,
"Had stream parser but got document.close().");
mDocumentClosed = true;
if (!mBlocked) {
if (!mBlocked && !mInDocumentWrite) {
ParseUntilBlocked();
}
return NS_OK;
}
// If we got this far, we are dealing with a document.write or
// document.writeln call--not document.close().
NS_ASSERTION(IsInsertionPointDefined(),
"Doc.write reached parser with undefined insertion point.");
NS_ASSERTION(!(mStreamParser && !aKey),
"Got a null key in a non-script-created parser");
// XXX is this optimization bogus?
if (aSourceBuffer.IsEmpty()) {
return NS_OK;
}
// This guard is here to prevent document.close from tokenizing synchronously
// while a document.write (that wrote the script that called document.close!)
// is still on the call stack.
mozilla::AutoRestore<bool> guard(mInDocumentWrite);
mInDocumentWrite = true;
// The script is identified by aKey. If there's nothing in the buffer
// chain for that key, we'll insert at the head of the queue.
// When the script leaves something in the queue, a zero-length
// key-holder "buffer" is inserted in the queue. If the same script
// leaves something in the chain again, it will be inserted immediately
// before the old key holder belonging to the same script.
//
// We don't do the actual data insertion yet in the hope that the data gets
// tokenized and there no data or less data to copy to the heap after
// tokenization. Also, this way, we avoid inserting one empty data buffer
// per document.write, which matters for performance when the parser isn't
// blocked and a badly-authored script calls document.write() once per
// input character. (As seen in a benchmark!)
//
// The insertion into the input stream happens conceptually before anything
// gets tokenized. To make sure multi-level document.write works right,
// it's necessary to establish the location of our parser key up front
// in case this is the first write with this key.
//
// In a document.open() case, the first write level has a null key, so that
// case is handled separately, because normal buffers containing data
// have null keys.
// These don't need to be owning references, because they always point to
// the buffer queue and buffers can't be removed from the buffer queue
// before document.write() returns. The buffer queue clean-up happens the
// next time ParseUntilBlocked() is called.
// However, they are made owning just in case the reasoning above is flawed
// and a flaw would lead to worse problems with plain pointers. If this
// turns out to be a perf problem, it's worthwhile to consider making
// prevSearchbuf a plain pointer again.
nsRefPtr<nsHtml5OwningUTF16Buffer> prevSearchBuf;
nsRefPtr<nsHtml5OwningUTF16Buffer> firstLevelMarker;
if (aKey) {
if (mFirstBuffer == mLastBuffer) {
nsHtml5OwningUTF16Buffer* keyHolder = new nsHtml5OwningUTF16Buffer(aKey);
keyHolder->next = mLastBuffer;
mFirstBuffer = keyHolder;
} else if (mFirstBuffer->key != aKey) {
prevSearchBuf = mFirstBuffer;
for (;;) {
if (prevSearchBuf->next == mLastBuffer) {
// key was not found
nsHtml5OwningUTF16Buffer* keyHolder =
new nsHtml5OwningUTF16Buffer(aKey);
keyHolder->next = mFirstBuffer;
mFirstBuffer = keyHolder;
prevSearchBuf = nsnull;
break;
}
if (prevSearchBuf->next->key == aKey) {
// found a key holder
break;
}
prevSearchBuf = prevSearchBuf->next;
}
} // else mFirstBuffer is the keyholder
// prevSearchBuf is the previous buffer before the keyholder or null if
// there isn't one.
} else {
// We have a first-level write in the document.open() case. We insert
// before mLastBuffer. We need to put a marker there, because otherwise
// additional document.writes from nested event loops would insert in the
// wrong place. Sigh.
firstLevelMarker = new nsHtml5OwningUTF16Buffer((void*)nsnull);
if (mFirstBuffer == mLastBuffer) {
firstLevelMarker->next = mLastBuffer;
mFirstBuffer = firstLevelMarker;
} else {
prevSearchBuf = mFirstBuffer;
while (prevSearchBuf->next != mLastBuffer) {
prevSearchBuf = prevSearchBuf->next;
}
firstLevelMarker->next = mLastBuffer;
prevSearchBuf->next = firstLevelMarker;
}
}
nsHtml5DependentUTF16Buffer stackBuffer(aSourceBuffer);
while (!mBlocked && stackBuffer.hasMore()) {
@ -355,60 +442,35 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
}
}
// The buffer is inserted to the stream here in case it won't be parsed
// to completion.
// The script is identified by aKey. If there's nothing in the buffer
// chain for that key, we'll insert at the head of the queue.
// When the script leaves something in the queue, a zero-length
// key-holder "buffer" is inserted in the queue. If the same script
// leaves something in the chain again, it will be inserted immediately
// before the old key holder belonging to the same script.
nsHtml5OwningUTF16Buffer* prevSearchBuf = nsnull;
nsHtml5OwningUTF16Buffer* searchBuf = mFirstBuffer;
// after document.open, the first level of document.write has null key
if (aKey) {
while (searchBuf != mLastBuffer) {
if (searchBuf->key == aKey) {
// found a key holder
// now insert the new buffer between the previous buffer
// and the key holder if we have a buffer left.
if (heapBuffer) {
heapBuffer->next = searchBuf;
if (prevSearchBuf) {
prevSearchBuf->next = heapBuffer;
} else {
mFirstBuffer = heapBuffer;
}
}
break;
}
prevSearchBuf = searchBuf;
searchBuf = searchBuf->next;
}
if (searchBuf == mLastBuffer) {
// key was not found
nsHtml5OwningUTF16Buffer* keyHolder = new nsHtml5OwningUTF16Buffer(aKey);
keyHolder->next = mFirstBuffer;
if (heapBuffer) {
heapBuffer->next = keyHolder;
if (heapBuffer) {
// We have something to insert before the keyholder holding in the non-null
// aKey case and we have something to swap into firstLevelMarker in the
// null aKey case.
if (aKey) {
NS_ASSERTION(mFirstBuffer != mLastBuffer,
"Where's the keyholder?");
// the key holder is still somewhere further down the list from
// prevSearchBuf (which may be null)
if (mFirstBuffer->key == aKey) {
NS_ASSERTION(!prevSearchBuf,
"Non-null prevSearchBuf when mFirstBuffer is the key holder?");
heapBuffer->next = mFirstBuffer;
mFirstBuffer = heapBuffer;
} else {
mFirstBuffer = keyHolder;
if (!prevSearchBuf) {
prevSearchBuf = mFirstBuffer;
}
// We created a key holder earlier, so we will find it without walking
// past the end of the list.
while (prevSearchBuf->next->key != aKey) {
prevSearchBuf = prevSearchBuf->next;
}
heapBuffer->next = prevSearchBuf->next;
prevSearchBuf->next = heapBuffer;
}
}
} else if (heapBuffer) {
// we have a first level document.write after document.open()
// insert immediately before mLastBuffer
while (searchBuf != mLastBuffer) {
prevSearchBuf = searchBuf;
searchBuf = searchBuf->next;
}
heapBuffer->next = mLastBuffer;
if (prevSearchBuf) {
prevSearchBuf->next = heapBuffer;
} else {
mFirstBuffer = heapBuffer;
NS_ASSERTION(firstLevelMarker, "How come we don't have a marker.");
firstLevelMarker->Swap(heapBuffer);
}
}
@ -657,14 +719,12 @@ nsHtml5Parser::ParseUntilBlocked()
NS_PRECONDITION(!mExecutor->IsFragmentMode(),
"ParseUntilBlocked called in fragment mode.");
if (mBlocked ||
mExecutor->IsComplete() ||
mExecutor->IsBroken() ||
mInDocumentWrite) {
if (mBlocked || mExecutor->IsComplete() || mExecutor->IsBroken()) {
return;
}
NS_ASSERTION(mExecutor->HasStarted(), "Bad life cycle.");
NS_ASSERTION(!mInDocumentWrite,
"ParseUntilBlocked entered while in doc.write!");
mDocWriteSpeculatorActive = false;

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

@ -53,3 +53,17 @@ nsHtml5UTF16Buffer::DeleteBuffer()
{
delete[] buffer;
}
void
nsHtml5UTF16Buffer::Swap(nsHtml5UTF16Buffer* aOther)
{
PRUnichar* tempBuffer = buffer;
PRInt32 tempStart = start;
PRInt32 tempEnd = end;
buffer = aOther->buffer;
start = aOther->start;
end = aOther->end;
aOther->buffer = tempBuffer;
aOther->start = tempStart;
aOther->end = tempEnd;
}

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

@ -43,3 +43,8 @@ protected:
* For working around the privacy of |buffer| in the generated code.
*/
void DeleteBuffer();
/**
* For working around the privacy of |buffer| in the generated code.
*/
void Swap(nsHtml5UTF16Buffer* aOther);

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

@ -0,0 +1 @@
<!DOCTYPE html>CcBbAa

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

@ -0,0 +1,2 @@
<!DOCTYPE html>
<body><script>document.write("\u003cscript>document.write(\"\\u003cscript src='bug696651-external.js'>\\u003c/script>B\"); document.write(\"b\");\u003c/script>A"); document.write("a");</script>

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

@ -0,0 +1 @@
<!DOCTYPE html><iframe src="data:text/html,<!DOCTYPE html>CcBbAa"></iframe>

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

@ -0,0 +1,6 @@
<!DOCTYPE html>
<body>
<iframe></iframe>
<script>
var doc = document.getElementsByTagName("iframe")[0].contentDocument;
doc.open(); doc.write("\u003cscript>document.write(\"\\u003cscript src='bug696651-external.js'>\\u003c/script>B\"); document.write(\"b\");\u003c/script>A"); doc.write("a"); doc.close();</script>

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

@ -0,0 +1 @@
document.write("C"); document.write("c");

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

@ -5,3 +5,5 @@
== bug592656-1.html bug592656-1-ref.html
== bug608373-1.html bug608373-1-ref.html
== view-source:bug673094-1.html view-source:bug673094-1-ref.html
== bug696651-1.html bug696651-1-ref.html
== bug696651-2.html bug696651-2-ref.html

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

@ -162,6 +162,10 @@ HISTOGRAM(HTTP_CACHE_DISPOSITION, 1, 5, 5, LINEAR, "HTTP Cache Hit, Reval, Faile
HISTOGRAM(HTTP_DISK_CACHE_DISPOSITION, 1, 5, 5, LINEAR, "HTTP Disk Cache Hit, Reval, Failed-Reval, Miss")
HISTOGRAM(HTTP_MEMORY_CACHE_DISPOSITION, 1, 5, 5, LINEAR, "HTTP Memory Cache Hit, Reval, Failed-Reval, Miss")
HISTOGRAM(HTTP_OFFLINE_CACHE_DISPOSITION, 1, 5, 5, LINEAR, "HTTP Offline Cache Hit, Reval, Failed-Reval, Miss")
HISTOGRAM(CACHE_DEVICE_SEARCH, 1, 100, 100, LINEAR, "Time to search cache (ms)")
HISTOGRAM(CACHE_MEMORY_SEARCH, 1, 100, 100, LINEAR, "Time to search memory cache (ms)")
HISTOGRAM(CACHE_DISK_SEARCH, 1, 100, 100, LINEAR, "Time to search disk cache (ms)")
HISTOGRAM(CACHE_OFFLINE_SEARCH, 1, 100, 100, LINEAR, "Time to search offline cache (ms)")
HISTOGRAM(FIND_PLUGINS, 1, 3000, 10, EXPONENTIAL, "Time spent scanning filesystem for plugins (ms)")
HISTOGRAM(CHECK_JAVA_ENABLED, 1, 3000, 10, EXPONENTIAL, "Time spent checking if Java is enabled (ms)")