Merge m-c to b2g-inbound.

This commit is contained in:
Ryan VanderMeulen 2014-03-31 17:31:58 -04:00
commit 67e0ae5c09
133 changed files with 3620 additions and 1754 deletions

View File

@ -55,6 +55,7 @@ enum AccType {
eProgressType,
eRootType,
eXULLabelType,
eXULListItemType,
eXULTabpanelsType,
eXULTreeType,

View File

@ -9,6 +9,7 @@
#include "nsEventShell.h"
#include "DocAccessible.h"
#include "nsAccessibilityService.h"
#include "nsTextEquivUtils.h"
#ifdef A11Y_LOG
#include "Logging.h"
#endif
@ -37,6 +38,38 @@ EventQueue::PushEvent(AccEvent* aEvent)
// Filter events.
CoalesceEvents();
// Fire name change event on parent given that this event hasn't been
// coalesced, the parent's name was calculated from its subtree, and the
// subtree was changed.
Accessible* target = aEvent->mAccessible;
if (aEvent->mEventRule != AccEvent::eDoNotEmit &&
target->HasNameDependentParent() &&
(aEvent->mEventType == nsIAccessibleEvent::EVENT_NAME_CHANGE ||
aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED ||
aEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW ||
aEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE)) {
// Only continue traversing up the tree if it's possible that the parent
// accessible's name can depend on this accessible's name.
Accessible* parent = target->Parent();
while (parent &&
nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) {
// Test possible name dependent parent.
if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
nsAutoString name;
ENameValueFlag nameFlag = parent->Name(name);
// If name is obtained from subtree, fire name change event.
if (nameFlag == eNameFromSubtree) {
nsRefPtr<AccEvent> nameChangeEvent =
new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent);
PushEvent(nameChangeEvent);
}
break;
}
parent = parent->Parent();
}
}
// Associate text change with hide event if it wasn't stolen from hiding
// siblings during coalescence.
AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent);

View File

@ -344,7 +344,7 @@ nsTextEquivUtils::AppendString(nsAString *aString,
return true;
}
uint32_t
uint32_t
nsTextEquivUtils::GetRoleRule(role aRole)
{
#define ROLE(geckoRole, stringRole, atkRole, \
@ -360,4 +360,3 @@ nsTextEquivUtils::GetRoleRule(role aRole)
#undef ROLE
}

View File

@ -43,6 +43,18 @@ class nsTextEquivUtils
public:
typedef mozilla::a11y::Accessible Accessible;
/**
* Determines if the accessible has a given name rule.
*
* @param aAccessible [in] the given accessible
* @param aRule [in] a given name rule
* @return true if the accessible has the rule
*/
static inline bool HasNameRule(Accessible* aAccessible, ETextEquivRule aRule)
{
return (GetRoleRule(aAccessible->Role()) & aRule) == aRule;
}
/**
* Calculates the name from accessible subtree if allowed.
*

View File

@ -111,8 +111,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Accessible, LastRelease())
Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) :
mContent(aContent), mDoc(aDoc),
mParent(nullptr), mIndexInParent(-1), mChildrenFlags(eChildrenUninitialized),
mStateFlags(0), mType(0), mGenericTypes(0), mIndexOfEmbeddedChild(-1),
mRoleMapEntry(nullptr)
mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0),
mIndexOfEmbeddedChild(-1), mRoleMapEntry(nullptr)
{
#ifdef NS_DEBUG_X
{
@ -2533,6 +2533,12 @@ Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
mIndexInParent = aIndexInParent;
mParent->InvalidateChildrenGroupInfo();
// Note: this is currently only used for richlistitems and their children.
if (mParent->HasNameDependentParent() || mParent->IsXULListItem())
mContextFlags |= eHasNameDependentParent;
else
mContextFlags &= ~eHasNameDependentParent;
}
// Accessible protected
@ -2544,6 +2550,7 @@ Accessible::UnbindFromParent()
mIndexInParent = -1;
mIndexOfEmbeddedChild = -1;
mGroupInfo = nullptr;
mContextFlags &= ~eHasNameDependentParent;
}
////////////////////////////////////////////////////////////////////////////////
@ -3241,6 +3248,8 @@ Accessible::StaticAsserts() const
"Accessible::mStateFlags was oversized by eLastStateFlag!");
static_assert(eLastAccType <= (1 << kTypeBits) - 1,
"Accessible::mType was oversized by eLastAccType!");
static_assert(eLastContextFlag <= (1 << kContextFlagsBits) - 1,
"Accessible::mContextFlags was oversized by eLastContextFlag!");
static_assert(eLastAccGenericType <= (1 << kGenericTypesBits) - 1,
"Accessible::mGenericType was oversized by eLastAccGenericType!");
}

View File

@ -579,6 +579,8 @@ public:
bool IsXULLabel() const { return mType == eXULLabelType; }
XULLabelAccessible* AsXULLabel();
bool IsXULListItem() const { return mType == eXULListItemType; }
bool IsXULTabpanels() const { return mType == eXULTabpanelsType; }
bool IsXULTree() const { return mType == eXULTreeType; }
@ -790,6 +792,13 @@ public:
bool NeedsDOMUIEvent() const
{ return !(mStateFlags & eIgnoreDOMUIEvent); }
/**
* Return true if this accessible has a parent whose name depends on this
* accessible.
*/
bool HasNameDependentParent() const
{ return mContextFlags & eHasNameDependentParent; }
protected:
/**
@ -867,6 +876,15 @@ protected:
eLastStateFlag = eGroupInfoDirty
};
/**
* Flags used for contextual information about the accessible.
*/
enum ContextFlags {
eHasNameDependentParent = 1 << 0, // Parent's name depends on this accessible.
eLastContextFlag = eHasNameDependentParent
};
protected:
//////////////////////////////////////////////////////////////////////////////
@ -970,14 +988,16 @@ protected:
static const uint8_t kChildrenFlagsBits = 2;
static const uint8_t kStateFlagsBits = 6;
static const uint8_t kContextFlagsBits = 1;
static const uint8_t kTypeBits = 6;
static const uint8_t kGenericTypesBits = 12;
/**
* Keep in sync with ChildrenFlags, StateFlags and AccTypes.
* Keep in sync with ChildrenFlags, StateFlags, ContextFlags, and AccTypes.
*/
uint32_t mChildrenFlags : kChildrenFlagsBits;
uint32_t mStateFlags : kStateFlagsBits;
uint32_t mContextFlags : kContextFlagsBits;
uint32_t mType : kTypeBits;
uint32_t mGenericTypes : kGenericTypesBits;

View File

@ -582,6 +582,7 @@ XULListitemAccessible::
nsGkAtoms::type,
nsGkAtoms::checkbox,
eCaseMatters);
mType = eXULListItemType;
}
NS_IMPL_ISUPPORTS_INHERITED0(XULListitemAccessible, Accessible)

View File

@ -41,6 +41,7 @@ skip-if = os == 'win' || os == 'linux'
[test_menu.xul]
[test_mutation.html]
[test_mutation.xhtml]
[test_name.xul]
[test_scroll.xul]
[test_selection.html]
[test_selection.xul]

View File

@ -0,0 +1,92 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="chrome://mochikit/content/chrome-harness.js"/>
<script type="application/javascript"
src="../common.js" />
<script type="application/javascript"
src="../events.js" />
<script type="application/javascript">
<![CDATA[
/**
* Check name changed a11y event.
*/
function nameChangeChecker(aMsg, aID)
{
this.type = EVENT_NAME_CHANGE;
function targetGetter()
{
return getAccessible(aID);
}
Object.defineProperty(this, "target", { get: targetGetter });
this.getID = function getID()
{
return aMsg + " name changed";
}
}
function changeRichListItemChild()
{
this.invoke = function changeRichListItemChild_invoke()
{
getNode('childcontent').setAttribute('value', 'Changed.');
}
this.eventSeq =
[
new nameChangeChecker("changeRichListItemChild: ", "listitem")
];
this.getID = function changeRichListItemChild_getID()
{
return "changeRichListItemChild";
}
}
function doTest()
{
var queue = new eventQueue();
queue.push(new changeRichListItemChild());
queue.invoke();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<vbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=986054"
title="Propagate name change events">
Mozilla Bug 986054
</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<richlistbox>
<richlistitem id="listitem">
<description id="childcontent" value="This will be changed."/>
</richlistitem>
</richlistbox>
</vbox>
</window>

View File

@ -0,0 +1,31 @@
. $topsrcdir/build/macosx/mozconfig.common
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --enable-signmar
# Nightlies only since this has a cost in performance
ac_add_options --enable-js-diagnostics
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1
export MOZ_TELEMETRY_REPORTING=1
#ac_add_options --with-macbundlename-prefix=Firefox
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
ac_add_options --enable-warnings-as-errors
# B2G Stuff
ac_add_options --enable-application=b2g
ac_add_options --enable-debug-symbols
ac_add_options --enable-debug
ac_add_options --with-ccache
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
GAIADIR=$topsrcdir/gaia
. "$topsrcdir/b2g/config/mozconfigs/common.override"

View File

@ -5840,6 +5840,10 @@ if test "$OS_TARGET" = "WINNT" -a -z "$CROSS_COMPILE"; then
fi
fi
# On mingw, check if headers are provided by toolchain.
if test "$OS_TARGET" = "WINNT" -a -n "$GNU_CC"; then
MOZ_CHECK_HEADER(d3d10.h, MOZ_HAS_WINSDK_WITH_D3D=1)
fi
dnl ========================================================
dnl D3D compiler DLL
@ -5914,7 +5918,7 @@ if test -n "$MOZ_ANGLE_RENDERER"; then
fi
fi
if test -z "$MOZ_D3DCOMPILER_DLL_PATH" -a -z "$MOZ_D3DCOMPILER_CAB"; then
if test -z "$MOZ_D3DCOMPILER_DLL_PATH" -a -z "$MOZ_D3DCOMPILER_CAB" -a -z "$CROSS_COMPILE"; then
AC_MSG_ERROR([Couldn't find an acceptable D3D compiler DLL. Either install Windows SDK 8.0+ and reconfigure with --enable-winsdk-directx, install DirectX SDK (June 2010 version or newer), or reconfigure with --disable-webgl.])
fi
fi

View File

@ -7,8 +7,9 @@
#include "base/basictypes.h"
#include "gfx2DGlue.h"
#include "gfxImageSurface.h"
#include "gfxPattern.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMWindow.h"
#include "nsIDocShell.h"
@ -26,6 +27,7 @@
#include "mozilla/gfx/Matrix.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::ipc;
DocumentRendererChild::DocumentRendererChild()
@ -72,12 +74,13 @@ DocumentRendererChild::RenderDocument(nsIDOMWindow *window,
// Draw directly into the output array.
data.SetLength(renderSize.width * renderSize.height * 4);
nsRefPtr<gfxImageSurface> surf =
new gfxImageSurface(reinterpret_cast<uint8_t*>(data.BeginWriting()),
gfxIntSize(renderSize.width, renderSize.height),
4 * renderSize.width,
gfxImageFormat::ARGB32);
nsRefPtr<gfxContext> ctx = new gfxContext(surf);
RefPtr<DrawTarget> dt =
Factory::CreateDrawTargetForData(BackendType::CAIRO,
reinterpret_cast<uint8_t*>(data.BeginWriting()),
IntSize(renderSize.width, renderSize.height),
4 * renderSize.width,
SurfaceFormat::B8G8R8A8);
nsRefPtr<gfxContext> ctx = new gfxContext(dt);
ctx->SetMatrix(mozilla::gfx::ThebesMatrix(transform));
nsCOMPtr<nsIPresShell> shell = presContext->PresShell();

View File

@ -816,7 +816,6 @@ protected:
WebGLVertexAttrib0Status WhatDoesVertexAttrib0Need();
bool DoFakeVertexAttrib0(GLuint vertexCount);
void UndoFakeVertexAttrib0();
void InvalidateFakeVertexAttrib0();
static CheckedUint32 GetImageSize(GLsizei height,
GLsizei width,

View File

@ -60,7 +60,7 @@ WebGLContext::CreateQuery()
if (IsContextLost())
return nullptr;
if (mActiveOcclusionQuery && !gl->IsGLES2()) {
if (mActiveOcclusionQuery && !gl->IsGLES()) {
/* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
* Calling either GenQueriesARB or DeleteQueriesARB while any query of
* any target is active causes an INVALID_OPERATION error to be
@ -95,7 +95,7 @@ WebGLContext::DeleteQuery(WebGLQuery *query)
EndQuery(query->mType);
}
if (mActiveOcclusionQuery && !gl->IsGLES2()) {
if (mActiveOcclusionQuery && !gl->IsGLES()) {
/* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
* Calling either GenQueriesARB or DeleteQueriesARB while any query of
* any target is active causes an INVALID_OPERATION error to be

View File

@ -0,0 +1,726 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGLContext.h"
#include "GLContext.h"
#include "mozilla/CheckedInt.h"
#include "WebGLBuffer.h"
#include "WebGLFramebuffer.h"
#include "WebGLProgram.h"
#include "WebGLRenderbuffer.h"
#include "WebGLShader.h"
#include "WebGLTexture.h"
#include "WebGLUniformInfo.h"
#include "WebGLVertexArray.h"
#include "WebGLVertexAttribData.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gl;
// For a Tegra workaround.
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
bool
WebGLContext::DrawInstanced_check(const char* info)
{
// This restriction was removed in GLES3, so WebGL2 shouldn't have it.
if (!IsWebGL2() &&
IsExtensionEnabled(ANGLE_instanced_arrays) &&
!mBufferFetchingHasPerVertex)
{
/* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
* If all of the enabled vertex attribute arrays that are bound to active
* generic attributes in the program have a non-zero divisor, the draw
* call should return INVALID_OPERATION.
*
* NB: This also appears to apply to NV_instanced_arrays, though the
* INVALID_OPERATION emission is not explicitly stated.
* ARB_instanced_arrays does not have this restriction.
*/
ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
return false;
}
return true;
}
bool WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount, const char* info)
{
if (first < 0 || count < 0) {
ErrorInvalidValue("%s: negative first or count", info);
return false;
}
if (primcount < 0) {
ErrorInvalidValue("%s: negative primcount", info);
return false;
}
if (!ValidateStencilParamsForDrawCall()) {
return false;
}
// If count is 0, there's nothing to do.
if (count == 0 || primcount == 0) {
return false;
}
// If there is no current program, this is silently ignored.
// Any checks below this depend on a program being available.
if (!mCurrentProgram) {
return false;
}
if (!ValidateBufferFetching(info)) {
return false;
}
CheckedInt<GLsizei> checked_firstPlusCount = CheckedInt<GLsizei>(first) + count;
if (!checked_firstPlusCount.isValid()) {
ErrorInvalidOperation("%s: overflow in first+count", info);
return false;
}
if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient size for given first and count", info);
return false;
}
if (uint32_t(primcount) > mMaxFetchedInstances) {
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
return false;
}
MakeContextCurrent();
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
return false;
}
}
if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
return false;
}
BindFakeBlackTextures();
return true;
}
void
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
{
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
return;
if (!DrawArrays_check(first, count, 1, "drawArrays"))
return;
SetupContextLossTimer();
gl->fDrawArrays(mode, first, count);
Draw_cleanup();
}
void
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
{
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawArraysInstanced: mode"))
return;
if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
return;
if (!DrawInstanced_check("drawArraysInstanced"))
return;
SetupContextLossTimer();
gl->fDrawArraysInstanced(mode, first, count, primcount);
Draw_cleanup();
}
bool
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount,
const char* info, GLuint* out_upperBound)
{
if (count < 0 || byteOffset < 0) {
ErrorInvalidValue("%s: negative count or offset", info);
return false;
}
if (primcount < 0) {
ErrorInvalidValue("%s: negative primcount", info);
return false;
}
if (!ValidateStencilParamsForDrawCall()) {
return false;
}
// If count is 0, there's nothing to do.
if (count == 0 || primcount == 0) {
return false;
}
CheckedUint32 checked_byteCount;
GLsizei first = 0;
if (type == LOCAL_GL_UNSIGNED_SHORT) {
checked_byteCount = 2 * CheckedUint32(count);
if (byteOffset % 2 != 0) {
ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)", info);
return false;
}
first = byteOffset / 2;
}
else if (type == LOCAL_GL_UNSIGNED_BYTE) {
checked_byteCount = count;
first = byteOffset;
}
else if (type == LOCAL_GL_UNSIGNED_INT && IsExtensionEnabled(OES_element_index_uint)) {
checked_byteCount = 4 * CheckedUint32(count);
if (byteOffset % 4 != 0) {
ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_INT (must be a multiple of 4)", info);
return false;
}
first = byteOffset / 4;
}
else {
ErrorInvalidEnum("%s: type must be UNSIGNED_SHORT or UNSIGNED_BYTE", info);
return false;
}
if (!checked_byteCount.isValid()) {
ErrorInvalidValue("%s: overflow in byteCount", info);
return false;
}
// If there is no current program, this is silently ignored.
// Any checks below this depend on a program being available.
if (!mCurrentProgram) {
return false;
}
if (!mBoundVertexArray->mBoundElementArrayBuffer) {
ErrorInvalidOperation("%s: must have element array buffer binding", info);
return false;
}
WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mBoundElementArrayBuffer;
if (!elemArrayBuffer.ByteLength()) {
ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
return false;
}
CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
if (!checked_neededByteCount.isValid()) {
ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
return false;
}
if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
return false;
}
if (!ValidateBufferFetching(info))
return false;
if (!mMaxFetchedVertices ||
!elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
{
ErrorInvalidOperation(
"%s: bound vertex attribute buffers do not have sufficient "
"size for given indices from the bound element array", info);
return false;
}
if (uint32_t(primcount) > mMaxFetchedInstances) {
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
return false;
}
MakeContextCurrent();
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
return false;
}
}
if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
return false;
}
BindFakeBlackTextures();
return true;
}
void
WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset)
{
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
return;
GLuint upperBound = UINT_MAX;
if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
&upperBound))
{
return;
}
SetupContextLossTimer();
if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
gl->fDrawRangeElements(mode, 0, upperBound,
count, type, reinterpret_cast<GLvoid*>(byteOffset));
} else {
gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
}
Draw_cleanup();
}
void
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount)
{
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
return;
if (!DrawElements_check(count, type, byteOffset, primcount, "drawElementsInstanced"))
return;
if (!DrawInstanced_check("drawElementsInstanced"))
return;
SetupContextLossTimer();
gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
Draw_cleanup();
}
void WebGLContext::Draw_cleanup()
{
UndoFakeVertexAttrib0();
UnbindFakeBlackTextures();
if (!mBoundFramebuffer) {
Invalidate();
mShouldPresent = true;
mIsScreenCleared = false;
}
if (gl->WorkAroundDriverBugs()) {
if (gl->Renderer() == gl::GLRenderer::Tegra) {
mDrawCallsSinceLastFlush++;
if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
gl->fFlush();
mDrawCallsSinceLastFlush = 0;
}
}
}
// Let's check the viewport
const WebGLRectangleObject* rect = CurValidFBRectObject();
if (rect) {
if (mViewportWidth > rect->Width() ||
mViewportHeight > rect->Height())
{
if (!mAlreadyWarnedAboutViewportLargerThanDest) {
GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
"(This warning will only be given once)");
mAlreadyWarnedAboutViewportLargerThanDest = true;
}
}
}
}
/*
* Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
* that will be legal to be read from bound VBOs.
*/
bool
WebGLContext::ValidateBufferFetching(const char *info)
{
#ifdef DEBUG
GLint currentProgram = 0;
MakeContextCurrent();
gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->GLName(),
"WebGL: current program doesn't agree with GL state");
#endif
if (mBufferFetchingIsVerified) {
return true;
}
bool hasPerVertex = false;
uint32_t maxVertices = UINT32_MAX;
uint32_t maxInstances = UINT32_MAX;
uint32_t attribs = mBoundVertexArray->mAttribs.Length();
for (uint32_t i = 0; i < attribs; ++i) {
const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[i];
// If the attrib array isn't enabled, there's nothing to check;
// it's a static value.
if (!vd.enabled)
continue;
if (vd.buf == nullptr) {
ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
return false;
}
// If the attrib is not in use, then we don't have to validate
// it, just need to make sure that the binding is non-null.
if (!mCurrentProgram->IsAttribInUse(i))
continue;
// the base offset
CheckedUint32 checked_byteLength = CheckedUint32(vd.buf->ByteLength()) - vd.byteOffset;
CheckedUint32 checked_sizeOfLastElement = CheckedUint32(vd.componentSize()) * vd.size;
if (!checked_byteLength.isValid() ||
!checked_sizeOfLastElement.isValid())
{
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false;
}
if (checked_byteLength.value() < checked_sizeOfLastElement.value()) {
maxVertices = 0;
maxInstances = 0;
break;
}
CheckedUint32 checked_maxAllowedCount = ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
if (!checked_maxAllowedCount.isValid()) {
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false;
}
if (vd.divisor == 0) {
maxVertices = std::min(maxVertices, checked_maxAllowedCount.value());
hasPerVertex = true;
} else {
maxInstances = std::min(maxInstances, checked_maxAllowedCount.value() / vd.divisor);
}
}
mBufferFetchingIsVerified = true;
mBufferFetchingHasPerVertex = hasPerVertex;
mMaxFetchedVertices = maxVertices;
mMaxFetchedInstances = maxInstances;
return true;
}
WebGLVertexAttrib0Status
WebGLContext::WhatDoesVertexAttrib0Need()
{
MOZ_ASSERT(mCurrentProgram);
// work around Mac OSX crash, see bug 631420
#ifdef XP_MACOSX
if (gl->WorkAroundDriverBugs() &&
mBoundVertexArray->IsAttribArrayEnabled(0) &&
!mCurrentProgram->IsAttribInUse(0))
{
return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
}
#endif
if (MOZ_LIKELY(gl->IsGLES() ||
mBoundVertexArray->IsAttribArrayEnabled(0)))
{
return WebGLVertexAttrib0Status::Default;
}
return mCurrentProgram->IsAttribInUse(0)
? WebGLVertexAttrib0Status::EmulatedInitializedArray
: WebGLVertexAttrib0Status::EmulatedUninitializedArray;
}
bool
WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
{
WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
return true;
if (!mAlreadyWarnedAboutFakeVertexAttrib0) {
GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser "
"to do expensive emulation work when running on desktop OpenGL "
"platforms, for example on Mac. It is preferable to always draw "
"with vertex attrib 0 array enabled, by using bindAttribLocation "
"to bind some always-used attribute to location 0.");
mAlreadyWarnedAboutFakeVertexAttrib0 = true;
}
CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(GLfloat);
if (!checked_dataSize.isValid()) {
ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
"with %d vertices. Try reducing the number of vertices.", vertexCount);
return false;
}
GLuint dataSize = checked_dataSize.value();
if (!mFakeVertexAttrib0BufferObject) {
gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject);
}
// if the VBO status is already exactly what we need, or if the only difference is that it's initialized and
// we don't need it to be, then consider it OK
bool vertexAttrib0BufferStatusOK =
mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need ||
(mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray &&
whatDoesAttrib0Need == WebGLVertexAttrib0Status::EmulatedUninitializedArray);
if (!vertexAttrib0BufferStatusOK ||
mFakeVertexAttrib0BufferObjectSize < dataSize ||
mFakeVertexAttrib0BufferObjectVector[0] != mVertexAttrib0Vector[0] ||
mFakeVertexAttrib0BufferObjectVector[1] != mVertexAttrib0Vector[1] ||
mFakeVertexAttrib0BufferObjectVector[2] != mVertexAttrib0Vector[2] ||
mFakeVertexAttrib0BufferObjectVector[3] != mVertexAttrib0Vector[3])
{
mFakeVertexAttrib0BufferStatus = whatDoesAttrib0Need;
mFakeVertexAttrib0BufferObjectSize = dataSize;
mFakeVertexAttrib0BufferObjectVector[0] = mVertexAttrib0Vector[0];
mFakeVertexAttrib0BufferObjectVector[1] = mVertexAttrib0Vector[1];
mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
GetAndFlushUnderlyingGLErrors();
if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]);
for(size_t i = 0; i < vertexCount; ++i) {
array[4 * i + 0] = mVertexAttrib0Vector[0];
array[4 * i + 1] = mVertexAttrib0Vector[1];
array[4 * i + 2] = mVertexAttrib0Vector[2];
array[4 * i + 3] = mVertexAttrib0Vector[3];
}
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array, LOCAL_GL_DYNAMIC_DRAW);
} else {
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW);
}
GLenum error = GetAndFlushUnderlyingGLErrors();
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
// note that we do this error checking and early return AFTER having restored the buffer binding above
if (error) {
ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation "
"with %d vertices. Try reducing the number of vertices.", vertexCount);
return false;
}
}
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0);
return true;
}
void
WebGLContext::UndoFakeVertexAttrib0()
{
WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
return;
if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) {
const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName());
gl->fVertexAttribPointer(0,
attrib0.size,
attrib0.type,
attrib0.normalized,
attrib0.stride,
reinterpret_cast<const GLvoid *>(attrib0.byteOffset));
} else {
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
}
WebGLContextFakeBlackStatus
WebGLContext::ResolvedFakeBlackStatus()
{
// handle this case first, it's the generic case
if (MOZ_LIKELY(mFakeBlackStatus == WebGLContextFakeBlackStatus::NotNeeded))
return mFakeBlackStatus;
if (mFakeBlackStatus == WebGLContextFakeBlackStatus::Needed)
return mFakeBlackStatus;
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if ((mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) ||
(mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded))
{
mFakeBlackStatus = WebGLContextFakeBlackStatus::Needed;
return mFakeBlackStatus;
}
}
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
// that means that we do NOT need it.
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
return mFakeBlackStatus;
}
void
WebGLContext::BindFakeBlackTexturesHelper(
GLenum target,
const nsTArray<WebGLRefPtr<WebGLTexture> > & boundTexturesArray,
ScopedDeletePtr<FakeBlackTexture> & opaqueTextureScopedPtr,
ScopedDeletePtr<FakeBlackTexture> & transparentTextureScopedPtr)
{
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if (!boundTexturesArray[i]) {
continue;
}
WebGLTextureFakeBlackStatus s = boundTexturesArray[i]->ResolvedFakeBlackStatus();
MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown);
if (MOZ_LIKELY(s == WebGLTextureFakeBlackStatus::NotNeeded)) {
continue;
}
bool alpha = s == WebGLTextureFakeBlackStatus::UninitializedImageData &&
FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().InternalFormat());
ScopedDeletePtr<FakeBlackTexture>&
blackTexturePtr = alpha
? transparentTextureScopedPtr
: opaqueTextureScopedPtr;
if (!blackTexturePtr) {
GLenum format = alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
blackTexturePtr
= new FakeBlackTexture(gl, target, format);
}
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(target,
blackTexturePtr->GLName());
}
}
void
WebGLContext::BindFakeBlackTextures()
{
// this is the generic case: try to return early
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
return;
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_2D,
mBound2DTextures,
mBlackOpaqueTexture2D,
mBlackTransparentTexture2D);
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_CUBE_MAP,
mBoundCubeMapTextures,
mBlackOpaqueTextureCubeMap,
mBlackTransparentTextureCubeMap);
}
void
WebGLContext::UnbindFakeBlackTextures()
{
// this is the generic case: try to return early
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
return;
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if (mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->GLName());
}
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->GLName());
}
}
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
}
WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format)
: mGL(gl)
, mGLName(0)
{
MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP);
MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA);
mGL->MakeCurrent();
GLuint formerBinding = 0;
gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D
? LOCAL_GL_TEXTURE_BINDING_2D
: LOCAL_GL_TEXTURE_BINDING_CUBE_MAP,
&formerBinding);
gl->fGenTextures(1, &mGLName);
gl->fBindTexture(target, mGLName);
// we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
// to minimize the risk of running into a driver bug in texImage2D, as it is
// a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
// that texImage2D expects.
void* zeros = calloc(1, 16);
if (target == LOCAL_GL_TEXTURE_2D) {
gl->fTexImage2D(target, 0, format, 1, 1,
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
} else {
for (GLuint i = 0; i < 6; ++i) {
gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
}
}
free(zeros);
gl->fBindTexture(target, formerBinding);
}
WebGLContext::FakeBlackTexture::~FakeBlackTexture()
{
if (mGL) {
mGL->MakeCurrent();
mGL->fDeleteTextures(1, &mGLName);
}
}

