mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 21:55:31 +00:00
Merge m-c to b2g-inbound.
This commit is contained in:
commit
67e0ae5c09
@ -55,6 +55,7 @@ enum AccType {
|
||||
eProgressType,
|
||||
eRootType,
|
||||
eXULLabelType,
|
||||
eXULListItemType,
|
||||
eXULTabpanelsType,
|
||||
eXULTreeType,
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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!");
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -582,6 +582,7 @@ XULListitemAccessible::
|
||||
nsGkAtoms::type,
|
||||
nsGkAtoms::checkbox,
|
||||
eCaseMatters);
|
||||
mType = eXULListItemType;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(XULListitemAccessible, Accessible)
|
||||
|
@ -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]
|
||||
|
92
accessible/tests/mochitest/events/test_name.xul
Normal file
92
accessible/tests/mochitest/events/test_name.xul
Normal 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>
|
31
b2g/config/mozconfigs/macosx64_gecko/debug
Normal file
31
b2g/config/mozconfigs/macosx64_gecko/debug
Normal 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"
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -816,7 +816,6 @@ protected:
|
||||
WebGLVertexAttrib0Status WhatDoesVertexAttrib0Need();
|
||||
bool DoFakeVertexAttrib0(GLuint vertexCount);
|
||||
void UndoFakeVertexAttrib0();
|
||||
void InvalidateFakeVertexAttrib0();
|
||||
|
||||
static CheckedUint32 GetImageSize(GLsizei height,
|
||||
GLsizei width,
|
||||
|
@ -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
|
||||
|
726
content/canvas/src/WebGLContextDraw.cpp
Normal file
726
content/canvas/src/WebGLContextDraw.cpp
Normal 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, ¤tProgram);
|
||||
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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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, ¤tProgram);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ if CONFIG['MOZ_WEBGL']:
|
||||
'WebGLContext.cpp',
|
||||
'WebGLContextAsyncQueries.cpp',
|
||||
'WebGLContextBuffers.cpp',
|
||||
'WebGLContextDraw.cpp',
|
||||
'WebGLContextExtensions.cpp',
|
||||
'WebGLContextFramebufferOperations.cpp',
|
||||
'WebGLContextGL.cpp',
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
20
dom/plugins/test/mochitest/test_bug986930.html
Normal file
20
dom/plugins/test/mochitest/test_bug986930.html
Normal 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>
|
@ -31,7 +31,7 @@
|
||||
<string>tst</string>
|
||||
</array>
|
||||
<key>WebPluginTypeDescription</key>
|
||||
<string>Test mimetype</string>
|
||||
<string>Test ™ mimetype</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
@ -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"
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
|
10
gfx/2d/2D.h
10
gfx/2d/2D.h
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
122
gfx/gl/GLDrawRectHelper.cpp
Normal 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
41
gfx/gl/GLDrawRectHelper.h
Normal 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_
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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',
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -132,6 +132,7 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
|
||||
|
||||
EffectChain effectChain(this);
|
||||
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
|
||||
|
||||
nsIntRegion visibleRegion = GetEffectiveVisibleRegion();
|
||||
|
||||
TiledLayerProperties tiledLayerProps;
|
||||
|
@ -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()) {
|
||||
|
@ -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.");
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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
1039
gfx/thebes/CJKCompatSVS.cpp
Normal file
File diff suppressed because it is too large
Load Diff
77
gfx/thebes/gencjkcisvs.py
Normal file
77
gfx/thebes/gencjkcisvs.py
Normal 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)
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -226,6 +226,7 @@ SOURCES += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'CJKCompatSVS.cpp',
|
||||
'gfx3DMatrix.cpp',
|
||||
'gfxAlphaRecovery.cpp',
|
||||
'gfxBaseSharedMemorySurface.cpp',
|
||||
|
8
js/src/jit-test/tests/gc/bug-986864.js
Normal file
8
js/src/jit-test/tests/gc/bug-986864.js
Normal 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)
|
||||
})()
|
||||
}
|
@ -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())
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_;
|
||||
|
@ -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_);
|
||||
}
|
||||
|
@ -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_;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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}")
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
22
layout/reftests/font-face/cjkcisvs-1-ref.html
Normal file
22
layout/reftests/font-face/cjkcisvs-1-ref.html
Normal 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></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
22
layout/reftests/font-face/cjkcisvs-1.html
Normal file
22
layout/reftests/font-face/cjkcisvs-1.html
Normal 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>神</td>
|
||||
<td>神󠄀</td>
|
||||
<td>神󠄃</td>
|
||||
<td>神︀</td>
|
||||
</tr>
|
@ -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
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user