diff --git a/accessible/src/base/AccTypes.h b/accessible/src/base/AccTypes.h index 4d18bbe46df0281f7fe92accf1e0159c483673fa..a5ee2be7a2747ec18869d2974c9903ed24a89d88 100644 --- a/accessible/src/base/AccTypes.h +++ b/accessible/src/base/AccTypes.h @@ -55,6 +55,7 @@ enum AccType { eProgressType, eRootType, eXULLabelType, + eXULListItemType, eXULTabpanelsType, eXULTreeType, diff --git a/accessible/src/base/EventQueue.cpp b/accessible/src/base/EventQueue.cpp index b0a485f5937e3424380beb6d08586faae4ae1b65..6338785e49c9bdf2c88b9f2003e8b42f276ee824 100644 --- a/accessible/src/base/EventQueue.cpp +++ b/accessible/src/base/EventQueue.cpp @@ -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); diff --git a/accessible/src/base/nsTextEquivUtils.cpp b/accessible/src/base/nsTextEquivUtils.cpp index e6651e96c0198960fc08f75dae78ff35ee3727be..bab1eee56942c1dbfe6c2a986df6cb60a6129109 100644 --- a/accessible/src/base/nsTextEquivUtils.cpp +++ b/accessible/src/base/nsTextEquivUtils.cpp @@ -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 } - diff --git a/accessible/src/base/nsTextEquivUtils.h b/accessible/src/base/nsTextEquivUtils.h index 77ed2d39043a6c3cba286d4b9b6d99b912ea135e..3c35d0c072114d2e43d5089c773ef9161403ecc2 100644 --- a/accessible/src/base/nsTextEquivUtils.h +++ b/accessible/src/base/nsTextEquivUtils.h @@ -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. * diff --git a/accessible/src/generic/Accessible.cpp b/accessible/src/generic/Accessible.cpp index 1e5d44fcb84b1bc2f682f6599765bc410fb2c4c2..24bf9814f84fc0e6db1905d9935de889527ce24e 100644 --- a/accessible/src/generic/Accessible.cpp +++ b/accessible/src/generic/Accessible.cpp @@ -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!"); } diff --git a/accessible/src/generic/Accessible.h b/accessible/src/generic/Accessible.h index caba51d52010b87f3b9a544f3bedb088bb69749c..70ab16b899289afe8d5f89446854f4b9687ab959 100644 --- a/accessible/src/generic/Accessible.h +++ b/accessible/src/generic/Accessible.h @@ -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; diff --git a/accessible/src/xul/XULListboxAccessible.cpp b/accessible/src/xul/XULListboxAccessible.cpp index d008e5fc711e92d4a9cabad6a0ceea6c75b85d6f..b6757fd62cd36093848655e270a77a60185568e7 100644 --- a/accessible/src/xul/XULListboxAccessible.cpp +++ b/accessible/src/xul/XULListboxAccessible.cpp @@ -582,6 +582,7 @@ XULListitemAccessible:: nsGkAtoms::type, nsGkAtoms::checkbox, eCaseMatters); + mType = eXULListItemType; } NS_IMPL_ISUPPORTS_INHERITED0(XULListitemAccessible, Accessible) diff --git a/accessible/tests/mochitest/events/a11y.ini b/accessible/tests/mochitest/events/a11y.ini index fb35ef23ba5f3b71882bfe84be52c62873e79b09..20daae2fb41e45c0ccdd8be394579b103819f24c 100644 --- a/accessible/tests/mochitest/events/a11y.ini +++ b/accessible/tests/mochitest/events/a11y.ini @@ -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] diff --git a/accessible/tests/mochitest/events/test_name.xul b/accessible/tests/mochitest/events/test_name.xul new file mode 100644 index 0000000000000000000000000000000000000000..9d688585c7659d021af81098b5ca4d7f6abcf69a --- /dev/null +++ b/accessible/tests/mochitest/events/test_name.xul @@ -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> diff --git a/configure.in b/configure.in index 32ca632210eae2b16cfa46ed71df85e264865ef2..8f9d85cd6537a9266e595b56bfda5cbdb6f684d6 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/content/canvas/src/DocumentRendererChild.cpp b/content/canvas/src/DocumentRendererChild.cpp index 3187a179e9a191c1fb18206dc14c7b968c3f39f4..d81d00d052d1ec0e8481bcf267c9894897783ab1 100644 --- a/content/canvas/src/DocumentRendererChild.cpp +++ b/content/canvas/src/DocumentRendererChild.cpp @@ -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(); diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 81e2ac6921d6b4f3701fc41d78342f1dd42cde6c..b6177a428e9d118015ad553b32ca541ea4a5b941 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -816,7 +816,6 @@ protected: WebGLVertexAttrib0Status WhatDoesVertexAttrib0Need(); bool DoFakeVertexAttrib0(GLuint vertexCount); void UndoFakeVertexAttrib0(); - void InvalidateFakeVertexAttrib0(); static CheckedUint32 GetImageSize(GLsizei height, GLsizei width, diff --git a/content/canvas/src/WebGLContextAsyncQueries.cpp b/content/canvas/src/WebGLContextAsyncQueries.cpp index e87b5c0f5d80e5499939beef6a54d73cf2ecd981..7c767d640fad8db835a985fe67166bbb82e5de76 100644 --- a/content/canvas/src/WebGLContextAsyncQueries.cpp +++ b/content/canvas/src/WebGLContextAsyncQueries.cpp @@ -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 diff --git a/content/canvas/src/WebGLContextDraw.cpp b/content/canvas/src/WebGLContextDraw.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9611575ae326cab6325a143f8894a3615b7b835 --- /dev/null +++ b/content/canvas/src/WebGLContextDraw.cpp @@ -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); + } +} diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 2c3a47f8eb4ba09550e4cbe867e69d89ad60f31c..6ed3790fdd4dbf0bfde03cceb33434ca1d0385bb 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -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; diff --git a/content/canvas/src/WebGLContextValidate.cpp b/content/canvas/src/WebGLContextValidate.cpp index b1c24df0dc8d8a51fa5de35c8b57d5cb4d970e8b..4f35dd13c23e56aba478011c5e8d276181e2928a 100644 --- a/content/canvas/src/WebGLContextValidate.cpp +++ b/content/canvas/src/WebGLContextValidate.cpp @@ -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); diff --git a/content/canvas/src/WebGLContextVertices.cpp b/content/canvas/src/WebGLContextVertices.cpp index e7786c0966f4dab81704f038c1cb37f52be4dfdc..c6afab4a64f143e6e943f07ac47c2568d3942e76 100644 --- a/content/canvas/src/WebGLContextVertices.cpp +++ b/content/canvas/src/WebGLContextVertices.cpp @@ -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; -} - diff --git a/content/canvas/src/WebGLFramebuffer.cpp b/content/canvas/src/WebGLFramebuffer.cpp index a9e55f238e6dbb63973a874a0355d0020cdd22d1..401f10f07bb21364ca2a13517b282d44e6f28efa 100644 --- a/content/canvas/src/WebGLFramebuffer.cpp +++ b/content/canvas/src/WebGLFramebuffer.cpp @@ -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)) { diff --git a/content/canvas/src/WebGLRenderbuffer.cpp b/content/canvas/src/WebGLRenderbuffer.cpp index 793ba63ad9956e97bad1ad99e390ec26d4bba4bf..5910f08e0fdeb0d77eb16b9f9e3cd675a248c538 100644 --- a/content/canvas/src/WebGLRenderbuffer.cpp +++ b/content/canvas/src/WebGLRenderbuffer.cpp @@ -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; diff --git a/content/canvas/src/WebGLTexture.cpp b/content/canvas/src/WebGLTexture.cpp index 1974fc48352a71de8bc225d47b9e9e1aadf792f4..c4c68baff308a8e7de72b903d34135fca2f2c03a 100644 --- a/content/canvas/src/WebGLTexture.cpp +++ b/content/canvas/src/WebGLTexture.cpp @@ -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); } diff --git a/content/canvas/src/moz.build b/content/canvas/src/moz.build index d103574501b42ad3dbff9d6c564269b9c8bcfd88..8479d6f69f6205997fa4f29af857e2c9cb092940 100644 --- a/content/canvas/src/moz.build +++ b/content/canvas/src/moz.build @@ -32,6 +32,7 @@ if CONFIG['MOZ_WEBGL']: 'WebGLContext.cpp', 'WebGLContextAsyncQueries.cpp', 'WebGLContextBuffers.cpp', + 'WebGLContextDraw.cpp', 'WebGLContextExtensions.cpp', 'WebGLContextFramebufferOperations.cpp', 'WebGLContextGL.cpp', diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index a948b7e3840817b018a2bf1d85fc23235b09148d..29a8a43e3a15ce6ee2893ef684c791debb5150f1 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -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); } diff --git a/dom/contacts/tests/test_migration_chrome.js b/dom/contacts/tests/test_migration_chrome.js index 118f266e95ba3589642100d1f94aa1318b55e8e1..90b0d922ec1414d1cbb544b4daf3e7783258ceb8 100644 --- a/dom/contacts/tests/test_migration_chrome.js +++ b/dom/contacts/tests/test_migration_chrome.js @@ -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) { diff --git a/dom/plugins/base/nsPluginTags.cpp b/dom/plugins/base/nsPluginTags.cpp index e8c39857b54fbf3bd2d14689e582e2bee8744715..71e549c19686388be16a864d13df3de549721a1b 100644 --- a/dom/plugins/base/nsPluginTags.cpp +++ b/dom/plugins/base/nsPluginTags.cpp @@ -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; diff --git a/dom/plugins/test/mochitest/mochitest.ini b/dom/plugins/test/mochitest/mochitest.ini index c620694236f662f52da6d8ec02ec30584b8cf2d3..a96f663cf20ab029d8584182d46ac9b28bc39b74 100644 --- a/dom/plugins/test/mochitest/mochitest.ini +++ b/dom/plugins/test/mochitest/mochitest.ini @@ -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 diff --git a/dom/plugins/test/mochitest/test_bug986930.html b/dom/plugins/test/mochitest/test_bug986930.html new file mode 100644 index 0000000000000000000000000000000000000000..620f93913fc50a6cfb57549dbc41cb0d6b777e06 --- /dev/null +++ b/dom/plugins/test/mochitest/test_bug986930.html @@ -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> diff --git a/dom/plugins/test/testplugin/Info.plist b/dom/plugins/test/testplugin/Info.plist index e592c2c2d1edcc7570da693231c9caa12485445f..dc6aa5cec3942711923f26122d6a099c63e51471 100644 --- a/dom/plugins/test/testplugin/Info.plist +++ b/dom/plugins/test/testplugin/Info.plist @@ -31,7 +31,7 @@ <string>tst</string> </array> <key>WebPluginTypeDescription</key> - <string>Test mimetype</string> + <string>Test â„¢ mimetype</string> </dict> </dict> </dict> diff --git a/dom/plugins/test/testplugin/nptest.rc b/dom/plugins/test/testplugin/nptest.rc index a7676f83eb3d181dd942e8e758306f8173cc6021..948fb846ef5268315a18f25258a0605d458a1c5b 100644 --- a/dom/plugins/test/testplugin/nptest.rc +++ b/dom/plugins/test/testplugin/nptest.rc @@ -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" diff --git a/dom/plugins/test/testplugin/nptest_name.cpp b/dom/plugins/test/testplugin/nptest_name.cpp index 3b152c703ffd07e8fb857dc63e2d207f2aadaa95..f9b57dfa8f22330944e77da5f29438fbb73295ae 100644 --- a/dom/plugins/test/testplugin/nptest_name.cpp +++ b/dom/plugins/test/testplugin/nptest_name.cpp @@ -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"; diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index a93225c44c4103ddce8ba9b8f62c60ae785afbb5..ca486a5e02ddd596a7ab2dd5076cd7760916d523 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -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; diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 7d4c6e0d7970821508b4b704936a21dcda46143e..8b96cbb3ff3ce8f53ddff2230b31697589e28c8f 100644 --- a/gfx/2d/2D.h +++ b/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 diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in index 847f96bffafe57c69604c933db60359a7203f5a0..7ef26dc555e116ba9f7ede55ce26fa1ca1093e85 100644 --- a/gfx/angle/Makefile.in +++ b/gfx/angle/Makefile.in @@ -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 diff --git a/gfx/angle/src/libGLESv2/Makefile.in b/gfx/angle/src/libGLESv2/Makefile.in index 6dc82efa58c26b262a94e4e073065310cb86514f..27a47d5cca740c677fb81b153073c5bcacd2a72d 100644 --- a/gfx/angle/src/libGLESv2/Makefile.in +++ b/gfx/angle/src/libGLESv2/Makefile.in @@ -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) diff --git a/gfx/gl/DecomposeIntoNoRepeatTriangles.h b/gfx/gl/DecomposeIntoNoRepeatTriangles.h index 5730d249b1b22c65e8e947c7e925e1a7f30c3c5d..d65e9737bc0638b708c1ec78d02c850149186e79 100644 --- a/gfx/gl/DecomposeIntoNoRepeatTriangles.h +++ b/gfx/gl/DecomposeIntoNoRepeatTriangles.h @@ -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; diff --git a/gfx/gl/GLBlitTextureImageHelper.cpp b/gfx/gl/GLBlitTextureImageHelper.cpp index a647ef1f408d4e743652cefb3fca66cf3f861832..340a4b1b0aae6dc46098a511ce9f1b41468e0d3d 100644 --- a/gfx/gl/GLBlitTextureImageHelper.cpp +++ b/gfx/gl/GLBlitTextureImageHelper.cpp @@ -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); diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 47b6aa7595f8325271a8ba850495da593da542ff..415d6258e2f92f617a3f58a29611801f1ee15453 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -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) { diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 32a291b8d33162286e5b424decc091cec6c9fe96..7b9e001cb930500e1a39aef9eee33c71821c9408 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -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 { diff --git a/gfx/gl/GLDrawRectHelper.cpp b/gfx/gl/GLDrawRectHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d77eb981cb90b1ee4d02d04fdeb25554a23fff77 --- /dev/null +++ b/gfx/gl/GLDrawRectHelper.cpp @@ -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); +} + +} +} diff --git a/gfx/gl/GLDrawRectHelper.h b/gfx/gl/GLDrawRectHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..7694a7f7e4617b8c5cbc99557f7df9185fa0f8be --- /dev/null +++ b/gfx/gl/GLDrawRectHelper.h @@ -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_ diff --git a/gfx/gl/GLReadTexImageHelper.cpp b/gfx/gl/GLReadTexImageHelper.cpp index 778a441411e307d14790871eeb2d3dbbf47a54df..85b3c045a6adf2b73bff7300ffab3ebfc1af7216 100644 --- a/gfx/gl/GLReadTexImageHelper.cpp +++ b/gfx/gl/GLReadTexImageHelper.cpp @@ -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); diff --git a/gfx/gl/GLUploadHelpers.cpp b/gfx/gl/GLUploadHelpers.cpp index 3b3498885c67cfde19adab4b642eb3cd23de7d87..fc36719b9f250992a839e3e377a4291a49013ab1 100644 --- a/gfx/gl/GLUploadHelpers.cpp +++ b/gfx/gl/GLUploadHelpers.cpp @@ -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"); diff --git a/gfx/gl/SkiaGLGlue.cpp b/gfx/gl/SkiaGLGlue.cpp index c1ad6f700598a470777abd5f5236cfa090e8c732..83b346c34a79435e20a721c101952fd32665a440 100755 --- a/gfx/gl/SkiaGLGlue.cpp +++ b/gfx/gl/SkiaGLGlue.cpp @@ -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; diff --git a/gfx/gl/moz.build b/gfx/gl/moz.build index 04762ecb542784e33160d42c6b671e1d4fb79204..a375eec02f4b06b3c42d00239637512249a220b6 100644 --- a/gfx/gl/moz.build +++ b/gfx/gl/moz.build @@ -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', diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index dddc829dd4c044a46971fecf7e8fdabed1742638..746efb860f2d55a23d8b3a5261c40268096ad9e7 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.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(); -} - } } diff --git a/gfx/layers/client/CanvasClient.h b/gfx/layers/client/CanvasClient.h index de6c983e9613cafaa33588e60f52a882037c2c3c..e4b2daf36646d9d204efaa06abbe7447b56f12cb 100644 --- a/gfx/layers/client/CanvasClient.h +++ b/gfx/layers/client/CanvasClient.h @@ -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; -}; - } } diff --git a/gfx/layers/client/ClientTiledThebesLayer.cpp b/gfx/layers/client/ClientTiledThebesLayer.cpp index d46dc0be1432ad332aba90336edc9d63e5e0ad76..2c0fddadfc106c3b664b0929e5212ea255abc4bd 100644 --- a/gfx/layers/client/ClientTiledThebesLayer.cpp +++ b/gfx/layers/client/ClientTiledThebesLayer.cpp @@ -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"); diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 369a6970fe2010c93f9a45372ec8bda747693d7f..0e97c6329822376ec8346c629b94970793fda346 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -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); diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 91a94ca4ab6ff145416946f3383cd82bd4f624df..1035ce1590e3d2aa2513408e34b2e0e11ad551b6 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -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); diff --git a/gfx/layers/composite/ThebesLayerComposite.cpp b/gfx/layers/composite/ThebesLayerComposite.cpp index 7db09829d9efe05c1a3edb2f59ba9c5629e8f39b..40b6102a9e0511546363779e1dee9360f24cfeb0 100644 --- a/gfx/layers/composite/ThebesLayerComposite.cpp +++ b/gfx/layers/composite/ThebesLayerComposite.cpp @@ -132,6 +132,7 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect) EffectChain effectChain(this); LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain); + nsIntRegion visibleRegion = GetEffectiveVisibleRegion(); TiledLayerProperties tiledLayerProps; diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index b5b01d1c7df47defa8ae41d13e8cacb87c68f90b..801cee6827863cac1637b6816294bd81e3f9f736 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -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()) { diff --git a/gfx/layers/d3d9/TextureD3D9.cpp b/gfx/layers/d3d9/TextureD3D9.cpp index 61d44133645b30e00d35727039faac1ca09655e7..e8016e75b32f431f3bbfab7b5be78f85acdea6f0 100644 --- a/gfx/layers/d3d9/TextureD3D9.cpp +++ b/gfx/layers/d3d9/TextureD3D9.cpp @@ -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."); diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index 26eeab9b20cf448e6a89464f0560851d1e3b51de..4f1364307cc92886ca724089afc104c3c8d6f836 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -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()); } } diff --git a/gfx/layers/ipc/Axis.cpp b/gfx/layers/ipc/Axis.cpp index 875566877e6352cc2eda77dfa216c940c18ce0b5..00e22093c2857bf4846ea88bc22777a71b3327b7 100644 --- a/gfx/layers/ipc/Axis.cpp +++ b/gfx/layers/ipc/Axis.cpp @@ -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), diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index 6d29d20ca6e60cbaa0551c091997e8477b0aa9b6..cc7600a985ef25f1f6870f530094854d1bf61d4d 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -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) { diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index b9302496435d7b5ca0c975f6223adfa8fbd789b8..b843cf241556ec9476463907a01e5e6341410160 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -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 diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h index 2b166a08f17ae011fb75a0f924a6550a5f218e29..33d036cccb00c82a18fad602a0d732dc8fc13840 100644 --- a/gfx/layers/opengl/CompositorOGL.h +++ b/gfx/layers/opengl/CompositorOGL.h @@ -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, diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp index 5df9de84f776aceea7bf763c1fca4bbc49842a84..a54ae57123af3ca5ab012fc1e2bcea63468a5061 100644 --- a/gfx/src/nsFontMetrics.cpp +++ b/gfx/src/nsFontMetrics.cpp @@ -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"); diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index 933df231e4f770a284f22aa8672186fe76efb98b..357f84d730a71b914714df98e21b607281f5f96e 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -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); diff --git a/gfx/thebes/CJKCompatSVS.cpp b/gfx/thebes/CJKCompatSVS.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e68d98e92d1dbb48338e324cb2c1b322fbba031e --- /dev/null +++ b/gfx/thebes/CJKCompatSVS.cpp @@ -0,0 +1,1039 @@ +// Generated by gencjkcisvs.py. 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 StandardizedVariants-6.3.0.txt. +// 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[] = { + U16(14), // format + U32(5065), // length + U32(3), // numVarSelectorRecords + U24(0xFE00), U32(0), U32(43), // varSelectorRecord[0] + U24(0xFE01), U32(0), U32(4557), // varSelectorRecord[1] + U24(0xFE02), U32(0), U32(5001), // varSelectorRecord[2] + // 0xFE00 + U32(902), // numUVSMappings + U24(0x349E), GLYPH(0x2F80C), + U24(0x34B9), GLYPH(0x2F813), + U24(0x34BB), GLYPH(0x2F9CA), + U24(0x34DF), GLYPH(0x2F81F), + U24(0x3515), GLYPH(0x2F824), + U24(0x36EE), GLYPH(0x2F867), + U24(0x36FC), GLYPH(0x2F868), + U24(0x3781), GLYPH(0x2F876), + U24(0x382F), GLYPH(0x2F883), + U24(0x3862), GLYPH(0x2F888), + U24(0x387C), GLYPH(0x2F88A), + U24(0x38C7), GLYPH(0x2F896), + U24(0x38E3), GLYPH(0x2F89B), + U24(0x391C), GLYPH(0x2F8A2), + U24(0x393A), GLYPH(0x2F8A1), + U24(0x3A2E), GLYPH(0x2F8C2), + U24(0x3A6C), GLYPH(0x2F8C7), + U24(0x3AE4), GLYPH(0x2F8D1), + U24(0x3B08), GLYPH(0x2F8D0), + U24(0x3B19), GLYPH(0x2F8CE), + U24(0x3B49), GLYPH(0x2F8DE), + U24(0x3B9D), GLYPH(0xFAD2), + U24(0x3C18), GLYPH(0x2F8EE), + U24(0x3C4E), GLYPH(0x2F8F2), + U24(0x3D33), GLYPH(0x2F90A), + U24(0x3D96), GLYPH(0x2F916), + U24(0x3EAC), GLYPH(0x2F92A), + U24(0x3EB8), GLYPH(0x2F92C), + U24(0x3F1B), GLYPH(0x2F933), + U24(0x3FFC), GLYPH(0x2F93E), + U24(0x4008), GLYPH(0x2F93F), + U24(0x4018), GLYPH(0xFAD3), + U24(0x4039), GLYPH(0xFAD4), + U24(0x4046), GLYPH(0x2F94B), + U24(0x4096), GLYPH(0x2F94C), + U24(0x40E3), GLYPH(0x2F951), + U24(0x412F), GLYPH(0x2F958), + U24(0x4202), GLYPH(0x2F960), + U24(0x4227), GLYPH(0x2F964), + U24(0x42A0), GLYPH(0x2F967), + U24(0x4301), GLYPH(0x2F96D), + U24(0x4334), GLYPH(0x2F971), + U24(0x4359), GLYPH(0x2F974), + U24(0x43D5), GLYPH(0x2F981), + U24(0x43D9), GLYPH(0x2F8D7), + U24(0x440B), GLYPH(0x2F984), + U24(0x446B), GLYPH(0x2F98E), + U24(0x452B), GLYPH(0x2F9A7), + U24(0x455D), GLYPH(0x2F9AE), + U24(0x4561), GLYPH(0x2F9AF), + U24(0x456B), GLYPH(0x2F9B2), + U24(0x45D7), GLYPH(0x2F9BF), + U24(0x45F9), GLYPH(0x2F9C2), + U24(0x4635), GLYPH(0x2F9C8), + U24(0x46BE), GLYPH(0x2F9CD), + U24(0x46C7), GLYPH(0x2F9CE), + U24(0x4995), GLYPH(0x2F9EF), + U24(0x49E6), GLYPH(0x2F9F2), + U24(0x4A6E), GLYPH(0x2F9F8), + U24(0x4A76), GLYPH(0x2F9F9), + U24(0x4AB2), GLYPH(0x2F9FC), + U24(0x4B33), GLYPH(0x2FA03), + U24(0x4BCE), GLYPH(0x2FA08), + U24(0x4CCE), GLYPH(0x2FA0D), + U24(0x4CED), GLYPH(0x2FA0E), + U24(0x4CF8), GLYPH(0x2FA11), + U24(0x4D56), GLYPH(0x2FA16), + U24(0x4E0D), GLYPH(0xF967), + U24(0x4E26), GLYPH(0xFA70), + U24(0x4E32), GLYPH(0xF905), + U24(0x4E38), GLYPH(0x2F801), + U24(0x4E39), GLYPH(0xF95E), + U24(0x4E3D), GLYPH(0x2F800), + U24(0x4E41), GLYPH(0x2F802), + U24(0x4E82), GLYPH(0xF91B), + U24(0x4E86), GLYPH(0xF9BA), + U24(0x4EAE), GLYPH(0xF977), + U24(0x4EC0), GLYPH(0xF9FD), + U24(0x4ECC), GLYPH(0x2F819), + U24(0x4EE4), GLYPH(0xF9A8), + U24(0x4F60), GLYPH(0x2F804), + U24(0x4F80), GLYPH(0xFA73), + U24(0x4F86), GLYPH(0xF92D), + U24(0x4F8B), GLYPH(0xF9B5), + U24(0x4FAE), GLYPH(0xFA30), + U24(0x4FBB), GLYPH(0x2F806), + U24(0x4FBF), GLYPH(0xF965), + U24(0x5002), GLYPH(0x2F807), + U24(0x502B), GLYPH(0xF9D4), + U24(0x507A), GLYPH(0x2F808), + U24(0x5099), GLYPH(0x2F809), + U24(0x50CF), GLYPH(0x2F80B), + U24(0x50DA), GLYPH(0xF9BB), + U24(0x50E7), GLYPH(0xFA31), + U24(0x5140), GLYPH(0xFA0C), + U24(0x5145), GLYPH(0xFA74), + U24(0x514D), GLYPH(0xFA32), + U24(0x5154), GLYPH(0x2F80F), + U24(0x5164), GLYPH(0x2F810), + U24(0x5167), GLYPH(0x2F814), + U24(0x5168), GLYPH(0xFA72), + U24(0x5169), GLYPH(0xF978), + U24(0x516D), GLYPH(0xF9D1), + U24(0x5177), GLYPH(0x2F811), + U24(0x5180), GLYPH(0xFA75), + U24(0x518D), GLYPH(0x2F815), + U24(0x5192), GLYPH(0x2F8D2), + U24(0x5195), GLYPH(0x2F8D3), + U24(0x5197), GLYPH(0x2F817), + U24(0x51A4), GLYPH(0x2F818), + U24(0x51AC), GLYPH(0x2F81A), + U24(0x51B5), GLYPH(0xFA71), + U24(0x51B7), GLYPH(0xF92E), + U24(0x51C9), GLYPH(0xF979), + U24(0x51CC), GLYPH(0xF955), + U24(0x51DC), GLYPH(0xF954), + U24(0x51DE), GLYPH(0xFA15), + U24(0x51F5), GLYPH(0x2F81D), + U24(0x5203), GLYPH(0x2F81E), + U24(0x5207), GLYPH(0xFA00), + U24(0x5217), GLYPH(0xF99C), + U24(0x5229), GLYPH(0xF9DD), + U24(0x523A), GLYPH(0xF9FF), + U24(0x523B), GLYPH(0x2F820), + U24(0x5246), GLYPH(0x2F821), + U24(0x5272), GLYPH(0x2F822), + U24(0x5277), GLYPH(0x2F823), + U24(0x5289), GLYPH(0xF9C7), + U24(0x529B), GLYPH(0xF98A), + U24(0x52A3), GLYPH(0xF99D), + U24(0x52B3), GLYPH(0x2F992), + U24(0x52C7), GLYPH(0xFA76), + U24(0x52C9), GLYPH(0xFA33), + U24(0x52D2), GLYPH(0xF952), + U24(0x52DE), GLYPH(0xF92F), + U24(0x52E4), GLYPH(0xFA34), + U24(0x52F5), GLYPH(0xF97F), + U24(0x52FA), GLYPH(0xFA77), + U24(0x5305), GLYPH(0x2F829), + U24(0x5306), GLYPH(0x2F82A), + U24(0x5317), GLYPH(0xF963), + U24(0x533F), GLYPH(0xF9EB), + U24(0x5349), GLYPH(0x2F82C), + U24(0x5351), GLYPH(0xFA35), + U24(0x535A), GLYPH(0x2F82E), + U24(0x5373), GLYPH(0x2F82F), + U24(0x5375), GLYPH(0xF91C), + U24(0x537D), GLYPH(0x2F830), + U24(0x537F), GLYPH(0x2F831), + U24(0x53C3), GLYPH(0xF96B), + U24(0x53CA), GLYPH(0x2F836), + U24(0x53DF), GLYPH(0x2F837), + U24(0x53E5), GLYPH(0xF906), + U24(0x53EB), GLYPH(0x2F839), + U24(0x53F1), GLYPH(0x2F83A), + U24(0x5406), GLYPH(0x2F83B), + U24(0x540F), GLYPH(0xF9DE), + U24(0x541D), GLYPH(0xF9ED), + U24(0x5438), GLYPH(0x2F83D), + U24(0x5442), GLYPH(0xF980), + U24(0x5448), GLYPH(0x2F83E), + U24(0x5468), GLYPH(0x2F83F), + U24(0x549E), GLYPH(0x2F83C), + U24(0x54A2), GLYPH(0x2F840), + U24(0x54BD), GLYPH(0xF99E), + U24(0x54F6), GLYPH(0x2F841), + U24(0x5510), GLYPH(0x2F842), + U24(0x5553), GLYPH(0x2F843), + U24(0x5555), GLYPH(0xFA79), + U24(0x5563), GLYPH(0x2F844), + U24(0x5584), GLYPH(0x2F845), + U24(0x5587), GLYPH(0xF90B), + U24(0x5599), GLYPH(0xFA7A), + U24(0x559D), GLYPH(0xFA36), + U24(0x55AB), GLYPH(0x2F848), + U24(0x55B3), GLYPH(0x2F849), + U24(0x55C0), GLYPH(0xFA0D), + U24(0x55C2), GLYPH(0x2F84A), + U24(0x55E2), GLYPH(0xFA7B), + U24(0x5606), GLYPH(0xFA37), + U24(0x5651), GLYPH(0x2F84E), + U24(0x5668), GLYPH(0xFA38), + U24(0x5674), GLYPH(0x2F84F), + U24(0x56F9), GLYPH(0xF9A9), + U24(0x5716), GLYPH(0x2F84B), + U24(0x5717), GLYPH(0x2F84D), + U24(0x578B), GLYPH(0x2F855), + U24(0x57CE), GLYPH(0x2F852), + U24(0x57F4), GLYPH(0x2F853), + U24(0x580D), GLYPH(0x2F854), + U24(0x5831), GLYPH(0x2F857), + U24(0x5832), GLYPH(0x2F856), + U24(0x5840), GLYPH(0xFA39), + U24(0x585A), GLYPH(0xFA10), + U24(0x585E), GLYPH(0xF96C), + U24(0x58A8), GLYPH(0xFA3A), + U24(0x58AC), GLYPH(0x2F858), + U24(0x58B3), GLYPH(0xFA7D), + U24(0x58D8), GLYPH(0xF94A), + U24(0x58DF), GLYPH(0xF942), + U24(0x58EE), GLYPH(0x2F851), + U24(0x58F2), GLYPH(0x2F85A), + U24(0x58F7), GLYPH(0x2F85B), + U24(0x5906), GLYPH(0x2F85C), + U24(0x591A), GLYPH(0x2F85D), + U24(0x5922), GLYPH(0x2F85E), + U24(0x5944), GLYPH(0xFA7E), + U24(0x5948), GLYPH(0xF90C), + U24(0x5951), GLYPH(0xF909), + U24(0x5954), GLYPH(0xFA7F), + U24(0x5962), GLYPH(0x2F85F), + U24(0x5973), GLYPH(0xF981), + U24(0x59D8), GLYPH(0x2F865), + U24(0x59EC), GLYPH(0x2F862), + U24(0x5A1B), GLYPH(0x2F863), + U24(0x5A27), GLYPH(0x2F864), + U24(0x5A62), GLYPH(0xFA80), + U24(0x5A66), GLYPH(0x2F866), + U24(0x5AB5), GLYPH(0x2F986), + U24(0x5B08), GLYPH(0x2F869), + U24(0x5B28), GLYPH(0xFA81), + U24(0x5B3E), GLYPH(0x2F86A), + U24(0x5B85), GLYPH(0xFA04), + U24(0x5BC3), GLYPH(0x2F86D), + U24(0x5BD8), GLYPH(0x2F86E), + U24(0x5BE7), GLYPH(0xF95F), + U24(0x5BEE), GLYPH(0xF9BC), + U24(0x5BF3), GLYPH(0x2F870), + U24(0x5BFF), GLYPH(0x2F872), + U24(0x5C06), GLYPH(0x2F873), + U24(0x5C22), GLYPH(0x2F875), + U24(0x5C3F), GLYPH(0xF9BD), + U24(0x5C60), GLYPH(0x2F877), + U24(0x5C62), GLYPH(0xF94B), + U24(0x5C64), GLYPH(0xFA3B), + U24(0x5C65), GLYPH(0xF9DF), + U24(0x5C6E), GLYPH(0xFA3C), + U24(0x5C8D), GLYPH(0x2F87A), + U24(0x5CC0), GLYPH(0x2F879), + U24(0x5D19), GLYPH(0xF9D5), + U24(0x5D43), GLYPH(0x2F87C), + U24(0x5D50), GLYPH(0xF921), + U24(0x5D6B), GLYPH(0x2F87F), + U24(0x5D6E), GLYPH(0x2F87E), + U24(0x5D7C), GLYPH(0x2F880), + U24(0x5DB2), GLYPH(0x2F9F4), + U24(0x5DBA), GLYPH(0xF9AB), + U24(0x5DE1), GLYPH(0x2F881), + U24(0x5DE2), GLYPH(0x2F882), + U24(0x5DFD), GLYPH(0x2F884), + U24(0x5E28), GLYPH(0x2F885), + U24(0x5E3D), GLYPH(0x2F886), + U24(0x5E69), GLYPH(0x2F887), + U24(0x5E74), GLYPH(0xF98E), + U24(0x5EA6), GLYPH(0xFA01), + U24(0x5EB0), GLYPH(0x2F88B), + U24(0x5EB3), GLYPH(0x2F88C), + U24(0x5EB6), GLYPH(0x2F88D), + U24(0x5EC9), GLYPH(0xF9A2), + U24(0x5ECA), GLYPH(0xF928), + U24(0x5ED2), GLYPH(0xFA82), + U24(0x5ED3), GLYPH(0xFA0B), + U24(0x5ED9), GLYPH(0xFA83), + U24(0x5EEC), GLYPH(0xF982), + U24(0x5EFE), GLYPH(0x2F890), + U24(0x5F04), GLYPH(0xF943), + U24(0x5F22), GLYPH(0x2F894), + U24(0x5F53), GLYPH(0x2F874), + U24(0x5F62), GLYPH(0x2F899), + U24(0x5F69), GLYPH(0xFA84), + U24(0x5F6B), GLYPH(0x2F89A), + U24(0x5F8B), GLYPH(0xF9D8), + U24(0x5F9A), GLYPH(0x2F89C), + U24(0x5FA9), GLYPH(0xF966), + U24(0x5FAD), GLYPH(0xFA85), + U24(0x5FCD), GLYPH(0x2F89D), + U24(0x5FD7), GLYPH(0x2F89E), + U24(0x5FF5), GLYPH(0xF9A3), + U24(0x5FF9), GLYPH(0x2F89F), + U24(0x6012), GLYPH(0xF960), + U24(0x601C), GLYPH(0xF9AC), + U24(0x6075), GLYPH(0xFA6B), + U24(0x6081), GLYPH(0x2F8A0), + U24(0x6094), GLYPH(0xFA3D), + U24(0x60C7), GLYPH(0x2F8A5), + U24(0x60D8), GLYPH(0xFA86), + U24(0x60E1), GLYPH(0xF9B9), + U24(0x6108), GLYPH(0xFA88), + U24(0x6144), GLYPH(0xF9D9), + U24(0x6148), GLYPH(0x2F8A6), + U24(0x614C), GLYPH(0x2F8A7), + U24(0x614E), GLYPH(0xFA87), + U24(0x6160), GLYPH(0xFA8A), + U24(0x6168), GLYPH(0xFA3E), + U24(0x617A), GLYPH(0x2F8AA), + U24(0x618E), GLYPH(0xFA3F), + U24(0x6190), GLYPH(0xF98F), + U24(0x61A4), GLYPH(0x2F8AD), + U24(0x61AF), GLYPH(0x2F8AE), + U24(0x61B2), GLYPH(0x2F8AC), + U24(0x61DE), GLYPH(0x2F8AF), + U24(0x61F2), GLYPH(0xFA40), + U24(0x61F6), GLYPH(0xF90D), + U24(0x6200), GLYPH(0xF990), + U24(0x6210), GLYPH(0x2F8B2), + U24(0x621B), GLYPH(0x2F8B3), + U24(0x622E), GLYPH(0xF9D2), + U24(0x6234), GLYPH(0xFA8C), + U24(0x625D), GLYPH(0x2F8B4), + U24(0x62B1), GLYPH(0x2F8B5), + U24(0x62C9), GLYPH(0xF925), + U24(0x62CF), GLYPH(0xF95B), + U24(0x62D3), GLYPH(0xFA02), + U24(0x62D4), GLYPH(0x2F8B6), + U24(0x62FC), GLYPH(0x2F8BA), + U24(0x62FE), GLYPH(0xF973), + U24(0x633D), GLYPH(0x2F8B9), + U24(0x6350), GLYPH(0x2F8B7), + U24(0x6368), GLYPH(0x2F8BB), + U24(0x637B), GLYPH(0xF9A4), + U24(0x6383), GLYPH(0x2F8BC), + U24(0x63A0), GLYPH(0xF975), + U24(0x63A9), GLYPH(0x2F8C1), + U24(0x63C4), GLYPH(0xFA8D), + U24(0x63C5), GLYPH(0x2F8C0), + U24(0x63E4), GLYPH(0x2F8BD), + U24(0x641C), GLYPH(0xFA8E), + U24(0x6422), GLYPH(0x2F8BF), + U24(0x6452), GLYPH(0xFA8F), + U24(0x6469), GLYPH(0x2F8C3), + U24(0x6477), GLYPH(0x2F8C6), + U24(0x647E), GLYPH(0x2F8C4), + U24(0x649A), GLYPH(0xF991), + U24(0x649D), GLYPH(0x2F8C5), + U24(0x64C4), GLYPH(0xF930), + U24(0x654F), GLYPH(0xFA41), + U24(0x6556), GLYPH(0xFA90), + U24(0x656C), GLYPH(0x2F8C9), + U24(0x6578), GLYPH(0xF969), + U24(0x6599), GLYPH(0xF9BE), + U24(0x65C5), GLYPH(0xF983), + U24(0x65E2), GLYPH(0xFA42), + U24(0x65E3), GLYPH(0x2F8CB), + U24(0x6613), GLYPH(0xF9E0), + U24(0x6649), GLYPH(0x2F8CD), + U24(0x6674), GLYPH(0xFA12), + U24(0x6688), GLYPH(0xF9C5), + U24(0x6691), GLYPH(0xFA43), + U24(0x669C), GLYPH(0x2F8D5), + U24(0x66B4), GLYPH(0xFA06), + U24(0x66C6), GLYPH(0xF98B), + U24(0x66F4), GLYPH(0xF901), + U24(0x66F8), GLYPH(0x2F8CC), + U24(0x6700), GLYPH(0x2F8D4), + U24(0x6717), GLYPH(0xF929), + U24(0x671B), GLYPH(0xFA93), + U24(0x6721), GLYPH(0x2F8DA), + U24(0x674E), GLYPH(0xF9E1), + U24(0x6753), GLYPH(0x2F8DC), + U24(0x6756), GLYPH(0xFA94), + U24(0x675E), GLYPH(0x2F8DB), + U24(0x677B), GLYPH(0xF9C8), + U24(0x6785), GLYPH(0x2F8E0), + U24(0x6797), GLYPH(0xF9F4), + U24(0x67F3), GLYPH(0xF9C9), + U24(0x67FA), GLYPH(0x2F8DF), + U24(0x6817), GLYPH(0xF9DA), + U24(0x681F), GLYPH(0x2F8E5), + U24(0x6852), GLYPH(0x2F8E1), + U24(0x6881), GLYPH(0xF97A), + U24(0x6885), GLYPH(0xFA44), + U24(0x688E), GLYPH(0x2F8E4), + U24(0x68A8), GLYPH(0xF9E2), + U24(0x6914), GLYPH(0x2F8E6), + U24(0x6942), GLYPH(0x2F8E8), + U24(0x69A3), GLYPH(0x2F8E9), + U24(0x69EA), GLYPH(0x2F8EA), + U24(0x6A02), GLYPH(0xF914), + U24(0x6A13), GLYPH(0xF94C), + U24(0x6AA8), GLYPH(0x2F8EB), + U24(0x6AD3), GLYPH(0xF931), + U24(0x6ADB), GLYPH(0x2F8ED), + U24(0x6B04), GLYPH(0xF91D), + U24(0x6B21), GLYPH(0x2F8EF), + U24(0x6B54), GLYPH(0x2F8F1), + U24(0x6B72), GLYPH(0x2F8F3), + U24(0x6B77), GLYPH(0xF98C), + U24(0x6B79), GLYPH(0xFA95), + U24(0x6B9F), GLYPH(0x2F8F4), + U24(0x6BAE), GLYPH(0xF9A5), + U24(0x6BBA), GLYPH(0xF970), + U24(0x6BBB), GLYPH(0x2F8F6), + U24(0x6C4E), GLYPH(0x2F8FA), + U24(0x6C67), GLYPH(0x2F8FE), + U24(0x6C88), GLYPH(0xF972), + U24(0x6CBF), GLYPH(0x2F8FC), + U24(0x6CCC), GLYPH(0xF968), + U24(0x6CCD), GLYPH(0x2F8FD), + U24(0x6CE5), GLYPH(0xF9E3), + U24(0x6D16), GLYPH(0x2F8FF), + U24(0x6D1B), GLYPH(0xF915), + U24(0x6D1E), GLYPH(0xFA05), + U24(0x6D34), GLYPH(0x2F907), + U24(0x6D3E), GLYPH(0x2F900), + U24(0x6D41), GLYPH(0xF9CA), + U24(0x6D69), GLYPH(0x2F903), + U24(0x6D6A), GLYPH(0xF92A), + U24(0x6D77), GLYPH(0xFA45), + U24(0x6D78), GLYPH(0x2F904), + U24(0x6D85), GLYPH(0x2F905), + U24(0x6DCB), GLYPH(0xF9F5), + U24(0x6DDA), GLYPH(0xF94D), + U24(0x6DEA), GLYPH(0xF9D6), + U24(0x6DF9), GLYPH(0x2F90E), + U24(0x6E1A), GLYPH(0xFA46), + U24(0x6E2F), GLYPH(0x2F908), + U24(0x6E6E), GLYPH(0x2F909), + U24(0x6E9C), GLYPH(0xF9CB), + U24(0x6EBA), GLYPH(0xF9EC), + U24(0x6EC7), GLYPH(0x2F90C), + U24(0x6ECB), GLYPH(0xFA99), + U24(0x6ED1), GLYPH(0xF904), + U24(0x6EDB), GLYPH(0xFA98), + U24(0x6F0F), GLYPH(0xF94E), + U24(0x6F22), GLYPH(0xFA47), + U24(0x6F23), GLYPH(0xF992), + U24(0x6F6E), GLYPH(0x2F90F), + U24(0x6FC6), GLYPH(0x2F912), + U24(0x6FEB), GLYPH(0xF922), + U24(0x6FFE), GLYPH(0xF984), + U24(0x701B), GLYPH(0x2F915), + U24(0x701E), GLYPH(0xFA9B), + U24(0x7039), GLYPH(0x2F913), + U24(0x704A), GLYPH(0x2F917), + U24(0x7070), GLYPH(0x2F835), + U24(0x7077), GLYPH(0x2F919), + U24(0x707D), GLYPH(0x2F918), + U24(0x7099), GLYPH(0xF9FB), + U24(0x70AD), GLYPH(0x2F91A), + U24(0x70C8), GLYPH(0xF99F), + U24(0x70D9), GLYPH(0xF916), + U24(0x7145), GLYPH(0x2F91C), + U24(0x7149), GLYPH(0xF993), + U24(0x716E), GLYPH(0xFA48), + U24(0x719C), GLYPH(0x2F91E), + U24(0x71CE), GLYPH(0xF9C0), + U24(0x71D0), GLYPH(0xF9EE), + U24(0x7210), GLYPH(0xF932), + U24(0x721B), GLYPH(0xF91E), + U24(0x7228), GLYPH(0x2F920), + U24(0x722B), GLYPH(0xFA49), + U24(0x7235), GLYPH(0xFA9E), + U24(0x7250), GLYPH(0x2F922), + U24(0x7262), GLYPH(0xF946), + U24(0x7280), GLYPH(0x2F924), + U24(0x7295), GLYPH(0x2F925), + U24(0x72AF), GLYPH(0xFA9F), + U24(0x72C0), GLYPH(0xF9FA), + U24(0x72FC), GLYPH(0xF92B), + U24(0x732A), GLYPH(0xFA16), + U24(0x7375), GLYPH(0xF9A7), + U24(0x737A), GLYPH(0x2F928), + U24(0x7387), GLYPH(0xF961), + U24(0x738B), GLYPH(0x2F929), + U24(0x73A5), GLYPH(0x2F92B), + U24(0x73B2), GLYPH(0xF9AD), + U24(0x73DE), GLYPH(0xF917), + U24(0x7406), GLYPH(0xF9E4), + U24(0x7409), GLYPH(0xF9CC), + U24(0x7422), GLYPH(0xFA4A), + U24(0x7447), GLYPH(0x2F92E), + U24(0x745C), GLYPH(0x2F92F), + U24(0x7469), GLYPH(0xF9AE), + U24(0x7471), GLYPH(0xFAA1), + U24(0x7485), GLYPH(0x2F931), + U24(0x7489), GLYPH(0xF994), + U24(0x7498), GLYPH(0xF9EF), + U24(0x74CA), GLYPH(0x2F932), + U24(0x7506), GLYPH(0xFAA2), + U24(0x7524), GLYPH(0x2F934), + U24(0x753B), GLYPH(0xFAA3), + U24(0x753E), GLYPH(0x2F936), + U24(0x7559), GLYPH(0xF9CD), + U24(0x7565), GLYPH(0xF976), + U24(0x7570), GLYPH(0xF962), + U24(0x75E2), GLYPH(0xF9E5), + U24(0x7610), GLYPH(0x2F93A), + U24(0x761D), GLYPH(0xFAA4), + U24(0x761F), GLYPH(0xFAA5), + U24(0x7642), GLYPH(0xF9C1), + U24(0x7669), GLYPH(0xF90E), + U24(0x76CA), GLYPH(0xFA17), + U24(0x76DB), GLYPH(0xFAA7), + U24(0x76E7), GLYPH(0xF933), + U24(0x76F4), GLYPH(0xFAA8), + U24(0x7701), GLYPH(0xF96D), + U24(0x771E), GLYPH(0x2F945), + U24(0x771F), GLYPH(0x2F946), + U24(0x7740), GLYPH(0xFAAA), + U24(0x774A), GLYPH(0xFAA9), + U24(0x778B), GLYPH(0x2F94A), + U24(0x77A7), GLYPH(0xFA9D), + U24(0x784E), GLYPH(0x2F94E), + U24(0x786B), GLYPH(0xF9CE), + U24(0x788C), GLYPH(0xF93B), + U24(0x7891), GLYPH(0xFA4B), + U24(0x78CA), GLYPH(0xF947), + U24(0x78CC), GLYPH(0xFAAB), + U24(0x78FB), GLYPH(0xF964), + U24(0x792A), GLYPH(0xF985), + U24(0x793C), GLYPH(0xFA18), + U24(0x793E), GLYPH(0xFA4C), + U24(0x7948), GLYPH(0xFA4E), + U24(0x7949), GLYPH(0xFA4D), + U24(0x7950), GLYPH(0xFA4F), + U24(0x7956), GLYPH(0xFA50), + U24(0x795D), GLYPH(0xFA51), + U24(0x795E), GLYPH(0xFA19), + U24(0x7965), GLYPH(0xFA1A), + U24(0x797F), GLYPH(0xF93C), + U24(0x798D), GLYPH(0xFA52), + U24(0x798E), GLYPH(0xFA53), + U24(0x798F), GLYPH(0xFA1B), + U24(0x79AE), GLYPH(0xF9B6), + U24(0x79CA), GLYPH(0xF995), + U24(0x79EB), GLYPH(0x2F957), + U24(0x7A1C), GLYPH(0xF956), + U24(0x7A40), GLYPH(0xFA54), + U24(0x7A4A), GLYPH(0x2F95A), + U24(0x7A4F), GLYPH(0x2F95B), + U24(0x7A81), GLYPH(0xFA55), + U24(0x7AB1), GLYPH(0xFAAC), + U24(0x7ACB), GLYPH(0xF9F7), + U24(0x7AEE), GLYPH(0x2F95F), + U24(0x7B20), GLYPH(0xF9F8), + U24(0x7BC0), GLYPH(0xFA56), + U24(0x7BC6), GLYPH(0x2F962), + U24(0x7BC9), GLYPH(0x2F963), + U24(0x7C3E), GLYPH(0xF9A6), + U24(0x7C60), GLYPH(0xF944), + U24(0x7C7B), GLYPH(0xFAAE), + U24(0x7C92), GLYPH(0xF9F9), + U24(0x7CBE), GLYPH(0xFA1D), + U24(0x7CD2), GLYPH(0x2F966), + U24(0x7CD6), GLYPH(0xFA03), + U24(0x7CE3), GLYPH(0x2F969), + U24(0x7CE7), GLYPH(0xF97B), + U24(0x7CE8), GLYPH(0x2F968), + U24(0x7D00), GLYPH(0x2F96A), + U24(0x7D10), GLYPH(0xF9CF), + U24(0x7D22), GLYPH(0xF96A), + U24(0x7D2F), GLYPH(0xF94F), + U24(0x7D5B), GLYPH(0xFAAF), + U24(0x7D63), GLYPH(0x2F96C), + U24(0x7DA0), GLYPH(0xF93D), + U24(0x7DBE), GLYPH(0xF957), + U24(0x7DC7), GLYPH(0x2F96E), + U24(0x7DF4), GLYPH(0xF996), + U24(0x7E02), GLYPH(0x2F96F), + U24(0x7E09), GLYPH(0xFA58), + U24(0x7E37), GLYPH(0xF950), + U24(0x7E41), GLYPH(0xFA59), + U24(0x7E45), GLYPH(0x2F970), + U24(0x7F3E), GLYPH(0xFAB1), + U24(0x7F72), GLYPH(0xFA5A), + U24(0x7F79), GLYPH(0xF9E6), + U24(0x7F7A), GLYPH(0x2F976), + U24(0x7F85), GLYPH(0xF90F), + U24(0x7F95), GLYPH(0x2F978), + U24(0x7F9A), GLYPH(0xF9AF), + U24(0x7FBD), GLYPH(0xFA1E), + U24(0x7FFA), GLYPH(0x2F979), + U24(0x8001), GLYPH(0xF934), + U24(0x8005), GLYPH(0xFA5B), + U24(0x8046), GLYPH(0xF9B0), + U24(0x8060), GLYPH(0x2F97D), + U24(0x806F), GLYPH(0xF997), + U24(0x8070), GLYPH(0x2F97F), + U24(0x807E), GLYPH(0xF945), + U24(0x808B), GLYPH(0xF953), + U24(0x80AD), GLYPH(0x2F8D6), + U24(0x80B2), GLYPH(0x2F982), + U24(0x8103), GLYPH(0x2F983), + U24(0x813E), GLYPH(0x2F985), + U24(0x81D8), GLYPH(0xF926), + U24(0x81E8), GLYPH(0xF9F6), + U24(0x81ED), GLYPH(0xFA5C), + U24(0x8201), GLYPH(0x2F893), + U24(0x8204), GLYPH(0x2F98C), + U24(0x8218), GLYPH(0xFA6D), + U24(0x826F), GLYPH(0xF97C), + U24(0x8279), GLYPH(0xFA5D), + U24(0x828B), GLYPH(0x2F990), + U24(0x8291), GLYPH(0x2F98F), + U24(0x829D), GLYPH(0x2F991), + U24(0x82B1), GLYPH(0x2F993), + U24(0x82B3), GLYPH(0x2F994), + U24(0x82BD), GLYPH(0x2F995), + U24(0x82E5), GLYPH(0xF974), + U24(0x82E6), GLYPH(0x2F996), + U24(0x831D), GLYPH(0x2F999), + U24(0x8323), GLYPH(0x2F99C), + U24(0x8336), GLYPH(0xF9FE), + U24(0x8352), GLYPH(0xFAB3), + U24(0x8353), GLYPH(0x2F9A0), + U24(0x8363), GLYPH(0x2F99A), + U24(0x83AD), GLYPH(0x2F99B), + U24(0x83BD), GLYPH(0x2F99D), + U24(0x83C9), GLYPH(0xF93E), + U24(0x83CA), GLYPH(0x2F9A1), + U24(0x83CC), GLYPH(0x2F9A2), + U24(0x83DC), GLYPH(0x2F9A3), + U24(0x83E7), GLYPH(0x2F99E), + U24(0x83EF), GLYPH(0xFAB4), + U24(0x83F1), GLYPH(0xF958), + U24(0x843D), GLYPH(0xF918), + U24(0x8449), GLYPH(0xF96E), + U24(0x8457), GLYPH(0xFA5F), + U24(0x84EE), GLYPH(0xF999), + U24(0x84F1), GLYPH(0x2F9A8), + U24(0x84F3), GLYPH(0x2F9A9), + U24(0x84FC), GLYPH(0xF9C2), + U24(0x8516), GLYPH(0x2F9AA), + U24(0x8564), GLYPH(0x2F9AC), + U24(0x85CD), GLYPH(0xF923), + U24(0x85FA), GLYPH(0xF9F0), + U24(0x8606), GLYPH(0xF935), + U24(0x8612), GLYPH(0xFA20), + U24(0x862D), GLYPH(0xF91F), + U24(0x863F), GLYPH(0xF910), + U24(0x8650), GLYPH(0x2F9B3), + U24(0x865C), GLYPH(0xF936), + U24(0x8667), GLYPH(0x2F9B5), + U24(0x8669), GLYPH(0x2F9B6), + U24(0x8688), GLYPH(0x2F9B8), + U24(0x86A9), GLYPH(0x2F9B7), + U24(0x86E2), GLYPH(0x2F9BA), + U24(0x870E), GLYPH(0x2F9B9), + U24(0x8728), GLYPH(0x2F9BC), + U24(0x876B), GLYPH(0x2F9BD), + U24(0x8779), GLYPH(0xFAB5), + U24(0x8786), GLYPH(0x2F9BE), + U24(0x87BA), GLYPH(0xF911), + U24(0x87E1), GLYPH(0x2F9C0), + U24(0x8801), GLYPH(0x2F9C1), + U24(0x881F), GLYPH(0xF927), + U24(0x884C), GLYPH(0xFA08), + U24(0x8860), GLYPH(0x2F9C3), + U24(0x8863), GLYPH(0x2F9C4), + U24(0x88C2), GLYPH(0xF9A0), + U24(0x88CF), GLYPH(0xF9E7), + U24(0x88D7), GLYPH(0x2F9C6), + U24(0x88DE), GLYPH(0x2F9C7), + U24(0x88E1), GLYPH(0xF9E8), + U24(0x88F8), GLYPH(0xF912), + U24(0x88FA), GLYPH(0x2F9C9), + U24(0x8910), GLYPH(0xFA60), + U24(0x8941), GLYPH(0xFAB6), + U24(0x8964), GLYPH(0xF924), + U24(0x8986), GLYPH(0xFAB7), + U24(0x898B), GLYPH(0xFA0A), + U24(0x8996), GLYPH(0xFA61), + U24(0x8AA0), GLYPH(0x2F9CF), + U24(0x8AAA), GLYPH(0xF96F), + U24(0x8ABF), GLYPH(0xFAB9), + U24(0x8ACB), GLYPH(0xFABB), + U24(0x8AD2), GLYPH(0xF97D), + U24(0x8AD6), GLYPH(0xF941), + U24(0x8AED), GLYPH(0xFABE), + U24(0x8AF8), GLYPH(0xFA22), + U24(0x8AFE), GLYPH(0xF95D), + U24(0x8B01), GLYPH(0xFA62), + U24(0x8B39), GLYPH(0xFA63), + U24(0x8B58), GLYPH(0xF9FC), + U24(0x8B80), GLYPH(0xF95A), + U24(0x8B8A), GLYPH(0xFAC0), + U24(0x8C48), GLYPH(0xF900), + U24(0x8C55), GLYPH(0x2F9D2), + U24(0x8CAB), GLYPH(0x2F9D4), + U24(0x8CC1), GLYPH(0x2F9D5), + U24(0x8CC2), GLYPH(0xF948), + U24(0x8CC8), GLYPH(0xF903), + U24(0x8CD3), GLYPH(0xFA64), + U24(0x8D08), GLYPH(0xFA65), + U24(0x8D1B), GLYPH(0x2F9D6), + U24(0x8D77), GLYPH(0x2F9D7), + U24(0x8DBC), GLYPH(0x2F9DB), + U24(0x8DCB), GLYPH(0x2F9DA), + U24(0x8DEF), GLYPH(0xF937), + U24(0x8DF0), GLYPH(0x2F9DC), + U24(0x8ECA), GLYPH(0xF902), + U24(0x8ED4), GLYPH(0x2F9DE), + U24(0x8F26), GLYPH(0xF998), + U24(0x8F2A), GLYPH(0xF9D7), + U24(0x8F38), GLYPH(0xFAC2), + U24(0x8F3B), GLYPH(0xFA07), + U24(0x8F62), GLYPH(0xF98D), + U24(0x8F9E), GLYPH(0x2F98D), + U24(0x8FB0), GLYPH(0xF971), + U24(0x8FB6), GLYPH(0xFA66), + U24(0x9023), GLYPH(0xF99A), + U24(0x9038), GLYPH(0xFA25), + U24(0x9072), GLYPH(0xFAC3), + U24(0x907C), GLYPH(0xF9C3), + U24(0x908F), GLYPH(0xF913), + U24(0x9094), GLYPH(0x2F9E2), + U24(0x90CE), GLYPH(0xF92C), + U24(0x90DE), GLYPH(0xFA2E), + U24(0x90F1), GLYPH(0x2F9E3), + U24(0x90FD), GLYPH(0xFA26), + U24(0x9111), GLYPH(0x2F9E4), + U24(0x911B), GLYPH(0x2F9E6), + U24(0x916A), GLYPH(0xF919), + U24(0x9199), GLYPH(0xFAC4), + U24(0x91B4), GLYPH(0xF9B7), + U24(0x91CC), GLYPH(0xF9E9), + U24(0x91CF), GLYPH(0xF97E), + U24(0x91D1), GLYPH(0xF90A), + U24(0x9234), GLYPH(0xF9B1), + U24(0x9238), GLYPH(0x2F9E7), + U24(0x9276), GLYPH(0xFAC5), + U24(0x927C), GLYPH(0x2F9EA), + U24(0x92D7), GLYPH(0x2F9E8), + U24(0x92D8), GLYPH(0x2F9E9), + U24(0x9304), GLYPH(0xF93F), + U24(0x934A), GLYPH(0xF99B), + U24(0x93F9), GLYPH(0x2F9EB), + U24(0x9415), GLYPH(0x2F9EC), + U24(0x958B), GLYPH(0x2F9EE), + U24(0x95AD), GLYPH(0xF986), + U24(0x95B7), GLYPH(0x2F9F0), + U24(0x962E), GLYPH(0xF9C6), + U24(0x964B), GLYPH(0xF951), + U24(0x964D), GLYPH(0xFA09), + U24(0x9675), GLYPH(0xF959), + U24(0x9678), GLYPH(0xF9D3), + U24(0x967C), GLYPH(0xFAC6), + U24(0x9686), GLYPH(0xF9DC), + U24(0x96A3), GLYPH(0xF9F1), + U24(0x96B7), GLYPH(0xFA2F), + U24(0x96B8), GLYPH(0xF9B8), + U24(0x96C3), GLYPH(0x2F9F3), + U24(0x96E2), GLYPH(0xF9EA), + U24(0x96E3), GLYPH(0xFA68), + U24(0x96F6), GLYPH(0xF9B2), + U24(0x96F7), GLYPH(0xF949), + U24(0x9723), GLYPH(0x2F9F5), + U24(0x9732), GLYPH(0xF938), + U24(0x9748), GLYPH(0xF9B3), + U24(0x9756), GLYPH(0xFA1C), + U24(0x97DB), GLYPH(0xFAC9), + U24(0x97E0), GLYPH(0x2F9FA), + U24(0x97FF), GLYPH(0xFA69), + U24(0x980B), GLYPH(0xFACB), + U24(0x9818), GLYPH(0xF9B4), + U24(0x9829), GLYPH(0x2FA00), + U24(0x983B), GLYPH(0xFA6A), + U24(0x985E), GLYPH(0xF9D0), + U24(0x98E2), GLYPH(0x2FA02), + U24(0x98EF), GLYPH(0xFA2A), + U24(0x98FC), GLYPH(0xFA2B), + U24(0x9928), GLYPH(0xFA2C), + U24(0x9929), GLYPH(0x2FA04), + U24(0x99A7), GLYPH(0x2FA05), + U24(0x99C2), GLYPH(0x2FA06), + U24(0x99F1), GLYPH(0xF91A), + U24(0x99FE), GLYPH(0x2FA07), + U24(0x9A6A), GLYPH(0xF987), + U24(0x9B12), GLYPH(0xFACD), + U24(0x9B6F), GLYPH(0xF939), + U24(0x9C40), GLYPH(0x2FA0B), + U24(0x9C57), GLYPH(0xF9F2), + U24(0x9CFD), GLYPH(0x2FA0C), + U24(0x9D67), GLYPH(0x2FA0F), + U24(0x9DB4), GLYPH(0xFA2D), + U24(0x9DFA), GLYPH(0xF93A), + U24(0x9E1E), GLYPH(0xF920), + U24(0x9E7F), GLYPH(0xF940), + U24(0x9E97), GLYPH(0xF988), + U24(0x9E9F), GLYPH(0xF9F3), + U24(0x9EBB), GLYPH(0x2FA15), + U24(0x9ECE), GLYPH(0xF989), + U24(0x9EF9), GLYPH(0x2FA17), + U24(0x9EFE), GLYPH(0x2FA18), + U24(0x9F05), GLYPH(0x2FA19), + U24(0x9F0F), GLYPH(0x2FA1A), + U24(0x9F16), GLYPH(0x2FA1B), + U24(0x9F3B), GLYPH(0x2FA1C), + U24(0x9F43), GLYPH(0xFAD8), + U24(0x9F8D), GLYPH(0xF9C4), + U24(0x9F8E), GLYPH(0xFAD9), + U24(0x9F9C), GLYPH(0xF907), + U24(0x20122), GLYPH(0x2F803), + U24(0x2051C), GLYPH(0x2F812), + U24(0x20525), GLYPH(0x2F91B), + U24(0x2054B), GLYPH(0x2F816), + U24(0x2063A), GLYPH(0x2F80D), + U24(0x20804), GLYPH(0x2F9D9), + U24(0x208DE), GLYPH(0x2F9DD), + U24(0x20A2C), GLYPH(0x2F834), + U24(0x20B63), GLYPH(0x2F838), + U24(0x214E4), GLYPH(0x2F859), + U24(0x216A8), GLYPH(0x2F860), + U24(0x216EA), GLYPH(0x2F861), + U24(0x219C8), GLYPH(0x2F86C), + U24(0x21B18), GLYPH(0x2F871), + U24(0x21D0B), GLYPH(0x2F8F8), + U24(0x21DE4), GLYPH(0x2F87B), + U24(0x21DE6), GLYPH(0x2F87D), + U24(0x22183), GLYPH(0x2F889), + U24(0x2219F), GLYPH(0x2F939), + U24(0x22331), GLYPH(0x2F891), + U24(0x226D4), GLYPH(0x2F8A4), + U24(0x22844), GLYPH(0xFAD0), + U24(0x2284A), GLYPH(0xFACF), + U24(0x22B0C), GLYPH(0x2F8B8), + U24(0x22BF1), GLYPH(0x2F8BE), + U24(0x2300A), GLYPH(0x2F8CA), + U24(0x232B8), GLYPH(0x2F897), + U24(0x2335F), GLYPH(0x2F980), + U24(0x23393), GLYPH(0x2F989), + U24(0x2339C), GLYPH(0x2F98A), + U24(0x233C3), GLYPH(0x2F8DD), + U24(0x233D5), GLYPH(0xFAD1), + U24(0x2346D), GLYPH(0x2F8E3), + U24(0x236A3), GLYPH(0x2F8EC), + U24(0x238A7), GLYPH(0x2F8F0), + U24(0x23A8D), GLYPH(0x2F8F7), + U24(0x23AFA), GLYPH(0x2F8F9), + U24(0x23CBC), GLYPH(0x2F8FB), + U24(0x23D1E), GLYPH(0x2F906), + U24(0x23ED1), GLYPH(0x2F90D), + U24(0x23F5E), GLYPH(0x2F910), + U24(0x23F8E), GLYPH(0x2F911), + U24(0x24263), GLYPH(0x2F91D), + U24(0x242EE), GLYPH(0xFA6C), + U24(0x243AB), GLYPH(0x2F91F), + U24(0x24608), GLYPH(0x2F923), + U24(0x24735), GLYPH(0x2F926), + U24(0x24814), GLYPH(0x2F927), + U24(0x24C36), GLYPH(0x2F935), + U24(0x24C92), GLYPH(0x2F937), + U24(0x24FA1), GLYPH(0x2F93B), + U24(0x24FB8), GLYPH(0x2F93C), + U24(0x25044), GLYPH(0x2F93D), + U24(0x250F2), GLYPH(0x2F942), + U24(0x250F3), GLYPH(0x2F941), + U24(0x25119), GLYPH(0x2F943), + U24(0x25133), GLYPH(0x2F944), + U24(0x25249), GLYPH(0xFAD5), + U24(0x2541D), GLYPH(0x2F94D), + U24(0x25626), GLYPH(0x2F952), + U24(0x2569A), GLYPH(0x2F954), + U24(0x256C5), GLYPH(0x2F955), + U24(0x2597C), GLYPH(0x2F95C), + U24(0x25AA7), GLYPH(0x2F95D), + U24(0x25BAB), GLYPH(0x2F961), + U24(0x25C80), GLYPH(0x2F965), + U24(0x25CD0), GLYPH(0xFAD6), + U24(0x25F86), GLYPH(0x2F96B), + U24(0x261DA), GLYPH(0x2F898), + U24(0x26228), GLYPH(0x2F972), + U24(0x26247), GLYPH(0x2F973), + U24(0x262D9), GLYPH(0x2F975), + U24(0x2633E), GLYPH(0x2F977), + U24(0x264DA), GLYPH(0x2F97B), + U24(0x26523), GLYPH(0x2F97C), + U24(0x265A8), GLYPH(0x2F97E), + U24(0x267A7), GLYPH(0x2F987), + U24(0x267B5), GLYPH(0x2F988), + U24(0x26B3C), GLYPH(0x2F997), + U24(0x26C36), GLYPH(0x2F9A4), + U24(0x26CD5), GLYPH(0x2F9A6), + U24(0x26D6B), GLYPH(0x2F9A5), + U24(0x26F2C), GLYPH(0x2F9AD), + U24(0x26FB1), GLYPH(0x2F9B0), + U24(0x270D2), GLYPH(0x2F9B1), + U24(0x273CA), GLYPH(0x2F9AB), + U24(0x27667), GLYPH(0x2F9C5), + U24(0x278AE), GLYPH(0x2F9CB), + U24(0x27966), GLYPH(0x2F9CC), + U24(0x27CA8), GLYPH(0x2F9D3), + U24(0x27ED3), GLYPH(0xFAD7), + U24(0x27F2F), GLYPH(0x2F9D8), + U24(0x285D2), GLYPH(0x2F9E0), + U24(0x285ED), GLYPH(0x2F9E1), + U24(0x2872E), GLYPH(0x2F9E5), + U24(0x28BFA), GLYPH(0x2F9ED), + U24(0x28D77), GLYPH(0x2F9F1), + U24(0x29145), GLYPH(0x2F9F6), + U24(0x291DF), GLYPH(0x2F81C), + U24(0x2921A), GLYPH(0x2F9F7), + U24(0x2940A), GLYPH(0x2F9FB), + U24(0x29496), GLYPH(0x2F9FD), + U24(0x295B6), GLYPH(0x2FA01), + U24(0x29B30), GLYPH(0x2FA09), + U24(0x2A0CE), GLYPH(0x2FA10), + U24(0x2A105), GLYPH(0x2FA12), + U24(0x2A20E), GLYPH(0x2FA13), + U24(0x2A291), GLYPH(0x2FA14), + U24(0x2A392), GLYPH(0x2F88F), + U24(0x2A600), GLYPH(0x2FA1D), + // 0xFE01 + U32(88), // numUVSMappings + U24(0x3B9D), GLYPH(0x2F8E7), + U24(0x3EB8), GLYPH(0x2F92D), + U24(0x4039), GLYPH(0x2F949), + U24(0x4FAE), GLYPH(0x2F805), + U24(0x50E7), GLYPH(0x2F80A), + U24(0x514D), GLYPH(0x2F80E), + U24(0x51B5), GLYPH(0x2F81B), + U24(0x5207), GLYPH(0x2F850), + U24(0x52C7), GLYPH(0x2F825), + U24(0x52C9), GLYPH(0x2F826), + U24(0x52E4), GLYPH(0x2F827), + U24(0x52FA), GLYPH(0x2F828), + U24(0x5317), GLYPH(0x2F82B), + U24(0x5351), GLYPH(0x2F82D), + U24(0x537F), GLYPH(0x2F832), + U24(0x5584), GLYPH(0x2F846), + U24(0x5599), GLYPH(0x2F847), + U24(0x559D), GLYPH(0xFA78), + U24(0x5606), GLYPH(0x2F84C), + U24(0x585A), GLYPH(0xFA7C), + U24(0x5B3E), GLYPH(0x2F86B), + U24(0x5BE7), GLYPH(0xF9AA), + U24(0x5C6E), GLYPH(0x2F878), + U24(0x5ECA), GLYPH(0x2F88E), + U24(0x5F22), GLYPH(0x2F895), + U24(0x6094), GLYPH(0x2F8A3), + U24(0x614C), GLYPH(0x2F8A9), + U24(0x614E), GLYPH(0x2F8A8), + U24(0x618E), GLYPH(0xFA89), + U24(0x61F2), GLYPH(0xFA8B), + U24(0x61F6), GLYPH(0x2F8B1), + U24(0x654F), GLYPH(0x2F8C8), + U24(0x6674), GLYPH(0xFA91), + U24(0x6691), GLYPH(0x2F8CF), + U24(0x6717), GLYPH(0xFA92), + U24(0x671B), GLYPH(0x2F8D9), + U24(0x6885), GLYPH(0x2F8E2), + U24(0x6A02), GLYPH(0xF95C), + U24(0x6BBA), GLYPH(0xFA96), + U24(0x6D41), GLYPH(0xFA97), + U24(0x6D77), GLYPH(0x2F901), + U24(0x6ECB), GLYPH(0x2F90B), + U24(0x6F22), GLYPH(0xFA9A), + U24(0x701E), GLYPH(0x2F914), + U24(0x716E), GLYPH(0xFA9C), + U24(0x7235), GLYPH(0x2F921), + U24(0x732A), GLYPH(0xFAA0), + U24(0x7387), GLYPH(0xF9DB), + U24(0x7471), GLYPH(0x2F930), + U24(0x7570), GLYPH(0x2F938), + U24(0x76CA), GLYPH(0xFAA6), + U24(0x76F4), GLYPH(0x2F940), + U24(0x771F), GLYPH(0x2F947), + U24(0x774A), GLYPH(0x2F948), + U24(0x788C), GLYPH(0x2F94F), + U24(0x78CC), GLYPH(0x2F950), + U24(0x7956), GLYPH(0x2F953), + U24(0x798F), GLYPH(0x2F956), + U24(0x7A40), GLYPH(0x2F959), + U24(0x7BC0), GLYPH(0xFAAD), + U24(0x7DF4), GLYPH(0xFA57), + U24(0x8005), GLYPH(0xFAB2), + U24(0x8201), GLYPH(0x2F98B), + U24(0x8279), GLYPH(0xFA5E), + U24(0x82E5), GLYPH(0x2F998), + U24(0x8457), GLYPH(0x2F99F), + U24(0x865C), GLYPH(0x2F9B4), + U24(0x8779), GLYPH(0x2F9BB), + U24(0x8996), GLYPH(0xFAB8), + U24(0x8AAA), GLYPH(0xF9A1), + U24(0x8AED), GLYPH(0x2F9D0), + U24(0x8AF8), GLYPH(0xFABA), + U24(0x8AFE), GLYPH(0xFABD), + U24(0x8B01), GLYPH(0xFABC), + U24(0x8B39), GLYPH(0xFABF), + U24(0x8B8A), GLYPH(0x2F9D1), + U24(0x8D08), GLYPH(0xFAC1), + U24(0x8F38), GLYPH(0x2F9DF), + U24(0x9038), GLYPH(0xFA67), + U24(0x96E3), GLYPH(0xFAC7), + U24(0x9756), GLYPH(0xFAC8), + U24(0x97FF), GLYPH(0xFACA), + U24(0x980B), GLYPH(0x2F9FE), + U24(0x983B), GLYPH(0xFACC), + U24(0x9B12), GLYPH(0x2FA0A), + U24(0x9F9C), GLYPH(0xF908), + U24(0x22331), GLYPH(0x2F892), + U24(0x25AA7), GLYPH(0x2F95E), + // 0xFE02 + U32(12), // numUVSMappings + U24(0x537F), GLYPH(0x2F833), + U24(0x5BE7), GLYPH(0x2F86F), + U24(0x618E), GLYPH(0x2F8AB), + U24(0x61F2), GLYPH(0x2F8B0), + U24(0x6717), GLYPH(0x2F8D8), + U24(0x6A02), GLYPH(0xF9BF), + U24(0x6BBA), GLYPH(0x2F8F5), + U24(0x6D41), GLYPH(0x2F902), + U24(0x7DF4), GLYPH(0xFAB0), + U24(0x8005), GLYPH(0x2F97A), + U24(0x980B), GLYPH(0x2F9FF), + U24(0x9F9C), GLYPH(0xFACE), +}; + +#undef U16 +#undef U24 +#undef U32 +#undef GLYPH + +static_assert(sizeof sCJKCompatSVSTable == 5065, "Table generator has a bug."); diff --git a/gfx/thebes/gencjkcisvs.py b/gfx/thebes/gencjkcisvs.py new file mode 100644 index 0000000000000000000000000000000000000000..401ebaa97a058e939de5774bd8c734a94d36b3f1 --- /dev/null +++ b/gfx/thebes/gencjkcisvs.py @@ -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) diff --git a/gfx/thebes/gfxFT2FontBase.cpp b/gfx/thebes/gfxFT2FontBase.cpp index a77b9ad9342dea6e78b44bed304d8f7f6ce639f0..0693b9aff38bcd0bf419c741e8d073bb147a6f83 100644 --- a/gfx/thebes/gfxFT2FontBase.cpp +++ b/gfx/thebes/gfxFT2FontBase.cpp @@ -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); diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 1028459c5d7a0a72be9ccf30996085bd2c0933f9..033f1ea7f42ebed63c84d0155be59c55a9e38813 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -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; } diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 5ae3a0faa562d89fc3f3ac3174d5b292ff8cc8b3..9c8a697ac30171f4536acad7e0b9576eb260bc67 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -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. diff --git a/gfx/thebes/gfxFontUtils.cpp b/gfx/thebes/gfxFontUtils.cpp index f9bfbb0ee5c9371d02a15ce5411101aeec598d07..d45753c13189832b2cc0b81841823b7ca316cc95 100644 --- a/gfx/thebes/gfxFontUtils.cpp +++ b/gfx/thebes/gfxFontUtils.cpp @@ -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 } diff --git a/gfx/thebes/gfxFontUtils.h b/gfx/thebes/gfxFontUtils.h index 88c3d850c302ecf4bab4db3fdb75aa4b30bfe14b..7e3f24cf0885df7a43f3d9c0a23f70cd27d989ad 100644 --- a/gfx/thebes/gfxFontUtils.h +++ b/gfx/thebes/gfxFontUtils.h @@ -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); diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp index 24ea0ee8ff25f6e6a6821bafa8b64bbd126865b6..5c4b803490d9cbdda87b1333e0cf9bfe863a2b91 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.cpp +++ b/gfx/thebes/gfxHarfBuzzShaper.cpp @@ -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; diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 5e602b2c2094e2bd7f2779b79b1cae4370e1efb3..3fb2e01595b5746d5fe7b6fd6db1e8b3b38869bf 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -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 (copy) { + copy->Unmap(); + } + 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; + // 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; } + } - srcBuffer = Factory::CreateWrappingDataSourceSurface(imgSurface->Data(), - imgSurface->Stride(), - size, format); - + 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; } diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 0a429f90829280716155ac373c3b1de4db1163dc..9989428879f08ba989212f85a41fb01f0a78d5dc 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -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); diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index 9493632c45a316ffc91602e20a890aeb1a8acbb6..221e158c7717b1fba08e6179d093a8a420c9883b 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -226,6 +226,7 @@ SOURCES += [ ] UNIFIED_SOURCES += [ + 'CJKCompatSVS.cpp', 'gfx3DMatrix.cpp', 'gfxAlphaRecovery.cpp', 'gfxBaseSharedMemorySurface.cpp', diff --git a/js/src/jit-test/tests/gc/bug-986864.js b/js/src/jit-test/tests/gc/bug-986864.js new file mode 100644 index 0000000000000000000000000000000000000000..abb8de6b2b5a8f563b761b77043649f9ad36cd04 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-986864.js @@ -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) + })() +} diff --git a/js/src/jit/Bailouts.cpp b/js/src/jit/Bailouts.cpp index 487a7aa033ee486b902f95f0793450206ae12c13..f8ee8402bf098c23879caf32cdd693388b1b4c95 100644 --- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -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()) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index ab80e0f682bdc973af57b525d6745c4e330c002c..ee8848d5c646eedb59f67185f4d51260748678a8 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -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) diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 7adc1721d61c6d3d6ceee72c8b64b6e7e19735d2..108dc1657ead83d87f5c38f5669cc701c876bbf5 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -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) { diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h index bbac4c43ed4eb07d38f8fe2335b0c011c6bbef16..bdf1e691b640b9b382d0f2c9fb33b11ec9eb57d4 100644 --- a/js/src/jit/IonCode.h +++ b/js/src/jit/IonCode.h @@ -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); diff --git a/js/src/jit/IonFrameIterator.h b/js/src/jit/IonFrameIterator.h index 9de60268d44f0c365b51fd593a687e2265b810a5..a924755296f40698dc0da41a930d99419f76069f 100644 --- a/js/src/jit/IonFrameIterator.h +++ b/js/src/jit/IonFrameIterator.h @@ -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(); diff --git a/js/src/jit/IonFrames.cpp b/js/src/jit/IonFrames.cpp index b64ce84897c71784b9fb6f480973d4c11084e19d..d7d1ff70469bfd7c9554743a468f70d5c3f871e6 100644 --- a/js/src/jit/IonFrames.cpp +++ b/js/src/jit/IonFrames.cpp @@ -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) { diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h index 8b7e87ae1be3e793bdd4552229b8b8a98aea79ae..f5c8fd4daab8e7f67aba31e353c2cdb0f2e99e1f 100644 --- a/js/src/jit/IonTypes.h +++ b/js/src/jit/IonTypes.h @@ -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 diff --git a/js/src/jit/LIR.cpp b/js/src/jit/LIR.cpp index f25e7d5a2a99ccdc744a2ce359695aceb9431cdb..3116a86faf934c5aad6fdd7fc70c75358fd2e0de 100644 --- a/js/src/jit/LIR.cpp +++ b/js/src/jit/LIR.cpp @@ -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; } diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h index 211e4fbefc5f46314f6f76f66cc783006ae1e075..20652f80d2dac449583601fec22521d601ef237c 100644 --- a/js/src/jit/LIR.h +++ b/js/src/jit/LIR.h @@ -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_; diff --git a/js/src/jit/Snapshots.cpp b/js/src/jit/Snapshots.cpp index ac58faa9368188cc8a80308716f748a00b22e766..63ca5fb7d491c548b01c64e5aac35db5746f7305 100644 --- a/js/src/jit/Snapshots.cpp +++ b/js/src/jit/Snapshots.cpp @@ -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 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)); + IonSpew(IonSpew_Snapshots, "starting snapshot with recover offset %u, bailout kind %u", + recoverOffset, kind); - uint32_t bits = (uint32_t(kind) << SNAPSHOT_BAILOUTKIND_SHIFT) | - (frameCount << SNAPSHOT_FRAMECOUNT_SHIFT); - if (resumeAfter) - bits |= (1 << SNAPSHOT_RESUMEAFTER_SHIFT); + JS_ASSERT(uint32_t(kind) < (1 << SNAPSHOT_BAILOUTKIND_BITS)); + 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_); } diff --git a/js/src/jit/Snapshots.h b/js/src/jit/Snapshots.h index c4d652f27ec5892a023e1e0876d1fed7fd41f6e7..39d46209f72f3e958aeb6e509437ed198cb385d9 100644 --- a/js/src/jit/Snapshots.h +++ b/js/src/jit/Snapshots.h @@ -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, BailoutKind kind, bool resumeAfter); + SnapshotOffset startRecover(uint32_t frameCount, 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_; diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index c84dd1ab32bab281ffea115091734b6a4334e145..94cb728554df448142ffaa2bb79e94b5399baffb 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -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(); - - IonSpew(IonSpew_Snapshots, "Encoding LSnapshot %p (frameCount %u)", - (void *)snapshot, frameCount); + uint32_t frameCount = recover->mir()->frameCount(); + IonSpew(IonSpew_Snapshots, "Encoding LRecoverInfo %p (frameCount %u)", + (void *)recover, 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); - -#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 + RecoverOffset offset = recovers_.startRecover(frameCount, resumeAfter); - 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); + recovers_.writeFrame(fun, script, pc, exprStack); +#ifdef DEBUG // 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); - -#ifdef DEBUG 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 + } + + recovers_.endRecover(); + 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; - recovers_.endFrame(); } - recovers_.endRecover(); + MOZ_ASSERT(snapshots_.allocWritten() == snapshot->numSlots()); + snapshots_.endSnapshot(); snapshot->setSnapshotOffset(offset); - return !snapshots_.oom(); } diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index ea3807d9967e12ff6024d5ea087d761d08c8fce5..8c621a37aa99ad1f32a72147c9233b1a88ce1610 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -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); diff --git a/js/src/jit/shared/Lowering-shared.cpp b/js/src/jit/shared/Lowering-shared.cpp index 62b376b3a79e24bfaeb413d9704b681ce0cccfa5..f23ecd9361095320789cdf2b43d8c35c231c98f9 100644 --- a/js/src/jit/shared/Lowering-shared.cpp +++ b/js/src/jit/shared/Lowering-shared.cpp @@ -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; diff --git a/js/src/jit/shared/Lowering-shared.h b/js/src/jit/shared/Lowering-shared.h index d26982909f64675b51aba29c2136c7aeccf4c4f6..26bd474c375fd089598d8875ea063a12ec59f450 100644 --- a/js/src/jit/shared/Lowering-shared.h +++ b/js/src/jit/shared/Lowering-shared.h @@ -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); diff --git a/js/src/js.msg b/js/src/js.msg index 146b1136d68266ce7f8c384c4b8de4f3ed71f872..235aed7e4019792938757659d418438c212e9b1a 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -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}") diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index c6df08f8083e32d3075ad5d47e6e596183cf6694..38d9ca2eda4772fbef4b1f2f4bd298f3c2ad80b8 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -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; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index a7afc7e2a9629d839be0b6e75e90ed5abf5c7d6d..7eac22b62a6b8297f970298fafe649fd5e7c2e07 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -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) +{ + // 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) { - cache_.numSuppressPurges_--; - JS_ASSERT(cache_.numSuppressPurges_ == oldValue_); + 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; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index f80bad30a6421969e62eb385b6614e3e400b6e98..3ca098cf6e844929115973e9e6ab0b3a8f9d55b8 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -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; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index a8d0d4c7b541934d23a68c9a5c45156a99cae44c..41332fa668a46cf69824ecb0860eae78c8678da0 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -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()); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 30320ffb6eb12677d71012c63d250f3dbe425f81..30d375cd9d78b4ea2749e2f4e31cdf29235dd36c 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -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) { diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 843aafdf706ef98bb2dd2a019e7d9c6dc1bcf25d..e16dbd12f398d1d345bea46a6b1e99d9c9f7f8ea 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -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. diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index e1cd9c15ba662ed1cf8b35f7744fb623ea855daf..f5ecd43769a5843e220c0c23902d46b2b07f2ac1 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -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); diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 8cb725d5edd889e623bba5cd340365d3ff59f700..db056162c54de197e7c18784cdc3d469ae031485 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -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 diff --git a/layout/generic/test/test_bug470212.html b/layout/generic/test/test_bug470212.html index 3ac6f3a3aab665bc13a07383b81d4efc0a69d8ae..42c600348117ed6eb80e550355574804344395a1 100644 --- a/layout/generic/test/test_bug470212.html +++ b/layout/generic/test/test_bug470212.html @@ -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); diff --git a/layout/reftests/font-face/cjkcisvs-1-ref.html b/layout/reftests/font-face/cjkcisvs-1-ref.html new file mode 100644 index 0000000000000000000000000000000000000000..49c384b153f77ea20524b59656799fcc206fcf8b --- /dev/null +++ b/layout/reftests/font-face/cjkcisvs-1-ref.html @@ -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> diff --git a/layout/reftests/font-face/cjkcisvs-1.html b/layout/reftests/font-face/cjkcisvs-1.html new file mode 100644 index 0000000000000000000000000000000000000000..e0d63e4917c4f380a589062a7e3bc4949a8e9e71 --- /dev/null +++ b/layout/reftests/font-face/cjkcisvs-1.html @@ -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> diff --git a/layout/reftests/font-face/reftest.list b/layout/reftests/font-face/reftest.list index afd0a23a106c749e30aaa1f255cabd4b0024a016..46e47592f205495ba8bd70c9d3c9ffa32debe115 100644 --- a/layout/reftests/font-face/reftest.list +++ b/layout/reftests/font-face/reftest.list @@ -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 diff --git a/layout/reftests/fonts/gw432047-license.txt b/layout/reftests/fonts/glyphwiki-license.txt similarity index 97% rename from layout/reftests/fonts/gw432047-license.txt rename to layout/reftests/fonts/glyphwiki-license.txt index b47419fbc5b8b0a7ee3fc642966e9cb6caf3ff35..927c138d6a7187da1f55d472dcc9123463a4f59d 100644 --- a/layout/reftests/fonts/gw432047-license.txt +++ b/layout/reftests/fonts/glyphwiki-license.txt @@ -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.''' diff --git a/layout/reftests/fonts/gw1270797.ttf b/layout/reftests/fonts/gw1270797.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b3041fd9aea6396e58cf7ee2576a9c1513983d88 Binary files /dev/null and b/layout/reftests/fonts/gw1270797.ttf differ diff --git a/layout/svg/nsSVGImageFrame.cpp b/layout/svg/nsSVGImageFrame.cpp index bf0fa875891f4f3fafc0821bb71bf05e29654d2e..617e50fc45d9bef72bd419938b7256498cefcdd6 100644 --- a/layout/svg/nsSVGImageFrame.cpp +++ b/layout/svg/nsSVGImageFrame.cpp @@ -6,6 +6,7 @@ // Keep in (case-insensitive) order: #include "gfxContext.h" #include "gfxPlatform.h" +#include "mozilla/gfx/2D.h" #include "imgIContainer.h" #include "nsIImageLoadingContent.h" #include "nsLayoutUtils.h" @@ -23,6 +24,7 @@ using namespace mozilla; using namespace mozilla::dom; +using namespace mozilla::gfx; class nsSVGImageFrame; @@ -469,32 +471,11 @@ nsSVGImageFrame::ReflowSVG() return; } - gfxContext tmpCtx(gfxPlatform::GetPlatform()->ScreenReferenceSurface()); - - // We'd like to just pass the identity matrix to GeneratePath, but if - // this frame's user space size is _very_ large/small then the extents we - // obtain below might have overflowed or otherwise be broken. This would - // cause us to end up with a broken mRect and visual overflow rect and break - // painting of this frame. This is particularly noticeable if the transforms - // between us and our nsSVGOuterSVGFrame scale this frame to a reasonable - // size. To avoid this we sadly have to do extra work to account for the - // transforms between us and our nsSVGOuterSVGFrame, even though the - // overwhelming number of SVGs will never have this problem. - // XXX Will Azure eventually save us from having to do this? - gfxSize scaleFactors = GetCanvasTM(FOR_OUTERSVG_TM).ScaleFactors(true); - bool applyScaling = fabs(scaleFactors.width) >= 1e-6 && - fabs(scaleFactors.height) >= 1e-6; - Matrix scaling; - if (applyScaling) { - scaling.Scale(scaleFactors.width, scaleFactors.height); - } - tmpCtx.Save(); - GeneratePath(&tmpCtx, scaling); - tmpCtx.Restore(); - gfxRect extent = tmpCtx.GetUserPathExtent(); - if (applyScaling) { - extent.Scale(1 / scaleFactors.width, 1 / scaleFactors.height); - } + float x, y, width, height; + SVGImageElement *element = static_cast<SVGImageElement*>(mContent); + element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); + + Rect extent(x, y, width, height); if (!extent.IsEmpty()) { mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 20c7e280928fda216abd77b2225779a7f1d7b871..b37ad139d747c9e039ec022f2293fb274ad2326a 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -4002,12 +4002,13 @@ pref("layers.offmainthreadcomposition.enabled", false); // -1 -> default (match layout.frame_rate or 60 FPS) // 0 -> full-tilt mode: Recomposite even if not transaction occured. pref("layers.offmainthreadcomposition.frame-rate", -1); - -#ifdef XP_WIN +// Whether to use the deprecated texture architecture rather than the new one. +#ifndef XP_WIN // Asynchonous video compositing using the ImageBridge IPDL protocol. // requires off-main-thread compositing. // Never works on Windows, so no point pref'ing it on. -pref("layers.async-video.enabled", false); +pref("layers.async-video.enabled",false); +pref("layers.use-deprecated-textures", true); #endif #ifdef MOZ_X11 diff --git a/rdf/base/src/nsCompositeDataSource.cpp b/rdf/base/src/nsCompositeDataSource.cpp index 50ee18f2b619fb66cfe0c305987aa9251d9413c6..76ad9f51001c08432cd96b692fa537ee8806ad03 100644 --- a/rdf/base/src/nsCompositeDataSource.cpp +++ b/rdf/base/src/nsCompositeDataSource.cpp @@ -42,7 +42,7 @@ #include "nsEnumeratorUtils.h" -#ifdef DEBUG +#ifdef PR_LOGGING #include "prlog.h" #include "prprf.h" #include <stdio.h> diff --git a/security/manager/ssl/tests/unit/test_ev_certs.js b/security/manager/ssl/tests/unit/test_ev_certs.js index 682a3b675db309a8d0eaa91bc038d4f477d70f98..19fc0253b6603b729a92b351c7a88093b70be9c4 100644 --- a/security/manager/ssl/tests/unit/test_ev_certs.js +++ b/security/manager/ssl/tests/unit/test_ev_certs.js @@ -21,6 +21,8 @@ let certList = [ // Test for successful EV validation 'int-ev-valid', 'ev-valid', + 'ev-valid-anypolicy-int', + 'int-ev-valid-anypolicy-int', 'no-ocsp-url-cert', // a cert signed by the EV auth that has no OCSP url // but that contains a valid CRLDP. @@ -136,6 +138,17 @@ function add_tests_in_mode(useMozillaPKIX) ocspResponder.stop(run_next_test); }); + + add_test(function () { + clearOCSPCache(); + + let ocspResponder = start_ocsp_responder( + isDebugBuild ? ["int-ev-valid-anypolicy-int", "ev-valid-anypolicy-int"] + : ["ev-valid-anypolicy-int"]); + check_ee_for_ev("ev-valid-anypolicy-int", isDebugBuild); + ocspResponder.stop(run_next_test); + }); + add_test(function() { clearOCSPCache(); let ocspResponder = start_ocsp_responder(["non-ev-root"]); @@ -205,6 +218,7 @@ function add_tests_in_mode(useMozillaPKIX) : SEC_ERROR_EXTENSION_NOT_FOUND)); }); + // Test the EV continues to work with flags after successful EV verification add_test(function () { clearOCSPCache(); @@ -231,6 +245,7 @@ function add_tests_in_mode(useMozillaPKIX) failingOcspResponder.stop(run_next_test); }); }); + } // bug 950240: add FLAG_MUST_BE_EV to CertVerifier::VerifyCert @@ -258,3 +273,4 @@ function check_no_ocsp_requests(cert_name, expected_error) { do_check_eq(identityInfo.isExtendedValidation, false); ocspResponder.stop(run_next_test); } + diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cert8.db b/security/manager/ssl/tests/unit/test_ev_certs/cert8.db index 226f654774ea5d474a98f53a0f9e0bdefaa2339e..79ee652ead3a79cbc5f95c612bd890fcb92620ff 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/cert8.db and b/security/manager/ssl/tests/unit/test_ev_certs/cert8.db differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/ev-valid-anypolicy-int.der b/security/manager/ssl/tests/unit/test_ev_certs/ev-valid-anypolicy-int.der new file mode 100644 index 0000000000000000000000000000000000000000..629415c57588253011125db925e9a78bdb7bc12c Binary files /dev/null and b/security/manager/ssl/tests/unit/test_ev_certs/ev-valid-anypolicy-int.der differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/ev-valid.der b/security/manager/ssl/tests/unit/test_ev_certs/ev-valid.der index a046525fc039a8e7cdac3445b6a9b42513d3e699..2cfaa2758baf6c900f36e18d480cbdd758bb5bf5 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/ev-valid.der and b/security/manager/ssl/tests/unit/test_ev_certs/ev-valid.der differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/generate.py b/security/manager/ssl/tests/unit/test_ev_certs/generate.py index f09b854c7ae882aea824da190c0908bc83677d1b..a790f6709c4ab3c61d34c19529f4ba17dbb4e633 100755 --- a/security/manager/ssl/tests/unit/test_ev_certs/generate.py +++ b/security/manager/ssl/tests/unit/test_ev_certs/generate.py @@ -40,6 +40,13 @@ mozilla_testing_ev_policy = ("certificatePolicies = @v3_ca_ev_cp\n\n" + "1.3.6.1.4.1.13769.666.666.666.1.500.9.1\n\n" + "CPS.1 = \"http://mytestdomain.local/cps\"") +anypolicy_policy = ("certificatePolicies = @v3_ca_ev_cp\n\n" + + "[ v3_ca_ev_cp ]\n" + + "policyIdentifier = " + + "2.5.29.32.0\n\n" + + "CPS.1 = \"http://mytestdomain.local/cps\"") + + def import_untrusted_cert(certfile, nickname): os.system("certutil -A -d . -n " + nickname + " -i " + certfile + " -t ',,'") @@ -108,6 +115,30 @@ def generate_certs(): int_key, int_cert); import_untrusted_cert(no_ocsp_cert, 'no-ocsp-url-cert'); + # add an ev cert whose intermediate has a anypolicy oid + prefix = "ev-valid-anypolicy-int" + ee_ext_text = (EE_basic_constraints + EE_full_ku + Server_eku + + authority_key_ident + aia_prefix + prefix + aia_suffix + + endentity_crl + mozilla_testing_ev_policy) + int_ext_text = (CA_basic_constraints + EE_full_ku + CA_eku + + authority_key_ident + subject_key_ident + + aia_prefix + "int-" + prefix + aia_suffix + + intermediate_crl + anypolicy_policy) + + [int_key, int_cert, ee_key, ee_cert] = CertUtils.generate_int_and_ee(db, + srcdir, + ca_key, + ca_cert, + prefix, + int_ext_text, + ee_ext_text, + key_type) + pk12file = CertUtils.generate_pkcs12(db, srcdir, int_cert, int_key, + "int-" + prefix) + import_cert_and_pkcs12(int_cert, pk12file, "int-" + prefix, ",,") + import_untrusted_cert(ee_cert, prefix) + + [bad_ca_key, bad_ca_cert] = CertUtils.generate_cert_generic( db, srcdir, 1, diff --git a/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid-anypolicy-int.der b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid-anypolicy-int.der new file mode 100644 index 0000000000000000000000000000000000000000..0839693dd55e497cd9d87a76da518dd7a74da934 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid-anypolicy-int.der differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.der b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.der index c7c60fa406cdb5ecf223494e3b8b746320a723ff..60eddd88f5b64026c26029f835b56571b3f7aea8 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.der and b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.der differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.p12 b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.p12 index e0d5e73f8f140c32abb9e8e7b5604af6831d93e6..9a50320d4c08382248f37e15f2ddb18b5cbe1692 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.p12 and b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.p12 differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.der b/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.der index ad245b2e045348bbe2ca6a67db245116f30468ed..cc848f221e169cb3d22c7ad9b089419bafa6c27d 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.der and b/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.der differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.p12 b/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.p12 index 7377f689a24b4f2036629e96b59c03639370a49a..4170d2bdebcf38363c14641dd7bdb17457d14b22 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.p12 and b/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.p12 differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/key3.db b/security/manager/ssl/tests/unit/test_ev_certs/key3.db index 974fc126ac56159cf9489521f1bad44cc3884a14..faafb6bec8d2d7726db65f7154d418e194a2eb99 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/key3.db and b/security/manager/ssl/tests/unit/test_ev_certs/key3.db differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-url-cert.der b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-url-cert.der index eb6b1ccb84ccc60ed2555cc9a179f685b9179478..b0e5832fba34ab62a9cc2574f69710ab194d63f7 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-url-cert.der and b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-url-cert.der differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root.der b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root.der index 6907db91afdde1093315cfb77f0bd7a17092c2df..144171257c96107f474ef611a6d925d3ebf4a94f 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root.der and b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root.der differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.der b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.der index 32257c7f656f14683ee1a887ccd76587cf8cec25..6fa04d6b0177c9f7bf97ea8da93460d21e3d0658 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.der and b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.der differ diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.p12 b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.p12 index 09920a30db25e82a7306833d511c06e8000a4170..c706797c5cc16d96ab5a2ce7852089ecbe1b5b29 100644 Binary files a/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.p12 and b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.p12 differ diff --git a/security/pkix/include/pkix/pkix.h b/security/pkix/include/pkix/pkix.h index 7d23ccefb0cc7b44189ada514e0827296b288498..dc59c0cff245e83c9fc63c8c023edab097333027 100644 --- a/security/pkix/include/pkix/pkix.h +++ b/security/pkix/include/pkix/pkix.h @@ -34,11 +34,13 @@ namespace mozilla { namespace pkix { // // * user-initial-policy-set = { requiredPolicy }. // * initial-explicit-policy = true -// * initial-any-policy-inhibit = true +// * initial-any-policy-inhibit = false // +// We allow intermediate cerificates to use this extension but since +// we do not process the inhibit anyPolicy extesion we will fail if this +// extension is present. TODO(bug 989051) // Because we force explicit policy and because we prohibit policy mapping, we -// do not bother processing the policy mapping, policy constraint, or inhibit -// anyPolicy extensions. +// do not bother processing the policy mapping, or policy constraint. // // ---------------------------------------------------------------------------- // ERROR RANKING diff --git a/security/pkix/lib/pkixbuild.cpp b/security/pkix/lib/pkixbuild.cpp index 3aa0ca4ba00f12b40d40f9c21cc240c94b3db289..119e595ef662c8ab04aa959c25663f6732726cb8 100644 --- a/security/pkix/lib/pkixbuild.cpp +++ b/security/pkix/lib/pkixbuild.cpp @@ -68,6 +68,7 @@ BackCert::Init() case 32: out = &encodedCertificatePolicies; break; case 35: out = &dummyEncodedAuthorityKeyIdentifier; break; // bug 965136 case 37: out = &encodedExtendedKeyUsage; break; + case 54: out = &encodedInhibitAnyPolicy; break; // Bug 989051 } } else if (ext->id.len == 9 && ext->id.data[0] == 0x2b && ext->id.data[1] == 0x06 && diff --git a/security/pkix/lib/pkixcheck.cpp b/security/pkix/lib/pkixcheck.cpp index ca4f3deb542d667a5d85f01d014df5fa567dc0c4..b10330005268151f8a798e8ad38ca74f7e52d782 100644 --- a/security/pkix/lib/pkixcheck.cpp +++ b/security/pkix/lib/pkixcheck.cpp @@ -118,6 +118,14 @@ CheckCertificatePolicies(BackCert& cert, EndEntityOrCA endEntityOrCA, return FatalError; } + // Bug 989051. Until we handle inhibitAnyPolicy we will fail close when + // inhibitAnyPolicy extension is present and we need to evaluate certificate + // policies. + if (cert.encodedInhibitAnyPolicy) { + PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0); + return RecoverableError; + } + // The root CA certificate may omit the policies that it has been // trusted for, so we cannot require the policies to be present in those // certificates. Instead, the determination of which roots are trusted for @@ -143,6 +151,11 @@ CheckCertificatePolicies(BackCert& cert, EndEntityOrCA endEntityOrCA, if ((*policyInfos)->oid == requiredPolicy) { return Success; } + // Intermediate certs are allowed to have the anyPolicy OID + if (endEntityOrCA == MustBeCA && + (*policyInfos)->oid == SEC_OID_X509_ANY_POLICY) { + return Success; + } } PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0); diff --git a/security/pkix/lib/pkixutil.h b/security/pkix/lib/pkixutil.h index a9b7edfd4d23ab1a35abb4b34ab062afaff7aad9..d261ba4efa549e1d1a0ef162902004e38057b8fc 100644 --- a/security/pkix/lib/pkixutil.h +++ b/security/pkix/lib/pkixutil.h @@ -94,6 +94,7 @@ public: , encodedExtendedKeyUsage(nullptr) , encodedKeyUsage(nullptr) , encodedNameConstraints(nullptr) + , encodedInhibitAnyPolicy(nullptr) , childCert(childCert) , nssCert(nssCert) , constrainedNames(nullptr) @@ -108,6 +109,7 @@ public: const SECItem* encodedExtendedKeyUsage; const SECItem* encodedKeyUsage; const SECItem* encodedNameConstraints; + const SECItem* encodedInhibitAnyPolicy; BackCert* const childCert; diff --git a/testing/mach_commands.py b/testing/mach_commands.py index 48144e278c43f355aa9e773f5626d37c28a55f72..2f3f04644a0ade988fae740858696c5923a0b369 100644 --- a/testing/mach_commands.py +++ b/testing/mach_commands.py @@ -62,6 +62,11 @@ TEST_SUITES = { 'mach_command': 'jetpack-test', 'kwargs': {}, }, + 'jittest': { + 'aliases': ('Jit', 'jit'), + 'mach_command': 'jittest', + 'kwargs': {'test_file': None}, + }, 'mochitest-a11y': { 'mach_command': 'mochitest-a11y', 'kwargs': {'test_file': None}, @@ -204,3 +209,24 @@ class MachCommands(MachCommandBase): result = False return 0 if result else 1 + +@CommandProvider +class JittestCommand(MachCommandBase): + @Command('jittest', category='testing', description='Run jit-test tests.') + @CommandArgument('--valgrind', action='store_true', help='Run jit-test suite with valgrind flag') + + def run_jittest(self, **params): + import subprocess + import sys + + if sys.platform.startswith('win'): + js = os.path.join(self.bindir, 'js.exe') + else: + js = os.path.join(self.bindir, 'js') + cmd = [os.path.join(self.topsrcdir, 'js', 'src', 'jit-test', 'jit_test.py'), + js, '--no-slow', '--no-progress', '--tinderbox', '--tbpl'] + + if params['valgrind']: + cmd.append('--valgrind') + + return subprocess.call(cmd) diff --git a/testing/mozbase/mozrunner/mozrunner/remote.py b/testing/mozbase/mozrunner/mozrunner/remote.py index cf7bc9fa6f71bcf2427ecbdb0e65ab43de470b0f..bc17b523156f4a34a4224cca37a8731299db9182 100644 --- a/testing/mozbase/mozrunner/mozrunner/remote.py +++ b/testing/mozbase/mozrunner/mozrunner/remote.py @@ -45,7 +45,8 @@ class RemoteRunner(Runner): self.remote_test_root = remote_test_root or self.dm.getDeviceRoot() self.remote_profile = posixpath.join(self.remote_test_root, 'profile') self.restore = restore - self.backup_files = set([]) + self.added_files = set() + self.backup_files = set() def backup_file(self, remote_path): if not self.restore: @@ -54,7 +55,8 @@ class RemoteRunner(Runner): if self.dm.fileExists(remote_path): self.dm.shellCheckOutput(['dd', 'if=%s' % remote_path, 'of=%s.orig' % remote_path]) self.backup_files.add(remote_path) - + else: + self.added_files.add(remote_path) def check_for_crashes(self, last_test=None): last_test = last_test or self.last_test @@ -80,7 +82,10 @@ class RemoteRunner(Runner): Runner.cleanup(self) self.dm.remount() - # Restore the original profiles.ini + # Restore the original profile + for added_file in self.added_files: + self.dm.removeFile(added_file) + for backup_file in self.backup_files: if self.dm.fileExists('%s.orig' % backup_file): self.dm.shellCheckOutput(['dd', 'if=%s.orig' % backup_file, 'of=%s' % backup_file]) @@ -100,8 +105,9 @@ class RemoteRunner(Runner): class B2GRunner(RemoteRunner): - def __init__(self, profile, devicemanager, marionette, context_chrome=True, - test_script=None, test_script_args=None, **kwargs): + def __init__(self, profile, devicemanager, marionette=None, context_chrome=True, + test_script=None, test_script_args=None, + marionette_port=None, emulator=None, **kwargs): RemoteRunner.__init__(self, profile, devicemanager, **kwargs) self.log = mozlog.getLogger('B2GRunner') @@ -120,7 +126,22 @@ class B2GRunner(RemoteRunner): 'NO_EM_RESTART': '1', } self.env.update(tmp_env) self.last_test = "automation" + self.marionette = marionette + if self.marionette is not None: + if marionette_port is None: + marionette_port = self.marionette.port + elif self.marionette.port != marionette_port: + raise ValueError("Got a marionette object and a port but they don't match") + + if emulator is None: + emulator = marionette.emulator + elif marionette.emulator != emulator: + raise ValueError("Got a marionette object and an emulator argument but they don't match") + + self.marionette_port = marionette_port + self.emulator = emulator + self.context_chrome = context_chrome self.test_script = test_script self.test_script_args = test_script_args @@ -144,8 +165,8 @@ class B2GRunner(RemoteRunner): self.outputTimeout = outputTimeout self._setup_remote_profile() # reboot device so it starts up with the proper profile - if not self.marionette.emulator: - self._reboot_device() + if not self.emulator: + self.dm.reboot(wait=True) #wait for wlan to come up if not self._wait_for_net(): raise Exception("network did not come up, please configure the network" + @@ -161,11 +182,19 @@ class B2GRunner(RemoteRunner): # Set up port forwarding again for Marionette, since any that # existed previously got wiped out by the reboot. - if not self.marionette.emulator: + if self.emulator is None: subprocess.Popen([self.dm._adbPath, 'forward', - 'tcp:%s' % self.marionette.port, - 'tcp:%s' % self.marionette.port]).communicate() + 'tcp:%s' % self.marionette_port, + 'tcp:2828']).communicate() + + if self.marionette is not None: + self.start_marionette() + + if self.test_script is not None: + self.start_tests() + + def start_marionette(self): self.marionette.wait_for_port() # start a marionette session @@ -189,18 +218,15 @@ class B2GRunner(RemoteRunner): else: self.marionette.set_context(self.marionette.CONTEXT_CONTENT) - # run the script that starts the tests - if self.test_script: - if os.path.isfile(self.test_script): - script = open(self.test_script, 'r') - self.marionette.execute_script(script.read(), script_args=self.test_script_args) - script.close() - elif isinstance(self.test_script, basestring): - self.marionette.execute_script(self.test_script, script_args=self.test_script_args) - else: - # assumes the tests are started on startup automatically - pass + def start_tests(self): + # run the script that starts the tests + if os.path.isfile(self.test_script): + script = open(self.test_script, 'r') + self.marionette.execute_script(script.read(), script_args=self.test_script_args) + script.close() + elif isinstance(self.test_script, basestring): + self.marionette.execute_script(self.test_script, script_args=self.test_script_args) def on_output(self, line): match = re.findall(r"TEST-START \| ([^\s]*)", line) @@ -221,29 +247,6 @@ class B2GRunner(RemoteRunner): self.log.testFail(msg % (self.last_test, timeout)) self.check_for_crashes() - def _reboot_device(self): - serial, status = self._get_device_status() - - buf = StringIO() - self.dm.shell('/system/bin/reboot', buf) - buf.close() - - # The reboot command can return while adb still thinks the device is - # connected, so wait a little bit for it to disconnect from adb. - time.sleep(10) - - # wait for device to come back to previous status - self.log.info('waiting for device to come back online after reboot') - start = time.time() - rserial, rstatus = self._get_device_status(serial) - while rstatus != 'device': - if time.time() - start > 120: - # device hasn't come back online in 2 minutes, something's wrong - raise Exception("Device %s (status: %s) not back online after reboot" % (serial, rstatus)) - time.sleep(5) - rserial, rstatus = self._get_device_status(serial) - self.log.info('device: %s, status: %s' % (serial, rstatus)) - def _get_device_status(self, serial=None): # If we know the device serial number, we look for that, # otherwise we use the (presumably only) device shown in 'adb devices'. diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setup.py index 355cfe65bbf09d3ec58bda5aec343fd938626797..d724c39c06273e6b0bfd65e3107cd2fd3151b659 100644 --- a/testing/mozbase/mozrunner/setup.py +++ b/testing/mozbase/mozrunner/setup.py @@ -6,7 +6,7 @@ import sys from setuptools import setup PACKAGE_NAME = 'mozrunner' -PACKAGE_VERSION = '5.35' +PACKAGE_VERSION = '5.36' desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)""" diff --git a/testing/specialpowers/content/specialpowers.js b/testing/specialpowers/content/specialpowers.js index 34f0ab9dc6a48873b03b9c8369f7cd6c89e7f14e..31ff09303ae5d32d3050c3e7a8bb2a5920f7ff8b 100644 --- a/testing/specialpowers/content/specialpowers.js +++ b/testing/specialpowers/content/specialpowers.js @@ -104,17 +104,7 @@ function attachSpecialPowersToWindow(aWindow) { if ((aWindow !== null) && (aWindow !== undefined) && (aWindow.wrappedJSObject) && - (aWindow.parent !== null) && - (aWindow.parent !== undefined) && - (aWindow.parent.wrappedJSObject.SpecialPowers) && - !(aWindow.wrappedJSObject.SpecialPowers) && - aWindow.location.hostname == aWindow.parent.location.hostname) { - aWindow.wrappedJSObject.SpecialPowers = aWindow.parent.wrappedJSObject.SpecialPowers; - } - else if ((aWindow !== null) && - (aWindow !== undefined) && - (aWindow.wrappedJSObject) && - !(aWindow.wrappedJSObject.SpecialPowers)) { + !(aWindow.wrappedJSObject.SpecialPowers)) { aWindow.wrappedJSObject.SpecialPowers = new SpecialPowers(aWindow); } } catch(ex) { diff --git a/testing/tps/tps/cli.py b/testing/tps/tps/cli.py index 54dd934f3de4f700d4ef10c060c9c04b63141eb0..862caa11f1590508baeff8b06f8e72d8a6dada54 100644 --- a/testing/tps/tps/cli.py +++ b/testing/tps/tps/cli.py @@ -14,29 +14,6 @@ from tps import TPSTestRunner def main(): parser = optparse.OptionParser() - parser.add_option('--mobile', - action='store_true', - dest='mobile', - default=False, - help='run with mobile settings') - parser.add_option('--testfile', - action='store', - type='string', - dest='testfile', - default='../../services/sync/tests/tps/all_tests.json', - help='path to the test file to run [default: %default]') - parser.add_option('--logfile', - action='store', - type='string', - dest='logfile', - default='tps.log', - help='path to the log file [default: %default]') - parser.add_option('--resultfile', - action='store', - type='string', - dest='resultfile', - default='tps_result.json', - help='path to the result file [default: %default]') parser.add_option('--binary', action='store', type='string', @@ -51,6 +28,28 @@ def main(): dest='configfile', default=None, help='path to the config file to use default: %default]') + parser.add_option('--debug', + action='store_true', + dest='debug', + default=False, + help='run in debug mode') + parser.add_option('--ignore-unused-engines', + default=False, + action='store_true', + dest='ignore_unused_engines', + help='If defined, do not load unused engines in individual tests.' + ' Has no effect for pulse monitor.') + parser.add_option('--logfile', + action='store', + type='string', + dest='logfile', + default='tps.log', + help='path to the log file [default: %default]') + parser.add_option('--mobile', + action='store_true', + dest='mobile', + default=False, + help='run with mobile settings') parser.add_option('--pulsefile', action='store', type='string', @@ -58,12 +57,18 @@ def main(): default=None, help='path to file containing a pulse message in ' 'json format that you want to inject into the monitor') - parser.add_option('--ignore-unused-engines', - default=False, - action='store_true', - dest='ignore_unused_engines', - help='If defined, do not load unused engines in individual tests.' - ' Has no effect for pulse monitor.') + parser.add_option('--resultfile', + action='store', + type='string', + dest='resultfile', + default='tps_result.json', + help='path to the result file [default: %default]') + parser.add_option('--testfile', + action='store', + type='string', + dest='testfile', + default='../../services/sync/tests/tps/all_tests.json', + help='path to the test file to run [default: %default]') (options, args) = parser.parse_args() configfile = options.configfile @@ -97,14 +102,16 @@ def main(): extensionDir = extensionDir.replace('/', '\\') TPS = TPSTestRunner(extensionDir, - testfile=options.testfile, - logfile=options.logfile, binary=options.binary, config=config, - rlock=rlock, + debug=options.debug, + ignore_unused_engines=options.ignore_unused_engines, + logfile=options.logfile, mobile=options.mobile, resultfile=options.resultfile, - ignore_unused_engines=options.ignore_unused_engines) + rlock=rlock, + testfile=options.testfile, + ) TPS.run_tests() if __name__ == '__main__': diff --git a/testing/tps/tps/testrunner.py b/testing/tps/tps/testrunner.py index 4d86e34c155e2d4d9d6c7f13cd0e1fda4a5d3310..1e5255cbc13f0fa04a7c014bae08f69b8f8a28a1 100644 --- a/testing/tps/tps/testrunner.py +++ b/testing/tps/tps/testrunner.py @@ -46,35 +46,58 @@ class TempFile(object): class TPSTestRunner(object): - default_env = { 'MOZ_CRASHREPORTER_DISABLE': '1', - 'GNOME_DISABLE_CRASH_DIALOG': '1', - 'XRE_NO_WINDOWS_CRASH_DIALOG': '1', - 'MOZ_NO_REMOTE': '1', - 'XPCOM_DEBUG_BREAK': 'warn', - } - default_preferences = { 'app.update.enabled' : False, - 'browser.dom.window.dump.enabled': True, - 'browser.sessionstore.resume_from_crash': False, - 'browser.shell.checkDefaultBrowser' : False, - 'browser.tabs.warnOnClose' : False, - 'browser.warnOnQuit': False, - # Allow installing extensions dropped into the profile folder - 'extensions.autoDisableScopes': 10, - 'extensions.getAddons.get.url': 'http://127.0.0.1:4567/addons/api/%IDS%.xml', - 'extensions.update.enabled' : False, - # Don't open a dialog to show available add-on updates - 'extensions.update.notifyUser' : False, - 'services.sync.addons.ignoreRepositoryChecking': True, - 'services.sync.firstSync': 'notReady', - 'services.sync.lastversion': '1.0', - 'services.sync.log.rootLogger': 'Trace', - 'services.sync.log.logger.engine.addons': 'Trace', - 'services.sync.log.logger.service.main': 'Trace', - 'services.sync.log.logger.engine.bookmarks': 'Trace', - 'services.sync.log.appender.console': 'Trace', - 'services.sync.log.appender.debugLog.enabled': True, - 'toolkit.startup.max_resumed_crashes': -1, - } + default_env = { + 'MOZ_CRASHREPORTER_DISABLE': '1', + 'GNOME_DISABLE_CRASH_DIALOG': '1', + 'XRE_NO_WINDOWS_CRASH_DIALOG': '1', + 'MOZ_NO_REMOTE': '1', + 'XPCOM_DEBUG_BREAK': 'warn', + } + + default_preferences = { + 'app.update.enabled': False, + 'browser.dom.window.dump.enabled': True, + 'browser.sessionstore.resume_from_crash': False, + 'browser.shell.checkDefaultBrowser': False, + 'browser.tabs.warnOnClose': False, + 'browser.warnOnQuit': False, + # Allow installing extensions dropped into the profile folder + 'extensions.autoDisableScopes': 10, + 'extensions.getAddons.get.url': 'http://127.0.0.1:4567/addons/api/%IDS%.xml', + 'extensions.update.enabled': False, + # Don't open a dialog to show available add-on updates + 'extensions.update.notifyUser': False, + 'services.sync.addons.ignoreRepositoryChecking': True, + 'services.sync.firstSync': 'notReady', + 'services.sync.lastversion': '1.0', + 'toolkit.startup.max_resumed_crashes': -1, + } + + debug_preferences = { + 'services.sync.log.appender.console': 'Trace', + 'services.sync.log.appender.dump': 'Trace', + 'services.sync.log.appender.file.level': 'Trace', + 'services.sync.log.appender.file.logOnSuccess': True, + 'services.sync.log.rootLogger': 'Trace', + 'services.sync.log.logger.addonutils': 'Trace', + 'services.sync.log.logger.declined': 'Trace', + 'services.sync.log.logger.service.main': 'Trace', + 'services.sync.log.logger.status': 'Trace', + 'services.sync.log.logger.authenticator': 'Trace', + 'services.sync.log.logger.network.resources': 'Trace', + 'services.sync.log.logger.service.jpakeclient': 'Trace', + 'services.sync.log.logger.engine.bookmarks': 'Trace', + 'services.sync.log.logger.engine.clients': 'Trace', + 'services.sync.log.logger.engine.forms': 'Trace', + 'services.sync.log.logger.engine.history': 'Trace', + 'services.sync.log.logger.engine.passwords': 'Trace', + 'services.sync.log.logger.engine.prefs': 'Trace', + 'services.sync.log.logger.engine.tabs': 'Trace', + 'services.sync.log.logger.engine.addons': 'Trace', + 'services.sync.log.logger.engine.apps': 'Trace', + 'services.sync.log.logger.identity': 'Trace', + 'services.sync.log.logger.userapi': 'Trace', + } syncVerRe = re.compile( r'Sync version: (?P<syncversion>.*)\n') @@ -84,32 +107,39 @@ class TPSTestRunner(object): r'Firefox builddate: (?P<ffdate>.*)\n') def __init__(self, extensionDir, - testfile='sync.test', - binary=None, config=None, rlock=None, mobile=False, - logfile='tps.log', resultfile='tps_result.json', - ignore_unused_engines=False): + binary=None, + config=None, + debug=False, + ignore_unused_engines=False, + logfile='tps.log', + mobile=False, + rlock=None, + resultfile='tps_result.json', + testfile=None): + self.binary = binary + self.config = config if config else {} + self.debug = debug self.extensions = [] - self.testfile = testfile + self.ignore_unused_engines = ignore_unused_engines self.logfile = os.path.abspath(logfile) + self.mobile = mobile + self.rlock = rlock self.resultfile = resultfile - self.binary = binary - self.ignore_unused_engines = ignore_unused_engines - self.config = config if config else {} - self.repo = None - self.changeset = None + self.testfile = testfile + + self.addonversion = None self.branch = None + self.changeset = None + self.errorlogs = {} + self.extensionDir = extensionDir + self.firefoxRunner = None + self.nightly = False self.numfailed = 0 self.numpassed = 0 - self.nightly = False - self.rlock = rlock - self.mobile = mobile - self.tpsxpi = None - self.firefoxRunner = None - self.extensionDir = extensionDir - self.productversion = None - self.addonversion = None self.postdata = {} - self.errorlogs = {} + self.productversion = None + self.repo = None + self.tpsxpi = None @property def mobile(self): @@ -301,15 +331,9 @@ class TPSTestRunner(object): return resultdata - def run_tests(self): - # delete the logfile if it already exists - if os.access(self.logfile, os.F_OK): - os.remove(self.logfile) - - # Make a copy of the default env variables and preferences, and update - # them for mobile settings if needed. - self.env = self.default_env.copy() + def update_preferences(self): self.preferences = self.default_preferences.copy() + if self.mobile: self.preferences.update({'services.sync.client.type' : 'mobile'}) @@ -319,6 +343,19 @@ class TPSTestRunner(object): auth_type = self.config.get('auth_type', 'fx_account') self.preferences.update({'services.sync.username': dummy[auth_type]}) + if self.debug: + self.preferences.update(self.debug_preferences) + + def run_tests(self): + # delete the logfile if it already exists + if os.access(self.logfile, os.F_OK): + os.remove(self.logfile) + + # Make a copy of the default env variables and preferences, and update + # them for custom settings + self.env = self.default_env.copy() + self.update_preferences() + # Acquire a lock to make sure no other threads are running tests # at the same time. if self.rlock: diff --git a/toolkit/components/osfile/NativeOSFileInternals.cpp b/toolkit/components/osfile/NativeOSFileInternals.cpp index 71b4caab95847a7937d6a6c561d4f29f98f6002f..ae6ba8106fab084946e587b79601d6e33be48478 100644 --- a/toolkit/components/osfile/NativeOSFileInternals.cpp +++ b/toolkit/components/osfile/NativeOSFileInternals.cpp @@ -46,7 +46,7 @@ #endif // defined (XP_UNIX) #if defined(XP_WIN) -#include <Windows.h> +#include <windows.h> #endif // defined (XP_WIN) namespace mozilla { diff --git a/toolkit/devtools/tests/unit/test_async-utils.js b/toolkit/devtools/tests/unit/test_async-utils.js index ddd2a6426993cb61369d6be15f7af650ad647038..a4a91c831ba63af5753fec6794c02d156acd0ebc 100644 --- a/toolkit/devtools/tests/unit/test_async-utils.js +++ b/toolkit/devtools/tests/unit/test_async-utils.js @@ -7,9 +7,11 @@ const {Task} = Cu.import("resource://gre/modules/Task.jsm", {}); // |const| will not work because // it will make the Promise object immutable before assigning. -// Using |let| and Object.freeze() instead. -let {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); -Object.freeze(Promise); +// Using Object.defineProperty() instead. +Object.defineProperty(this, "Promise", { + value: Cu.import("resource://gre/modules/Promise.jsm", {}).Promise, + writable: false, configurable: false +}); const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools; const {async, asyncOnce, promiseInvoke, promiseCall} = require("devtools/async-utils"); diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index 2f513b2f632f65e57df92a966714ddc4f8d7b731..86d48d69be099f7ec44629c76be23216c10a7ebb 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -233,18 +233,10 @@ ifdef MOZ_METRO OS_LIBS += $(call EXPAND_LIBNAME,uiautomationcore runtimeobject) endif ifdef MOZ_GAMEPAD -ifndef GNU_CC ifdef MOZ_HAS_WINSDK_WITH_D3D -OS_LIBS += dxguid.lib dinput8.lib -else -DXSDK := $(subst \,/,$(MOZ_DIRECTX_SDK_PATH))/Lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX) -OS_LIBS += \ - '$(DXSDK)/dxguid.lib' \ - '$(DXSDK)/dinput8.lib' \ - $(NULL) -endif -else OS_LIBS += $(call EXPAND_LIBNAME,dxguid dinput8) +else +OS_LIBS += $(call EXPAND_LIBNAME_PATH,dxguid dinput8, $(subst \,/,$(MOZ_DIRECTX_SDK_PATH))/Lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)) endif endif endif # WINNT diff --git a/tools/profiler/platform.h b/tools/profiler/platform.h index 9a68f1e4c573fbec39d98072572061ca8b678426..5fb03960dc22f39ff184d1069e715bbb6c2771ea 100644 --- a/tools/profiler/platform.h +++ b/tools/profiler/platform.h @@ -40,6 +40,7 @@ #endif #include <stdint.h> +#include <math.h> #include "mozilla/unused.h" #include "mozilla/TimeStamp.h" #include "mozilla/Mutex.h"