View File

@ -72,49 +72,6 @@ WebGLContext::CurValidFBRectObject() const
return rect;
}
WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format)
: mGL(gl)
, mGLName(0)
{
MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP);
MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA);
mGL->MakeCurrent();
GLuint formerBinding = 0;
gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D
? LOCAL_GL_TEXTURE_BINDING_2D
: LOCAL_GL_TEXTURE_BINDING_CUBE_MAP,
&formerBinding);
gl->fGenTextures(1, &mGLName);
gl->fBindTexture(target, mGLName);
// we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
// to minimize the risk of running into a driver bug in texImage2D, as it is
// a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
// that texImage2D expects.
void* zeros = calloc(1, 16);
if (target == LOCAL_GL_TEXTURE_2D) {
gl->fTexImage2D(target, 0, format, 1, 1,
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
} else {
for (GLuint i = 0; i < 6; ++i) {
gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
}
}
free(zeros);
gl->fBindTexture(target, formerBinding);
}
WebGLContext::FakeBlackTexture::~FakeBlackTexture()
{
if (mGL) {
mGL->MakeCurrent();
mGL->fDeleteTextures(1, &mGLName);
}
}
//
// WebGL API
//
@ -834,237 +791,6 @@ WebGLContext::DepthRange(GLfloat zNear, GLfloat zFar)
gl->fDepthRange(zNear, zFar);
}
WebGLVertexAttrib0Status
WebGLContext::WhatDoesVertexAttrib0Need()
{
// here we may assume that mCurrentProgram != null
// work around Mac OSX crash, see bug 631420
#ifdef XP_MACOSX
if (gl->WorkAroundDriverBugs() &&
mBoundVertexArray->IsAttribArrayEnabled(0) &&
!mCurrentProgram->IsAttribInUse(0))
{
return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
}
#endif
return (gl->IsGLES2() || mBoundVertexArray->IsAttribArrayEnabled(0)) ? WebGLVertexAttrib0Status::Default
: mCurrentProgram->IsAttribInUse(0) ? WebGLVertexAttrib0Status::EmulatedInitializedArray
: WebGLVertexAttrib0Status::EmulatedUninitializedArray;
}
bool
WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
{
WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
if (whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default)
return true;
if (!mAlreadyWarnedAboutFakeVertexAttrib0) {
GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser "
"to do expensive emulation work when running on desktop OpenGL "
"platforms, for example on Mac. It is preferable to always draw "
"with vertex attrib 0 array enabled, by using bindAttribLocation "
"to bind some always-used attribute to location 0.");
mAlreadyWarnedAboutFakeVertexAttrib0 = true;
}
CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(GLfloat);
if (!checked_dataSize.isValid()) {
ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
"with %d vertices. Try reducing the number of vertices.", vertexCount);
return false;
}
GLuint dataSize = checked_dataSize.value();
if (!mFakeVertexAttrib0BufferObject) {
gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject);
}
// if the VBO status is already exactly what we need, or if the only difference is that it's initialized and
// we don't need it to be, then consider it OK
bool vertexAttrib0BufferStatusOK =
mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need ||
(mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray &&
whatDoesAttrib0Need == WebGLVertexAttrib0Status::EmulatedUninitializedArray);
if (!vertexAttrib0BufferStatusOK ||
mFakeVertexAttrib0BufferObjectSize < dataSize ||
mFakeVertexAttrib0BufferObjectVector[0] != mVertexAttrib0Vector[0] ||
mFakeVertexAttrib0BufferObjectVector[1] != mVertexAttrib0Vector[1] ||
mFakeVertexAttrib0BufferObjectVector[2] != mVertexAttrib0Vector[2] ||
mFakeVertexAttrib0BufferObjectVector[3] != mVertexAttrib0Vector[3])
{
mFakeVertexAttrib0BufferStatus = whatDoesAttrib0Need;
mFakeVertexAttrib0BufferObjectSize = dataSize;
mFakeVertexAttrib0BufferObjectVector[0] = mVertexAttrib0Vector[0];
mFakeVertexAttrib0BufferObjectVector[1] = mVertexAttrib0Vector[1];
mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
GetAndFlushUnderlyingGLErrors();
if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]);
for(size_t i = 0; i < vertexCount; ++i) {
array[4 * i + 0] = mVertexAttrib0Vector[0];
array[4 * i + 1] = mVertexAttrib0Vector[1];
array[4 * i + 2] = mVertexAttrib0Vector[2];
array[4 * i + 3] = mVertexAttrib0Vector[3];
}
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array, LOCAL_GL_DYNAMIC_DRAW);
} else {
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW);
}
GLenum error = GetAndFlushUnderlyingGLErrors();
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
// note that we do this error checking and early return AFTER having restored the buffer binding above
if (error) {
ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation "
"with %d vertices. Try reducing the number of vertices.", vertexCount);
return false;
}
}
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0);
return true;
}
void
WebGLContext::UndoFakeVertexAttrib0()
{
WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
if (whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default)
return;
if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) {
const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName());
gl->fVertexAttribPointer(0,
attrib0.size,
attrib0.type,
attrib0.normalized,
attrib0.stride,
reinterpret_cast<const GLvoid *>(attrib0.byteOffset));
} else {
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
}
WebGLContextFakeBlackStatus
WebGLContext::ResolvedFakeBlackStatus()
{
// handle this case first, it's the generic case
if (MOZ_LIKELY(mFakeBlackStatus == WebGLContextFakeBlackStatus::NotNeeded))
return mFakeBlackStatus;
if (mFakeBlackStatus == WebGLContextFakeBlackStatus::Needed)
return mFakeBlackStatus;
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if ((mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) ||
(mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded))
{
mFakeBlackStatus = WebGLContextFakeBlackStatus::Needed;
return mFakeBlackStatus;
}
}
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
// that means that we do NOT need it.
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
return mFakeBlackStatus;
}
void
WebGLContext::BindFakeBlackTexturesHelper(
GLenum target,
const nsTArray<WebGLRefPtr<WebGLTexture> > & boundTexturesArray,
ScopedDeletePtr<FakeBlackTexture> & opaqueTextureScopedPtr,
ScopedDeletePtr<FakeBlackTexture> & transparentTextureScopedPtr)
{
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if (!boundTexturesArray[i]) {
continue;
}
WebGLTextureFakeBlackStatus s = boundTexturesArray[i]->ResolvedFakeBlackStatus();
MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown);
if (MOZ_LIKELY(s == WebGLTextureFakeBlackStatus::NotNeeded)) {
continue;
}
bool alpha = s == WebGLTextureFakeBlackStatus::UninitializedImageData &&
FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().InternalFormat());
ScopedDeletePtr<FakeBlackTexture>&
blackTexturePtr = alpha
? transparentTextureScopedPtr
: opaqueTextureScopedPtr;
if (!blackTexturePtr) {
GLenum format = alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
blackTexturePtr
= new FakeBlackTexture(gl, target, format);
}
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(target,
blackTexturePtr->GLName());
}
}
void
WebGLContext::BindFakeBlackTextures()
{
// this is the generic case: try to return early
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
return;
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_2D,
mBound2DTextures,
mBlackOpaqueTexture2D,
mBlackTransparentTexture2D);
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_CUBE_MAP,
mBoundCubeMapTextures,
mBlackOpaqueTextureCubeMap,
mBlackTransparentTextureCubeMap);
}
void
WebGLContext::UnbindFakeBlackTextures()
{
// this is the generic case: try to return early
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
return;
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if (mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->GLName());
}
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->GLName());
}
}
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
}
void
WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum rbtarget, WebGLRenderbuffer *wrb)
{
@ -2622,14 +2348,14 @@ WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGB5_A1:
// 16-bit RGBA formats are not supported on desktop GL
if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGBA8;
if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGBA8;
break;
case LOCAL_GL_RGB565:
// the RGB565 format is not supported on desktop GL
if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGB8;
if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGB8;
break;
case LOCAL_GL_DEPTH_COMPONENT16:
if (!gl->IsGLES2() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
internalformatForGL = LOCAL_GL_DEPTH_COMPONENT24;
else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil))
internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
@ -3230,7 +2956,7 @@ WebGLContext::CompileShader(WebGLShader *shader)
MakeContextCurrent();
ShShaderOutput targetShaderSourceLanguage = gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
ShShaderOutput targetShaderSourceLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
bool useShaderSourceTranslation = true;
if (shader->NeedsTranslation() && mShaderValidation) {
@ -3800,7 +3526,7 @@ GLenum WebGLContext::CheckedTexImage2D(GLenum target,
// convert type for half float if not on GLES2
GLenum realType = type;
if (realType == LOCAL_GL_HALF_FLOAT_OES && !gl->IsGLES2()) {
if (realType == LOCAL_GL_HALF_FLOAT_OES && !gl->IsGLES()) {
realType = LOCAL_GL_HALF_FLOAT;
}
@ -3882,7 +3608,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
// Handle ES2 and GL differences in floating point internal formats. Note that
// format == internalformat, as checked above and as required by ES.
internalformat = InternalFormatForFormatAndType(format, type, gl->IsGLES2());
internalformat = InternalFormatForFormatAndType(format, type, gl->IsGLES());
// Handle ES2 and GL differences when supporting sRGB internal formats. GL ES
// requires that format == internalformat, but GL will fail in this case.
@ -3890,7 +3616,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
// format -> internalformat
// GL_RGB GL_SRGB_EXT
// GL_RGBA GL_SRGB_ALPHA_EXT
if (!gl->IsGLES2()) {
if (!gl->IsGLES()) {
switch (internalformat) {
case LOCAL_GL_SRGB_EXT:
format = LOCAL_GL_RGB;

View File

@ -1631,7 +1631,7 @@ WebGLContext::InitAndValidateGL()
MakeContextCurrent();
// on desktop OpenGL, we always keep vertex attrib 0 array enabled
if (!gl->IsGLES2()) {
if (!gl->IsGLES()) {
gl->fEnableVertexAttribArray(0);
}
@ -1729,7 +1729,7 @@ WebGLContext::InitAndValidateGL()
// Always 1 for GLES2
mMaxFramebufferColorAttachments = 1;
if (!gl->IsGLES2()) {
if (!gl->IsGLES()) {
// gl_PointSize is always available in ES2 GLSL, but has to be
// specifically enabled on desktop GLSL.
gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);

View File

@ -20,9 +20,6 @@
using namespace mozilla;
using namespace dom;
// For a Tegra workaround.
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
void
WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
{
@ -38,7 +35,7 @@ WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
mVertexAttrib0Vector[1] = 0;
mVertexAttrib0Vector[2] = 0;
mVertexAttrib0Vector[3] = 1;
if (gl->IsGLES2())
if (gl->IsGLES())
gl->fVertexAttrib1f(index, x0);
}
}
@ -58,7 +55,7 @@ WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1)
mVertexAttrib0Vector[1] = x1;
mVertexAttrib0Vector[2] = 0;
mVertexAttrib0Vector[3] = 1;
if (gl->IsGLES2())
if (gl->IsGLES())
gl->fVertexAttrib2f(index, x0, x1);
}
}
@ -78,7 +75,7 @@ WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2)
mVertexAttrib0Vector[1] = x1;
mVertexAttrib0Vector[2] = x2;
mVertexAttrib0Vector[3] = 1;
if (gl->IsGLES2())
if (gl->IsGLES())
gl->fVertexAttrib3f(index, x0, x1, x2);
}
}
@ -99,7 +96,7 @@ WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1,
mVertexAttrib0Vector[1] = x1;
mVertexAttrib0Vector[2] = x2;
mVertexAttrib0Vector[3] = x3;
if (gl->IsGLES2())
if (gl->IsGLES())
gl->fVertexAttrib4f(index, x0, x1, x2, x3);
}
}
@ -120,7 +117,7 @@ WebGLContext::VertexAttrib1fv_base(GLuint idx, uint32_t arrayLength,
mVertexAttrib0Vector[1] = GLfloat(0);
mVertexAttrib0Vector[2] = GLfloat(0);
mVertexAttrib0Vector[3] = GLfloat(1);
if (gl->IsGLES2())
if (gl->IsGLES())
gl->fVertexAttrib1fv(idx, ptr);
}
}
@ -140,7 +137,7 @@ WebGLContext::VertexAttrib2fv_base(GLuint idx, uint32_t arrayLength,
mVertexAttrib0Vector[1] = ptr[1];
mVertexAttrib0Vector[2] = GLfloat(0);
mVertexAttrib0Vector[3] = GLfloat(1);
if (gl->IsGLES2())
if (gl->IsGLES())
gl->fVertexAttrib2fv(idx, ptr);
}
}
@ -160,7 +157,7 @@ WebGLContext::VertexAttrib3fv_base(GLuint idx, uint32_t arrayLength,
mVertexAttrib0Vector[1] = ptr[1];
mVertexAttrib0Vector[2] = ptr[2];
mVertexAttrib0Vector[3] = GLfloat(1);
if (gl->IsGLES2())
if (gl->IsGLES())
gl->fVertexAttrib3fv(idx, ptr);
}
}
@ -180,7 +177,7 @@ WebGLContext::VertexAttrib4fv_base(GLuint idx, uint32_t arrayLength,
mVertexAttrib0Vector[1] = ptr[1];
mVertexAttrib0Vector[2] = ptr[2];
mVertexAttrib0Vector[3] = ptr[3];
if (gl->IsGLES2())
if (gl->IsGLES())
gl->fVertexAttrib4fv(idx, ptr);
}
}
@ -214,7 +211,7 @@ WebGLContext::DisableVertexAttribArray(GLuint index)
MakeContextCurrent();
InvalidateBufferFetching();
if (index || gl->IsGLES2())
if (index || gl->IsGLES())
gl->fDisableVertexAttribArray(index);
MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier
@ -426,425 +423,3 @@ WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
gl->fVertexAttribDivisor(index, divisor);
}
bool
WebGLContext::DrawInstanced_check(const char* info)
{
// This restriction was removed in GLES3, so WebGL2 shouldn't have it.
if (!IsWebGL2() &&
IsExtensionEnabled(ANGLE_instanced_arrays) &&
!mBufferFetchingHasPerVertex)
{
/* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
* If all of the enabled vertex attribute arrays that are bound to active
* generic attributes in the program have a non-zero divisor, the draw
* call should return INVALID_OPERATION.
*
* NB: This also appears to apply to NV_instanced_arrays, though the
* INVALID_OPERATION emission is not explicitly stated.
* ARB_instanced_arrays does not have this restriction.
*/
ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
return false;
}
return true;
}
bool WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount, const char* info)
{
if (first < 0 || count < 0) {
ErrorInvalidValue("%s: negative first or count", info);
return false;
}
if (primcount < 0) {
ErrorInvalidValue("%s: negative primcount", info);
return false;
}
if (!ValidateStencilParamsForDrawCall()) {
return false;
}
// If count is 0, there's nothing to do.
if (count == 0 || primcount == 0) {
return false;
}
// If there is no current program, this is silently ignored.
// Any checks below this depend on a program being available.
if (!mCurrentProgram) {
return false;
}
if (!ValidateBufferFetching(info)) {
return false;
}
CheckedInt<GLsizei> checked_firstPlusCount = CheckedInt<GLsizei>(first) + count;
if (!checked_firstPlusCount.isValid()) {
ErrorInvalidOperation("%s: overflow in first+count", info);
return false;
}
if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient size for given first and count", info);
return false;
}
if (uint32_t(primcount) > mMaxFetchedInstances) {
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
return false;
}
MakeContextCurrent();
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
return false;
}
}
if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
return false;
}
BindFakeBlackTextures();
return true;
}
void
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
{
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
return;
if (!DrawArrays_check(first, count, 1, "drawArrays"))
return;
SetupContextLossTimer();
gl->fDrawArrays(mode, first, count);
Draw_cleanup();
}
void
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
{
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawArraysInstanced: mode"))
return;
if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
return;
if (!DrawInstanced_check("drawArraysInstanced"))
return;
SetupContextLossTimer();
gl->fDrawArraysInstanced(mode, first, count, primcount);
Draw_cleanup();
}
bool
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount,
const char* info, GLuint* out_upperBound)
{
if (count < 0 || byteOffset < 0) {
ErrorInvalidValue("%s: negative count or offset", info);
return false;
}
if (primcount < 0) {
ErrorInvalidValue("%s: negative primcount", info);
return false;
}
if (!ValidateStencilParamsForDrawCall()) {
return false;
}
// If count is 0, there's nothing to do.
if (count == 0 || primcount == 0) {
return false;
}
CheckedUint32 checked_byteCount;
GLsizei first = 0;
if (type == LOCAL_GL_UNSIGNED_SHORT) {
checked_byteCount = 2 * CheckedUint32(count);
if (byteOffset % 2 != 0) {
ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)", info);
return false;
}
first = byteOffset / 2;
}
else if (type == LOCAL_GL_UNSIGNED_BYTE) {
checked_byteCount = count;
first = byteOffset;
}
else if (type == LOCAL_GL_UNSIGNED_INT && IsExtensionEnabled(OES_element_index_uint)) {
checked_byteCount = 4 * CheckedUint32(count);
if (byteOffset % 4 != 0) {
ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_INT (must be a multiple of 4)", info);
return false;
}
first = byteOffset / 4;
}
else {
ErrorInvalidEnum("%s: type must be UNSIGNED_SHORT or UNSIGNED_BYTE", info);
return false;
}
if (!checked_byteCount.isValid()) {
ErrorInvalidValue("%s: overflow in byteCount", info);
return false;
}
// If there is no current program, this is silently ignored.
// Any checks below this depend on a program being available.
if (!mCurrentProgram) {
return false;
}
if (!mBoundVertexArray->mBoundElementArrayBuffer) {
ErrorInvalidOperation("%s: must have element array buffer binding", info);
return false;
}
WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mBoundElementArrayBuffer;
if (!elemArrayBuffer.ByteLength()) {
ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
return false;
}
CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
if (!checked_neededByteCount.isValid()) {
ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
return false;
}
if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
return false;
}
if (!ValidateBufferFetching(info))
return false;
if (!mMaxFetchedVertices ||
!elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
{
ErrorInvalidOperation(
"%s: bound vertex attribute buffers do not have sufficient "
"size for given indices from the bound element array", info);
return false;
}
if (uint32_t(primcount) > mMaxFetchedInstances) {
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
return false;
}
MakeContextCurrent();
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
return false;
}
}
if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
return false;
}
BindFakeBlackTextures();
return true;
}
void
WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset)
{
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
return;
GLuint upperBound = UINT_MAX;
if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
&upperBound))
{
return;
}
SetupContextLossTimer();
if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
gl->fDrawRangeElements(mode, 0, upperBound,
count, type, reinterpret_cast<GLvoid*>(byteOffset));
} else {
gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
}
Draw_cleanup();
}
void
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount)
{
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
return;
if (!DrawElements_check(count, type, byteOffset, primcount, "drawElementsInstanced"))
return;
if (!DrawInstanced_check("drawElementsInstanced"))
return;
SetupContextLossTimer();
gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
Draw_cleanup();
}
void WebGLContext::Draw_cleanup()
{
UndoFakeVertexAttrib0();
UnbindFakeBlackTextures();
if (!mBoundFramebuffer) {
Invalidate();
mShouldPresent = true;
mIsScreenCleared = false;
}
if (gl->WorkAroundDriverBugs()) {
if (gl->Renderer() == gl::GLRenderer::Tegra) {
mDrawCallsSinceLastFlush++;
if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
gl->fFlush();
mDrawCallsSinceLastFlush = 0;
}
}
}
// Let's check the viewport
const WebGLRectangleObject* rect = CurValidFBRectObject();
if (rect) {
if (mViewportWidth > rect->Width() ||
mViewportHeight > rect->Height())
{
if (!mAlreadyWarnedAboutViewportLargerThanDest) {
GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
"(This warning will only be given once)");
mAlreadyWarnedAboutViewportLargerThanDest = true;
}
}
}
}
/*
* Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
* that will be legal to be read from bound VBOs.
*/
bool
WebGLContext::ValidateBufferFetching(const char *info)
{
#ifdef DEBUG
GLint currentProgram = 0;
MakeContextCurrent();
gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->GLName(),
"WebGL: current program doesn't agree with GL state");
#endif
if (mBufferFetchingIsVerified) {
return true;
}
bool hasPerVertex = false;
uint32_t maxVertices = UINT32_MAX;
uint32_t maxInstances = UINT32_MAX;
uint32_t attribs = mBoundVertexArray->mAttribs.Length();
for (uint32_t i = 0; i < attribs; ++i) {
const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[i];
// If the attrib array isn't enabled, there's nothing to check;
// it's a static value.
if (!vd.enabled)
continue;
if (vd.buf == nullptr) {
ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
return false;
}
// If the attrib is not in use, then we don't have to validate
// it, just need to make sure that the binding is non-null.
if (!mCurrentProgram->IsAttribInUse(i))
continue;
// the base offset
CheckedUint32 checked_byteLength = CheckedUint32(vd.buf->ByteLength()) - vd.byteOffset;
CheckedUint32 checked_sizeOfLastElement = CheckedUint32(vd.componentSize()) * vd.size;
if (!checked_byteLength.isValid() ||
!checked_sizeOfLastElement.isValid())
{
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false;
}
if (checked_byteLength.value() < checked_sizeOfLastElement.value()) {
maxVertices = 0;
maxInstances = 0;
break;
}
CheckedUint32 checked_maxAllowedCount = ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
if (!checked_maxAllowedCount.isValid()) {
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false;
}
if (vd.divisor == 0) {
maxVertices = std::min(maxVertices, checked_maxAllowedCount.value());
hasPerVertex = true;
} else {
maxInstances = std::min(maxInstances, checked_maxAllowedCount.value() / vd.divisor);
}
}
mBufferFetchingIsVerified = true;
mBufferFetchingHasPerVertex = hasPerVertex;
mMaxFetchedVertices = maxVertices;
mMaxFetchedInstances = maxInstances;
return true;
}

View File

@ -890,7 +890,7 @@ FinalizeDrawAndReadBuffers(GLContext* aGL, bool aColorBufferDefined)
//
// Note that this test is not performed if OpenGL 4.2 or ARB_ES2_compatibility is
// available.
if (aGL->IsGLES2() ||
if (aGL->IsGLES() ||
aGL->IsSupported(GLFeature::ES2_compatibility) ||
aGL->IsAtLeast(ContextProfile::OpenGL, 420))
{

View File

@ -16,7 +16,7 @@ using namespace mozilla::gl;
static GLenum
DepthStencilDepthFormat(GLContext* gl) {
// We might not be able to get 24-bit, so let's pretend!
if (gl->IsGLES2() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
if (gl->IsGLES() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
return LOCAL_GL_DEPTH_COMPONENT16;
return LOCAL_GL_DEPTH_COMPONENT24;

View File

@ -125,7 +125,7 @@ WebGLTexture::Bind(GLenum aTarget) {
// thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
// present in GLES 2, but is present in GL and it seems as if for cube maps
// we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior.
if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES2())
if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES())
mContext->gl->fTexParameteri(mTarget, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
}

View File

@ -32,6 +32,7 @@ if CONFIG['MOZ_WEBGL']:
'WebGLContext.cpp',
'WebGLContextAsyncQueries.cpp',
'WebGLContextBuffers.cpp',
'WebGLContextDraw.cpp',
'WebGLContextExtensions.cpp',
'WebGLContextFramebufferOperations.cpp',
'WebGLContextGL.cpp',

View File

@ -669,6 +669,22 @@ CouldBeDOMBinding(nsWrapperCache* aCache)
return aCache->IsDOMBinding();
}
inline bool
TryToOuterize(JSContext* cx, JS::MutableHandle<JS::Value> rval)
{
if (js::IsInnerObject(&rval.toObject())) {
JS::Rooted<JSObject*> obj(cx, &rval.toObject());
obj = JS_ObjectToOuterObject(cx, obj);
if (!obj) {
return false;
}
rval.set(JS::ObjectValue(*obj));
}
return true;
}
// Make sure to wrap the given string value into the right compartment, as
// needed.
MOZ_ALWAYS_INLINE
@ -697,10 +713,10 @@ MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
return JS_WrapValue(cx, rval);
}
// We're same-compartment. If we're a WebIDL object, we're done.
// We're same-compartment, but even then we might need to wrap
// objects specially. Check for that.
if (IsDOMObject(obj)) {
rval.set(JS::ObjectValue(*obj));
return true;
return TryToOuterize(cx, rval);
}
// It's not a WebIDL object. But it might be an XPConnect one, in which case
@ -821,14 +837,17 @@ WrapNewBindingObject(JSContext* cx, JS::Handle<JSObject*> scope, T* value,
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
#endif
rval.set(JS::ObjectValue(*obj));
bool sameCompartment =
js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
if (sameCompartment && couldBeDOMBinding) {
rval.set(JS::ObjectValue(*obj));
return true;
// We only need to outerize Window objects, so anything inheriting from
// nsGlobalWindow (which inherits from EventTarget itself).
return IsBaseOf<nsGlobalWindow, T>::value || IsSame<EventTarget, T>::value ?
TryToOuterize(cx, rval) : true;
}
rval.set(JS::ObjectValue(*obj));
return JS_WrapValue(cx, rval);
}

View File

@ -14,18 +14,19 @@ Cu.import("resource://gre/modules/ContactService.jsm", imports);
Cu.import("resource://gre/modules/Promise.jsm", imports);
Cu.importGlobalProperties(["indexedDB"]);
// |const| will not work because
// it will make the Promise object immutable before assigning.
// Using |let| and Object.freeze() instead.
let {
const {
STORE_NAME,
SAVED_GETALL_STORE_NAME,
REVISION_STORE,
DB_NAME,
ContactService,
Promise
} = imports;
Object.freeze(imports);
// |const| will not work because
// it will make the Promise object immutable before assigning.
// Using Object.defineProperty() instead.
Object.defineProperty(this, "Promise", {
value: imports.Promise, writable: false, configurable: false
});
let DEBUG = false;
function debug(str) {

View File

@ -419,7 +419,7 @@ nsPluginTag::GetMimeTypes(uint32_t* aCount, char16_t*** aResults)
*aCount = count;
for (uint32_t i = 0; i < count; i++) {
(*aResults)[i] = ToNewUnicode(mMimeTypes[i]);
(*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(mMimeTypes[i]));
}
return NS_OK;
@ -436,7 +436,7 @@ nsPluginTag::GetMimeDescriptions(uint32_t* aCount, char16_t*** aResults)
*aCount = count;
for (uint32_t i = 0; i < count; i++) {
(*aResults)[i] = ToNewUnicode(mMimeDescriptions[i]);
(*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(mMimeDescriptions[i]));
}
return NS_OK;
@ -453,7 +453,7 @@ nsPluginTag::GetExtensions(uint32_t* aCount, char16_t*** aResults)
*aCount = count;
for (uint32_t i = 0; i < count; i++) {
(*aResults)[i] = ToNewUnicode(mExtensions[i]);
(*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(mExtensions[i]));
}
return NS_OK;

View File

@ -39,6 +39,7 @@ support-files =
[test_bug863792.html]
[test_bug967694.html]
[test_bug985859.html]
[test_bug986930.html]
[test_cocoa_focus.html]
skip-if = toolkit != "cocoa"
support-files = cocoa_focus.html

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Test for Bug 986930</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="utils.js"></script>
</head>
<body>
<script class="testbody" type="application/javascript">
var testPlugin = getTestPlugin("Test Plug-in");
var mimeDescriptions = testPlugin.getMimeDescriptions({});
is(mimeDescriptions[0], "Test \u2122 mimetype",
"Plugin should handle non-ascii mime description");
</script>
</body>
</html>

View File

@ -31,7 +31,7 @@
<string>tst</string>
</array>
<key>WebPluginTypeDescription</key>
<string>Test mimetype</string>
<string>Test mimetype</string>
</dict>
</dict>
</dict>

View File

@ -26,7 +26,7 @@ BEGIN
VALUE "CompanyName", "mozilla.org"
VALUE "FileDescription", L"Plug-in for testing purposes.\x2122 (\x0939\x093f\x0928\x094d\x0926\x0940 \x4e2d\x6587 \x0627\x0644\x0639\x0631\x0628\x064a\x0629)"
VALUE "FileExtents", "tst"
VALUE "FileOpenName", "Test mimetype"
VALUE "FileOpenName", L"Test \x2122 mimetype"
VALUE "FileVersion", "1.0"
VALUE "InternalName", "nptest"
VALUE "MIMEType", "application/x-test"

View File

@ -3,4 +3,4 @@ const char *sPluginDescription = "Plug-in for testing purposes.\xE2\x84\xA2 " \
"(\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\xa8\xe0\xa5\x8d\xe0\xa4\xa6\xe0\xa5\x80 " \
"\xe4\xb8\xad\xe6\x96\x87 " \
"\xd8\xa7\xd9\x84\xd8\xb9\xd8\xb1\xd8\xa8\xd9\x8a\xd8\xa9)";
const char *sMimeDescription = "application/x-test:tst:Test mimetype";
const char *sMimeDescription = "application/x-test:tst:Test \xE2\x84\xA2 mimetype";

View File

@ -304,6 +304,9 @@ partial interface Window {
*/
[Throws] readonly attribute unsigned long long mozPaintCount;
[Pure]
attribute EventHandler onwheel;
attribute EventHandler ondevicemotion;
attribute EventHandler ondeviceorientation;
attribute EventHandler ondeviceproximity;

View File

@ -336,6 +336,16 @@ public:
* DataSourceSurface's data can be accessed directly.
*/
virtual TemporaryRef<DataSourceSurface> GetDataSurface() = 0;
void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
mUserData.Add(key, userData, destroy);
}
void *GetUserData(UserDataKey *key) {
return mUserData.Get(key);
}
protected:
UserData mUserData;
};
class DataSourceSurface : public SourceSurface

View File

@ -5,7 +5,7 @@
ifdef MOZ_ANGLE_RENDERER
libs::
ifdef MOZ_HAS_WINSDK_WITH_D3D
ifdef MOZ_D3DCOMPILER_DLL_PATH
cp -fp "$(MOZ_D3DCOMPILER_DLL_PATH)" "$(DIST)/bin"
else
ifdef MOZ_D3DCOMPILER_CAB

View File

@ -5,6 +5,8 @@
ifndef GNU_CC
# Enable unwind semantics for exception handlers in response to warning C4530.
OS_CPPFLAGS += -EHsc
else
OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
endif
# End build_angle.gypi transcription.
@ -15,19 +17,9 @@ ifndef MOZ_HAS_WINSDK_WITH_D3D
CXXFLAGS += -I'$(MOZ_DIRECTX_SDK_PATH)/include'
endif
ifdef GNU_CC
OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
OS_LIBS += -ld3d9 -ldxguid
else
ifdef MOZ_HAS_WINSDK_WITH_D3D
EXTRA_DSO_LDOPTS = d3d9.lib dxguid.lib delayimp.lib
EXTRA_DSO_LDOPTS = $(call EXPAND_LIBNAME,d3d9 dxguid)
else
EXTRA_DSO_LDOPTS = '$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3d9.lib' \
'$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/dxguid.lib' \
delayimp.lib
endif
EXTRA_DSO_LDOPTS = $(call EXPAND_LIBNAME_PATH,d3d9 dxguid,$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX))
endif
EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME,delayimp)

View File

@ -47,10 +47,6 @@ public:
InfallibleTArray<coord>& texCoords() {
return mTexCoords;
}
unsigned int elements() {
return mVertexCoords.Length();
}
private:
// Reserve inline storage for one quad (2 triangles, 3 coords).
nsAutoTArray<coord, 6> mVertexCoords;

View File

@ -12,6 +12,7 @@
#include "nsRect.h"
#include "gfx2DGlue.h"
#include "gfxUtils.h"
#include "GLDrawRectHelper.h"
namespace mozilla {
namespace gl {
@ -147,25 +148,10 @@ GLBlitTextureImageHelper::BlitTextureImage(TextureImage *aSrc, const nsIntRect&
ScopedBindTextureUnit autoTexUnit(mGL, LOCAL_GL_TEXTURE0);
ScopedBindTexture autoTex(mGL, aSrc->GetTextureID());
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertCoords().Elements());
mGL->fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoords().Elements());
mGL->fEnableVertexAttribArray(0);
mGL->fEnableVertexAttribArray(1);
mGL->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
mGL->fDisableVertexAttribArray(0);
mGL->fDisableVertexAttribArray(1);
mGL->DrawRectHelper()->DrawRects(0, 1, rects);
} while (aSrc->NextTile());
} while (aDst->NextTile());
mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, nullptr);
mGL->fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, nullptr);
// unbind the previous texture from the framebuffer
SetBlitFramebufferForDestTexture(0);

View File

@ -13,6 +13,7 @@
#include "GLBlitHelper.h"
#include "GLBlitTextureImageHelper.h"
#include "GLReadTexImageHelper.h"
#include "GLDrawRectHelper.h"
#include "gfxCrashReporterUtils.h"
#include "gfxUtils.h"
@ -483,7 +484,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
// Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2.
if (mInitialized) {
if (IsGLES2()) {
if (IsGLES()) {
SymLoadStruct symbols_ES2[] = {
{ (PRFuncPtr*) &mSymbols.fGetShaderPrecisionFormat, { "GetShaderPrecisionFormat", nullptr } },
{ (PRFuncPtr*) &mSymbols.fClearDepthf, { "ClearDepthf", nullptr } },
@ -1337,7 +1338,7 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
// If we're on ES2 hardware and we have an explicit request for 16 bits of color or less
// OR we don't support full 8-bit color, return a 4444 or 565 format.
bool bpp16 = caps.bpp16;
if (IsGLES2()) {
if (IsGLES()) {
if (!IsExtensionSupported(OES_rgb8_rgba8))
bpp16 = true;
} else {
@ -1347,7 +1348,7 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
}
if (bpp16) {
MOZ_ASSERT(IsGLES2());
MOZ_ASSERT(IsGLES());
if (caps.alpha) {
formats.color_texInternalFormat = LOCAL_GL_RGBA;
formats.color_texFormat = LOCAL_GL_RGBA;
@ -1363,11 +1364,11 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
formats.color_texType = LOCAL_GL_UNSIGNED_BYTE;
if (caps.alpha) {
formats.color_texInternalFormat = IsGLES2() ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
formats.color_texFormat = LOCAL_GL_RGBA;
formats.color_rbFormat = LOCAL_GL_RGBA8;
} else {
formats.color_texInternalFormat = IsGLES2() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
formats.color_texFormat = LOCAL_GL_RGB;
formats.color_rbFormat = LOCAL_GL_RGB8;
}
@ -1386,12 +1387,12 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
// Be clear that these are 0 if unavailable.
formats.depthStencil = 0;
if (!IsGLES2() || IsExtensionSupported(OES_packed_depth_stencil)) {
if (!IsGLES() || IsExtensionSupported(OES_packed_depth_stencil)) {
formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8;
}
formats.depth = 0;
if (IsGLES2()) {
if (IsGLES()) {
if (IsExtensionSupported(OES_depth24)) {
formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
} else {
@ -1685,6 +1686,7 @@ GLContext::MarkDestroyed()
mBlitHelper = nullptr;
mBlitTextureImageHelper = nullptr;
mReadTexImageHelper = nullptr;
mDrawRectHelper = nullptr;
mTexGarbageBin->GLContextTeardown();
} else {
@ -2010,6 +2012,16 @@ GLContext::ReadTexImageHelper()
return mReadTexImageHelper;
}
GLDrawRectHelper*
GLContext::DrawRectHelper()
{
if (!mDrawRectHelper) {
mDrawRectHelper = new GLDrawRectHelper(this);
}
return mDrawRectHelper;
}
bool
DoesStringMatch(const char* aString, const char *aWantedString)
{

View File

@ -71,6 +71,7 @@ namespace mozilla {
class GLBlitTextureImageHelper;
class GLReadTexImageHelper;
class SharedSurface_GL;
class GLDrawRectHelper;
}
namespace layers {
@ -287,16 +288,6 @@ public:
virtual bool IsCurrent() = 0;
/**
* If this context is the GLES2 API, returns TRUE.
* This means that various GLES2 restrictions might be in effect (modulo
* extensions).
*/
inline bool IsGLES2() const {
return IsAtLeast(ContextProfile::OpenGLES, 200);
}
protected:
bool mInitialized;
@ -1779,7 +1770,7 @@ public:
private:
void raw_fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
MOZ_ASSERT(IsGLES2());
MOZ_ASSERT(IsGLES());
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fGetShaderPrecisionFormat);
@ -1789,7 +1780,7 @@ private:
public:
void fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
if (IsGLES2()) {
if (IsGLES()) {
raw_fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
} else {
// Fall back to automatic values because almost all desktop hardware supports the OpenGL standard precisions.
@ -1877,7 +1868,7 @@ public:
private:
void raw_fDepthRange(GLclampf a, GLclampf b) {
MOZ_ASSERT(!IsGLES2());
MOZ_ASSERT(!IsGLES());
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fDepthRange);
@ -1886,7 +1877,7 @@ private:
}
void raw_fDepthRangef(GLclampf a, GLclampf b) {
MOZ_ASSERT(IsGLES2());
MOZ_ASSERT(IsGLES());
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fDepthRangef);
@ -1895,7 +1886,7 @@ private:
}
void raw_fClearDepth(GLclampf v) {
MOZ_ASSERT(!IsGLES2());
MOZ_ASSERT(!IsGLES());
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fClearDepth);
@ -1904,7 +1895,7 @@ private:
}
void raw_fClearDepthf(GLclampf v) {
MOZ_ASSERT(IsGLES2());
MOZ_ASSERT(IsGLES());
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fClearDepthf);
@ -1914,7 +1905,7 @@ private:
public:
void fDepthRange(GLclampf a, GLclampf b) {
if (IsGLES2()) {
if (IsGLES()) {
raw_fDepthRangef(a, b);
} else {
raw_fDepthRange(a, b);
@ -1922,7 +1913,7 @@ public:
}
void fClearDepth(GLclampf v) {
if (IsGLES2()) {
if (IsGLES()) {
raw_fClearDepthf(v);
} else {
raw_fClearDepth(v);
@ -2735,11 +2726,13 @@ protected:
ScopedDeletePtr<GLBlitHelper> mBlitHelper;
ScopedDeletePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
ScopedDeletePtr<GLReadTexImageHelper> mReadTexImageHelper;
ScopedDeletePtr<GLDrawRectHelper> mDrawRectHelper;
public:
GLBlitHelper* BlitHelper();
GLBlitTextureImageHelper* BlitTextureImageHelper();
GLReadTexImageHelper* ReadTexImageHelper();
GLDrawRectHelper* DrawRectHelper();
// Assumes shares are created by all sharing with the same global context.
bool SharesWith(const GLContext* other) const {

122
gfx/gl/GLDrawRectHelper.cpp Normal file
View File

@ -0,0 +1,122 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GLDrawRectHelper.h"
#include "GLContext.h"
#include "DecomposeIntoNoRepeatTriangles.h"
namespace mozilla {
namespace gl {
static GLfloat quad[] = {
/* First quad vertices */
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
/* Then quad texcoords */
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
};
#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
GLDrawRectHelper::GLDrawRectHelper(GLContext *aGL)
: mGL(aGL)
{
mGL->fGenBuffers(1, &mQuadVBO);
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(quad), quad, LOCAL_GL_STATIC_DRAW);
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
GLDrawRectHelper::~GLDrawRectHelper()
{
mGL->fDeleteBuffers(1, &mQuadVBO);
}
void
GLDrawRectHelper::DrawRect(GLuint aVertAttribIndex,
GLuint aTexCoordAttribIndex)
{
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
mGL->fVertexAttribPointer(aVertAttribIndex,
2, LOCAL_GL_FLOAT,
LOCAL_GL_FALSE,
0, BUFFER_OFFSET(0));
mGL->fEnableVertexAttribArray(aVertAttribIndex);
if (aTexCoordAttribIndex != GLuint(-1)) {
mGL->fVertexAttribPointer(aTexCoordAttribIndex,
2, LOCAL_GL_FLOAT,
LOCAL_GL_FALSE,
0, BUFFER_OFFSET(sizeof(quad)/2));
mGL->fEnableVertexAttribArray(aTexCoordAttribIndex);
}
mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
if (aTexCoordAttribIndex != GLuint(-1)) {
mGL->fDisableVertexAttribArray(aTexCoordAttribIndex);
}
mGL->fDisableVertexAttribArray(aVertAttribIndex);
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
void
GLDrawRectHelper::DrawRects(GLuint aVertAttribIndex,
GLuint aTexCoordAttribIndex,
RectTriangles& aRects)
{
GLsizei bytes = aRects.vertCoords().Length() * 2 * sizeof(GLfloat);
GLsizei total = bytes;
if (aTexCoordAttribIndex != GLuint(-1)) {
total *= 2;
}
GLuint vbo;
mGL->fGenBuffers(1, &vbo);
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER,
total,
nullptr,
LOCAL_GL_STREAM_DRAW);
mGL->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
0,
bytes,
aRects.vertCoords().Elements());
mGL->fVertexAttribPointer(aVertAttribIndex,
2, LOCAL_GL_FLOAT,
LOCAL_GL_FALSE,
0, BUFFER_OFFSET(0));
mGL->fEnableVertexAttribArray(aVertAttribIndex);
if (aTexCoordAttribIndex != GLuint(-1)) {
mGL->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
bytes,
bytes,
aRects.texCoords().Elements());
mGL->fVertexAttribPointer(aTexCoordAttribIndex,
2, LOCAL_GL_FLOAT,
LOCAL_GL_FALSE,
0, BUFFER_OFFSET(bytes));
mGL->fEnableVertexAttribArray(aTexCoordAttribIndex);
}
mGL->fDrawArrays(LOCAL_GL_TRIANGLES, 0, aRects.vertCoords().Length());
if (aTexCoordAttribIndex != GLuint(-1)) {
mGL->fDisableVertexAttribArray(aTexCoordAttribIndex);
}
mGL->fDisableVertexAttribArray(aVertAttribIndex);
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
mGL->fDeleteBuffers(1, &vbo);
}
}
}

41
gfx/gl/GLDrawRectHelper.h Normal file
View File

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GLDRAWRECTHELPER_H_
#define GLDRAWRECTHELPER_H_
#include "GLContextTypes.h"
#include "GLConsts.h"
namespace mozilla {
namespace gl {
class GLContext;
class RectTriangles;
/** Helper to draw rectangles to the frame buffer. */
class GLDrawRectHelper MOZ_FINAL
{
public:
GLDrawRectHelper(GLContext* aGL);
~GLDrawRectHelper();
void DrawRect(GLuint aVertAttribIndex,
GLuint aTexCoordAttribIndex);
void DrawRects(GLuint aVertAttribIndex,
GLuint aTexCoordAttribIndex,
RectTriangles& aRects);
private:
// The GLContext is the sole owner of the GLDrawHelper.
GLContext* mGL;
GLuint mQuadVBO;
};
}
}
#endif // GLDRAWRECTHELPER_H_

View File

@ -168,7 +168,7 @@ GetActualReadFormats(GLContext* gl,
}
bool fallback = true;
if (gl->IsGLES2()) {
if (gl->IsGLES()) {
GLenum auxFormat = 0;
GLenum auxType = 0;
@ -209,6 +209,10 @@ GetActualReadFormats(GLContext* gl,
static void SwapRAndBComponents(DataSourceSurface* surf)
{
uint8_t *row = surf->GetData();
if (!row) {
MOZ_ASSERT(false, "SwapRAndBComponents: Failed to get data from DataSourceSurface.");
return;
}
size_t rowBytes = surf->GetSize().width*4;
size_t rowHole = surf->Stride() - rowBytes;
@ -764,7 +768,7 @@ GLReadTexImageHelper::ReadTexImage(GLuint aTextureId,
mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb);
GLenum rbInternalFormat =
mGL->IsGLES2()
mGL->IsGLES()
? (mGL->IsExtensionSupported(GLContext::OES_rgb8_rgba8) ? LOCAL_GL_RGBA8 : LOCAL_GL_RGBA4)
: LOCAL_GL_RGBA;
mGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, rbInternalFormat, aSize.width, aSize.height);

View File

@ -225,7 +225,7 @@ TexSubImage2DHelper(GLContext *gl,
GLint pixelsize, GLenum format,
GLenum type, const GLvoid* pixels)
{
if (gl->IsGLES2()) {
if (gl->IsGLES()) {
if (stride == width * pixelsize) {
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
std::min(GetAddressAlignment((ptrdiff_t)pixels),
@ -278,7 +278,7 @@ TexImage2DHelper(GLContext *gl,
GLint pixelsize, GLint border, GLenum format,
GLenum type, const GLvoid *pixels)
{
if (gl->IsGLES2()) {
if (gl->IsGLES()) {
NS_ASSERTION(format == (GLenum)internalformat,
"format and internalformat not the same for glTexImage2D on GLES2");

View File

@ -322,7 +322,7 @@ const GLubyte* glGetString_mozilla(GrGLenum name)
// on the GL implementation and change them to match what GLContext actually exposes.
if (name == LOCAL_GL_VERSION) {
if (sGLContext.get()->IsGLES2()) {
if (sGLContext.get()->IsGLES()) {
return reinterpret_cast<const GLubyte*>("OpenGL ES 2.0");
} else {
return reinterpret_cast<const GLubyte*>("2.0");
@ -336,7 +336,7 @@ const GLubyte* glGetString_mozilla(GrGLenum name)
if (!extensionsStringBuilt) {
extensionsString[0] = '\0';
if (sGLContext.get()->IsGLES2()) {
if (sGLContext.get()->IsGLES()) {
// OES is only applicable to GLES2
if (sGLContext.get()->IsExtensionSupported(GLContext::OES_packed_depth_stencil)) {
strcat(extensionsString, "GL_OES_packed_depth_stencil ");
@ -384,7 +384,7 @@ const GLubyte* glGetString_mozilla(GrGLenum name)
return reinterpret_cast<const GLubyte*>(extensionsString);
} else if (name == LOCAL_GL_SHADING_LANGUAGE_VERSION) {
if (sGLContext.get()->IsGLES2()) {
if (sGLContext.get()->IsGLES()) {
return reinterpret_cast<const GLubyte*>("OpenGL ES GLSL ES 1.0");
} else {
return reinterpret_cast<const GLubyte*>("1.10");
@ -770,7 +770,7 @@ static GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
context->MakeCurrent();
// We support both desktop GL and GLES2
if (context->IsGLES2()) {
if (context->IsGLES()) {
i->fStandard = kGLES_GrGLStandard;
} else {
i->fStandard = kGL_GrGLStandard;

View File

@ -38,6 +38,7 @@ EXPORTS += [
'GLContextSymbols.h',
'GLContextTypes.h',
'GLDefs.h',
'GLDrawRectHelper.h',
'GLLibraryEGL.h',
'GLLibraryLoader.h',
'GLReadTexImageHelper.h',
@ -123,6 +124,7 @@ UNIFIED_SOURCES += [
'GLContextFeatures.cpp',
'GLContextTypes.cpp',
'GLDebugUtils.cpp',
'GLDrawRectHelper.cpp',
'GLLibraryEGL.cpp',
'GLLibraryLoader.cpp',
'GLReadTexImageHelper.cpp',

View File

@ -41,10 +41,6 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType,
aFlags |= TEXTURE_DEALLOCATE_CLIENT;
return new CanvasClientSurfaceStream(aForwarder, aFlags);
}
if (gfxPlatform::GetPlatform()->UseDeprecatedTextures()) {
aFlags |= TEXTURE_DEALLOCATE_CLIENT;
return new DeprecatedCanvasClient2D(aForwarder, aFlags);
}
return new CanvasClient2D(aForwarder, aFlags);
}
@ -65,21 +61,12 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
: gfxContentType::COLOR_ALPHA;
gfxImageFormat format
= gfxPlatform::GetPlatform()->OptimalFormatForContent(contentType);
mBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format),
TEXTURE_FLAGS_DEFAULT,
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend(),
aSize);
bool allocSuccess = false;
if (mBuffer->AsTextureClientSurface()) {
allocSuccess = mBuffer->AsTextureClientSurface()->AllocateForSurface(aSize);
} else {
MOZ_ASSERT(mBuffer->AsTextureClientDrawTarget());
allocSuccess = mBuffer->AsTextureClientDrawTarget()->AllocateForSurface(aSize);
}
if (!allocSuccess) {
mBuffer = nullptr;
return;
}
mBuffer = CreateBufferTextureClient(gfx::ImageFormatToSurfaceFormat(format),
TEXTURE_FLAGS_DEFAULT,
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend());
MOZ_ASSERT(mBuffer->AsTextureClientSurface());
mBuffer->AsTextureClientSurface()->AllocateForSurface(aSize);
bufferCreated = true;
}
@ -90,18 +77,8 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
bool updated = false;
{
// Restrict drawTarget to a scope so that terminates before Unlock.
nsRefPtr<gfxASurface> surface;
if (mBuffer->AsTextureClientSurface()) {
surface = mBuffer->AsTextureClientSurface()->GetAsSurface();
} else {
RefPtr<gfx::DrawTarget> dt
= mBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
if (dt) {
surface = gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(dt);
}
// the DrawTarget will be kept alive until mBuffer->Unlock() so it's
// OK to let go of dt before we destroy surface.
}
nsRefPtr<gfxASurface> surface =
mBuffer->AsTextureClientSurface()->GetAsSurface();
if (surface) {
aLayer->DeprecatedUpdateSurface(surface);
updated = true;
@ -199,133 +176,5 @@ CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
aLayer->Painted();
}
void
DeprecatedCanvasClient2D::Updated()
{
mForwarder->UpdateTexture(this, 1, mDeprecatedTextureClient->LockSurfaceDescriptor());
}
DeprecatedCanvasClient2D::DeprecatedCanvasClient2D(CompositableForwarder* aFwd,
TextureFlags aFlags)
: CanvasClient(aFwd, aFlags)
{
mTextureInfo.mCompositableType = BUFFER_IMAGE_SINGLE;
}
void
DeprecatedCanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
{
bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
gfxContentType contentType = isOpaque
? gfxContentType::COLOR
: gfxContentType::COLOR_ALPHA;
if (!mDeprecatedTextureClient) {
mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_CONTENT, contentType);
if (!mDeprecatedTextureClient) {
mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_FALLBACK, contentType);
if (!mDeprecatedTextureClient) {
NS_WARNING("Could not create texture client");
return;
}
}
}
if (!mDeprecatedTextureClient->EnsureAllocated(aSize, contentType)) {
// We might already be on the fallback texture client if we couldn't create a
// better one above. In which case this call to create is wasted. But I don't
// think this will happen often enough to be worth complicating the code with
// further checks.
mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_FALLBACK, contentType);
MOZ_ASSERT(mDeprecatedTextureClient, "Failed to create texture client");
if (!mDeprecatedTextureClient->EnsureAllocated(aSize, contentType)) {
NS_WARNING("Could not allocate texture client");
return;
}
}
gfxASurface* surface = mDeprecatedTextureClient->LockSurface();
aLayer->DeprecatedUpdateSurface(surface);
mDeprecatedTextureClient->Unlock();
}
void
DeprecatedCanvasClientSurfaceStream::Updated()
{
mForwarder->UpdateTextureNoSwap(this, 1, mDeprecatedTextureClient->LockSurfaceDescriptor());
}
DeprecatedCanvasClientSurfaceStream::DeprecatedCanvasClientSurfaceStream(CompositableForwarder* aFwd,
TextureFlags aFlags)
: CanvasClient(aFwd, aFlags)
{
mTextureInfo.mCompositableType = BUFFER_IMAGE_SINGLE;
}
void
DeprecatedCanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
{
if (!mDeprecatedTextureClient) {
mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_STREAM_GL,
aLayer->GetSurfaceMode() == SurfaceMode::SURFACE_OPAQUE
? gfxContentType::COLOR
: gfxContentType::COLOR_ALPHA);
MOZ_ASSERT(mDeprecatedTextureClient, "Failed to create texture client");
}
NS_ASSERTION(aLayer->mGLContext, "CanvasClientSurfaceStream should only be used with GL canvases");
// the content type won't be used
mDeprecatedTextureClient->EnsureAllocated(aSize, gfxContentType::COLOR);
GLScreenBuffer* screen = aLayer->mGLContext->Screen();
SurfaceStream* stream = nullptr;
if (aLayer->mStream) {
stream = aLayer->mStream;
stream->CopySurfaceToProducer(aLayer->mTextureSurface, aLayer->mFactory);
stream->SwapProducer(aLayer->mFactory, gfx::IntSize(aSize.width, aSize.height));
} else {
stream = screen->Stream();
}
bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
if (isCrossProcess) {
// swap staging -> consumer so we can send it to the compositor
SharedSurface* surf = stream->SwapConsumer();
if (!surf) {
printf_stderr("surf is null post-SwapConsumer!\n");
return;
}
#ifdef MOZ_WIDGET_GONK
if (surf->Type() != SharedSurfaceType::Gralloc) {
printf_stderr("Unexpected non-Gralloc SharedSurface in IPC path!");
return;
}
SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf);
//XXX todo
//mDeprecatedTextureClient->SetDescriptor(grallocSurf->GetDescriptor());
#else
printf_stderr("isCrossProcess, but not MOZ_WIDGET_GONK! Someone needs to write some code!");
MOZ_ASSERT(false);
#endif
} else {
SurfaceStreamHandle handle = stream->GetShareHandle();
mDeprecatedTextureClient->SetDescriptor(SurfaceStreamDescriptor(handle, false));
// Bug 894405
//
// Ref this so the SurfaceStream doesn't disappear unexpectedly. The
// Compositor will need to unref it when finished.
aLayer->mGLContext->AddRef();
}
aLayer->Painted();
}
}
}

View File

@ -132,56 +132,6 @@ private:
RefPtr<TextureClient> mBuffer;
};
class DeprecatedCanvasClient2D : public CanvasClient
{
public:
DeprecatedCanvasClient2D(CompositableForwarder* aLayerForwarder,
TextureFlags aFlags);
TextureInfo GetTextureInfo() const MOZ_OVERRIDE
{
return mTextureInfo;
}
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer);
virtual void Updated() MOZ_OVERRIDE;
virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
{
mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
}
private:
RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
};
// Used for GL canvases where we don't need to do any readback, i.e., with a
// GL backend.
class DeprecatedCanvasClientSurfaceStream : public CanvasClient
{
public:
DeprecatedCanvasClientSurfaceStream(CompositableForwarder* aFwd,
TextureFlags aFlags);
TextureInfo GetTextureInfo() const MOZ_OVERRIDE
{
return mTextureInfo;
}
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer);
virtual void Updated() MOZ_OVERRIDE;
virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
{
mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
}
private:
RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
};
}
}

View File

@ -216,13 +216,17 @@ ClientTiledThebesLayer::RenderLayer()
ToClientLayer(GetMaskLayer())->RenderLayer();
}
bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition();
// Fast path for no progressive updates, no low-precision updates and no
// critical display-port set, or no display-port set.
// critical display-port set, or no display-port set, or this is a fixed
// position layer/contained in a fixed position layer
const FrameMetrics& parentMetrics = GetParent()->GetFrameMetrics();
if ((!gfxPrefs::UseProgressiveTilePainting() &&
!gfxPrefs::UseLowPrecisionBuffer() &&
parentMetrics.mCriticalDisplayPort.IsEmpty()) ||
parentMetrics.mDisplayPort.IsEmpty()) {
parentMetrics.mDisplayPort.IsEmpty() ||
isFixed) {
mValidRegion = mVisibleRegion;
NS_ASSERTION(!ClientManager()->IsRepeatTransaction(), "Didn't paint our mask layer");

View File

@ -38,6 +38,22 @@ using namespace gfx;
namespace layers {
static TextureFlags TextureFlagsForRotatedContentBufferFlags(uint32_t aBufferFlags)
{
TextureFlags result = 0;
if (aBufferFlags & RotatedContentBuffer::BUFFER_COMPONENT_ALPHA) {
result |= TEXTURE_COMPONENT_ALPHA;
}
if (aBufferFlags & RotatedContentBuffer::ALLOW_REPEAT) {
result |= TEXTURE_ALLOW_REPEAT;
}
return result;
}
/* static */ TemporaryRef<ContentClient>
ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
{
@ -51,7 +67,12 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
bool useDoubleBuffering = false;
bool useDeprecatedTextures = true;
// XXX We need support for gralloc with non-deprecated textures content before
// we can use them with FirefoxOS (bug 946720). We need the same locking for
// Windows.
#if !defined(XP_WIN)
useDeprecatedTextures = gfxPlatform::GetPlatform()->UseDeprecatedTextures();
#endif
#ifdef XP_WIN
if (backend == LayersBackend::LAYERS_D3D11) {
@ -210,7 +231,7 @@ ContentClientRemoteBuffer::BuildTextureClients(SurfaceFormat aFormat,
mSurfaceFormat = aFormat;
mSize = gfx::IntSize(aRect.width, aRect.height);
mTextureInfo.mTextureFlags = aFlags & ~TEXTURE_DEALLOCATE_CLIENT;
mTextureInfo.mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
if (!CreateAndAllocateTextureClient(mTextureClient, TEXTURE_ON_BLACK) ||
!AddTextureClient(mTextureClient)) {
@ -396,19 +417,18 @@ DeprecatedContentClientRemoteBuffer::BuildDeprecatedTextureClients(ContentType a
mContentType = aType;
mSize = gfx::IntSize(aRect.width, aRect.height);
mTextureInfo.mTextureFlags = aFlags & ~TEXTURE_DEALLOCATE_CLIENT;
mTextureInfo.mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
if (!CreateAndAllocateDeprecatedTextureClient(mDeprecatedTextureClient)) {
return;
}
if (aFlags & BUFFER_COMPONENT_ALPHA) {
if (!CreateAndAllocateDeprecatedTextureClient(mDeprecatedTextureClientOnWhite)) {
mDeprecatedTextureClient->SetFlags(0);
mDeprecatedTextureClient = nullptr;
return;
}
mTextureInfo.mTextureFlags |= TEXTURE_COMPONENT_ALPHA;
}
CreateFrontBufferAndNotify(aRect);

View File

@ -282,10 +282,6 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
aMoz2DBackend = gfxPlatform::GetPlatform()->GetContentBackend();
}
#if defined(XP_WIN) || defined(MOZ_WIDGET_GONK)
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
#endif
RefPtr<TextureClient> result;
#ifdef XP_WIN
@ -294,10 +290,9 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
(aMoz2DBackend == gfx::BackendType::DIRECT2D ||
aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) {
result = new TextureClientD3D11(aFormat, aTextureFlags);
}
result = new TextureClientD3D11(aFormat, aTextureFlags);
}
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
aMoz2DBackend == gfx::BackendType::CAIRO &&
@ -342,6 +337,7 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
if (!DisableGralloc(aFormat, aSizeHint)) {
// Don't allow Gralloc texture clients to exceed the maximum texture size.
// BufferTextureClients have code to handle tiling the surface client-side.
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) {
result = new GrallocTextureClientOGL(aAllocator, aFormat, aMoz2DBackend,
aTextureFlags);

View File

@ -132,6 +132,7 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
EffectChain effectChain(this);
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
nsIntRegion visibleRegion = GetEffectiveVisibleRegion();
TiledLayerProperties tiledLayerProps;

View File

@ -171,10 +171,6 @@ bool
TextureClientD3D11::Lock(OpenMode aMode)
{
MOZ_ASSERT(!mIsLocked, "The Texture is already locked!");
if (!mTexture) {
return false;
}
LockD3DTexture(mTexture.get());
mIsLocked = true;
@ -215,10 +211,6 @@ TextureClientD3D11::GetAsDrawTarget()
return mDrawTarget;
}
if (!mTexture) {
return nullptr;
}
mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, mFormat);
return mDrawTarget;
}
@ -229,7 +221,7 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
mSize = aSize;
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
CD3D10_TEXTURE2D_DESC newDesc(SurfaceFormatToDXGIFormat(mFormat),
aSize.width, aSize.height, 1, 1,
D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
@ -337,10 +329,10 @@ DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
nsIntRegion* aDestRegion,
IntPoint* aSrcOffset)
{
// Right now we only support full surface update. If aDestRegion is provided,
// It will be ignered. Incremental update with a source offset is only used
// on Mac so it is not clear that we ever will need to support it for D3D.
MOZ_ASSERT(!aSrcOffset);
// Right now we only support null aDestRegion and aSrcOffset (which means)
// full surface update. Incremental update is only used on Mac so it is
// not clear that we ever will need to support it for D3D.
MOZ_ASSERT(!aDestRegion && !aSrcOffset);
MOZ_ASSERT(aSurface);
if (!mCompositor || !mCompositor->GetDevice()) {

View File

@ -1061,10 +1061,10 @@ DataTextureSourceD3D9::Update(gfx::DataSourceSurface* aSurface,
nsIntRegion* aDestRegion,
gfx::IntPoint* aSrcOffset)
{
// Right now we only support full surface update. If aDestRegion is provided,
// It will be ignered. Incremental update with a source offset is only used
// on Mac so it is not clear that we ever will need to support it for D3D.
MOZ_ASSERT(!aSrcOffset);
// Right now we only support null aDestRegion and aSrcOffset (which means
// full surface update). Incremental update is only used on Mac so it is
// not clear that we ever will need to support it for D3D.
MOZ_ASSERT(!aDestRegion && !aSrcOffset);
if (!mCompositor || !mCompositor->device()) {
NS_WARNING("No D3D device to update the texture.");

View File

@ -20,7 +20,7 @@
#include "base/message_loop.h" // for MessageLoop
#include "base/task.h" // for NewRunnableMethod, etc
#include "base/tracked.h" // for FROM_HERE
#include "gfxPrefs.h" // for gfxPrefs::UseProgressiveTilePainting
#include "gfxPrefs.h" // for gfxPrefs
#include "gfxTypes.h" // for gfxFloat
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/BasicEvents.h" // for Modifiers, MODIFIER_*
@ -133,18 +133,100 @@ namespace layers {
typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior;
/**
* Specifies whether touch-action property is in force.
*/
static bool gTouchActionPropertyEnabled = false;
/**
/*
* The following prefs are used to control the behaviour of the APZC.
* The default values are provided in gfxPrefs.h.
*
* "apz.allow-checkerboarding"
* Pref that allows or disallows checkerboarding
*
* "apz.asyncscroll.throttle"
* The time period in ms that throttles mozbrowserasyncscroll event.
*
* "apz.asyncscroll.timeout"
* The timeout in ms for mAsyncScrollTimeoutTask delay task.
*
* "apz.axis_lock_mode"
* The preferred axis locking style. See AxisLockMode for possible values.
*
* "apz.content_response_timeout"
* Amount of time before we timeout response from content. For example, if
* content is being unruly/slow and we don't get a response back within this
* time, we will just pretend that content did not preventDefault any touch
* events we dispatched to it.
*
* "apz.cross_slide_enabled"
* Pref that enables integration with the Metro "cross-slide" gesture.
*
* "apz.enlarge_displayport_when_clipped"
* Pref that enables enlarging of the displayport along one axis when the
* generated displayport's size is beyond that of the scrollable rect on the
* opposite axis.
*
* "apz.fling_friction"
* Amount of friction applied during flings.
*
* "apz.fling_repaint_interval"
* Maximum amount of time flinging before sending a viewport change. This will
* asynchronously repaint the page.
*
* "apz.fling_stopped_threshold"
* When flinging, if the velocity goes below this number, we just stop the
* animation completely. This is to prevent asymptotically approaching 0
* velocity and rerendering unnecessarily.
*
* "apz.max_velocity_inches_per_ms"
* Maximum velocity in inches per millisecond. Velocity will be capped at this
* value if a faster fling occurs. Negative values indicate unlimited velocity.
*
* "apz.max_velocity_queue_size"
* Maximum size of velocity queue. The queue contains last N velocity records.
* On touch end we calculate the average velocity in order to compensate
* touch/mouse drivers misbehaviour.
*
* "apz.min_skate_speed"
* Minimum amount of speed along an axis before we switch to "skate" multipliers
* rather than using the "stationary" multipliers.
*
* "apz.num_paint_duration_samples"
* Number of samples to store of how long it took to paint after the previous
* requests.
*
* "apz.pan_repaint_interval"
* Maximum amount of time while panning before sending a viewport change. This
* will asynchronously repaint the page. It is also forced when panning stops.
*
* "apz.touch_start_tolerance"
* Constant describing the tolerance in distance we use, multiplied by the
* device DPI, before we start panning the screen. This is to prevent us from
* accidentally processing taps as touch moves, and from very short/accidental
* touches moving the screen.
*
* "apz.use_paint_duration"
* Whether or not to use the estimated paint duration as a factor when projecting
* the displayport in the direction of scrolling. If this value is set to false,
* a constant 50ms paint time is used; the projection can be scaled as desired
* using the apz.velocity_bias pref below.
*
* "apz.velocity_bias"
* How much to adjust the displayport in the direction of scrolling. This value
* is multiplied by the velocity and added to the displayport offset.
*
* "apz.x_skate_size_multiplier", "apz.y_skate_size_multiplier"
* The multiplier we apply to the displayport size if it is skating (current
* velocity is above apz.min_skate_speed). We prefer to increase the size of the
* Y axis because it is more natural in the case that a user is reading a page
* that scrolls up/down. Note that one, both or neither of these may be used
* at any instant.
* In general we want apz.[xy]_skate_size_multiplier to be smaller than the corresponding
* stationary size multiplier because when panning fast we would like to paint
* less and get faster, more predictable paint times. When panning slowly we
* can afford to paint more even though it's slower.
*
* "apz.x_stationary_size_multiplier", "apz.y_stationary_size_multiplier"
* The multiplier we apply to the displayport size if it is not skating (see
* documentation for the skate size multipliers above).
*/
static float gTouchStartTolerance = 1.0f/4.5f;
/**
* Default touch behavior (is used when not touch behavior is set).
@ -177,43 +259,6 @@ static const double AXIS_BREAKOUT_ANGLE = M_PI / 8.0; // 22.5 degrees
*/
static const double ALLOWED_DIRECT_PAN_ANGLE = M_PI / 3.0; // 60 degrees
/**
* The preferred axis locking style. See AxisLockMode for possible values.
*/
static int32_t gAxisLockMode = 0;
/**
* Maximum amount of time while panning before sending a viewport change. This
* will asynchronously repaint the page. It is also forced when panning stops.
*/
static int32_t gPanRepaintInterval = 250;
/**
* Maximum amount of time flinging before sending a viewport change. This will
* asynchronously repaint the page.
*/
static int32_t gFlingRepaintInterval = 75;
/**
* Minimum amount of speed along an axis before we switch to "skate" multipliers
* rather than using the "stationary" multipliers.
*/
static float gMinSkateSpeed = 1.0f;
/**
* Whether or not to use the estimated paint duration as a factor when projecting
* the displayport in the direction of scrolling. If this value is set to false,
* a constant 50ms paint time is used; the projection can be scaled as desired
* using the gVelocityBias pref below.
*/
static bool gUsePaintDuration = true;
/**
* How much to adjust the displayport in the direction of scrolling. This value
* is multiplied by the velocity and added to the displayport offset.
*/
static float gVelocityBias = 1.0f;
/**
* Duration of a zoom to animation.
*/
@ -234,71 +279,6 @@ static const CSSToScreenScale MAX_ZOOM(8.0f);
*/
static const CSSToScreenScale MIN_ZOOM(0.125f);
/**
* Amount of time before we timeout response from content. For example, if
* content is being unruly/slow and we don't get a response back within this
* time, we will just pretend that content did not preventDefault any touch
* events we dispatched to it.
*/
static int gContentResponseTimeout = 300;
/**
* Number of samples to store of how long it took to paint after the previous
* requests.
*/
static int gNumPaintDurationSamples = 3;
/**
* The multiplier we apply to the displayport size if it is skating (current
* velocity is above gMinSkateSpeed). We prefer to increase the size of the
* Y axis because it is more natural in the case that a user is reading a page
* that scrolls up/down. Note that one, both or neither of these may be used
* at any instant.
* In general we want g[XY]SkateSizeMultiplier to be smaller than the corresponding
* stationary size multiplier because when panning fast we would like to paint
* less and get faster, more predictable paint times. When panning slowly we
* can afford to paint more even though it's slower.
*/
static float gXSkateSizeMultiplier = 1.5f;
static float gYSkateSizeMultiplier = 2.5f;
/**
* The multiplier we apply to the displayport size if it is not skating (see
* documentation for gXSkateSizeMultiplier).
*/
static float gXStationarySizeMultiplier = 3.0f;
static float gYStationarySizeMultiplier = 3.5f;
/**
* The time period in ms that throttles mozbrowserasyncscroll event.
* Default is 100ms if there is no "apz.asyncscroll.throttle" in preference.
*/
static int gAsyncScrollThrottleTime = 100;
/**
* The timeout in ms for mAsyncScrollTimeoutTask delay task.
* Default is 300ms if there is no "apz.asyncscroll.timeout" in preference.
*/
static int gAsyncScrollTimeout = 300;
/**
* Pref that enables integration with the Metro "cross-slide" gesture.
*/
static bool gCrossSlideEnabled = false;
/**
* Pref that allows or disallows checkerboarding
*/
static bool gAllowCheckerboarding = true;
/**
* Pref that enables enlarging of the displayport along one axis when the
* generated displayport's size is beyond that of the scrollable rect on the
* opposite axis.
*/
static bool gEnlargeDisplayPortWhenClipped = false;
/**
* Is aAngle within the given threshold of the horizontal axis?
* @param aAngle an angle in radians in the range [0, pi]
@ -350,7 +330,7 @@ GetFrameTime() {
class FlingAnimation: public AsyncPanZoomAnimation {
public:
FlingAnimation(AsyncPanZoomController& aApzc)
: AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gFlingRepaintInterval))
: AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
, mApzc(aApzc)
{}
/**
@ -411,27 +391,6 @@ AsyncPanZoomController::InitializeGlobalState()
return;
sInitialized = true;
Preferences::AddBoolVarCache(&gTouchActionPropertyEnabled, "layout.css.touch_action.enabled", gTouchActionPropertyEnabled);
Preferences::AddIntVarCache(&gPanRepaintInterval, "apz.pan_repaint_interval", gPanRepaintInterval);
Preferences::AddIntVarCache(&gFlingRepaintInterval, "apz.fling_repaint_interval", gFlingRepaintInterval);
Preferences::AddFloatVarCache(&gMinSkateSpeed, "apz.min_skate_speed", gMinSkateSpeed);
Preferences::AddBoolVarCache(&gUsePaintDuration, "apz.use_paint_duration", gUsePaintDuration);
Preferences::AddFloatVarCache(&gVelocityBias, "apz.velocity_bias", gVelocityBias);
Preferences::AddIntVarCache(&gContentResponseTimeout, "apz.content_response_timeout", gContentResponseTimeout);
Preferences::AddIntVarCache(&gNumPaintDurationSamples, "apz.num_paint_duration_samples", gNumPaintDurationSamples);
Preferences::AddFloatVarCache(&gTouchStartTolerance, "apz.touch_start_tolerance", gTouchStartTolerance);
Preferences::AddFloatVarCache(&gXSkateSizeMultiplier, "apz.x_skate_size_multiplier", gXSkateSizeMultiplier);
Preferences::AddFloatVarCache(&gYSkateSizeMultiplier, "apz.y_skate_size_multiplier", gYSkateSizeMultiplier);
Preferences::AddFloatVarCache(&gXStationarySizeMultiplier, "apz.x_stationary_size_multiplier", gXStationarySizeMultiplier);
Preferences::AddFloatVarCache(&gYStationarySizeMultiplier, "apz.y_stationary_size_multiplier", gYStationarySizeMultiplier);
Preferences::AddIntVarCache(&gAsyncScrollThrottleTime, "apz.asyncscroll.throttle", gAsyncScrollThrottleTime);
Preferences::AddIntVarCache(&gAsyncScrollTimeout, "apz.asyncscroll.timeout", gAsyncScrollTimeout);
Preferences::AddBoolVarCache(&gCrossSlideEnabled, "apz.cross_slide.enabled", gCrossSlideEnabled);
Preferences::AddIntVarCache(&gAxisLockMode, "apz.axis_lock_mode", gAxisLockMode);
Preferences::AddBoolVarCache(&gAllowCheckerboarding, "apz.allow-checkerboarding", gAllowCheckerboarding);
Preferences::AddBoolVarCache(&gEnlargeDisplayPortWhenClipped, "apz.enlarge_displayport_when_clipped",
gEnlargeDisplayPortWhenClipped);
gComputedTimingFunction = new ComputedTimingFunction();
gComputedTimingFunction->Init(
nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
@ -448,7 +407,7 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
mGeckoContentController(aGeckoContentController),
mRefPtrMonitor("RefPtrMonitor"),
mMonitor("AsyncPanZoomController"),
mTouchActionPropertyEnabled(gTouchActionPropertyEnabled),
mTouchActionPropertyEnabled(gfxPrefs::TouchActionEnabled()),
mContentResponseTimeoutTask(nullptr),
mX(MOZ_THIS_IN_INITIALIZER_LIST()),
mY(MOZ_THIS_IN_INITIALIZER_LIST()),
@ -529,12 +488,12 @@ AsyncPanZoomController::IsDestroyed()
/* static */float
AsyncPanZoomController::GetTouchStartTolerance()
{
return (gTouchStartTolerance * APZCTreeManager::GetDPI());
return (gfxPrefs::APZTouchStartTolerance() * APZCTreeManager::GetDPI());
}
/* static */AsyncPanZoomController::AxisLockMode AsyncPanZoomController::GetAxisLockMode()
{
return static_cast<AxisLockMode>(gAxisLockMode);
return static_cast<AxisLockMode>(gfxPrefs::APZAxisLockMode());
}
nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent) {
@ -1088,7 +1047,7 @@ void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle, TouchBe
}
void AsyncPanZoomController::HandlePanning(double aAngle) {
if (!gCrossSlideEnabled && (!mX.Scrollable() || !mY.Scrollable())) {
if (!gfxPrefs::APZCrossSlideEnabled() && (!mX.Scrollable() || !mY.Scrollable())) {
SetState(PANNING);
} else if (IsCloseToHorizontal(aAngle, AXIS_LOCK_ANGLE)) {
mY.SetAxisLocked(true);
@ -1187,7 +1146,7 @@ void AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
ScheduleComposite();
TimeDuration timePaintDelta = mPaintThrottler.TimeSinceLastRequest(GetFrameTime());
if (timePaintDelta.ToMilliseconds() > gPanRepaintInterval) {
if (timePaintDelta.ToMilliseconds() > gfxPrefs::APZPanRepaintInterval()) {
RequestContentRepaint();
}
UpdateSharedCompositorFrameMetrics();
@ -1386,12 +1345,12 @@ static CSSSize
CalculateDisplayPortSize(const CSSSize& aCompositionSize,
const CSSPoint& aVelocity)
{
float xMultiplier = fabsf(aVelocity.x) < gMinSkateSpeed
? gXStationarySizeMultiplier
: gXSkateSizeMultiplier;
float yMultiplier = fabsf(aVelocity.y) < gMinSkateSpeed
? gYStationarySizeMultiplier
: gYSkateSizeMultiplier;
float xMultiplier = fabsf(aVelocity.x) < gfxPrefs::APZMinSkateSpeed()
? gfxPrefs::APZXStationarySizeMultiplier()
: gfxPrefs::APZXSkateSizeMultiplier();
float yMultiplier = fabsf(aVelocity.y) < gfxPrefs::APZMinSkateSpeed()
? gfxPrefs::APZYStationarySizeMultiplier()
: gfxPrefs::APZYSkateSizeMultiplier();
return CSSSize(aCompositionSize.width * xMultiplier,
aCompositionSize.height * yMultiplier);
}
@ -1439,15 +1398,15 @@ const LayerMargin AsyncPanZoomController::CalculatePendingDisplayPort(
// Calculate the displayport size based on how fast we're moving along each axis.
CSSSize displayPortSize = CalculateDisplayPortSize(compositionSize, velocity);
if (gEnlargeDisplayPortWhenClipped) {
if (gfxPrefs::APZEnlargeDisplayPortWhenClipped()) {
RedistributeDisplayPortExcess(displayPortSize, scrollableRect);
}
// Offset the displayport, depending on how fast we're moving and the
// estimated time it takes to paint, to try to minimise checkerboarding.
float estimatedPaintDurationMillis = (float)(aEstimatedPaintDuration * 1000.0);
float paintFactor = (gUsePaintDuration ? estimatedPaintDurationMillis : 50.0f);
CSSRect displayPort = CSSRect(scrollOffset + (velocity * paintFactor * gVelocityBias),
float paintFactor = (gfxPrefs::APZUsePaintDuration() ? estimatedPaintDurationMillis : 50.0f);
CSSRect displayPort = CSSRect(scrollOffset + (velocity * paintFactor * gfxPrefs::APZVelocityBias()),
displayPortSize);
// Re-center the displayport based on its expansion over the composition size.
@ -1646,7 +1605,7 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
// with the last event.
// Otherwise, start a timer to fire the event sAsyncScrollTimeout ms from now.
TimeDuration delta = aSampleTime - mLastAsyncScrollTime;
if (delta.ToMilliseconds() > gAsyncScrollThrottleTime &&
if (delta.ToMilliseconds() > gfxPrefs::APZAsyncScrollThrottleTime() &&
mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
ReentrantMonitorAutoEnter lock(mMonitor);
mLastAsyncScrollTime = aSampleTime;
@ -1658,7 +1617,7 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
NewRunnableMethod(this, &AsyncPanZoomController::FireAsyncScrollOnTimeout);
MessageLoop::current()->PostDelayedTask(FROM_HERE,
mAsyncScrollTimeoutTask,
gAsyncScrollTimeout);
gfxPrefs::APZAsyncScrollTimeout());
}
return requestAnimationFrame;
@ -1677,7 +1636,7 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
// If checkerboarding has been disallowed, clamp the scroll position to stay
// within rendered content.
if (!gAllowCheckerboarding &&
if (!gfxPrefs::APZAllowCheckerboarding() &&
!mLastContentPaintMetrics.mDisplayPort.IsEmpty()) {
CSSSize compositedSize = mLastContentPaintMetrics.CalculateCompositedSizeInCssPixels();
CSSPoint maxScrollOffset = lastPaintScrollOffset +
@ -1756,7 +1715,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
// Initialize our internal state to something sane when the content
// that was just painted is something we knew nothing about previously
mPaintThrottler.ClearHistory();
mPaintThrottler.SetMaxDurations(gNumPaintDurationSamples);
mPaintThrottler.SetMaxDurations(gfxPrefs::APZNumPaintDurationSamples());
mX.CancelTouch();
mY.CancelTouch();
@ -2045,7 +2004,7 @@ void AsyncPanZoomController::SetContentResponseTimer() {
mContentResponseTimeoutTask =
NewRunnableMethod(this, &AsyncPanZoomController::TimeoutContentResponse);
PostDelayedTask(mContentResponseTimeoutTask, gContentResponseTimeout);
PostDelayedTask(mContentResponseTimeoutTask, gfxPrefs::APZContentResponseTimeout());
}
}

View File

@ -22,58 +22,6 @@
namespace mozilla {
namespace layers {
/**
* These are the preferences that control the behavior of APZ
*/
/**
* "apz.max_event_acceleration"
*
* Maximum acceleration that can happen between two frames. Velocity is
* throttled if it's above this. This may happen if a time delta is very low,
* or we get a touch point very far away from the previous position for some
* reason.
*
* The default value is 999.0f, set in gfxPrefs.h
*/
/**
* "apz.fling_friction"
*
* Amount of friction applied during flings.
*
* The default value is 0.002f, set in gfxPrefs.h
*/
/**
* "apz.fling_stopped_threshold"
*
* When flinging, if the velocity goes below this number, we just stop the
* animation completely. This is to prevent asymptotically approaching 0
* velocity and rerendering unnecessarily.
*
* The default value is 0.01f, set in gfxPrefs.h.
*/
/**
* "apz.max_velocity_queue_size"
*
* Maximum size of velocity queue. The queue contains last N velocity records.
* On touch end we calculate the average velocity in order to compensate
* touch/mouse drivers misbehaviour.
*
* The default value is 5, set in gfxPrefs.h
*/
/**
* "apz.max_velocity_inches_per_ms"
*
* Maximum velocity in inches per millisecond. Velocity will be capped at this
* value if a faster fling occurs. Negative values indicate unlimited velocity.
*
* The default value is -1.0f, set in gfxPrefs.h
*/
Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
: mPos(0),
mVelocity(0.0f),

View File

@ -449,10 +449,6 @@ void
ShadowLayerForwarder::RemoveTextureFromCompositable(CompositableClient* aCompositable,
TextureClient* aTexture)
{
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(aCompositable->GetIPDLActor());
MOZ_ASSERT(aTexture);
MOZ_ASSERT(aTexture->GetIPDLActor());
mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(),
nullptr, aTexture->GetIPDLActor()));
if (aTexture->GetFlags() & TEXTURE_DEALLOCATE_CLIENT) {

View File

@ -98,7 +98,7 @@ DrawQuads(GLContext *aGLContext,
aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
bool texCoords = (texCoordAttribIndex != GLuint(-1));
GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat);
GLsizei bytes = aRects.vertCoords().Length() * 2 * sizeof(GLfloat);
GLsizei total = bytes;
if (texCoords) {
@ -136,7 +136,7 @@ DrawQuads(GLContext *aGLContext,
aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
}
aGLContext->fDrawArrays(aMode, 0, aRects.elements());
aGLContext->fDrawArrays(aMode, 0, aRects.vertCoords().Length());
aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
@ -282,7 +282,7 @@ CompositorOGL::Initialize()
LOCAL_GL_NONE
};
if (!mGLContext->IsGLES2()) {
if (!mGLContext->IsGLES()) {
// No TEXTURE_RECTANGLE_ARB available on ES2
textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
}
@ -372,8 +372,6 @@ CompositorOGL::Initialize()
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
/* Then quad texcoords */
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
/* Then flipped quad texcoords */
0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
};
mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
@ -479,7 +477,7 @@ CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
Matrix4x4 transform;
ToMatrix4x4(aTextureTransform * textureTransform, transform);
aProg->SetTextureTransform(transform);
BindAndDrawQuad(aProg, false);
BindAndDrawQuad(aProg);
} else {
Matrix4x4 transform;
ToMatrix4x4(aTextureTransform, transform);
@ -736,7 +734,7 @@ CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
bool isFormatCompatibleWithRGBA
= gl()->IsGLES2() ? (format == LOCAL_GL_RGBA)
= gl()->IsGLES() ? (format == LOCAL_GL_RGBA)
: true;
if (isFormatCompatibleWithRGBA) {
@ -988,7 +986,7 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
}
BindAndDrawQuad(program, false, aDrawMode);
BindAndDrawQuad(program, aDrawMode);
}
break;
@ -1072,7 +1070,12 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
program->SetTextureTransform(Matrix4x4());
// Drawing is always flipped, but when copying between surfaces we want to avoid
// this, so apply a flip here to cancel the other one out.
Matrix transform;
transform.Translate(0.0, 1.0);
transform.Scale(1.0f, -1.0f);
program->SetTextureTransform(Matrix4x4::From2D(transform));
program->SetTextureUnit(0);
if (maskType != MaskNone) {
@ -1089,7 +1092,7 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
// Drawing is always flipped, but when copying between surfaces we want to avoid
// this. Pass true for the flip parameter to introduce a second flip
// that cancels the other one out.
BindAndDrawQuad(program, true);
BindAndDrawQuad(program);
}
break;
case EFFECT_COMPONENT_ALPHA: {
@ -1190,19 +1193,19 @@ CompositorOGL::EndFrame()
// Unbind all textures
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
if (!mGLContext->IsGLES2()) {
if (!mGLContext->IsGLES()) {
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
}
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1);
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
if (!mGLContext->IsGLES2()) {
if (!mGLContext->IsGLES()) {
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
}
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2);
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
if (!mGLContext->IsGLES2()) {
if (!mGLContext->IsGLES()) {
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
}
}
@ -1317,7 +1320,7 @@ CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform)
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
if (!mGLContext->IsGLES2()) {
if (!mGLContext->IsGLES()) {
// GLES2 promises that binding to any custom FBO will attach
// to GL_COLOR_ATTACHMENT0 attachment point.
mGLContext->fReadBuffer(LOCAL_GL_BACK);
@ -1429,28 +1432,16 @@ CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
(GLvoid*) QuadVBOTexCoordOffset());
}
void
CompositorOGL::QuadVBOFlippedTexCoordsAttrib(GLuint aAttribIndex) {
mGLContext->fVertexAttribPointer(aAttribIndex, 2,
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
(GLvoid*) QuadVBOFlippedTexCoordOffset());
}
void
CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex,
GLuint aTexCoordAttribIndex,
bool aFlipped,
GLuint aDrawMode)
{
BindQuadVBO();
QuadVBOVerticesAttrib(aVertAttribIndex);
if (aTexCoordAttribIndex != GLuint(-1)) {
if (aFlipped)
QuadVBOFlippedTexCoordsAttrib(aTexCoordAttribIndex);
else
QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex);
}
@ -1464,13 +1455,12 @@ CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex,
void
CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
bool aFlipped,
GLuint aDrawMode)
{
NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib),
aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib),
aFlipped, aDrawMode);
aDrawMode);
}
GLuint

View File

@ -311,9 +311,10 @@ private:
CompositingRenderTargetOGL* mWindowRenderTarget;
#endif
/** VBO that has some basics in it for a textured quad,
* including vertex coords and texcoords for both
* flipped and unflipped textures */
/**
* VBO that has some basics in it for a textured quad, including vertex
* coords and texcoords.
*/
GLuint mQuadVBO;
/**
@ -366,18 +367,14 @@ private:
GLintptr QuadVBOVertexOffset() { return 0; }
GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; }
GLintptr QuadVBOFlippedTexCoordOffset() { return sizeof(float)*8*2; }
void BindQuadVBO();
void QuadVBOVerticesAttrib(GLuint aAttribIndex);
void QuadVBOTexCoordsAttrib(GLuint aAttribIndex);
void QuadVBOFlippedTexCoordsAttrib(GLuint aAttribIndex);
void BindAndDrawQuad(GLuint aVertAttribIndex,
GLuint aTexCoordAttribIndex,
bool aFlipped = false,
GLuint aDrawMode = LOCAL_GL_TRIANGLE_STRIP);
void BindAndDrawQuad(ShaderProgramOGL *aProg,
bool aFlipped = false,
GLuint aDrawMode = LOCAL_GL_TRIANGLE_STRIP);
void BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
const gfx3DMatrix& aTextureTransform,

View File

@ -74,6 +74,14 @@ public:
NS_ERROR("This shouldn't be called because we never enable hyphens");
return 0;
}
virtual already_AddRefed<gfxContext> GetContext() {
NS_ERROR("This shouldn't be called because we never enable hyphens");
return nullptr;
}
virtual uint32_t GetAppUnitsPerDevUnit() {
NS_ERROR("This shouldn't be called because we never enable hyphens");
return 60;
}
virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
Spacing* aSpacing) {
NS_ERROR("This shouldn't be called because we never enable spacing");

View File

@ -335,14 +335,14 @@ ApzcTap(AsyncPanZoomController* apzc, int aX, int aY, int& aTime, int aTapLength
return ApzcUp(apzc, aX, aY, aTime);
}
TEST(AsyncPanZoomController, Constructor) {
TEST_F(AsyncPanZoomControllerTester, Constructor) {
// RefCounted class can't live in the stack
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
apzc->SetFrameMetrics(TestFrameMetrics());
}
TEST(AsyncPanZoomController, Pinch) {
TEST_F(AsyncPanZoomControllerTester, Pinch) {
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
@ -385,7 +385,7 @@ TEST(AsyncPanZoomController, Pinch) {
apzc->Destroy();
}
TEST(AsyncPanZoomController, PinchWithTouchActionNone) {
TEST_F(AsyncPanZoomControllerTester, PinchWithTouchActionNone) {
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
@ -419,7 +419,7 @@ TEST(AsyncPanZoomController, PinchWithTouchActionNone) {
EXPECT_EQ(fm.GetScrollOffset().y, 300);
}
TEST(AsyncPanZoomController, Overzoom) {
TEST_F(AsyncPanZoomControllerTester, Overzoom) {
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
@ -446,7 +446,7 @@ TEST(AsyncPanZoomController, Overzoom) {
EXPECT_LT(abs(fm.GetScrollOffset().y), 1e-5);
}
TEST(AsyncPanZoomController, SimpleTransform) {
TEST_F(AsyncPanZoomControllerTester, SimpleTransform) {
TimeStamp testStartTime = TimeStamp::Now();
// RefCounted class can't live in the stack
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
@ -462,7 +462,7 @@ TEST(AsyncPanZoomController, SimpleTransform) {
}
TEST(AsyncPanZoomController, ComplexTransform) {
TEST_F(AsyncPanZoomControllerTester, ComplexTransform) {
TimeStamp testStartTime = TimeStamp::Now();
AsyncPanZoomController::SetFrameTime(testStartTime);
@ -962,7 +962,7 @@ GetTargetAPZC(APZCTreeManager* manager, const ScreenPoint& aPoint,
}
// A simple hit testing test that doesn't involve any transforms on layers.
TEST(APZCTreeManager, HitTesting1) {
TEST_F(APZCTreeManagerTester, HitTesting1) {
nsTArray<nsRefPtr<Layer> > layers;
nsRefPtr<LayerManager> lm;
nsRefPtr<Layer> root = CreateTestLayerTree1(lm, layers);

1039
gfx/thebes/CJKCompatSVS.cpp Normal file

File diff suppressed because it is too large Load Diff

77
gfx/thebes/gencjkcisvs.py Normal file
View File

@ -0,0 +1,77 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
import os.path
import re
import sys
f = open(sys.argv[1] if len(sys.argv) > 1 else 'StandardizedVariants.txt')
line = f.readline()
m = re.compile('^# (StandardizedVariants(-\d+(\.\d+)*)?\.txt)').search(line)
fileversion = m.group(1)
vsdict = {}
r = re.compile('^([0-9A-F]{4,6}) (FE0[0-9A-F]); CJK COMPATIBILITY IDEOGRAPH-([0-9A-F]{4,6});')
while True:
line = f.readline()
if not line:
break
if not 'CJK COMPATIBILITY IDEOGRAPH-' in line:
continue
m = r.search(line)
unified = int(m.group(1), 16)
vs = int(m.group(2), 16)
compat = int(m.group(3), 16)
if not vs in vsdict:
vsdict[vs] = {}
vsdict[vs][unified] = compat
f.close
offsets = []
length = 10 + 11 * len(vsdict)
for (k, mappings) in sorted(vsdict.items()):
offsets.append(length)
length += 4 + 5 * len(mappings)
f = open(sys.argv[2] if len(sys.argv) > 2 else 'CJKCompatSVS.cpp', 'wb')
f.write("""// Generated by %s. Do not edit.
#include <stdint.h>
#define U16(v) (((v) >> 8) & 0xFF), ((v) & 0xFF)
#define U24(v) (((v) >> 16) & 0xFF), (((v) >> 8) & 0xFF), ((v) & 0xFF)
#define U32(v) (((v) >> 24) & 0xFF), (((v) >> 16) & 0xFF), (((v) >> 8) & 0xFF), ((v) & 0xFF)
#define GLYPH(v) U16(v >= 0x2F800 ? (v) - (0x2F800 - 0xFB00) : (v))
// Fallback mappings for CJK Compatibility Ideographs Standardized Variants
// taken from %s.
// Using OpenType format 14 cmap subtable structure to reuse the lookup code
// for fonts. The glyphID field is used to store the corresponding codepoints
// CJK Compatibility Ideographs. To fit codepoints into the 16-bit glyphID
// field, CJK Compatibility Ideographs Supplement (U+2F800..U+2FA1F) will be
// mapped to 0xFB00..0xFD1F.
extern const uint8_t sCJKCompatSVSTable[] = {
""" % (os.path.basename(sys.argv[0]), fileversion))
f.write(' U16(14), // format\n')
f.write(' U32(%d), // length\n' % length)
f.write(' U32(%d), // numVarSelectorRecords\n' % len(vsdict))
for i, k in enumerate(sorted(vsdict.keys())):
f.write(' U24(0x%04X), U32(0), U32(%d), // varSelectorRecord[%d]\n' % (k, offsets[i], i))
for (k, mappings) in sorted(vsdict.items()):
f.write(' // 0x%04X\n' % k)
f.write(' U32(%d), // numUVSMappings\n' % len(mappings))
for (unified, compat) in sorted(mappings.items()):
f.write(' U24(0x%04X), GLYPH(0x%04X),\n' % (unified, compat))
f.write("""};
#undef U16
#undef U24
#undef U32
#undef GLYPH
static_assert(sizeof sCJKCompatSVSTable == %d, "Table generator has a bug.");
""" % length)

View File

@ -8,6 +8,7 @@
#include "harfbuzz/hb.h"
#include "mozilla/Likely.h"
#include "gfxFontConstants.h"
#include "gfxFontUtils.h"
using namespace mozilla::gfx;
@ -155,6 +156,10 @@ gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
gfxFT2LockedFace(this).GetUVSGlyph(unicode, variation_selector);
if (id)
return id;
id = gfxFontUtils::GetUVSFallback(unicode, variation_selector);
if (id) {
unicode = id;
}
}
return GetGlyph(unicode);

View File

@ -4878,13 +4878,17 @@ gfxFontGroup::MakeHyphenTextRun(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit)
}
gfxFloat
gfxFontGroup::GetHyphenWidth(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit)
gfxFontGroup::GetHyphenWidth(gfxTextRun::PropertyProvider *aProvider)
{
if (mHyphenWidth < 0) {
nsAutoPtr<gfxTextRun> hyphRun(MakeHyphenTextRun(aCtx,
aAppUnitsPerDevUnit));
mHyphenWidth = hyphRun.get() ?
hyphRun->GetAdvanceWidth(0, hyphRun->GetLength(), nullptr) : 0;
nsRefPtr<gfxContext> ctx(aProvider->GetContext());
if (ctx) {
nsAutoPtr<gfxTextRun>
hyphRun(MakeHyphenTextRun(ctx,
aProvider->GetAppUnitsPerDevUnit()));
mHyphenWidth = hyphRun.get() ?
hyphRun->GetAdvanceWidth(0, hyphRun->GetLength(), nullptr) : 0;
}
}
return mHyphenWidth;
}

View File

@ -2834,6 +2834,14 @@ public:
*/
virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
Spacing *aSpacing) = 0;
// Returns a gfxContext that can be used to measure the hyphen glyph.
// Only called if the hyphen width is requested.
virtual already_AddRefed<gfxContext> GetContext() = 0;
// Return the appUnitsPerDevUnit value to be used when measuring.
// Only called if the hyphen width is requested.
virtual uint32_t GetAppUnitsPerDevUnit() = 0;
};
class ClusterIterator {
@ -3433,7 +3441,7 @@ public:
* needed to initialize the cached hyphen width; otherwise they are
* ignored.
*/
gfxFloat GetHyphenWidth(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit);
gfxFloat GetHyphenWidth(gfxTextRun::PropertyProvider* aProvider);
/**
* Make a text run representing a single hyphen character.

View File

@ -692,9 +692,27 @@ gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
uint32_t varGID =
gfxFontUtils::MapUVSToGlyphFormat14(aCmapBuf + uvsOffset,
aUnicode, aVarSelector);
if (!varGID) {
aUnicode = gfxFontUtils::GetUVSFallback(aUnicode, aVarSelector);
if (aUnicode) {
switch (format) {
case 4:
if (aUnicode < UNICODE_BMP_LIMIT) {
varGID = MapCharToGlyphFormat4(aCmapBuf + offset,
char16_t(aUnicode));
}
break;
case 12:
varGID = MapCharToGlyphFormat12(aCmapBuf + offset,
aUnicode);
break;
}
}
}
if (varGID) {
gid = varGID;
}
// else the variation sequence was not supported, use default mapping
// of the character code alone
}

View File

@ -639,6 +639,8 @@ enum gfxUserFontType {
GFX_USERFONT_WOFF = 3
};
extern const uint8_t sCJKCompatSVSTable[];
class gfxFontUtils {
public:
@ -784,6 +786,15 @@ public:
static uint16_t
MapUVSToGlyphFormat14(const uint8_t *aBuf, uint32_t aCh, uint32_t aVS);
// sCJKCompatSVSTable is a 'cmap' format 14 subtable that maps
// <char + var-selector> pairs to the corresponding Unicode
// compatibility ideograph codepoints.
static MOZ_ALWAYS_INLINE uint32_t
GetUVSFallback(uint32_t aCh, uint32_t aVS) {
aCh = MapUVSToGlyphFormat14(sCJKCompatSVSTable, aCh, aVS);
return aCh >= 0xFB00 ? aCh + (0x2F800 - 0xFB00) : aCh;
}
static uint32_t
MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
uint32_t aUnicode, uint32_t aVarSelector = 0);

View File

@ -95,6 +95,24 @@ gfxHarfBuzzShaper::GetGlyph(hb_codepoint_t unicode,
unicode,
variation_selector);
}
if (!gid) {
uint32_t compat =
gfxFontUtils::GetUVSFallback(unicode, variation_selector);
if (compat) {
switch (mCmapFormat) {
case 4:
if (compat < UNICODE_BMP_LIMIT) {
gid = gfxFontUtils::MapCharToGlyphFormat4(data + mSubtableOffset,
compat);
}
break;
case 12:
gid = gfxFontUtils::MapCharToGlyphFormat12(data + mSubtableOffset,
compat);
break;
}
}
}
// If the variation sequence was not supported, return zero here;
// harfbuzz will call us again for the base character alone
return gid;

View File

@ -273,7 +273,7 @@ gfxPlatform::gfxPlatform()
#ifdef XP_WIN
// XXX - When 957560 is fixed, the pref can go away entirely
mLayersUseDeprecated =
Preferences::GetBool("layers.use-deprecated-textures", false)
Preferences::GetBool("layers.use-deprecated-textures", true)
&& !gfxPrefs::LayersPreferOpenGL();
#else
mLayersUseDeprecated = false;
@ -632,6 +632,18 @@ void SourceBufferDestroy(void *srcSurfUD)
delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
}
UserDataKey kThebesSurface;
struct DependentSourceSurfaceUserData
{
nsRefPtr<gfxASurface> mSurface;
};
void SourceSurfaceDestroyed(void *aData)
{
delete static_cast<DependentSourceSurfaceUserData*>(aData);
}
#if MOZ_TREE_CAIRO
void SourceSnapshotDetached(cairo_surface_t *nullSurf)
{
@ -654,6 +666,34 @@ gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
aSurface->SetData(&kSourceSurface, nullptr, nullptr);
}
static TemporaryRef<DataSourceSurface>
CopySurface(gfxASurface* aSurface)
{
const nsIntSize size = aSurface->GetSize();
gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType());
RefPtr<DataSourceSurface> data =
Factory::CreateDataSourceSurface(ToIntSize(size),
ImageFormatToSurfaceFormat(format));
if (!data) {
return nullptr;
}
DataSourceSurface::MappedSurface map;
DebugOnly<bool> result = data->Map(DataSourceSurface::WRITE, &map);
MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
nsRefPtr<gfxImageSurface> image = new gfxImageSurface(map.mData, size, map.mStride, format);
nsRefPtr<gfxContext> ctx = new gfxContext(image);
ctx->SetSource(aSurface);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Paint();
data->Unmap();
return data;
}
RefPtr<SourceSurface>
gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
{
@ -722,18 +762,24 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
}
}
bool dependsOnData = false;
if (!srcBuffer) {
nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
bool isWin32ImageSurf = imgSurface &&
aSurface->GetType() == gfxSurfaceType::Win32;
RefPtr<DataSourceSurface> copy;
if (!imgSurface) {
imgSurface = new gfxImageSurface(aSurface->GetSize(), OptimalFormatForContent(aSurface->GetContentType()));
nsRefPtr<gfxContext> ctx = new gfxContext(imgSurface);
ctx->SetSource(aSurface);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Paint();
copy = CopySurface(aSurface);
if (!copy) {
return nullptr;
}
DataSourceSurface::MappedSurface map;
DebugOnly<bool> result = copy->Map(DataSourceSurface::WRITE, &map);
MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
imgSurface = new gfxImageSurface(map.mData, aSurface->GetSize(), map.mStride,
SurfaceFormatToImageFormat(copy->GetFormat()));
}
gfxImageFormat cairoFormat = imgSurface->Format();
@ -760,38 +806,56 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
imgSurface->Stride(),
format);
if (!srcBuffer) {
// We need to check if our gfxASurface will keep the underlying data
// alive. This is true if gfxASurface actually -is- an ImageSurface or
// if it is a gfxWindowsSurface which supports GetAsImageSurface.
if (imgSurface != aSurface && !isWin32ImageSurf) {
return nullptr;
}
srcBuffer = Factory::CreateWrappingDataSourceSurface(imgSurface->Data(),
imgSurface->Stride(),
size, format);
if (copy) {
copy->Unmap();
}
if (!srcBuffer) {
// If we had to make a copy, then just return that. Otherwise aSurface
// must have supported GetAsImageSurface, so we can just wrap that data.
if (copy) {
srcBuffer = copy;
} else {
srcBuffer = Factory::CreateWrappingDataSourceSurface(imgSurface->Data(),
imgSurface->Stride(),
size, format);
dependsOnData = true;
}
}
if (!srcBuffer) {
return nullptr;
}
if (!dependsOnData) {
#if MOZ_TREE_CAIRO
cairo_surface_t *nullSurf =
cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cairo_surface_set_user_data(nullSurf,
&kSourceSurface,
imgSurface,
nullptr);
cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
cairo_surface_destroy(nullSurf);
cairo_surface_t *nullSurf =
cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cairo_surface_set_user_data(nullSurf,
&kSourceSurface,
imgSurface,
nullptr);
cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
cairo_surface_destroy(nullSurf);
#else
cairo_surface_set_mime_data(imgSurface->CairoSurface(), "mozilla/magic", (const unsigned char*) "data", 4, SourceSnapshotDetached, imgSurface.get());
cairo_surface_set_mime_data(imgSurface->CairoSurface(), "mozilla/magic", (const unsigned char*) "data", 4, SourceSnapshotDetached, imgSurface.get());
#endif
}
}
SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
srcSurfUD->mBackendType = aTarget->GetType();
srcSurfUD->mSrcSurface = srcBuffer;
aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
if (dependsOnData) {
// If we wrapped the underlying data of aSurface, then we need to add user data
// to make sure aSurface stays alive until we are done with the data.
DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData;
srcSurfUD->mSurface = aSurface;
srcBuffer->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
} else {
// Otherwise add user data to aSurface so we can cache lookups in the future.
SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
srcSurfUD->mBackendType = aTarget->GetType();
srcSurfUD->mSrcSurface = srcBuffer;
aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
}
return srcBuffer;
}

View File

@ -103,11 +103,29 @@ private:
// We will keep these in an alphabetical order to make it easier to see if
// a method accessing a pref already exists. Just add yours in the list.
// The apz prefs are explained in AsyncPanZoomController.cpp
DECL_GFX_PREF(Live, "apz.allow-checkerboarding", APZAllowCheckerboarding, bool, true);
DECL_GFX_PREF(Live, "apz.asyncscroll.throttle", APZAsyncScrollThrottleTime, int32_t, 100);
DECL_GFX_PREF(Live, "apz.asyncscroll.timeout", APZAsyncScrollTimeout, int32_t, 300);
DECL_GFX_PREF(Live, "apz.axis_lock_mode", APZAxisLockMode, int32_t, 0);
DECL_GFX_PREF(Live, "apz.content_response_timeout", APZContentResponseTimeout, int32_t, 300);
DECL_GFX_PREF(Live, "apz.cross_slide.enabled", APZCrossSlideEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.enlarge_displayport_when_clipped", APZEnlargeDisplayPortWhenClipped, bool, false);
DECL_GFX_PREF(Once, "apz.fling_friction", APZFlingFriction, float, 0.002f);
DECL_GFX_PREF(Live, "apz.fling_repaint_interval", APZFlingRepaintInterval, int32_t, 75);
DECL_GFX_PREF(Once, "apz.fling_stopped_threshold", APZFlingStoppedThreshold, float, 0.01f);
DECL_GFX_PREF(Once, "apz.max_event_acceleration", APZMaxEventAcceleration, float, 999.0f);
DECL_GFX_PREF(Once, "apz.max_velocity_inches_per_ms", APZMaxVelocity, float, -1.0f);
DECL_GFX_PREF(Once, "apz.max_velocity_queue_size", APZMaxVelocityQueueSize, uint32_t, 5);
DECL_GFX_PREF(Live, "apz.min_skate_speed", APZMinSkateSpeed, float, 1.0f);
DECL_GFX_PREF(Live, "apz.num_paint_duration_samples", APZNumPaintDurationSamples, int32_t, 3);
DECL_GFX_PREF(Live, "apz.pan_repaint_interval", APZPanRepaintInterval, int32_t, 250);
DECL_GFX_PREF(Live, "apz.touch_start_tolerance", APZTouchStartTolerance, float, 1.0f/4.5f);
DECL_GFX_PREF(Live, "apz.use_paint_duration", APZUsePaintDuration, bool, true);
DECL_GFX_PREF(Live, "apz.velocity_bias", APZVelocityBias, float, 1.0f);
DECL_GFX_PREF(Live, "apz.x_skate_size_multiplier", APZXSkateSizeMultiplier, float, 1.5f);
DECL_GFX_PREF(Live, "apz.x_stationary_size_multiplier", APZXStationarySizeMultiplier, float, 3.0f);
DECL_GFX_PREF(Live, "apz.y_skate_size_multiplier", APZYSkateSizeMultiplier, float, 2.5f);
DECL_GFX_PREF(Live, "apz.y_stationary_size_multiplier", APZYStationarySizeMultiplier, float, 3.5f);
DECL_GFX_PREF(Once, "gfx.android.rgb16.force", AndroidRGB16Force, bool, false);
#if defined(ANDROID)
@ -175,6 +193,7 @@ private:
DECL_GFX_PREF(Once, "layers.progressive-paint", UseProgressiveTilePainting, bool, false);
DECL_GFX_PREF(Once, "layers.scroll-graph", LayersScrollGraph, bool, false);
DECL_GFX_PREF(Once, "layout.css.touch_action.enabled", TouchActionEnabled, bool, false);
DECL_GFX_PREF(Once, "layout.frame_rate", LayoutFrameRate, int32_t, -1);
DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false);

View File

@ -226,6 +226,7 @@ SOURCES += [
]
UNIFIED_SOURCES += [
'CJKCompatSVS.cpp',
'gfx3DMatrix.cpp',
'gfxAlphaRecovery.cpp',
'gfxBaseSharedMemorySurface.cpp',

View File

@ -0,0 +1,8 @@
// |jit-test| slow
function x() {}
for (var j = 0; j < 9999; ++j) {
(function() {
x += x.watch("endsWith", ArrayBuffer);
return 0 >> Function(x)
})()
}

View File

@ -41,7 +41,9 @@ SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter)
iter.snapshotOffset(),
iter.ionScript()->snapshotsRVATableSize(),
iter.ionScript()->snapshotsListSize()),
recover_(snapshot_),
recover_(snapshot_,
iter.ionScript()->recovers(),
iter.ionScript()->recoversSize()),
fp_(iter.jsFrame()),
machine_(iter.machineState()),
ionScript_(iter.ionScript())

View File

@ -6110,6 +6110,7 @@ CodeGenerator::generateAsmJS()
// every step in CodeGenerator::link must be a nop, as asserted here:
JS_ASSERT(snapshots_.listSize() == 0);
JS_ASSERT(snapshots_.RVATableSize() == 0);
JS_ASSERT(recovers_.size() == 0);
JS_ASSERT(bailouts_.empty());
JS_ASSERT(graph.numConstants() == 0);
JS_ASSERT(safepointIndices_.empty());
@ -6233,7 +6234,7 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
IonScript::New(cx, recompileInfo,
graph.totalSlotCount(), scriptFrameSize,
snapshots_.listSize(), snapshots_.RVATableSize(),
bailouts_.length(), graph.numConstants(),
recovers_.size(), bailouts_.length(), graph.numConstants(),
safepointIndices_.length(), osiIndices_.length(),
cacheList_.length(), runtimeData_.length(),
safepoints_.size(), callTargets.length(),
@ -6343,6 +6344,9 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
ionScript->copyOsiIndices(&osiIndices_[0], masm);
if (snapshots_.listSize())
ionScript->copySnapshots(&snapshots_);
MOZ_ASSERT_IF(snapshots_.listSize(), recovers_.size());
if (recovers_.size())
ionScript->copyRecovers(&recovers_);
if (graph.numConstants())
ionScript->copyConstants(graph.constantPool());
if (callTargets.length() > 0)

View File

@ -820,9 +820,11 @@ IonScript *
IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
uint32_t frameSlots, uint32_t frameSize,
size_t snapshotsListSize, size_t snapshotsRVATableSize,
size_t bailoutEntries, size_t constants, size_t safepointIndices,
size_t osiIndices, size_t cacheEntries, size_t runtimeSize,
size_t safepointsSize, size_t callTargetEntries, size_t backedgeEntries,
size_t recoversSize, size_t bailoutEntries,
size_t constants, size_t safepointIndices,
size_t osiIndices, size_t cacheEntries,
size_t runtimeSize, size_t safepointsSize,
size_t callTargetEntries, size_t backedgeEntries,
OptimizationLevel optimizationLevel)
{
static const int DataAlignment = sizeof(void *);
@ -838,6 +840,7 @@ IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
// *somewhere* and if their total overflowed there would be no memory left
// at all.
size_t paddedSnapshotsSize = AlignBytes(snapshotsListSize + snapshotsRVATableSize, DataAlignment);
size_t paddedRecoversSize = AlignBytes(recoversSize, DataAlignment);
size_t paddedBailoutSize = AlignBytes(bailoutEntries * sizeof(uint32_t), DataAlignment);
size_t paddedConstantsSize = AlignBytes(constants * sizeof(Value), DataAlignment);
size_t paddedSafepointIndicesSize = AlignBytes(safepointIndices * sizeof(SafepointIndex), DataAlignment);
@ -848,6 +851,7 @@ IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
size_t paddedCallTargetSize = AlignBytes(callTargetEntries * sizeof(JSScript *), DataAlignment);
size_t paddedBackedgeSize = AlignBytes(backedgeEntries * sizeof(PatchableBackedge), DataAlignment);
size_t bytes = paddedSnapshotsSize +
paddedRecoversSize +
paddedBailoutSize +
paddedConstantsSize +
paddedSafepointIndicesSize+
@ -895,6 +899,10 @@ IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
script->snapshotsRVATableSize_ = snapshotsRVATableSize;
offsetCursor += paddedSnapshotsSize;
script->recovers_ = offsetCursor;
script->recoversSize_ = recoversSize;
offsetCursor += paddedRecoversSize;
script->constantTable_ = offsetCursor;
script->constantEntries_ = constants;
offsetCursor += paddedConstantsSize;
@ -961,6 +969,13 @@ IonScript::copySnapshots(const SnapshotWriter *writer)
writer->RVATableBuffer(), snapshotsRVATableSize_);
}
void
IonScript::copyRecovers(const RecoverWriter *writer)
{
MOZ_ASSERT(writer->size() == recoversSize_);
memcpy((uint8_t *)this + recovers_, writer->buffer(), recoversSize_);
}
void
IonScript::copySafepoints(const SafepointWriter *writer)
{

View File

@ -143,6 +143,7 @@ class JitCode : public gc::BarrieredCell<JitCode>
};
class SnapshotWriter;
class RecoverWriter;
class SafepointWriter;
class SafepointIndex;
class OsiIndex;
@ -250,6 +251,10 @@ struct IonScript
uint32_t snapshotsListSize_;
uint32_t snapshotsRVATableSize_;
// List of instructions needed to recover stack frames.
uint32_t recovers_;
uint32_t recoversSize_;
// Constant table for constants stored in snapshots.
uint32_t constantTable_;
uint32_t constantEntries_;
@ -351,9 +356,10 @@ struct IonScript
static IonScript *New(JSContext *cx, types::RecompileInfo recompileInfo,
uint32_t frameLocals, uint32_t frameSize,
size_t snapshotsListSize, size_t snapshotsRVATableSize,
size_t bailoutEntries, size_t constants,
size_t safepointIndexEntries, size_t osiIndexEntries,
size_t cacheEntries, size_t runtimeSize, size_t safepointsSize,
size_t recoversSize, size_t bailoutEntries,
size_t constants, size_t safepointIndexEntries,
size_t osiIndexEntries, size_t cacheEntries,
size_t runtimeSize, size_t safepointsSize,
size_t callTargetEntries, size_t backedgeEntries,
OptimizationLevel optimizationLevel);
static void Trace(JSTracer *trc, IonScript *script);
@ -472,6 +478,12 @@ struct IonScript
size_t snapshotsRVATableSize() const {
return snapshotsRVATableSize_;
}
const uint8_t *recovers() const {
return reinterpret_cast<const uint8_t *>(this) + recovers_;
}
size_t recoversSize() const {
return recoversSize_;
}
const uint8_t *safepoints() const {
return reinterpret_cast<const uint8_t *>(this) + safepointsStart_;
}
@ -532,6 +544,7 @@ struct IonScript
void destroyCaches();
void unlinkFromRuntime(FreeOp *fop);
void copySnapshots(const SnapshotWriter *writer);
void copyRecovers(const RecoverWriter *writer);
void copyBailoutTable(const SnapshotOffset *table);
void copyConstants(const Value *vp);
void copySafepointIndices(const SafepointIndex *firstSafepointIndex, MacroAssembler &masm);

View File

@ -309,7 +309,7 @@ class SnapshotIterator
// the call.
if (moreFrames())
return false;
return snapshot_.resumeAfter();
return recover_.resumeAfter();
}
inline BailoutKind bailoutKind() const {
return snapshot_.bailoutKind();

View File

@ -1295,7 +1295,9 @@ SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshot
snapshotOffset,
ionScript->snapshotsRVATableSize(),
ionScript->snapshotsListSize()),
recover_(snapshot_),
recover_(snapshot_,
ionScript->recovers(),
ionScript->recoversSize()),
fp_(fp),
machine_(machine),
ionScript_(ionScript)
@ -1308,7 +1310,9 @@ SnapshotIterator::SnapshotIterator(const IonFrameIterator &iter)
iter.osiIndex()->snapshotOffset(),
iter.ionScript()->snapshotsRVATableSize(),
iter.ionScript()->snapshotsListSize()),
recover_(snapshot_),
recover_(snapshot_,
iter.ionScript()->recovers(),
iter.ionScript()->recoversSize()),
fp_(iter.jsFrame()),
machine_(iter.machineState()),
ionScript_(iter.ionScript())
@ -1317,7 +1321,7 @@ SnapshotIterator::SnapshotIterator(const IonFrameIterator &iter)
SnapshotIterator::SnapshotIterator()
: snapshot_(nullptr, 0, 0, 0),
recover_(snapshot_),
recover_(snapshot_, nullptr, 0),
fp_(nullptr),
ionScript_(nullptr)
{

View File

@ -14,6 +14,7 @@
namespace js {
namespace jit {
typedef uint32_t RecoverOffset;
typedef uint32_t SnapshotOffset;
typedef uint32_t BailoutId;
@ -25,6 +26,7 @@ static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
// Maximum number of scripted arg slots.
static const uint32_t SNAPSHOT_MAX_NARGS = 127;
static const SnapshotOffset INVALID_RECOVER_OFFSET = uint32_t(-1);
static const SnapshotOffset INVALID_SNAPSHOT_OFFSET = uint32_t(-1);
// Different kinds of bailouts. When extending this enum, make sure to check

View File

@ -119,10 +119,28 @@ TotalOperandCount(MResumePoint *mir)
return accum;
}
LSnapshot::LSnapshot(MResumePoint *mir, BailoutKind kind)
: numSlots_(TotalOperandCount(mir) * BOX_PIECES),
LRecoverInfo::LRecoverInfo(MResumePoint *mir)
: mir_(mir),
recoverOffset_(INVALID_RECOVER_OFFSET)
{ }
LRecoverInfo *
LRecoverInfo::New(MIRGenerator *gen, MResumePoint *mir)
{
LRecoverInfo *recover = new(gen->alloc()) LRecoverInfo(mir);
if (!recover)
return nullptr;
IonSpew(IonSpew_Snapshots, "Generating LIR recover %p from MIR (%p)",
(void *)recover, (void *)mir);
return recover;
}
LSnapshot::LSnapshot(LRecoverInfo *recover, BailoutKind kind)
: numSlots_(TotalOperandCount(recover->mir()) * BOX_PIECES),
slots_(nullptr),
mir_(mir),
recoverInfo_(recover),
snapshotOffset_(INVALID_SNAPSHOT_OFFSET),
bailoutId_(INVALID_BAILOUT_ID),
bailoutKind_(kind)
@ -136,14 +154,14 @@ LSnapshot::init(MIRGenerator *gen)
}
LSnapshot *
LSnapshot::New(MIRGenerator *gen, MResumePoint *mir, BailoutKind kind)
LSnapshot::New(MIRGenerator *gen, LRecoverInfo *recover, BailoutKind kind)
{
LSnapshot *snapshot = new(gen->alloc()) LSnapshot(mir, kind);
if (!snapshot->init(gen))
LSnapshot *snapshot = new(gen->alloc()) LSnapshot(recover, kind);
if (!snapshot || !snapshot->init(gen))
return nullptr;
IonSpew(IonSpew_Snapshots, "Generating LIR snapshot %p from MIR (%p)",
(void *)snapshot, (void *)mir);
IonSpew(IonSpew_Snapshots, "Generating LIR snapshot %p from recover (%p)",
(void *)snapshot, (void *)recover);
return snapshot;
}

View File

@ -876,6 +876,30 @@ class LCallInstructionHelper : public LInstructionHelper<Defs, Operands, Temps>
}
};
class LRecoverInfo : public TempObject
{
MResumePoint *mir_;
// Cached offset where this resume point is encoded.
RecoverOffset recoverOffset_;
LRecoverInfo(MResumePoint *mir);
public:
static LRecoverInfo *New(MIRGenerator *gen, MResumePoint *mir);
MResumePoint *mir() const {
return mir_;
}
RecoverOffset recoverOffset() const {
return recoverOffset_;
}
void setRecoverOffset(RecoverOffset offset) {
JS_ASSERT(recoverOffset_ == INVALID_RECOVER_OFFSET);
recoverOffset_ = offset;
}
};
// An LSnapshot is the reflection of an MResumePoint in LIR. Unlike MResumePoints,
// they cannot be shared, as they are filled in by the register allocator in
// order to capture the precise low-level stack state in between an
@ -886,16 +910,16 @@ class LSnapshot : public TempObject
private:
uint32_t numSlots_;
LAllocation *slots_;
MResumePoint *mir_;
LRecoverInfo *recoverInfo_;
SnapshotOffset snapshotOffset_;
BailoutId bailoutId_;
BailoutKind bailoutKind_;
LSnapshot(MResumePoint *mir, BailoutKind kind);
LSnapshot(LRecoverInfo *recover, BailoutKind kind);
bool init(MIRGenerator *gen);
public:
static LSnapshot *New(MIRGenerator *gen, MResumePoint *snapshot, BailoutKind kind);
static LSnapshot *New(MIRGenerator *gen, LRecoverInfo *recover, BailoutKind kind);
size_t numEntries() const {
return numSlots_;
@ -923,8 +947,11 @@ class LSnapshot : public TempObject
JS_ASSERT(i < numSlots_);
slots_[i] = alloc;
}
LRecoverInfo *recoverInfo() const {
return recoverInfo_;
}
MResumePoint *mir() const {
return mir_;
return recoverInfo()->mir();
}
SnapshotOffset snapshotOffset() const {
return snapshotOffset_;

View File

@ -465,19 +465,25 @@ SnapshotReader::SnapshotReader(const uint8_t *snapshots, uint32_t offset,
}
#define COMPUTE_SHIFT_AFTER_(name) (name ## _BITS + name ##_SHIFT)
#define COMPUTE_MASK_(name) (((1 << name ## _BITS) - 1) << name ##_SHIFT)
#define COMPUTE_MASK_(name) ((uint32_t(1 << name ## _BITS) - 1) << name ##_SHIFT)
// Details of snapshot header packing.
static const uint32_t SNAPSHOT_BAILOUTKIND_SHIFT = 0;
static const uint32_t SNAPSHOT_BAILOUTKIND_BITS = 3;
static const uint32_t SNAPSHOT_BAILOUTKIND_MASK = COMPUTE_MASK_(SNAPSHOT_BAILOUTKIND);
static const uint32_t SNAPSHOT_RESUMEAFTER_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);
static const uint32_t SNAPSHOT_RESUMEAFTER_BITS = 1;
static const uint32_t SNAPSHOT_RESUMEAFTER_MASK = COMPUTE_MASK_(SNAPSHOT_RESUMEAFTER);
static const uint32_t SNAPSHOT_ROFFSET_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);
static const uint32_t SNAPSHOT_ROFFSET_BITS = 32 - SNAPSHOT_ROFFSET_SHIFT;
static const uint32_t SNAPSHOT_ROFFSET_MASK = COMPUTE_MASK_(SNAPSHOT_ROFFSET);
static const uint32_t SNAPSHOT_FRAMECOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_RESUMEAFTER);
static const uint32_t SNAPSHOT_FRAMECOUNT_BITS = 32 - 4;
static const uint32_t SNAPSHOT_FRAMECOUNT_MASK = COMPUTE_MASK_(SNAPSHOT_FRAMECOUNT);
// Details of recover header packing.
static const uint32_t RECOVER_RESUMEAFTER_SHIFT = 0;
static const uint32_t RECOVER_RESUMEAFTER_BITS = 1;
static const uint32_t RECOVER_RESUMEAFTER_MASK = COMPUTE_MASK_(RECOVER_RESUMEAFTER);
static const uint32_t RECOVER_FRAMECOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(RECOVER_RESUMEAFTER);
static const uint32_t RECOVER_FRAMECOUNT_BITS = 32 - RECOVER_FRAMECOUNT_SHIFT;
static const uint32_t RECOVER_FRAMECOUNT_MASK = COMPUTE_MASK_(RECOVER_FRAMECOUNT);
#undef COMPUTE_MASK_
#undef COMPUTE_SHIFT_AFTER_
@ -486,24 +492,29 @@ void
SnapshotReader::readSnapshotHeader()
{
uint32_t bits = reader_.readUnsigned();
frameCount_ = bits >> SNAPSHOT_FRAMECOUNT_SHIFT;
JS_ASSERT(frameCount_ > 0);
bailoutKind_ = BailoutKind((bits & SNAPSHOT_BAILOUTKIND_MASK) >> SNAPSHOT_BAILOUTKIND_SHIFT);
resumeAfter_ = !!(bits & (1 << SNAPSHOT_RESUMEAFTER_SHIFT));
recoverOffset_ = (bits & SNAPSHOT_ROFFSET_MASK) >> SNAPSHOT_ROFFSET_SHIFT;
IonSpew(IonSpew_Snapshots, "Read snapshot header with bailout kind %u",
bailoutKind_);
#ifdef TRACK_SNAPSHOTS
readTrackSnapshot();
#endif
}
#ifdef TRACK_SNAPSHOTS
void
SnapshotReader::readTrackSnapshot()
{
pcOpcode_ = reader_.readUnsigned();
mirOpcode_ = reader_.readUnsigned();
mirId_ = reader_.readUnsigned();
lirOpcode_ = reader_.readUnsigned();
lirId_ = reader_.readUnsigned();
#endif
IonSpew(IonSpew_Snapshots, "Read snapshot header with frameCount %u, bailout kind %u (ra: %d)",
frameCount_, bailoutKind_, resumeAfter_);
}
#ifdef TRACK_SNAPSHOTS
void
SnapshotReader::spewBailingFrom() const
{
@ -539,25 +550,40 @@ SnapshotWriter::init()
return allocMap_.init(32);
}
RecoverReader::RecoverReader(SnapshotReader &snapshot)
: frameCount_(0),
RecoverReader::RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size)
: reader_(nullptr, nullptr),
frameCount_(0),
framesRead_(0),
allocCount_(0)
{
if (!snapshot.reader_.more())
if (!recovers)
return;
frameCount_ = snapshot.frameCount_;
reader_ = CompactBufferReader(recovers + snapshot.recoverOffset(), recovers + size);
readRecoverHeader();
readFrame(snapshot);
}
void
RecoverReader::readRecoverHeader()
{
uint32_t bits = reader_.readUnsigned();
frameCount_ = (bits & RECOVER_FRAMECOUNT_MASK) >> RECOVER_FRAMECOUNT_SHIFT;
resumeAfter_ = (bits & RECOVER_RESUMEAFTER_MASK) >> RECOVER_RESUMEAFTER_SHIFT;
JS_ASSERT(frameCount_);
IonSpew(IonSpew_Snapshots, "Read recover header with frameCount %u (ra: %d)",
frameCount_, resumeAfter_);
}
void
RecoverReader::readFrame(SnapshotReader &snapshot)
{
JS_ASSERT(moreFrames());
JS_ASSERT(snapshot.allocRead_ == allocCount_);
pcOffset_ = snapshot.reader_.readUnsigned();
allocCount_ = snapshot.reader_.readUnsigned();
pcOffset_ = reader_.readUnsigned();
allocCount_ = reader_.readUnsigned();
IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, allocCount_);
framesRead_++;
@ -565,20 +591,19 @@ RecoverReader::readFrame(SnapshotReader &snapshot)
}
SnapshotOffset
SnapshotWriter::startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter)
SnapshotWriter::startSnapshot(RecoverOffset recoverOffset, BailoutKind kind)
{
lastStart_ = writer_.length();
allocWritten_ = 0;
IonSpew(IonSpew_Snapshots, "starting snapshot with recover offset %u, bailout kind %u",
recoverOffset, kind);
IonSpew(IonSpew_Snapshots, "starting snapshot with frameCount %u, bailout kind %u",
frameCount, kind);
JS_ASSERT(frameCount > 0);
JS_ASSERT(frameCount < (1 << SNAPSHOT_FRAMECOUNT_BITS));
JS_ASSERT(uint32_t(kind) < (1 << SNAPSHOT_BAILOUTKIND_BITS));
uint32_t bits = (uint32_t(kind) << SNAPSHOT_BAILOUTKIND_SHIFT) |
(frameCount << SNAPSHOT_FRAMECOUNT_SHIFT);
if (resumeAfter)
bits |= (1 << SNAPSHOT_RESUMEAFTER_SHIFT);
JS_ASSERT(recoverOffset < (1 << SNAPSHOT_ROFFSET_BITS));
uint32_t bits =
(uint32_t(kind) << SNAPSHOT_BAILOUTKIND_SHIFT) |
(recoverOffset << SNAPSHOT_ROFFSET_SHIFT);
writer_.writeUnsigned(bits);
return lastStart_;
@ -637,22 +662,29 @@ SnapshotWriter::endSnapshot()
uint32_t(writer_.length() - lastStart_), lastStart_);
}
RecoverWriter::RecoverWriter(SnapshotWriter &snapshot)
: snapshot_(snapshot)
{
}
SnapshotOffset
RecoverWriter::startRecover(uint32_t frameCount, BailoutKind kind, bool resumeAfter)
RecoverOffset
RecoverWriter::startRecover(uint32_t frameCount, bool resumeAfter)
{
MOZ_ASSERT(frameCount);
nframes_ = frameCount;
framesWritten_ = 0;
return snapshot_.startSnapshot(frameCount, kind, resumeAfter);
IonSpew(IonSpew_Snapshots, "starting recover with frameCount %u",
frameCount);
MOZ_ASSERT(!(uint32_t(resumeAfter) &~ RECOVER_RESUMEAFTER_MASK));
MOZ_ASSERT(frameCount < uint32_t(1 << RECOVER_FRAMECOUNT_BITS));
uint32_t bits =
(uint32_t(resumeAfter) << RECOVER_RESUMEAFTER_SHIFT) |
(frameCount << RECOVER_FRAMECOUNT_SHIFT);
RecoverOffset recoverOffset = writer_.length();
writer_.writeUnsigned(bits);
return recoverOffset;
}
void
RecoverWriter::startFrame(JSFunction *fun, JSScript *script,
RecoverWriter::writeFrame(JSFunction *fun, JSScript *script,
jsbytecode *pc, uint32_t exprStack)
{
// Test if we honor the maximum of arguments at all times.
@ -662,30 +694,20 @@ RecoverWriter::startFrame(JSFunction *fun, JSScript *script,
uint32_t implicit = StartArgSlot(script);
uint32_t formalArgs = CountArgSlots(script, fun);
nallocs_ = formalArgs + script->nfixed() + exprStack;
snapshot_.allocWritten_ = 0;
uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u",
implicit, formalArgs - implicit, script->nfixed(), exprStack);
uint32_t pcoff = script->pcToOffset(pc);
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs_);
snapshot_.writer_.writeUnsigned(pcoff);
snapshot_.writer_.writeUnsigned(nallocs_);
}
void
RecoverWriter::endFrame()
{
MOZ_ASSERT(snapshot_.allocWritten_ == nallocs_);
nallocs_ = snapshot_.allocWritten_ = 0;
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs);
writer_.writeUnsigned(pcoff);
writer_.writeUnsigned(nallocs);
framesWritten_++;
}
void
RecoverWriter::endRecover()
{
snapshot_.endSnapshot();
JS_ASSERT(nframes_ == framesWritten_);
}

View File

@ -327,17 +327,21 @@ class SnapshotWriter
public:
bool init();
SnapshotOffset startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
SnapshotOffset startSnapshot(RecoverOffset recoverOffset, BailoutKind kind);
#ifdef TRACK_SNAPSHOTS
void trackSnapshot(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
uint32_t lirOpcode, uint32_t lirId);
#endif
bool add(const RValueAllocation &slot);
uint32_t allocWritten() const {
return allocWritten_;
}
void endSnapshot();
bool oom() const {
return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE ||
allocWriter_.oom() || allocWriter_.length() >= MAX_BUFFER_SIZE;
}
size_t listSize() const {
@ -357,22 +361,28 @@ class SnapshotWriter
class RecoverWriter
{
SnapshotWriter &snapshot_;
uint32_t nallocs_;
CompactBufferWriter writer_;
uint32_t nframes_;
uint32_t framesWritten_;
public:
RecoverWriter(SnapshotWriter &snapshot);
SnapshotOffset startRecover(uint32_t frameCount, bool resumeAfter);
SnapshotOffset startRecover(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
void startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
void endFrame();
void writeFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
void endRecover();
size_t size() const {
return writer_.length();
}
const uint8_t *buffer() const {
return writer_.buffer();
}
bool oom() const {
return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
}
};
class RecoverReader;
@ -389,10 +399,9 @@ class SnapshotReader
CompactBufferReader allocReader_;
const uint8_t* allocTable_;
uint32_t frameCount_;
BailoutKind bailoutKind_;
uint32_t allocRead_; // Number of slots that have been read.
bool resumeAfter_;
RecoverOffset recoverOffset_; // Offset of the recover instructions.
#ifdef TRACK_SNAPSHOTS
private:
@ -403,6 +412,7 @@ class SnapshotReader
uint32_t lirId_;
public:
void readTrackSnapshot();
void spewBailingFrom() const;
#endif
@ -419,23 +429,27 @@ class SnapshotReader
BailoutKind bailoutKind() const {
return bailoutKind_;
}
bool resumeAfter() const {
return resumeAfter_;
RecoverOffset recoverOffset() const {
return recoverOffset_;
}
};
class RecoverReader
{
CompactBufferReader reader_;
uint32_t frameCount_;
uint32_t framesRead_; // Number of frame headers that have been read.
uint32_t pcOffset_; // Offset from script->code.
uint32_t allocCount_; // Number of slots.
bool resumeAfter_;
private:
void readRecoverHeader();
void readFrame(SnapshotReader &snapshot);
public:
RecoverReader(SnapshotReader &snapshot);
RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size);
bool moreFrames() const {
return framesRead_ < frameCount_;
@ -450,6 +464,9 @@ class RecoverReader
uint32_t pcOffset() const {
return pcOffset_;
}
bool resumeAfter() const {
return resumeAfter_;
}
uint32_t allocations() const {
return allocCount_;

View File

@ -42,7 +42,7 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac
graph(*graph),
current(nullptr),
snapshots_(),
recovers_(snapshots_),
recovers_(),
deoptTable_(nullptr),
#ifdef DEBUG
pushedArgs_(0),
@ -235,48 +235,25 @@ CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resume
}
bool
CodeGeneratorShared::encode(LSnapshot *snapshot)
CodeGeneratorShared::encode(LRecoverInfo *recover)
{
if (snapshot->snapshotOffset() != INVALID_SNAPSHOT_OFFSET)
if (recover->recoverOffset() != INVALID_RECOVER_OFFSET)
return true;
uint32_t frameCount = snapshot->mir()->frameCount();
uint32_t frameCount = recover->mir()->frameCount();
IonSpew(IonSpew_Snapshots, "Encoding LRecoverInfo %p (frameCount %u)",
(void *)recover, frameCount);
IonSpew(IonSpew_Snapshots, "Encoding LSnapshot %p (frameCount %u)",
(void *)snapshot, frameCount);
MResumePoint::Mode mode = snapshot->mir()->mode();
MResumePoint::Mode mode = recover->mir()->mode();
JS_ASSERT(mode != MResumePoint::Outer);
bool resumeAfter = (mode == MResumePoint::ResumeAfter);
SnapshotOffset offset = recovers_.startRecover(frameCount, snapshot->bailoutKind(),
resumeAfter);
RecoverOffset offset = recovers_.startRecover(frameCount, resumeAfter);
#ifdef TRACK_SNAPSHOTS
uint32_t pcOpcode = 0;
uint32_t lirOpcode = 0;
uint32_t lirId = 0;
uint32_t mirOpcode = 0;
uint32_t mirId = 0;
if (LInstruction *ins = instruction()) {
lirOpcode = ins->op();
lirId = ins->id();
if (ins->mirRaw()) {
mirOpcode = ins->mirRaw()->op();
mirId = ins->mirRaw()->id();
if (ins->mirRaw()->trackedPc())
pcOpcode = *ins->mirRaw()->trackedPc();
}
}
snapshots_.trackSnapshot(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
#endif
FlattenedMResumePointIter mirOperandIter(snapshot->mir());
FlattenedMResumePointIter mirOperandIter(recover->mir());
if (!mirOperandIter.init())
return false;
uint32_t startIndex = 0;
for (MResumePoint **it = mirOperandIter.begin(), **end = mirOperandIter.end();
it != end;
++it)
@ -287,20 +264,24 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
JSScript *script = block->info().script();
jsbytecode *pc = mir->pc();
uint32_t exprStack = mir->stackDepth() - block->info().ninvoke();
recovers_.startFrame(fun, script, pc, exprStack);
// Ensure that all snapshot which are encoded can safely be used for
// bailouts.
DebugOnly<jsbytecode *> bailPC = pc;
if (mir->mode() == MResumePoint::ResumeAfter)
bailPC = GetNextPc(pc);
recovers_.writeFrame(fun, script, pc, exprStack);
#ifdef DEBUG
// Ensure that all snapshot which are encoded can safely be used for
// bailouts.
if (GetIonContext()->cx) {
uint32_t stackDepth;
bool reachablePC;
if (!ReconstructStackDepth(GetIonContext()->cx, script, bailPC, &stackDepth, &reachablePC))
jsbytecode *bailPC = pc;
if (mir->mode() == MResumePoint::ResumeAfter)
bailPC = GetNextPc(pc);
if (!ReconstructStackDepth(GetIonContext()->cx, script,
bailPC, &stackDepth, &reachablePC))
{
return false;
}
if (reachablePC) {
if (JSOp(*bailPC) == JSOP_FUNCALL) {
@ -326,15 +307,67 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
}
}
#endif
if (!encodeAllocations(snapshot, mir, &startIndex))
return false;
recovers_.endFrame();
}
recovers_.endRecover();
snapshot->setSnapshotOffset(offset);
recover->setRecoverOffset(offset);
return !recovers_.oom();
}
bool
CodeGeneratorShared::encode(LSnapshot *snapshot)
{
if (snapshot->snapshotOffset() != INVALID_SNAPSHOT_OFFSET)
return true;
if (!encode(snapshot->recoverInfo()))
return false;
RecoverOffset recoverOffset = snapshot->recoverInfo()->recoverOffset();
MOZ_ASSERT(recoverOffset != INVALID_RECOVER_OFFSET);
IonSpew(IonSpew_Snapshots, "Encoding LSnapshot %p (LRecoverInfo %p)",
(void *)snapshot, (void*) snapshot->recoverInfo());
SnapshotOffset offset = snapshots_.startSnapshot(recoverOffset, snapshot->bailoutKind());
#ifdef TRACK_SNAPSHOTS
uint32_t pcOpcode = 0;
uint32_t lirOpcode = 0;
uint32_t lirId = 0;
uint32_t mirOpcode = 0;
uint32_t mirId = 0;
if (LInstruction *ins = instruction()) {
lirOpcode = ins->op();
lirId = ins->id();
if (ins->mirRaw()) {
mirOpcode = ins->mirRaw()->op();
mirId = ins->mirRaw()->id();
if (ins->mirRaw()->trackedPc())
pcOpcode = *ins->mirRaw()->trackedPc();
}
}
snapshots_.trackSnapshot(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
#endif
FlattenedMResumePointIter mirOperandIter(snapshot->recoverInfo()->mir());
if (!mirOperandIter.init())
return false;
uint32_t startIndex = 0;
for (MResumePoint **it = mirOperandIter.begin(), **end = mirOperandIter.end();
it != end;
++it)
{
MResumePoint *mir = *it;
if (!encodeAllocations(snapshot, mir, &startIndex))
return false;
}
MOZ_ASSERT(snapshots_.allocWritten() == snapshot->numSlots());
snapshots_.endSnapshot();
snapshot->setSnapshotOffset(offset);
return !snapshots_.oom();
}

View File

@ -258,6 +258,7 @@ class CodeGeneratorShared : public LInstructionVisitor
protected:
// Encodes an LSnapshot into the compressed snapshot buffer, returning
// false on failure.
bool encode(LRecoverInfo *recover);
bool encode(LSnapshot *snapshot);
bool encodeAllocations(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex);

View File

@ -56,11 +56,26 @@ LIRGeneratorShared::lowerTypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock
lir->setOperand(inputPosition, LUse(operand->virtualRegister(), LUse::ANY));
}
LRecoverInfo *
LIRGeneratorShared::getRecoverInfo(MResumePoint *rp)
{
if (cachedRecoverInfo_ && cachedRecoverInfo_->mir() == rp)
return cachedRecoverInfo_;
LRecoverInfo *recoverInfo = LRecoverInfo::New(gen, rp);
cachedRecoverInfo_ = recoverInfo;
return recoverInfo;
}
#ifdef JS_NUNBOX32
LSnapshot *
LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind)
{
LSnapshot *snapshot = LSnapshot::New(gen, rp, kind);
LRecoverInfo *recover = getRecoverInfo(rp);
if (!recover)
return nullptr;
LSnapshot *snapshot = LSnapshot::New(gen, recover, kind);
if (!snapshot)
return nullptr;
@ -114,7 +129,11 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
LSnapshot *
LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind)
{
LSnapshot *snapshot = LSnapshot::New(gen, rp, kind);
LRecoverInfo *recover = getRecoverInfo(rp);
if (!recover)
return nullptr;
LSnapshot *snapshot = LSnapshot::New(gen, recover, kind);
if (!snapshot)
return nullptr;

View File

@ -31,6 +31,7 @@ class LIRGeneratorShared : public MInstructionVisitorWithDefaults
LIRGraph &lirGraph_;
LBlock *current;
MResumePoint *lastResumePoint_;
LRecoverInfo *cachedRecoverInfo_;
LOsiPoint *osiPoint_;
public:
@ -39,6 +40,7 @@ class LIRGeneratorShared : public MInstructionVisitorWithDefaults
graph(graph),
lirGraph_(lirGraph),
lastResumePoint_(nullptr),
cachedRecoverInfo_(nullptr),
osiPoint_(nullptr)
{ }
@ -160,6 +162,7 @@ class LIRGeneratorShared : public MInstructionVisitorWithDefaults
return tmp;
}
LRecoverInfo *getRecoverInfo(MResumePoint *rp);
LSnapshot *buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind);
bool assignPostSnapshot(MInstruction *mir, LInstruction *ins);

View File

@ -436,3 +436,4 @@ MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED, 381, 0, JSEXN_TYPEERR, "cannot crea
MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL, 382, 1, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed on {0}")
MSG_DEF(JSMSG_INVALID_ARG_TYPE, 383, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
MSG_DEF(JSMSG_TERMINATED, 384, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP, 385, 1, JSEXN_ERR, "No such property on self-hosted object: {0}")

View File

@ -1147,8 +1147,8 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
JS_ASSERT(lazy->source()->hasSourceData());
// Parse and compile the script from source.
SourceDataCache::AutoSuppressPurge asp(cx);
const jschar *chars = lazy->source()->chars(cx, asp);
SourceDataCache::AutoHoldEntry holder;
const jschar *chars = lazy->source()->chars(cx, holder);
if (!chars)
return false;

View File

@ -1392,33 +1392,77 @@ JSScript::sourceData(JSContext *cx)
return scriptSource()->substring(cx, sourceStart(), sourceEnd());
}
SourceDataCache::AutoSuppressPurge::AutoSuppressPurge(JSContext *cx)
: cache_(cx->runtime()->sourceDataCache)
SourceDataCache::AutoHoldEntry::AutoHoldEntry()
: cache_(nullptr), source_(nullptr), charsToFree_(nullptr)
{
oldValue_ = cache_.numSuppressPurges_++;
}
SourceDataCache::AutoSuppressPurge::~AutoSuppressPurge()
void
SourceDataCache::AutoHoldEntry::holdEntry(SourceDataCache *cache, ScriptSource *source)
{
cache_.numSuppressPurges_--;
JS_ASSERT(cache_.numSuppressPurges_ == oldValue_);
// Initialise the holder for a specific cache and script source. This will
// hold on to the cached source chars in the event that the cache is purged.
JS_ASSERT(!cache_ && !source_ && !charsToFree_);
cache_ = cache;
source_ = source;
}
void
SourceDataCache::AutoHoldEntry::deferDelete(const jschar *chars)
{
// Take ownership of source chars now the cache is being purged. Remove our
// reference to the ScriptSource which might soon be destroyed.
JS_ASSERT(cache_ && source_ && !charsToFree_);
cache_ = nullptr;
source_ = nullptr;
charsToFree_ = chars;
}
SourceDataCache::AutoHoldEntry::~AutoHoldEntry()
{
// The holder is going out of scope. If it has taken ownership of cached
// chars then delete them, otherwise unregister ourself with the cache.
if (charsToFree_) {
JS_ASSERT(!cache_ && !source_);
js_free(const_cast<jschar *>(charsToFree_));
} else if (cache_) {
JS_ASSERT(source_);
cache_->releaseEntry(*this);
}
}
void
SourceDataCache::holdEntry(AutoHoldEntry &holder, ScriptSource *ss)
{
JS_ASSERT(!holder_);
holder.holdEntry(this, ss);
holder_ = &holder;
}
void
SourceDataCache::releaseEntry(AutoHoldEntry &holder)
{
JS_ASSERT(holder_ == &holder);
holder_ = nullptr;
}
const jschar *
SourceDataCache::lookup(ScriptSource *ss, const AutoSuppressPurge &asp)
SourceDataCache::lookup(ScriptSource *ss, AutoHoldEntry &holder)
{
JS_ASSERT(this == &asp.cache());
JS_ASSERT(!holder_);
if (!map_)
return nullptr;
if (Map::Ptr p = map_->lookup(ss))
if (Map::Ptr p = map_->lookup(ss)) {
holdEntry(holder, ss);
return p->value();
}
return nullptr;
}
bool
SourceDataCache::put(ScriptSource *ss, const jschar *str, const AutoSuppressPurge &asp)
SourceDataCache::put(ScriptSource *ss, const jschar *str, AutoHoldEntry &holder)
{
JS_ASSERT(this == &asp.cache());
JS_ASSERT(!holder_);
if (!map_) {
map_ = js_new<Map>();
@ -1432,17 +1476,28 @@ SourceDataCache::put(ScriptSource *ss, const jschar *str, const AutoSuppressPurg
}
}
return map_->put(ss, str);
if (!map_->put(ss, str))
return false;
holdEntry(holder, ss);
return true;
}
void
SourceDataCache::purge()
{
if (!map_ || numSuppressPurges_ > 0)
if (!map_)
return;
for (Map::Range r = map_->all(); !r.empty(); r.popFront())
js_delete(const_cast<jschar*>(r.front().value()));
for (Map::Range r = map_->all(); !r.empty(); r.popFront()) {
const jschar *chars = r.front().value();
if (holder_ && r.front().key() == holder_->source()) {
holder_->deferDelete(chars);
holder_ = nullptr;
} else {
js_free(const_cast<jschar*>(chars));
}
}
js_delete(map_);
map_ = nullptr;
@ -1463,7 +1518,7 @@ SourceDataCache::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
}
const jschar *
ScriptSource::chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp)
ScriptSource::chars(JSContext *cx, SourceDataCache::AutoHoldEntry &holder)
{
if (const jschar *chars = getOffThreadCompressionChars(cx))
return chars;
@ -1471,9 +1526,9 @@ ScriptSource::chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp
#ifdef USE_ZLIB
if (compressed()) {
if (const jschar *decompressed = cx->runtime()->sourceDataCache.lookup(this, asp))
if (const jschar *decompressed = cx->runtime()->sourceDataCache.lookup(this, holder))
return decompressed;
const size_t nbytes = sizeof(jschar) * (length_ + 1);
jschar *decompressed = static_cast<jschar *>(js_malloc(nbytes));
if (!decompressed)
@ -1488,7 +1543,7 @@ ScriptSource::chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp
decompressed[length_] = 0;
if (!cx->runtime()->sourceDataCache.put(this, decompressed, asp)) {
if (!cx->runtime()->sourceDataCache.put(this, decompressed, holder)) {
JS_ReportOutOfMemory(cx);
js_free(decompressed);
return nullptr;
@ -1504,8 +1559,8 @@ JSFlatString *
ScriptSource::substring(JSContext *cx, uint32_t start, uint32_t stop)
{
JS_ASSERT(start <= stop);
SourceDataCache::AutoSuppressPurge asp(cx);
const jschar *chars = this->chars(cx, asp);
SourceDataCache::AutoHoldEntry holder;
const jschar *chars = this->chars(cx, holder);
if (!chars)
return nullptr;
return js_NewStringCopyN<CanGC>(cx, chars + start, stop - start);
@ -3784,13 +3839,13 @@ LazyScriptHashPolicy::match(JSScript *script, const Lookup &lookup)
return false;
}
SourceDataCache::AutoSuppressPurge asp(cx);
SourceDataCache::AutoHoldEntry holder;
const jschar *scriptChars = script->scriptSource()->chars(cx, asp);
const jschar *scriptChars = script->scriptSource()->chars(cx, holder);
if (!scriptChars)
return false;
const jschar *lazyChars = lazy->source()->chars(cx, asp);
const jschar *lazyChars = lazy->source()->chars(cx, holder);
if (!lazyChars)
return false;

View File

@ -349,28 +349,41 @@ class SourceDataCache
const jschar *,
DefaultHasher<ScriptSource *>,
SystemAllocPolicy> Map;
Map *map_;
size_t numSuppressPurges_;
public:
SourceDataCache() : map_(nullptr), numSuppressPurges_(0) {}
class AutoSuppressPurge
// Hold an entry in the source data cache and prevent it from being purged on GC.
class AutoHoldEntry
{
SourceDataCache &cache_;
mozilla::DebugOnly<size_t> oldValue_;
SourceDataCache *cache_;
ScriptSource *source_;
const jschar *charsToFree_;
public:
explicit AutoSuppressPurge(JSContext *cx);
~AutoSuppressPurge();
SourceDataCache &cache() const { return cache_; }
explicit AutoHoldEntry();
~AutoHoldEntry();
private:
void holdEntry(SourceDataCache *cache, ScriptSource *source);
void deferDelete(const jschar *chars);
ScriptSource *source() const { return source_; }
friend class SourceDataCache;
};
const jschar *lookup(ScriptSource *ss, const AutoSuppressPurge &asp);
bool put(ScriptSource *ss, const jschar *chars, const AutoSuppressPurge &asp);
private:
Map *map_;
AutoHoldEntry *holder_;
public:
SourceDataCache() : map_(nullptr), holder_(nullptr) {}
const jschar *lookup(ScriptSource *ss, AutoHoldEntry &asp);
bool put(ScriptSource *ss, const jschar *chars, AutoHoldEntry &asp);
void purge();
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
private:
void holdEntry(AutoHoldEntry &holder, ScriptSource *ss);
void releaseEntry(AutoHoldEntry &holder);
};
class ScriptSource
@ -484,7 +497,7 @@ class ScriptSource
JS_ASSERT(hasSourceData());
return argumentsNotIncluded_;
}
const jschar *chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp);
const jschar *chars(JSContext *cx, SourceDataCache::AutoHoldEntry &asp);
JSFlatString *substring(JSContext *cx, uint32_t start, uint32_t stop);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
JS::ScriptSourceInfo *info) const;

View File

@ -1000,15 +1000,17 @@ GetUnclonedValue(JSContext *cx, JSObject *selfHostedObject, jsid id, Value *vp)
if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) {
JS_ASSERT(selfHostedObject->is<GlobalObject>());
gc::AutoSuppressGC suppress(cx);
JS_ReportError(cx, "No such property on self hosted object");
return false;
RootedValue value(cx, IdToValue(id));
return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
}
Shape *shape = selfHostedObject->nativeLookupPure(id);
if (!shape) {
gc::AutoSuppressGC suppress(cx);
JS_ReportError(cx, "No such property on self hosted object");
return false;
RootedValue value(cx, IdToValue(id));
return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
}
JS_ASSERT(shape->hasSlot() && shape->hasDefaultGetter());

View File

@ -1801,6 +1801,34 @@ nsLayoutUtils::ChangeMatrixBasis(const gfxPoint3D &aOrigin,
return result;
}
static void ConstrainToCoordValues(float& aStart, float& aSize)
{
MOZ_ASSERT(aSize > 0);
// Here we try to make sure that the resulting nsRect will continue to cover
// as much of the area that was covered by the original gfx Rect as possible.
// We clamp the bounds of the rect to {nscoord_MIN,nscoord_MAX} since
// nsRect::X/Y() and nsRect::XMost/YMost() can't return values outwith this
// range:
float end = aStart + aSize;
aStart = clamped(aStart, float(nscoord_MIN), float(nscoord_MAX));
end = clamped(end, float(nscoord_MIN), float(nscoord_MAX));
aSize = end - aStart;
// We must also clamp aSize to {0,nscoord_MAX} since nsRect::Width/Height()
// can't return a value greater than nscoord_MAX. If aSize is greater than
// nscoord_MAX then we reduce it to nscoord_MAX while keeping the rect
// centered:
if (aSize > nscoord_MAX) {
float excess = aSize - nscoord_MAX;
excess /= 2;
aStart += excess;
aSize = nscoord_MAX;
}
}
/**
* Given a gfxFloat, constrains its value to be between nscoord_MIN and nscoord_MAX.
*
@ -1840,6 +1868,22 @@ static void ConstrainToCoordValues(gfxFloat& aStart, gfxFloat& aSize)
}
}
nsRect
nsLayoutUtils::RoundGfxRectToAppRect(const Rect &aRect, float aFactor)
{
/* Get a new Rect whose units are app units by scaling by the specified factor. */
Rect scaledRect = aRect;
scaledRect.ScaleRoundOut(aFactor);
/* We now need to constrain our results to the max and min values for coords. */
ConstrainToCoordValues(scaledRect.x, scaledRect.width);
ConstrainToCoordValues(scaledRect.y, scaledRect.height);
/* Now typecast everything back. This is guaranteed to be safe. */
return nsRect(nscoord(scaledRect.X()), nscoord(scaledRect.Y()),
nscoord(scaledRect.Width()), nscoord(scaledRect.Height()));
}
nsRect
nsLayoutUtils::RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor)
{

View File

@ -117,6 +117,7 @@ class nsLayoutUtils
typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
typedef mozilla::gfx::SourceSurface SourceSurface;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::Rect Rect;
public:
typedef mozilla::layers::FrameMetrics FrameMetrics;
@ -790,6 +791,16 @@ public:
static nsPoint MatrixTransformPoint(const nsPoint &aPoint,
const gfx3DMatrix &aMatrix, float aFactor);
/**
* Given a graphics rectangle in graphics space, return a rectangle in
* app space that contains the graphics rectangle, rounding out as necessary.
*
* @param aRect The graphics rect to round outward.
* @param aFactor The number of app units per graphics unit.
* @return The smallest rectangle in app space that contains aRect.
*/
static nsRect RoundGfxRectToAppRect(const Rect &aRect, float aFactor);
/**
* Given a graphics rectangle in graphics space, return a rectangle in
* app space that contains the graphics rectangle, rounding out as necessary.

View File

@ -4927,24 +4927,14 @@ PresShell::PaintRangePaintInfo(nsTArray<nsAutoPtr<RangePaintInfo> >* aItems,
aScreenRect->width = pixelArea.width;
aScreenRect->height = pixelArea.height;
nsRefPtr<gfxImageSurface> surface =
new gfxImageSurface(gfxIntSize(pixelArea.width, pixelArea.height),
gfxImageFormat::ARGB32);
if (surface->CairoStatus()) {
RefPtr<DrawTarget> dt =
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
IntSize(pixelArea.width, pixelArea.height),
SurfaceFormat::B8G8R8A8);
if (!dt) {
return nullptr;
}
// clear the image
gfxContext context(surface);
context.SetOperator(gfxContext::OPERATOR_CLEAR);
context.Rectangle(gfxRect(0, 0, pixelArea.width, pixelArea.height));
context.Fill();
RefPtr<DrawTarget> dt =
gfxPlatform::GetPlatform()->
CreateDrawTargetForSurface(surface, gfx::IntSize(pixelArea.width, pixelArea.height));
nsRefPtr<gfxContext> ctx = new gfxContext(dt);
nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
rc->Init(deviceContext, ctx);

View File

@ -2839,6 +2839,14 @@ public:
return mTextStyle->mHyphens;
}
virtual already_AddRefed<gfxContext> GetContext() {
return GetReferenceRenderingContext(GetFrame(), nullptr);
}
virtual uint32_t GetAppUnitsPerDevUnit() {
return mTextRun->GetAppUnitsPerDevUnit();
}
void GetSpacingInternal(uint32_t aStart, uint32_t aLength, Spacing* aSpacing,
bool aIgnoreTabs);
@ -3194,16 +3202,9 @@ gfxFloat
PropertyProvider::GetHyphenWidth()
{
if (mHyphenWidth < 0) {
mHyphenWidth = mLetterSpacing;
nsRefPtr<gfxContext> context(GetReferenceRenderingContext(GetFrame(),
nullptr));
if (context) {
mHyphenWidth +=
GetFontGroup()->GetHyphenWidth(context,
mTextRun->GetAppUnitsPerDevUnit());
}
mHyphenWidth = GetFontGroup()->GetHyphenWidth(this);
}
return mHyphenWidth;
return mHyphenWidth + mLetterSpacing;
}
void

View File

@ -20,12 +20,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=470212
function doShiftDrag(){
setTimeout(function() {
var wu = SpecialPowers.DOMWindowUtils;
wu.sendMouseEvent('mousedown', 0, 50, 0, 1, 4);
wu.sendMouseEvent('mousemove', 70, 70, 0, 0, 4);
wu.sendMouseEvent('mousemove', 80, 500, 0, 0, 4);
wu.sendMouseEvent('mousedown', 0, 0, 0, 1, 4);
wu.sendMouseEvent('mousemove', 60, 10, 0, 0, 4);
wu.sendMouseEvent('mousemove', 70, 250, 0, 0, 4);
is(window.getSelection().rangeCount, 0, "rangeCount should be 0");
wu.sendMouseEvent('mouseup', 80, 500, 0, 0, 4);
wu.sendMouseEvent('mouseup', 70, 250, 0, 0, 4);
SimpleTest.finish();
}, 0);

View File

@ -0,0 +1,22 @@
<!DOCTYPE html><meta charset=utf-8>
<title>Duplicate encoded quartet</title>
<style>
@font-face { font-family: DupEncQuartet; src: url('../fonts/gw1270797.ttf') format("truetype"); }
th { width: 72pt }
td { font-size: 72pt; font-family: DupEncQuartet, sans-serif; text-align: center }
</style>
<body>
<table border>
<caption>Duplicate encoded quartet</caption>
<tr>
<th>CJK Compatibility Ideographs</td>
<th>Adobe-Japan1 IVS</td>
<th>Hanyo-Denshi IVS</td>
<th>CJK Compatibility Ideographs Standardized Variant</td>
</tr>
<tr>
<td>&#xE000;</td>
<td>&#xE000;</td>
<td>&#xE000;</td>
<td>&#xE000;</td>
</tr>

View File

@ -0,0 +1,22 @@
<!DOCTYPE html><meta charset=utf-8>
<title>Duplicate encoded quartet</title>
<style>
@font-face { font-family: DupEncQuartet; src: url('../fonts/gw1270797.ttf') format("truetype"); }
th { width: 72pt }
td { font-size: 72pt; font-family: DupEncQuartet, sans-serif; text-align: center }
</style>
<body>
<table border>
<caption>Duplicate encoded quartet</caption>
<tr>
<th>CJK Compatibility Ideographs</td>
<th>Adobe-Japan1 IVS</td>
<th>Hanyo-Denshi IVS</td>
<th>CJK Compatibility Ideographs Standardized Variant</td>
</tr>
<tr>
<td>&#xFA19;</td>
<td>&#x795E;&#xE0100;</td>
<td>&#x795E;&#xE0103;</td>
<td>&#x795E;&#xFE00;</td>
</tr>

View File

@ -142,6 +142,7 @@ HTTP(..) == font-familiy-whitespace-1.html font-familiy-whitespace-1-ref.html
HTTP(..) != font-familiy-whitespace-1.html font-familiy-whitespace-1-notref.html
skip-if(B2G) HTTP(..) == ivs-1.html ivs-1-ref.html # bug 773482
skip-if(B2G) HTTP(..) == cjkcisvs-1.html cjkcisvs-1-ref.html
skip-if(B2G) HTTP(..) == missing-names.html missing-names-ref.html # bug 773482

View File

@ -1,3 +1,5 @@
gw432047.ttf, gw1270797.ttf
<http://en.glyphwiki.org/wiki/GlyphWiki:License>
'''This document is a direct translation of the October 8th, 2008 revision of the Japanese original at ([[GlyphWiki:データ・記事のライセンス]]). This translation is provided as a service, and should not be taken to be a definitive statement. Please be aware that in case the Japanese original and the English version differ, the Japanese original takes precedence.'''

Some files were not shown because too many files have changed in this diff Show More