зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-i to m-c
This commit is contained in:
Коммит
3b52fd5e83
|
@ -28,15 +28,6 @@
|
|||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
// converts a screen-global point in the cocoa coordinate system (with origo in the bottom-left corner
|
||||
// of the screen), into a top-left screen point, that gecko can use.
|
||||
static inline void
|
||||
ConvertCocoaToGeckoPoint(NSPoint &aInPoint, nsPoint &aOutPoint)
|
||||
{
|
||||
float mainScreenHeight = [(NSView*)[[NSScreen screens] objectAtIndex:0] frame].size.height;
|
||||
aOutPoint.MoveTo ((nscoord)aInPoint.x, (nscoord)(mainScreenHeight - aInPoint.y));
|
||||
}
|
||||
|
||||
// returns the passed in object if it is not ignored. if it's ignored, will return
|
||||
// the first unignored ancestor.
|
||||
static inline id
|
||||
|
@ -240,19 +231,20 @@ GetClosestInterestingAccessible(id anObject)
|
|||
if (!mGeckoAccessible)
|
||||
return nil;
|
||||
|
||||
// Convert from cocoa's coordinate system to gecko's. According to the docs
|
||||
// the point we're given is guaranteed to be bottom-left screen coordinates.
|
||||
nsPoint geckoPoint;
|
||||
ConvertCocoaToGeckoPoint (point, geckoPoint);
|
||||
// Convert the given screen-global point in the cocoa coordinate system (with
|
||||
// origin in the bottom-left corner of the screen) into point in the Gecko
|
||||
// coordinate system (with origin in a top-left screen point).
|
||||
NSScreen* mainView = [[NSScreen screens] objectAtIndex:0];
|
||||
NSPoint tmpPoint = NSMakePoint(point.x,
|
||||
[mainView frame].size.height - point.y);
|
||||
nsIntPoint geckoPoint = nsCocoaUtils::
|
||||
CocoaPointsToDevPixels(tmpPoint, nsCocoaUtils::GetBackingScaleFactor(mainView));
|
||||
|
||||
nsCOMPtr<nsIAccessible> deepestFoundChild;
|
||||
mGeckoAccessible->GetDeepestChildAtPoint((int32_t)geckoPoint.x,
|
||||
(int32_t)geckoPoint.y,
|
||||
getter_AddRefs(deepestFoundChild));
|
||||
Accessible* child = mGeckoAccessible->ChildAtPoint(geckoPoint.x, geckoPoint.y,
|
||||
Accessible::eDeepestChild);
|
||||
|
||||
// if we found something, return its native accessible.
|
||||
if (deepestFoundChild) {
|
||||
mozAccessible *nativeChild = GetNativeFromGeckoAccessible(deepestFoundChild);
|
||||
if (child) {
|
||||
mozAccessible* nativeChild = GetNativeFromGeckoAccessible(child);
|
||||
if (nativeChild)
|
||||
return GetClosestInterestingAccessible(nativeChild);
|
||||
}
|
||||
|
@ -379,19 +371,16 @@ GetClosestInterestingAccessible(id anObject)
|
|||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
int32_t x, y, width, height;
|
||||
if (!mGeckoAccessible)
|
||||
return nil;
|
||||
|
||||
int32_t x = 0, y = 0, width = 0, height = 0;
|
||||
mGeckoAccessible->GetBounds(&x, &y, &width, &height);
|
||||
NSPoint p = NSMakePoint (x, y);
|
||||
|
||||
// The coords we get from Gecko are top-left screen coordinates.
|
||||
// Cocoa wants us to return bottom-left screen coordinates.
|
||||
// This involves two steps:
|
||||
// 1. Put the rect in the bottom-left coord space
|
||||
// 2. Subtract the height of the rect's Y-coordinate, to make the
|
||||
// the rect's origin (0, 0) be in the bottom-left corner.
|
||||
|
||||
float mainScreenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height;
|
||||
p.y = mainScreenHeight - p.y - height;
|
||||
NSScreen* mainView = [[NSScreen screens] objectAtIndex:0];
|
||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mainView);
|
||||
NSPoint p = NSMakePoint(static_cast<CGFloat>(x) / scaleFactor,
|
||||
[mainView frame].size.height - static_cast<CGFloat>(y + height) / scaleFactor);
|
||||
|
||||
return [NSValue valueWithPoint:p];
|
||||
|
||||
|
@ -402,9 +391,15 @@ GetClosestInterestingAccessible(id anObject)
|
|||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
int32_t x, y, width, height;
|
||||
if (!mGeckoAccessible)
|
||||
return nil;
|
||||
|
||||
int32_t x = 0, y = 0, width = 0, height = 0;
|
||||
mGeckoAccessible->GetBounds (&x, &y, &width, &height);
|
||||
return [NSValue valueWithSize:NSMakeSize (width, height)];
|
||||
CGFloat scaleFactor =
|
||||
nsCocoaUtils::GetBackingScaleFactor([[NSScreen screens] objectAtIndex:0]);
|
||||
return [NSValue valueWithSize:NSMakeSize(static_cast<CGFloat>(width) / scaleFactor,
|
||||
static_cast<CGFloat>(height) / scaleFactor)];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ pref("mozilla.widget.force-24bpp", true);
|
|||
pref("mozilla.widget.use-buffer-pixmap", true);
|
||||
pref("mozilla.widget.disable-native-theme", true);
|
||||
pref("layout.reflow.synthMouseMove", false);
|
||||
pref("layers.enable-tiles", false);
|
||||
pref("layers.enable-tiles", true);
|
||||
/*
|
||||
Cross Process Mutex is not supported on Mac OS X so progressive
|
||||
paint can not be enabled for B2G on Mac OS X desktop
|
||||
|
|
|
@ -1226,7 +1226,7 @@ var diagnosticList = [
|
|||
check: function(frames, symbols, meta) {
|
||||
|
||||
return stepContains('PaintGradient', frames, symbols)
|
||||
&& stepContains('BasicTiledLayerBuffer::PaintThebesSingleBufferDraw', frames, symbols)
|
||||
&& stepContains('ClientTiledLayerBuffer::PaintThebesSingleBufferDraw', frames, symbols)
|
||||
;
|
||||
},
|
||||
},
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<nobr>
|
||||
<h4 contenteditable="true">
|
||||
<iframe></iframe>
|
||||
<applet></applet>
|
||||
<nobr>
|
|
@ -146,5 +146,6 @@ load 849601.html
|
|||
skip-if(Android) load 851353-1.html
|
||||
load 863950.html
|
||||
load 864448.html
|
||||
load 930250.html
|
||||
load 942979.html
|
||||
load 978646.html
|
||||
|
|
|
@ -1264,7 +1264,17 @@ public:
|
|||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
// It may be the case that the element was removed from the
|
||||
// DOM, causing this runnable to be created, then inserted back
|
||||
// into the document before the this runnable had a chance to
|
||||
// tear down the binding. Only tear down the binding if the element
|
||||
// is still no longer in the DOM. nsXBLService::LoadBinding tears
|
||||
// down the old binding if the element is inserted back into the
|
||||
// DOM and loads a different binding.
|
||||
if (!mElement->IsInDoc()) {
|
||||
mManager->RemovedFromDocumentInternal(mElement, mDoc);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "mozilla/dom/TextDecoder.h"
|
||||
#include "mozilla/dom/TouchEvent.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/InternalMutationEvent.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
|
@ -122,7 +123,6 @@
|
|||
#include "nsILineBreaker.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsIMEStateManager.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsINodeInfo.h"
|
||||
|
@ -4324,7 +4324,7 @@ nsContentUtils::DestroyAnonymousContent(nsCOMPtr<Element>* aElement)
|
|||
void
|
||||
nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling)
|
||||
{
|
||||
nsIMEStateManager::OnInstalledMenuKeyboardListener(aInstalling);
|
||||
IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling);
|
||||
}
|
||||
|
||||
static bool SchemeIs(nsIURI* aURI, const char* aScheme)
|
||||
|
|
|
@ -116,7 +116,6 @@ WebGLContext::WebGLContext()
|
|||
mOptionsFrozen = false;
|
||||
|
||||
mActiveTexture = 0;
|
||||
mWebGLError = LOCAL_GL_NO_ERROR;
|
||||
mPixelStoreFlipY = false;
|
||||
mPixelStorePremultiplyAlpha = false;
|
||||
mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
|
||||
|
@ -1289,7 +1288,7 @@ WebGLContext::RobustnessTimerCallback(nsITimer* timer)
|
|||
true);
|
||||
// Set all flags back to the state they were in before the context was
|
||||
// lost.
|
||||
mContextLostErrorSet = false;
|
||||
mEmitContextLostErrorOnce = true;
|
||||
mAllowRestore = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -244,10 +244,6 @@ public:
|
|||
// Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
|
||||
void ClearScreen();
|
||||
|
||||
// checks for GL errors, clears any pending GL error, stores the current GL error in currentGLError (if not nullptr),
|
||||
// and copies it into mWebGLError if it doesn't already have an error set
|
||||
void UpdateWebGLErrorAndClearGLError(GLenum *currentGLError = nullptr);
|
||||
|
||||
bool MinCapabilityMode() const { return mMinCapability; }
|
||||
|
||||
void RobustnessTimerCallback(nsITimer* timer);
|
||||
|
@ -852,7 +848,12 @@ protected:
|
|||
void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
|
||||
|
||||
GLuint mActiveTexture;
|
||||
|
||||
// glGetError sources:
|
||||
bool mEmitContextLostErrorOnce;
|
||||
GLenum mWebGLError;
|
||||
GLenum mUnderlyingGLError;
|
||||
GLenum GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
// whether shader validation is supported
|
||||
bool mShaderValidation;
|
||||
|
@ -895,6 +896,7 @@ protected:
|
|||
// -------------------------------------------------------------------------
|
||||
// WebGL extensions (implemented in WebGLContextExtensions.cpp)
|
||||
enum WebGLExtensionID {
|
||||
EXT_color_buffer_half_float,
|
||||
EXT_frag_depth,
|
||||
EXT_sRGB,
|
||||
EXT_texture_filter_anisotropic,
|
||||
|
@ -905,6 +907,7 @@ protected:
|
|||
OES_texture_half_float,
|
||||
OES_texture_half_float_linear,
|
||||
OES_vertex_array_object,
|
||||
WEBGL_color_buffer_float,
|
||||
WEBGL_compressed_texture_atc,
|
||||
WEBGL_compressed_texture_pvrtc,
|
||||
WEBGL_compressed_texture_s3tc,
|
||||
|
@ -933,7 +936,6 @@ protected:
|
|||
|
||||
nsTArray<GLenum> mCompressedTextureFormats;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// WebGL 2 specifics (implemented in WebGL2Context.cpp)
|
||||
|
||||
|
|
|
@ -485,10 +485,9 @@ WebGLContext::CheckedBufferData(GLenum target,
|
|||
|
||||
bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength();
|
||||
if (sizeChanges) {
|
||||
UpdateWebGLErrorAndClearGLError();
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
gl->fBufferData(target, size, data, usage);
|
||||
GLenum error = LOCAL_GL_NO_ERROR;
|
||||
UpdateWebGLErrorAndClearGLError(&error);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
return error;
|
||||
} else {
|
||||
gl->fBufferData(target, size, data, usage);
|
||||
|
|
|
@ -17,6 +17,7 @@ using namespace mozilla::gl;
|
|||
|
||||
// must match WebGLContext::WebGLExtensionID
|
||||
static const char *sExtensionNames[] = {
|
||||
"EXT_color_buffer_half_float",
|
||||
"EXT_frag_depth",
|
||||
"EXT_sRGB",
|
||||
"EXT_texture_filter_anisotropic",
|
||||
|
@ -27,6 +28,7 @@ static const char *sExtensionNames[] = {
|
|||
"OES_texture_half_float",
|
||||
"OES_texture_half_float_linear",
|
||||
"OES_vertex_array_object",
|
||||
"WEBGL_color_buffer_float",
|
||||
"WEBGL_compressed_texture_atc",
|
||||
"WEBGL_compressed_texture_pvrtc",
|
||||
"WEBGL_compressed_texture_s3tc",
|
||||
|
@ -108,6 +110,10 @@ bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
|
|||
gl->IsSupported(GLFeature::texture_half_float);
|
||||
case OES_texture_half_float_linear:
|
||||
return gl->IsSupported(GLFeature::texture_half_float_linear);
|
||||
case WEBGL_color_buffer_float:
|
||||
return WebGLExtensionColorBufferFloat::IsSupported(this);
|
||||
case EXT_color_buffer_half_float:
|
||||
return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
|
||||
case OES_vertex_array_object:
|
||||
return WebGLExtensionVertexArray::IsSupported(this);
|
||||
case EXT_texture_filter_anisotropic:
|
||||
|
@ -286,6 +292,12 @@ WebGLContext::EnableExtension(WebGLExtensionID ext)
|
|||
case OES_texture_half_float_linear:
|
||||
obj = new WebGLExtensionTextureHalfFloatLinear(this);
|
||||
break;
|
||||
case WEBGL_color_buffer_float:
|
||||
obj = new WebGLExtensionColorBufferFloat(this);
|
||||
break;
|
||||
case EXT_color_buffer_half_float:
|
||||
obj = new WebGLExtensionColorBufferHalfFloat(this);
|
||||
break;
|
||||
case WEBGL_draw_buffers:
|
||||
obj = new WebGLExtensionDrawBuffers(this);
|
||||
break;
|
||||
|
|
|
@ -538,13 +538,12 @@ WebGLContext::CopyTexImage2D(GLenum target,
|
|||
}
|
||||
|
||||
if (sizeMayChange)
|
||||
UpdateWebGLErrorAndClearGLError();
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
CopyTexSubImage2D_base(target, level, internalformat, 0, 0, x, y, width, height, false);
|
||||
|
||||
if (sizeMayChange) {
|
||||
GLenum error = LOCAL_GL_NO_ERROR;
|
||||
UpdateWebGLErrorAndClearGLError(&error);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
|
||||
return;
|
||||
|
@ -902,8 +901,7 @@ WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
|
|||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
|
||||
|
||||
GLenum error = LOCAL_GL_NO_ERROR;
|
||||
UpdateWebGLErrorAndClearGLError();
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
|
||||
nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]);
|
||||
|
@ -917,7 +915,7 @@ WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
|
|||
} else {
|
||||
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW);
|
||||
}
|
||||
UpdateWebGLErrorAndClearGLError(&error);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
|
||||
|
||||
|
@ -1391,8 +1389,47 @@ WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx,
|
|||
return JS::NumberValue(uint32_t(LOCAL_GL_RENDERBUFFER));
|
||||
|
||||
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
|
||||
{
|
||||
return WebGLObjectAsJSValue(cx, fba.Renderbuffer(), rv);
|
||||
|
||||
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: {
|
||||
if (!IsExtensionEnabled(EXT_color_buffer_half_float) &&
|
||||
!IsExtensionEnabled(WEBGL_color_buffer_float))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
ErrorInvalidOperation("getFramebufferAttachmentParameter: Cannot get component"
|
||||
" type of a depth-stencil attachment.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
if (!fba.IsComplete())
|
||||
return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
|
||||
|
||||
uint32_t ret = LOCAL_GL_NONE;
|
||||
switch (fba.Renderbuffer()->InternalFormat()) {
|
||||
case LOCAL_GL_RGBA4:
|
||||
case LOCAL_GL_RGB5_A1:
|
||||
case LOCAL_GL_RGB565:
|
||||
case LOCAL_GL_SRGB8_ALPHA8:
|
||||
ret = LOCAL_GL_UNSIGNED_NORMALIZED;
|
||||
break;
|
||||
case LOCAL_GL_RGB16F:
|
||||
case LOCAL_GL_RGBA16F:
|
||||
case LOCAL_GL_RGB32F:
|
||||
case LOCAL_GL_RGBA32F:
|
||||
ret = LOCAL_GL_FLOAT;
|
||||
break;
|
||||
case LOCAL_GL_DEPTH_COMPONENT16:
|
||||
case LOCAL_GL_STENCIL_INDEX8:
|
||||
ret = LOCAL_GL_UNSIGNED_INT;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unhandled RB component type.");
|
||||
break;
|
||||
}
|
||||
return JS::NumberValue(uint32_t(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1415,20 +1452,58 @@ WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx,
|
|||
return JS::NumberValue(uint32_t(LOCAL_GL_TEXTURE));
|
||||
|
||||
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
|
||||
{
|
||||
return WebGLObjectAsJSValue(cx, fba.Texture(), rv);
|
||||
}
|
||||
|
||||
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
|
||||
return JS::Int32Value(fba.TexImageLevel());
|
||||
|
||||
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
|
||||
{
|
||||
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: {
|
||||
GLenum face = fba.TexImageTarget();
|
||||
if (face == LOCAL_GL_TEXTURE_2D)
|
||||
face = 0;
|
||||
return JS::Int32Value(face);
|
||||
}
|
||||
|
||||
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: {
|
||||
if (!IsExtensionEnabled(EXT_color_buffer_half_float) &&
|
||||
!IsExtensionEnabled(WEBGL_color_buffer_float))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot component"
|
||||
" type of depth-stencil attachments.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
if (!fba.IsComplete())
|
||||
return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
|
||||
|
||||
uint32_t ret = LOCAL_GL_NONE;
|
||||
GLenum type = fba.Texture()->ImageInfoAt(fba.TexImageTarget(),
|
||||
fba.TexImageLevel()).Type();
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
ret = LOCAL_GL_UNSIGNED_NORMALIZED;
|
||||
break;
|
||||
case LOCAL_GL_FLOAT:
|
||||
case LOCAL_GL_HALF_FLOAT_OES:
|
||||
ret = LOCAL_GL_FLOAT;
|
||||
break;
|
||||
case LOCAL_GL_UNSIGNED_SHORT:
|
||||
case LOCAL_GL_UNSIGNED_INT:
|
||||
ret = LOCAL_GL_UNSIGNED_INT;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unhandled RB component type.");
|
||||
break;
|
||||
}
|
||||
return JS::NumberValue(uint32_t(ret));
|
||||
}
|
||||
}
|
||||
|
||||
ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
|
||||
|
@ -1499,19 +1574,53 @@ WebGLContext::CreateTexture()
|
|||
return globj.forget();
|
||||
}
|
||||
|
||||
static GLenum
|
||||
GetAndClearError(GLenum* errorVar)
|
||||
{
|
||||
MOZ_ASSERT(errorVar);
|
||||
GLenum ret = *errorVar;
|
||||
*errorVar = LOCAL_GL_NO_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
GLenum
|
||||
WebGLContext::GetError()
|
||||
{
|
||||
if (mContextStatus == ContextNotLost) {
|
||||
MakeContextCurrent();
|
||||
UpdateWebGLErrorAndClearGLError();
|
||||
} else if (!mContextLostErrorSet) {
|
||||
mWebGLError = LOCAL_GL_CONTEXT_LOST;
|
||||
mContextLostErrorSet = true;
|
||||
/* WebGL 1.0: Section 5.14.3: Setting and getting state:
|
||||
* If the context's webgl context lost flag is set, returns
|
||||
* CONTEXT_LOST_WEBGL the first time this method is called.
|
||||
* Afterward, returns NO_ERROR until the context has been
|
||||
* restored.
|
||||
*
|
||||
* WEBGL_lose_context:
|
||||
* [When this extension is enabled: ] loseContext and
|
||||
* restoreContext are allowed to generate INVALID_OPERATION errors
|
||||
* even when the context is lost.
|
||||
*/
|
||||
|
||||
if (IsContextLost()) {
|
||||
if (mEmitContextLostErrorOnce) {
|
||||
mEmitContextLostErrorOnce = false;
|
||||
return LOCAL_GL_CONTEXT_LOST;
|
||||
}
|
||||
// Don't return yet, since WEBGL_lose_contexts contradicts the
|
||||
// original spec, and allows error generation while lost.
|
||||
}
|
||||
|
||||
GLenum err = mWebGLError;
|
||||
mWebGLError = LOCAL_GL_NO_ERROR;
|
||||
GLenum err = GetAndClearError(&mWebGLError);
|
||||
if (err != LOCAL_GL_NO_ERROR)
|
||||
return err;
|
||||
|
||||
if (IsContextLost())
|
||||
return LOCAL_GL_NO_ERROR;
|
||||
|
||||
// Either no WebGL-side error, or it's already been cleared.
|
||||
// UnderlyingGL-side errors, now.
|
||||
|
||||
MakeContextCurrent();
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
err = GetAndClearError(&mUnderlyingGLError);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -2215,9 +2324,8 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
GLenum type, const Nullable<ArrayBufferView> &pixels,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
if (IsContextLost()) {
|
||||
if (IsContextLost())
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome()) {
|
||||
GenerateWarning("readPixels: Not allowed");
|
||||
|
@ -2255,20 +2363,34 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
int requiredDataType = 0;
|
||||
|
||||
// Check the type param
|
||||
bool isReadTypeValid = false;
|
||||
bool isReadTypeFloat = false;
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
isReadTypeValid = true;
|
||||
bytesPerPixel = 1*channels;
|
||||
requiredDataType = js::ArrayBufferView::TYPE_UINT8;
|
||||
break;
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
isReadTypeValid = true;
|
||||
bytesPerPixel = 2;
|
||||
requiredDataType = js::ArrayBufferView::TYPE_UINT16;
|
||||
break;
|
||||
default:
|
||||
return ErrorInvalidEnum("readPixels: Bad type");
|
||||
case LOCAL_GL_FLOAT:
|
||||
if (IsExtensionEnabled(WEBGL_color_buffer_float) ||
|
||||
IsExtensionEnabled(EXT_color_buffer_half_float))
|
||||
{
|
||||
isReadTypeValid = true;
|
||||
isReadTypeFloat = true;
|
||||
bytesPerPixel = 4*channels;
|
||||
requiredDataType = js::ArrayBufferView::TYPE_FLOAT32;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!isReadTypeValid)
|
||||
return ErrorInvalidEnum("readPixels: Bad type", type);
|
||||
|
||||
int dataType = JS_GetArrayBufferViewType(pixels.Value().Obj());
|
||||
|
||||
|
@ -2298,12 +2420,25 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
return rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
bool isSourceTypeFloat = false;
|
||||
if (mBoundFramebuffer &&
|
||||
mBoundFramebuffer->ColorAttachmentCount() &&
|
||||
mBoundFramebuffer->ColorAttachment(0).IsDefined())
|
||||
{
|
||||
isSourceTypeFloat = mBoundFramebuffer->ColorAttachment(0).IsReadableFloat();
|
||||
}
|
||||
|
||||
if (isReadTypeFloat != isSourceTypeFloat)
|
||||
return ErrorInvalidOperation("readPixels: Invalid type floatness");
|
||||
|
||||
// Check the format and type params to assure they are an acceptable pair (as per spec)
|
||||
switch (format) {
|
||||
case LOCAL_GL_RGBA: {
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
break;
|
||||
case LOCAL_GL_FLOAT:
|
||||
break;
|
||||
default:
|
||||
return ErrorInvalidOperation("readPixels: Invalid format/type pair");
|
||||
}
|
||||
|
@ -2431,6 +2566,20 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
rowp += 4;
|
||||
}
|
||||
|
||||
row += checked_alignedRowSize.value();
|
||||
}
|
||||
} else if (format == LOCAL_GL_RGBA && type == LOCAL_GL_FLOAT) {
|
||||
float* row = static_cast<float*>(data);
|
||||
|
||||
for (GLint j = 0; j < height; ++j) {
|
||||
float* pAlpha = row + 3;
|
||||
float* pAlphaEnd = pAlpha + 4*width;
|
||||
|
||||
while (pAlpha != pAlphaEnd) {
|
||||
*pAlpha = 1.0f;
|
||||
pAlpha += 4;
|
||||
}
|
||||
|
||||
row += checked_alignedRowSize.value();
|
||||
}
|
||||
} else {
|
||||
|
@ -2486,6 +2635,22 @@ WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei
|
|||
break;
|
||||
case LOCAL_GL_SRGB8_ALPHA8_EXT:
|
||||
break;
|
||||
case LOCAL_GL_RGB16F:
|
||||
case LOCAL_GL_RGBA16F: {
|
||||
bool hasExtensions = IsExtensionEnabled(OES_texture_half_float) &&
|
||||
IsExtensionEnabled(EXT_color_buffer_half_float);
|
||||
if (!hasExtensions)
|
||||
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", target);
|
||||
break;
|
||||
}
|
||||
case LOCAL_GL_RGB32F:
|
||||
case LOCAL_GL_RGBA32F: {
|
||||
bool hasExtensions = IsExtensionEnabled(OES_texture_float) &&
|
||||
IsExtensionEnabled(WEBGL_color_buffer_float);
|
||||
if (!hasExtensions)
|
||||
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", target);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
|
||||
}
|
||||
|
@ -2496,10 +2661,9 @@ WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei
|
|||
height != mBoundRenderbuffer->Height() ||
|
||||
internalformat != mBoundRenderbuffer->InternalFormat();
|
||||
if (sizeChanges) {
|
||||
UpdateWebGLErrorAndClearGLError();
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
|
||||
GLenum error = LOCAL_GL_NO_ERROR;
|
||||
UpdateWebGLErrorAndClearGLError(&error);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
GenerateWarning("renderbufferStorage generated error %s", ErrorName(error));
|
||||
return;
|
||||
|
@ -3632,12 +3796,11 @@ GLenum WebGLContext::CheckedTexImage2D(GLenum target,
|
|||
}
|
||||
|
||||
if (sizeMayChange) {
|
||||
UpdateWebGLErrorAndClearGLError();
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
gl->fTexImage2D(target, level, internalFormat, width, height, border, format, realType, data);
|
||||
|
||||
GLenum error = LOCAL_GL_NO_ERROR;
|
||||
UpdateWebGLErrorAndClearGLError(&error);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -3881,8 +4044,13 @@ WebGLContext::TexSubImage2D_base(GLenum target, GLint level,
|
|||
|
||||
// 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) {
|
||||
if (gl->IsSupported(gl::GLFeature::texture_half_float)) {
|
||||
realType = LOCAL_GL_HALF_FLOAT;
|
||||
} else {
|
||||
MOZ_ASSERT(gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
|
||||
}
|
||||
}
|
||||
|
||||
if (actualSrcFormat == dstFormat &&
|
||||
srcPremultiplied == mPixelStorePremultiplyAlpha &&
|
||||
|
|
|
@ -106,15 +106,12 @@ WebGLContext::GetImageSize(GLsizei height,
|
|||
void
|
||||
WebGLContext::SynthesizeGLError(GLenum err)
|
||||
{
|
||||
// If there is already a pending error, don't overwrite it;
|
||||
// but if there isn't, then we need to check for a gl error
|
||||
// that may have occurred before this one and use that code
|
||||
// instead.
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
UpdateWebGLErrorAndClearGLError();
|
||||
|
||||
/* ES2 section 2.5 "GL Errors" states that implementations can have
|
||||
* multiple 'flags', as errors might be caught in different parts of
|
||||
* a distributed implementation.
|
||||
* We're signing up as a distributed implementation here, with
|
||||
* separate flags for WebGL and the underlying GLContext.
|
||||
*/
|
||||
if (!mWebGLError)
|
||||
mWebGLError = err;
|
||||
}
|
||||
|
@ -234,14 +231,16 @@ WebGLContext::IsTextureFormatCompressed(GLenum format)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::UpdateWebGLErrorAndClearGLError(GLenum *currentGLError)
|
||||
GLenum
|
||||
WebGLContext::GetAndFlushUnderlyingGLErrors()
|
||||
{
|
||||
// get and clear GL error in ALL cases
|
||||
// Get and clear GL error in ALL cases.
|
||||
GLenum error = gl->GetAndClearError();
|
||||
if (currentGLError)
|
||||
*currentGLError = error;
|
||||
// only store in mWebGLError if is hasn't already recorded an error
|
||||
if (!mWebGLError)
|
||||
mWebGLError = error;
|
||||
|
||||
// Only store in mUnderlyingGLError if is hasn't already recorded an
|
||||
// error.
|
||||
if (!mUnderlyingGLError)
|
||||
mUnderlyingGLError = error;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -1586,7 +1586,9 @@ WebGLContext::InitAndValidateGL()
|
|||
}
|
||||
|
||||
mActiveTexture = 0;
|
||||
mEmitContextLostErrorOnce = true;
|
||||
mWebGLError = LOCAL_GL_NO_ERROR;
|
||||
mUnderlyingGLError = LOCAL_GL_NO_ERROR;
|
||||
|
||||
mBound2DTextures.Clear();
|
||||
mBoundCubeMapTextures.Clear();
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/* 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 "WebGLExtensions.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "WebGLContext.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
WebGLExtensionColorBufferFloat::WebGLExtensionColorBufferFloat(WebGLContext* context)
|
||||
: WebGLExtensionBase(context)
|
||||
{
|
||||
MOZ_ASSERT(IsSupported(context));
|
||||
}
|
||||
|
||||
WebGLExtensionColorBufferFloat::~WebGLExtensionColorBufferFloat()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLExtensionColorBufferFloat::IsSupported(const WebGLContext* context)
|
||||
{
|
||||
return context->GL()->IsSupported(gl::GLFeature::renderbuffer_color_float) &&
|
||||
context->GL()->IsSupported(gl::GLFeature::frag_color_float);
|
||||
}
|
||||
|
||||
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionColorBufferFloat)
|
|
@ -0,0 +1,30 @@
|
|||
/* 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 "WebGLExtensions.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "WebGLContext.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
WebGLExtensionColorBufferHalfFloat::WebGLExtensionColorBufferHalfFloat(WebGLContext* context)
|
||||
: WebGLExtensionBase(context)
|
||||
{
|
||||
MOZ_ASSERT(IsSupported(context));
|
||||
}
|
||||
|
||||
WebGLExtensionColorBufferHalfFloat::~WebGLExtensionColorBufferHalfFloat()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLExtensionColorBufferHalfFloat::IsSupported(const WebGLContext* context)
|
||||
{
|
||||
return context->GL()->IsSupported(gl::GLFeature::renderbuffer_color_half_float) &&
|
||||
context->GL()->IsSupported(gl::GLFeature::frag_color_float);
|
||||
}
|
||||
|
||||
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionColorBufferHalfFloat)
|
|
@ -6,9 +6,17 @@
|
|||
#ifndef WEBGLEXTENSIONS_H_
|
||||
#define WEBGLEXTENSIONS_H_
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "WebGLObjectModel.h"
|
||||
#include "WebGLTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLContext;
|
||||
class WebGLShader;
|
||||
class WebGLVertexArray;
|
||||
|
||||
class WebGLExtensionBase
|
||||
: public nsWrapperCache
|
||||
|
@ -205,6 +213,30 @@ public:
|
|||
DECL_WEBGL_EXTENSION_GOOP
|
||||
};
|
||||
|
||||
class WebGLExtensionColorBufferFloat
|
||||
: public WebGLExtensionBase
|
||||
{
|
||||
public:
|
||||
WebGLExtensionColorBufferFloat(WebGLContext*);
|
||||
virtual ~WebGLExtensionColorBufferFloat();
|
||||
|
||||
static bool IsSupported(const WebGLContext*);
|
||||
|
||||
DECL_WEBGL_EXTENSION_GOOP
|
||||
};
|
||||
|
||||
class WebGLExtensionColorBufferHalfFloat
|
||||
: public WebGLExtensionBase
|
||||
{
|
||||
public:
|
||||
WebGLExtensionColorBufferHalfFloat(WebGLContext*);
|
||||
virtual ~WebGLExtensionColorBufferHalfFloat();
|
||||
|
||||
static bool IsSupported(const WebGLContext*);
|
||||
|
||||
DECL_WEBGL_EXTENSION_GOOP
|
||||
};
|
||||
|
||||
class WebGLExtensionDrawBuffers
|
||||
: public WebGLExtensionBase
|
||||
{
|
||||
|
|
|
@ -60,6 +60,35 @@ WebGLFramebuffer::Attachment::HasAlpha() const
|
|||
return FormatHasAlpha(format);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLFramebuffer::Attachment::IsReadableFloat() const
|
||||
{
|
||||
if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) {
|
||||
GLenum type = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).Type();
|
||||
switch (type) {
|
||||
case LOCAL_GL_FLOAT:
|
||||
case LOCAL_GL_HALF_FLOAT_OES:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Renderbuffer()) {
|
||||
GLenum format = Renderbuffer()->InternalFormat();
|
||||
switch (format) {
|
||||
case LOCAL_GL_RGB16F:
|
||||
case LOCAL_GL_RGBA16F:
|
||||
case LOCAL_GL_RGB32F:
|
||||
case LOCAL_GL_RGBA32F:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "Should not get here.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level)
|
||||
{
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
bool IsDeleteRequested() const;
|
||||
|
||||
bool HasAlpha() const;
|
||||
bool IsReadableFloat() const;
|
||||
|
||||
void SetTexImage(WebGLTexture* tex, GLenum target, GLint level);
|
||||
void SetRenderbuffer(WebGLRenderbuffer* rb) {
|
||||
|
|
|
@ -113,6 +113,18 @@ WebGLRenderbuffer::MemoryUsage() const {
|
|||
case LOCAL_GL_DEPTH_COMPONENT32:
|
||||
primarySize = 4*pixels;
|
||||
break;
|
||||
case LOCAL_GL_RGB16F:
|
||||
primarySize = 2*3*pixels;
|
||||
break;
|
||||
case LOCAL_GL_RGBA16F:
|
||||
primarySize = 2*4*pixels;
|
||||
break;
|
||||
case LOCAL_GL_RGB32F:
|
||||
primarySize = 4*3*pixels;
|
||||
break;
|
||||
case LOCAL_GL_RGBA32F:
|
||||
primarySize = 4*4*pixels;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unknown `primaryFormat`.");
|
||||
break;
|
||||
|
|
|
@ -49,8 +49,8 @@ int64_t
|
|||
WebGLTexture::ImageInfo::MemoryUsage() const {
|
||||
if (mImageDataStatus == WebGLImageDataStatus::NoImageData)
|
||||
return 0;
|
||||
int64_t texelSizeInBits = WebGLContext::GetBitsPerTexel(mInternalFormat, mType);
|
||||
return int64_t(mWidth) * int64_t(mHeight) * texelSizeInBits / 8;
|
||||
int64_t bitsPerTexel = WebGLContext::GetBitsPerTexel(mInternalFormat, mType);
|
||||
return int64_t(mWidth) * int64_t(mHeight) * bitsPerTexel/8;
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -451,13 +451,12 @@ WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level)
|
|||
void *zeros = calloc(1, checked_byteLength.value());
|
||||
|
||||
GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat);
|
||||
mContext->UpdateWebGLErrorAndClearGLError();
|
||||
mContext->GetAndFlushUnderlyingGLErrors();
|
||||
mContext->gl->fTexImage2D(imageTarget, level, imageInfo.mInternalFormat,
|
||||
imageInfo.mWidth, imageInfo.mHeight,
|
||||
0, format, imageInfo.mType,
|
||||
zeros);
|
||||
GLenum error = LOCAL_GL_NO_ERROR;
|
||||
mContext->UpdateWebGLErrorAndClearGLError(&error);
|
||||
GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
free(zeros);
|
||||
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
|
|
|
@ -44,6 +44,8 @@ if CONFIG['MOZ_WEBGL']:
|
|||
'WebGLContextVertices.cpp',
|
||||
'WebGLElementArrayCache.cpp',
|
||||
'WebGLExtensionBase.cpp',
|
||||
'WebGLExtensionColorBufferFloat.cpp',
|
||||
'WebGLExtensionColorBufferHalfFloat.cpp',
|
||||
'WebGLExtensionCompressedTextureATC.cpp',
|
||||
'WebGLExtensionCompressedTexturePVRTC.cpp',
|
||||
'WebGLExtensionCompressedTextureS3TC.cpp',
|
||||
|
|
|
@ -147,7 +147,7 @@ var files = [
|
|||
frames: 33297,
|
||||
sampleRate: 48000,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 3,
|
||||
fuzzTolerance: 5,
|
||||
fuzzToleranceMobile: 1388
|
||||
},
|
||||
// An ogg file, 48khz, stereo
|
||||
|
|
|
@ -56,7 +56,7 @@ void EbmlComposer::GenerateHeader()
|
|||
}
|
||||
// The Recording length is unknow and ignore write the whole Segment element size
|
||||
}
|
||||
MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(),
|
||||
MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(),
|
||||
"write more data > EBML_BUFFER_SIZE");
|
||||
mClusterBuffs.AppendElement();
|
||||
mClusterBuffs.LastElement().SetLength(ebml.offset);
|
||||
|
@ -117,7 +117,7 @@ EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame)
|
|||
0, 0, (unsigned char*)aFrame->GetFrameData().Elements(),
|
||||
aFrame->GetFrameData().Length());
|
||||
}
|
||||
MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + aFrame->GetFrameData().Length(),
|
||||
MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + aFrame->GetFrameData().Length(),
|
||||
"write more data > EBML_BUFFER_SIZE");
|
||||
mClusterBuffs.LastElement().SetLength(ebml.offset);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "nsFrameTraversal.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsEventStateManager.h"
|
||||
#include "nsIMEStateManager.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsCaret.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
|
@ -41,6 +40,7 @@
|
|||
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
@ -933,7 +933,7 @@ nsFocusManager::WindowHidden(nsIDOMWindow* aWindow)
|
|||
|
||||
nsPresContext* focusedPresContext =
|
||||
presShell ? presShell->GetPresContext() : nullptr;
|
||||
nsIMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
|
||||
IMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
|
||||
GetFocusMoveActionCause(0));
|
||||
if (presShell) {
|
||||
SetCaretVisible(presShell, false, nullptr);
|
||||
|
@ -1529,7 +1529,7 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
|
|||
|
||||
nsPresContext* focusedPresContext =
|
||||
mActiveWindow ? presShell->GetPresContext() : nullptr;
|
||||
nsIMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
|
||||
IMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
|
||||
GetFocusMoveActionCause(0));
|
||||
|
||||
// now adjust the actual focus, by clearing the fields in the focus manager
|
||||
|
@ -1746,11 +1746,11 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
|
|||
// document and then the window.
|
||||
if (aIsNewDocument) {
|
||||
nsIDocument* doc = aWindow->GetExtantDoc();
|
||||
// The focus change should be notified to nsIMEStateManager from here if
|
||||
// The focus change should be notified to IMEStateManager from here if
|
||||
// the focused content is a designMode editor since any content won't
|
||||
// receive focus event.
|
||||
if (doc && doc->HasFlag(NODE_IS_EDITABLE)) {
|
||||
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr,
|
||||
IMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr,
|
||||
GetFocusMoveActionCause(aFlags));
|
||||
}
|
||||
if (doc)
|
||||
|
@ -1796,7 +1796,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
|
|||
}
|
||||
}
|
||||
|
||||
nsIMEStateManager::OnChangeFocus(presContext, aContent,
|
||||
IMEStateManager::OnChangeFocus(presContext, aContent,
|
||||
GetFocusMoveActionCause(aFlags));
|
||||
|
||||
// as long as this focus wasn't because a window was raised, update the
|
||||
|
@ -1810,7 +1810,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
|
|||
aContent, aFlags & FOCUSMETHOD_MASK,
|
||||
aWindowRaised, isRefocus);
|
||||
} else {
|
||||
nsIMEStateManager::OnChangeFocus(presContext, nullptr,
|
||||
IMEStateManager::OnChangeFocus(presContext, nullptr,
|
||||
GetFocusMoveActionCause(aFlags));
|
||||
if (!aWindowRaised) {
|
||||
aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
|
||||
|
@ -1834,7 +1834,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
|
|||
}
|
||||
|
||||
nsPresContext* presContext = presShell->GetPresContext();
|
||||
nsIMEStateManager::OnChangeFocus(presContext, nullptr,
|
||||
IMEStateManager::OnChangeFocus(presContext, nullptr,
|
||||
GetFocusMoveActionCause(aFlags));
|
||||
|
||||
if (!aWindowRaised)
|
||||
|
|
|
@ -24,11 +24,24 @@ using namespace mozilla;
|
|||
|
||||
StaticRefPtr<nsWindowMemoryReporter> sWindowReporter;
|
||||
|
||||
/**
|
||||
* Don't trigger a ghost window check when a DOM window is detached if we've
|
||||
* run it this recently.
|
||||
*/
|
||||
const int32_t kTimeBetweenChecks = 45; /* seconds */
|
||||
|
||||
nsWindowMemoryReporter::nsWindowMemoryReporter()
|
||||
: mCheckForGhostWindowsCallbackPending(false)
|
||||
: mLastCheckForGhostWindows(TimeStamp::NowLoRes()),
|
||||
mCycleCollectorIsRunning(false),
|
||||
mCheckTimerWaitingForCCEnd(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsWindowMemoryReporter::~nsWindowMemoryReporter()
|
||||
{
|
||||
KillCheckTimer();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS3(nsWindowMemoryReporter, nsIMemoryReporter, nsIObserver,
|
||||
nsSupportsWeakReference)
|
||||
|
||||
|
@ -105,6 +118,10 @@ nsWindowMemoryReporter::Init()
|
|||
/* weakRef = */ true);
|
||||
os->AddObserver(sWindowReporter, "after-minimize-memory-usage",
|
||||
/* weakRef = */ true);
|
||||
os->AddObserver(sWindowReporter, "cycle-collector-begin",
|
||||
/* weakRef = */ true);
|
||||
os->AddObserver(sWindowReporter, "cycle-collector-end",
|
||||
/* weakRef = */ true);
|
||||
}
|
||||
|
||||
RegisterStrongMemoryReporter(new GhostWindowsReporter());
|
||||
|
@ -608,6 +625,18 @@ nsWindowMemoryReporter::Observe(nsISupports *aSubject, const char *aTopic,
|
|||
ObserveDOMWindowDetached(aSubject);
|
||||
} else if (!strcmp(aTopic, "after-minimize-memory-usage")) {
|
||||
ObserveAfterMinimizeMemoryUsage();
|
||||
} else if (!strcmp(aTopic, "cycle-collector-begin")) {
|
||||
if (mCheckTimer) {
|
||||
mCheckTimerWaitingForCCEnd = true;
|
||||
KillCheckTimer();
|
||||
}
|
||||
mCycleCollectorIsRunning = true;
|
||||
} else if (!strcmp(aTopic, "cycle-collector-end")) {
|
||||
mCycleCollectorIsRunning = false;
|
||||
if (mCheckTimerWaitingForCCEnd) {
|
||||
mCheckTimerWaitingForCCEnd = false;
|
||||
AsyncCheckForGhostWindows();
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(false);
|
||||
}
|
||||
|
@ -626,12 +655,44 @@ nsWindowMemoryReporter::ObserveDOMWindowDetached(nsISupports* aWindow)
|
|||
|
||||
mDetachedWindows.Put(weakWindow, TimeStamp());
|
||||
|
||||
if (!mCheckForGhostWindowsCallbackPending) {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this,
|
||||
&nsWindowMemoryReporter::CheckForGhostWindowsCallback);
|
||||
NS_DispatchToCurrentThread(runnable);
|
||||
mCheckForGhostWindowsCallbackPending = true;
|
||||
AsyncCheckForGhostWindows();
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsWindowMemoryReporter::CheckTimerFired(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
if (sWindowReporter) {
|
||||
MOZ_ASSERT(!sWindowReporter->mCycleCollectorIsRunning);
|
||||
sWindowReporter->CheckForGhostWindows();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsWindowMemoryReporter::AsyncCheckForGhostWindows()
|
||||
{
|
||||
if (mCheckTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCycleCollectorIsRunning) {
|
||||
mCheckTimerWaitingForCCEnd = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// If more than kTimeBetweenChecks seconds have elapsed since the last check,
|
||||
// timerDelay is 0. Otherwise, it is kTimeBetweenChecks, reduced by the time
|
||||
// since the last check. Reducing the delay by the time since the last check
|
||||
// prevents the timer from being completely starved if it is repeatedly killed
|
||||
// and restarted.
|
||||
int32_t timeSinceLastCheck = (TimeStamp::NowLoRes() - mLastCheckForGhostWindows).ToSeconds();
|
||||
int32_t timerDelay = (kTimeBetweenChecks - std::min(timeSinceLastCheck, kTimeBetweenChecks)) * PR_MSEC_PER_SEC;
|
||||
|
||||
CallCreateInstance<nsITimer>("@mozilla.org/timer;1", getter_AddRefs(mCheckTimer));
|
||||
|
||||
if (mCheckTimer) {
|
||||
mCheckTimer->InitWithFuncCallback(CheckTimerFired, nullptr,
|
||||
timerDelay, nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -664,13 +725,6 @@ nsWindowMemoryReporter::ObserveAfterMinimizeMemoryUsage()
|
|||
&minTimeStamp);
|
||||
}
|
||||
|
||||
void
|
||||
nsWindowMemoryReporter::CheckForGhostWindowsCallback()
|
||||
{
|
||||
mCheckForGhostWindowsCallbackPending = false;
|
||||
CheckForGhostWindows();
|
||||
}
|
||||
|
||||
struct CheckForGhostWindowsEnumeratorData
|
||||
{
|
||||
nsTHashtable<nsCStringHashKey> *nonDetachedDomains;
|
||||
|
@ -808,6 +862,9 @@ nsWindowMemoryReporter::CheckForGhostWindows(
|
|||
return;
|
||||
}
|
||||
|
||||
mLastCheckForGhostWindows = TimeStamp::NowLoRes();
|
||||
KillCheckTimer();
|
||||
|
||||
nsTHashtable<nsCStringHashKey> nonDetachedWindowDomains;
|
||||
|
||||
// Populate nonDetachedWindowDomains.
|
||||
|
@ -820,7 +877,7 @@ nsWindowMemoryReporter::CheckForGhostWindows(
|
|||
// if it's not null.
|
||||
CheckForGhostWindowsEnumeratorData ghostEnumData =
|
||||
{ &nonDetachedWindowDomains, aOutGhostIDs, tldService,
|
||||
GetGhostTimeout(), TimeStamp::Now() };
|
||||
GetGhostTimeout(), mLastCheckForGhostWindows };
|
||||
mDetachedWindows.Enumerate(CheckForGhostWindowsEnumerator,
|
||||
&ghostEnumData);
|
||||
}
|
||||
|
@ -836,6 +893,15 @@ nsWindowMemoryReporter::GhostWindowsReporter::DistinguishedAmount()
|
|||
return ghostWindows.Count();
|
||||
}
|
||||
|
||||
void
|
||||
nsWindowMemoryReporter::KillCheckTimer()
|
||||
{
|
||||
if (mCheckTimer) {
|
||||
mCheckTimer->Cancel();
|
||||
mCheckTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static PLDHashOperator
|
||||
UnlinkGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void *)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
@ -139,6 +140,8 @@ public:
|
|||
|
||||
static void Init();
|
||||
|
||||
~nsWindowMemoryReporter();
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Unlink all known ghost windows, to enable investigating what caused them
|
||||
|
@ -187,13 +190,6 @@ private:
|
|||
void ObserveDOMWindowDetached(nsISupports* aWindow);
|
||||
void ObserveAfterMinimizeMemoryUsage();
|
||||
|
||||
/**
|
||||
* When we observe a DOM window being detached, we enqueue an asynchronous
|
||||
* event which calls this method. This method then calls
|
||||
* CheckForGhostWindows.
|
||||
*/
|
||||
void CheckForGhostWindowsCallback();
|
||||
|
||||
/**
|
||||
* Iterate over all weak window pointers in mDetachedWindows and update our
|
||||
* accounting of which windows meet ghost criterion (2).
|
||||
|
@ -209,6 +205,19 @@ private:
|
|||
*/
|
||||
void CheckForGhostWindows(nsTHashtable<nsUint64HashKey> *aOutGhostIDs = nullptr);
|
||||
|
||||
/**
|
||||
* Eventually do a check for ghost windows, if we haven't done one recently
|
||||
* and we aren't already planning to do one soon.
|
||||
*/
|
||||
void AsyncCheckForGhostWindows();
|
||||
|
||||
/**
|
||||
* Kill the check timer, if it exists.
|
||||
*/
|
||||
void KillCheckTimer();
|
||||
|
||||
static void CheckTimerFired(nsITimer* aTimer, void* aClosure);
|
||||
|
||||
/**
|
||||
* Maps a weak reference to a detached window (nsIWeakReference) to the time
|
||||
* when we observed that the window met ghost criterion (2) above.
|
||||
|
@ -222,9 +231,16 @@ private:
|
|||
nsDataHashtable<nsISupportsHashKey, mozilla::TimeStamp> mDetachedWindows;
|
||||
|
||||
/**
|
||||
* True if we have an asynchronous call to CheckForGhostWindows pending.
|
||||
* Track the last time we ran CheckForGhostWindows(), to avoid running it
|
||||
* too often after a DOM window is detached.
|
||||
*/
|
||||
bool mCheckForGhostWindowsCallbackPending;
|
||||
mozilla::TimeStamp mLastCheckForGhostWindows;
|
||||
|
||||
nsCOMPtr<nsITimer> mCheckTimer;
|
||||
|
||||
bool mCycleCollectorIsRunning;
|
||||
|
||||
bool mCheckTimerWaitingForCCEnd;
|
||||
};
|
||||
|
||||
#endif // nsWindowMemoryReporter_h__
|
||||
|
|
|
@ -1342,6 +1342,16 @@ DOMInterfaces = {
|
|||
'headerFile': 'WebGLExtensions.h'
|
||||
},
|
||||
|
||||
'WebGLExtensionColorBufferFloat': {
|
||||
'nativeType': 'mozilla::WebGLExtensionColorBufferFloat',
|
||||
'headerFile': 'WebGLExtensions.h'
|
||||
},
|
||||
|
||||
'WebGLExtensionColorBufferHalfFloat': {
|
||||
'nativeType': 'mozilla::WebGLExtensionColorBufferHalfFloat',
|
||||
'headerFile': 'WebGLExtensions.h'
|
||||
},
|
||||
|
||||
'WebGLExtensionDrawBuffers': {
|
||||
'nativeType': 'mozilla::WebGLExtensionDrawBuffers',
|
||||
'headerFile': 'WebGLExtensions.h'
|
||||
|
|
|
@ -0,0 +1,537 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et 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 "IMEContentObserver.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsAsyncDOMEvent.h"
|
||||
#include "nsContentEventHandler.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "TextComposition.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace widget;
|
||||
|
||||
NS_IMPL_ISUPPORTS5(IMEContentObserver,
|
||||
nsIMutationObserver,
|
||||
nsISelectionListener,
|
||||
nsIReflowObserver,
|
||||
nsIScrollObserver,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
IMEContentObserver::IMEContentObserver()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::Init(nsIWidget* aWidget,
|
||||
nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
mWidget = aWidget;
|
||||
mEditableNode = IMEStateManager::GetRootEditableNode(aPresContext, aContent);
|
||||
if (!mEditableNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIPresShell* presShell = aPresContext->PresShell();
|
||||
|
||||
// get selection and root content
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
if (mEditableNode->IsNodeOfType(nsINode::eCONTENT)) {
|
||||
nsIFrame* frame =
|
||||
static_cast<nsIContent*>(mEditableNode.get())->GetPrimaryFrame();
|
||||
NS_ENSURE_TRUE_VOID(frame);
|
||||
|
||||
frame->GetSelectionController(aPresContext,
|
||||
getter_AddRefs(selCon));
|
||||
} else {
|
||||
// mEditableNode is a document
|
||||
selCon = do_QueryInterface(presShell);
|
||||
}
|
||||
NS_ENSURE_TRUE_VOID(selCon);
|
||||
|
||||
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
||||
getter_AddRefs(mSelection));
|
||||
NS_ENSURE_TRUE_VOID(mSelection);
|
||||
|
||||
nsCOMPtr<nsIDOMRange> selDomRange;
|
||||
if (NS_SUCCEEDED(mSelection->GetRangeAt(0, getter_AddRefs(selDomRange)))) {
|
||||
nsRange* selRange = static_cast<nsRange*>(selDomRange.get());
|
||||
NS_ENSURE_TRUE_VOID(selRange && selRange->GetStartParent());
|
||||
|
||||
mRootContent = selRange->GetStartParent()->
|
||||
GetSelectionRootContent(presShell);
|
||||
} else {
|
||||
mRootContent = mEditableNode->GetSelectionRootContent(presShell);
|
||||
}
|
||||
if (!mRootContent && mEditableNode->IsNodeOfType(nsINode::eDOCUMENT)) {
|
||||
// The document node is editable, but there are no contents, this document
|
||||
// is not editable.
|
||||
return;
|
||||
}
|
||||
NS_ENSURE_TRUE_VOID(mRootContent);
|
||||
|
||||
if (IMEStateManager::IsTestingIME()) {
|
||||
nsIDocument* doc = aPresContext->Document();
|
||||
(new nsAsyncDOMEvent(doc, NS_LITERAL_STRING("MozIMEFocusIn"),
|
||||
false, false))->RunDOMEventWhenSafe();
|
||||
}
|
||||
|
||||
aWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS));
|
||||
|
||||
// NOTIFY_IME_OF_FOCUS might cause recreating IMEContentObserver
|
||||
// instance via IMEStateManager::UpdateIMEState(). So, this
|
||||
// instance might already have been destroyed, check it.
|
||||
if (!mRootContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDocShell = aPresContext->GetDocShell();
|
||||
|
||||
ObserveEditableNode();
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::ObserveEditableNode()
|
||||
{
|
||||
MOZ_ASSERT(mSelection);
|
||||
MOZ_ASSERT(mRootContent);
|
||||
|
||||
mUpdatePreference = mWidget->GetIMEUpdatePreference();
|
||||
if (mUpdatePreference.WantSelectionChange()) {
|
||||
// add selection change listener
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
|
||||
NS_ENSURE_TRUE_VOID(selPrivate);
|
||||
nsresult rv = selPrivate->AddSelectionListener(this);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}
|
||||
|
||||
if (mUpdatePreference.WantTextChange()) {
|
||||
// add text change observer
|
||||
mRootContent->AddMutationObserver(this);
|
||||
}
|
||||
|
||||
if (mUpdatePreference.WantPositionChanged() && mDocShell) {
|
||||
// Add scroll position listener and reflow observer to detect position and
|
||||
// size changes
|
||||
mDocShell->AddWeakScrollObserver(this);
|
||||
mDocShell->AddWeakReflowObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::Destroy()
|
||||
{
|
||||
// If CreateTextStateManager failed, mRootContent will be null,
|
||||
// and we should not call NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR))
|
||||
if (mRootContent) {
|
||||
if (IMEStateManager::IsTestingIME() && mEditableNode) {
|
||||
nsIDocument* doc = mEditableNode->OwnerDoc();
|
||||
(new nsAsyncDOMEvent(doc, NS_LITERAL_STRING("MozIMEFocusOut"),
|
||||
false, false))->RunDOMEventWhenSafe();
|
||||
}
|
||||
mWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
|
||||
}
|
||||
// Even if there are some pending notification, it'll never notify the widget.
|
||||
mWidget = nullptr;
|
||||
if (mUpdatePreference.WantSelectionChange() && mSelection) {
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
|
||||
if (selPrivate) {
|
||||
selPrivate->RemoveSelectionListener(this);
|
||||
}
|
||||
}
|
||||
mSelection = nullptr;
|
||||
if (mUpdatePreference.WantTextChange() && mRootContent) {
|
||||
mRootContent->RemoveMutationObserver(this);
|
||||
}
|
||||
if (mUpdatePreference.WantPositionChanged() && mDocShell) {
|
||||
mDocShell->RemoveWeakScrollObserver(this);
|
||||
mDocShell->RemoveWeakReflowObserver(this);
|
||||
}
|
||||
mRootContent = nullptr;
|
||||
mEditableNode = nullptr;
|
||||
mDocShell = nullptr;
|
||||
mUpdatePreference.mWantUpdates = nsIMEUpdatePreference::NOTIFY_NOTHING;
|
||||
}
|
||||
|
||||
bool
|
||||
IMEContentObserver::IsManaging(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
if (!mSelection || !mRootContent || !mEditableNode) {
|
||||
return false; // failed to initialize.
|
||||
}
|
||||
if (!mRootContent->IsInDoc()) {
|
||||
return false; // the focused editor has already been reframed.
|
||||
}
|
||||
return mEditableNode == IMEStateManager::GetRootEditableNode(aPresContext,
|
||||
aContent);
|
||||
}
|
||||
|
||||
bool
|
||||
IMEContentObserver::IsEditorHandlingEventForComposition() const
|
||||
{
|
||||
if (!mWidget) {
|
||||
return false;
|
||||
}
|
||||
nsRefPtr<TextComposition> composition =
|
||||
IMEStateManager::GetTextCompositionFor(mWidget);
|
||||
if (!composition) {
|
||||
return false;
|
||||
}
|
||||
return composition->IsEditorHandlingEvent();
|
||||
}
|
||||
|
||||
nsresult
|
||||
IMEContentObserver::GetSelectionAndRoot(nsISelection** aSelection,
|
||||
nsIContent** aRootContent) const
|
||||
{
|
||||
if (!mEditableNode || !mSelection) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mSelection && mRootContent, "uninitialized content observer");
|
||||
NS_ADDREF(*aSelection = mSelection);
|
||||
NS_ADDREF(*aRootContent = mRootContent);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Helper class, used for selection change notification
|
||||
class SelectionChangeEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SelectionChangeEvent(IMEContentObserver* aDispatcher,
|
||||
bool aCausedByComposition)
|
||||
: mDispatcher(aDispatcher)
|
||||
, mCausedByComposition(aCausedByComposition)
|
||||
{
|
||||
MOZ_ASSERT(mDispatcher);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mDispatcher->GetWidget()) {
|
||||
IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE);
|
||||
notification.mSelectionChangeData.mCausedByComposition =
|
||||
mCausedByComposition;
|
||||
mDispatcher->GetWidget()->NotifyIME(notification);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<IMEContentObserver> mDispatcher;
|
||||
bool mCausedByComposition;
|
||||
};
|
||||
|
||||
nsresult
|
||||
IMEContentObserver::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
|
||||
nsISelection* aSelection,
|
||||
int16_t aReason)
|
||||
{
|
||||
bool causedByComposition = IsEditorHandlingEventForComposition();
|
||||
if (causedByComposition &&
|
||||
!mUpdatePreference.WantChangesCausedByComposition()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t count = 0;
|
||||
nsresult rv = aSelection->GetRangeCount(&count);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (count > 0 && mWidget) {
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new SelectionChangeEvent(this, causedByComposition));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Helper class, used for position change notification
|
||||
class PositionChangeEvent MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
PositionChangeEvent(IMEContentObserver* aDispatcher)
|
||||
: mDispatcher(aDispatcher)
|
||||
{
|
||||
MOZ_ASSERT(mDispatcher);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mDispatcher->GetWidget()) {
|
||||
mDispatcher->GetWidget()->NotifyIME(
|
||||
IMENotification(NOTIFY_IME_OF_POSITION_CHANGE));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<IMEContentObserver> mDispatcher;
|
||||
};
|
||||
|
||||
void
|
||||
IMEContentObserver::ScrollPositionChanged()
|
||||
{
|
||||
if (mWidget) {
|
||||
nsContentUtils::AddScriptRunner(new PositionChangeEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IMEContentObserver::Reflow(DOMHighResTimeStamp aStart,
|
||||
DOMHighResTimeStamp aEnd)
|
||||
{
|
||||
if (mWidget) {
|
||||
nsContentUtils::AddScriptRunner(new PositionChangeEvent(this));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IMEContentObserver::ReflowInterruptible(DOMHighResTimeStamp aStart,
|
||||
DOMHighResTimeStamp aEnd)
|
||||
{
|
||||
if (mWidget) {
|
||||
nsContentUtils::AddScriptRunner(new PositionChangeEvent(this));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Helper class, used for text change notification
|
||||
class TextChangeEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
TextChangeEvent(IMEContentObserver* aDispatcher,
|
||||
uint32_t aStart, uint32_t aOldEnd, uint32_t aNewEnd,
|
||||
bool aCausedByComposition)
|
||||
: mDispatcher(aDispatcher)
|
||||
, mStart(aStart)
|
||||
, mOldEnd(aOldEnd)
|
||||
, mNewEnd(aNewEnd)
|
||||
, mCausedByComposition(aCausedByComposition)
|
||||
{
|
||||
MOZ_ASSERT(mDispatcher);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mDispatcher->GetWidget()) {
|
||||
IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE);
|
||||
notification.mTextChangeData.mStartOffset = mStart;
|
||||
notification.mTextChangeData.mOldEndOffset = mOldEnd;
|
||||
notification.mTextChangeData.mNewEndOffset = mNewEnd;
|
||||
notification.mTextChangeData.mCausedByComposition = mCausedByComposition;
|
||||
mDispatcher->GetWidget()->NotifyIME(notification);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<IMEContentObserver> mDispatcher;
|
||||
uint32_t mStart, mOldEnd, mNewEnd;
|
||||
bool mCausedByComposition;
|
||||
};
|
||||
|
||||
void
|
||||
IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
CharacterDataChangeInfo* aInfo)
|
||||
{
|
||||
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
|
||||
"character data changed for non-text node");
|
||||
|
||||
bool causedByComposition = IsEditorHandlingEventForComposition();
|
||||
if (causedByComposition &&
|
||||
!mUpdatePreference.WantChangesCausedByComposition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t offset = 0;
|
||||
// get offsets of change and fire notification
|
||||
nsresult rv =
|
||||
nsContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aContent,
|
||||
aInfo->mChangeStart,
|
||||
&offset);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
uint32_t oldEnd = offset + aInfo->mChangeEnd - aInfo->mChangeStart;
|
||||
uint32_t newEnd = offset + aInfo->mReplaceLength;
|
||||
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new TextChangeEvent(this, offset, oldEnd, newEnd, causedByComposition));
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
||||
int32_t aStartIndex,
|
||||
int32_t aEndIndex)
|
||||
{
|
||||
bool causedByComposition = IsEditorHandlingEventForComposition();
|
||||
if (causedByComposition &&
|
||||
!mUpdatePreference.WantChangesCausedByComposition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t offset = 0;
|
||||
nsresult rv =
|
||||
nsContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aContainer,
|
||||
aStartIndex, &offset);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
// get offset at the end of the last added node
|
||||
nsIContent* childAtStart = aContainer->GetChildAt(aStartIndex);
|
||||
uint32_t addingLength = 0;
|
||||
rv =
|
||||
nsContentEventHandler::GetFlatTextOffsetOfRange(childAtStart, aContainer,
|
||||
aEndIndex, &addingLength);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
if (!addingLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new TextChangeEvent(this, offset, offset, offset + addingLength,
|
||||
causedByComposition));
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::ContentAppended(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aFirstNewContent,
|
||||
int32_t aNewIndexInContainer)
|
||||
{
|
||||
NotifyContentAdded(aContainer, aNewIndexInContainer,
|
||||
aContainer->GetChildCount());
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::ContentInserted(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer)
|
||||
{
|
||||
NotifyContentAdded(NODE_FROM(aContainer, aDocument),
|
||||
aIndexInContainer, aIndexInContainer + 1);
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer,
|
||||
nsIContent* aPreviousSibling)
|
||||
{
|
||||
bool causedByComposition = IsEditorHandlingEventForComposition();
|
||||
if (causedByComposition &&
|
||||
!mUpdatePreference.WantChangesCausedByComposition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t offset = 0;
|
||||
nsresult rv =
|
||||
nsContentEventHandler::GetFlatTextOffsetOfRange(mRootContent,
|
||||
NODE_FROM(aContainer,
|
||||
aDocument),
|
||||
aIndexInContainer, &offset);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
// get offset at the end of the deleted node
|
||||
int32_t nodeLength =
|
||||
aChild->IsNodeOfType(nsINode::eTEXT) ?
|
||||
static_cast<int32_t>(aChild->TextLength()) :
|
||||
std::max(static_cast<int32_t>(aChild->GetChildCount()), 1);
|
||||
MOZ_ASSERT(nodeLength >= 0, "The node length is out of range");
|
||||
uint32_t textLength = 0;
|
||||
rv =
|
||||
nsContentEventHandler::GetFlatTextOffsetOfRange(aChild, aChild,
|
||||
nodeLength, &textLength);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
if (!textLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new TextChangeEvent(this, offset, offset + textLength, offset,
|
||||
causedByComposition));
|
||||
}
|
||||
|
||||
static nsIContent*
|
||||
GetContentBR(dom::Element* aElement)
|
||||
{
|
||||
if (!aElement->IsNodeOfType(nsINode::eCONTENT)) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIContent* content = static_cast<nsIContent*>(aElement);
|
||||
return content->IsHTML(nsGkAtoms::br) ? content : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::AttributeWillChange(nsIDocument* aDocument,
|
||||
dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
{
|
||||
nsIContent *content = GetContentBR(aElement);
|
||||
mPreAttrChangeLength = content ?
|
||||
nsContentEventHandler::GetNativeTextLength(content) : 0;
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::AttributeChanged(nsIDocument* aDocument,
|
||||
dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
{
|
||||
bool causedByComposition = IsEditorHandlingEventForComposition();
|
||||
if (causedByComposition &&
|
||||
!mUpdatePreference.WantChangesCausedByComposition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIContent *content = GetContentBR(aElement);
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t postAttrChangeLength =
|
||||
nsContentEventHandler::GetNativeTextLength(content);
|
||||
if (postAttrChangeLength == mPreAttrChangeLength) {
|
||||
return;
|
||||
}
|
||||
uint32_t start;
|
||||
nsresult rv =
|
||||
nsContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, content,
|
||||
0, &start);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new TextChangeEvent(this, start, start + mPreAttrChangeLength,
|
||||
start + postAttrChangeLength, causedByComposition));
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,79 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et 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 mozilla_IMEContentObserver_h_
|
||||
#define mozilla_IMEContentObserver_h_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDocShell.h" // XXX Why does only this need to be included here?
|
||||
#include "nsIReflowObserver.h"
|
||||
#include "nsISelectionListener.h"
|
||||
#include "nsIScrollObserver.h"
|
||||
#include "nsIWidget.h" // for nsIMEUpdatePreference
|
||||
#include "nsStubMutationObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsINode;
|
||||
class nsISelection;
|
||||
class nsPresContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// IMEContentObserver notifies widget of any text and selection changes
|
||||
// in the currently focused editor
|
||||
class IMEContentObserver MOZ_FINAL : public nsISelectionListener,
|
||||
public nsStubMutationObserver,
|
||||
public nsIReflowObserver,
|
||||
public nsIScrollObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
IMEContentObserver();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISELECTIONLISTENER
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
NS_DECL_NSIREFLOWOBSERVER
|
||||
|
||||
// nsIScrollObserver
|
||||
virtual void ScrollPositionChanged() MOZ_OVERRIDE;
|
||||
|
||||
void Init(nsIWidget* aWidget, nsPresContext* aPresContext,
|
||||
nsIContent* aContent);
|
||||
void Destroy();
|
||||
bool IsManaging(nsPresContext* aPresContext, nsIContent* aContent);
|
||||
bool IsEditorHandlingEventForComposition() const;
|
||||
bool KeepAliveDuringDeactive() const
|
||||
{
|
||||
return mUpdatePreference.WantDuringDeactive();
|
||||
}
|
||||
nsIWidget* GetWidget() const { return mWidget; }
|
||||
nsresult GetSelectionAndRoot(nsISelection** aSelection,
|
||||
nsIContent** aRoot) const;
|
||||
|
||||
private:
|
||||
void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
|
||||
void ObserveEditableNode();
|
||||
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
nsCOMPtr<nsISelection> mSelection;
|
||||
nsCOMPtr<nsIContent> mRootContent;
|
||||
nsCOMPtr<nsINode> mEditableNode;
|
||||
nsCOMPtr<nsIDocShell> mDocShell;
|
||||
nsIMEUpdatePreference mUpdatePreference;
|
||||
uint32_t mPreAttrChangeLength;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_IMEContentObserver_h_
|
|
@ -0,0 +1,775 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et 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 "mozilla/IMEStateManager.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
|
||||
#include "HTMLInputElement.h"
|
||||
#include "IMEContentObserver.h"
|
||||
#include "TextComposition.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "nsIForm.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsPresContext.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
using namespace widget;
|
||||
|
||||
nsIContent* IMEStateManager::sContent = nullptr;
|
||||
nsPresContext* IMEStateManager::sPresContext = nullptr;
|
||||
bool IMEStateManager::sInstalledMenuKeyboardListener = false;
|
||||
bool IMEStateManager::sIsTestingIME = false;
|
||||
|
||||
// sActiveIMEContentObserver points to the currently active IMEContentObserver.
|
||||
// sActiveIMEContentObserver is null if there is no focused editor.
|
||||
IMEContentObserver* IMEStateManager::sActiveIMEContentObserver = nullptr;
|
||||
TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
|
||||
|
||||
void
|
||||
IMEStateManager::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(!sTextCompositions || !sTextCompositions->Length());
|
||||
delete sTextCompositions;
|
||||
sTextCompositions = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPresContext);
|
||||
|
||||
// First, if there is a composition in the aPresContext, clean up it.
|
||||
if (sTextCompositions) {
|
||||
TextCompositionArray::index_type i =
|
||||
sTextCompositions->IndexOf(aPresContext);
|
||||
if (i != TextCompositionArray::NoIndex) {
|
||||
// there should be only one composition per presContext object.
|
||||
sTextCompositions->ElementAt(i)->Destroy();
|
||||
sTextCompositions->RemoveElementAt(i);
|
||||
MOZ_ASSERT(sTextCompositions->IndexOf(aPresContext) ==
|
||||
TextCompositionArray::NoIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (aPresContext != sPresContext) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
DestroyTextStateManager();
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
|
||||
if (widget) {
|
||||
IMEState newState = GetNewIMEState(sPresContext, nullptr);
|
||||
InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
|
||||
InputContextAction::LOST_FOCUS);
|
||||
SetIMEState(newState, nullptr, widget, action);
|
||||
}
|
||||
NS_IF_RELEASE(sContent);
|
||||
sPresContext = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPresContext);
|
||||
|
||||
// First, if there is a composition in the aContent, clean up it.
|
||||
if (sTextCompositions) {
|
||||
nsRefPtr<TextComposition> compositionInContent =
|
||||
sTextCompositions->GetCompositionInContent(aPresContext, aContent);
|
||||
|
||||
if (compositionInContent) {
|
||||
// Try resetting the native IME state. Be aware, typically, this method
|
||||
// is called during the content being removed. Then, the native
|
||||
// composition events which are caused by following APIs are ignored due
|
||||
// to unsafe to run script (in PresShell::HandleEvent()).
|
||||
nsCOMPtr<nsIWidget> widget = aPresContext->GetRootWidget();
|
||||
if (widget) {
|
||||
nsresult rv =
|
||||
compositionInContent->NotifyIME(REQUEST_TO_CANCEL_COMPOSITION);
|
||||
if (NS_FAILED(rv)) {
|
||||
compositionInContent->NotifyIME(REQUEST_TO_COMMIT_COMPOSITION);
|
||||
}
|
||||
// By calling the APIs, the composition may have been finished normally.
|
||||
compositionInContent =
|
||||
sTextCompositions->GetCompositionFor(
|
||||
compositionInContent->GetPresContext(),
|
||||
compositionInContent->GetEventTargetNode());
|
||||
}
|
||||
}
|
||||
|
||||
// If the compositionInContent is still available, we should finish the
|
||||
// composition just on the content forcibly.
|
||||
if (compositionInContent) {
|
||||
compositionInContent->SynthesizeCommit(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sPresContext || !sContent ||
|
||||
!nsContentUtils::ContentIsDescendantOf(sContent, aContent)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
DestroyTextStateManager();
|
||||
|
||||
// Current IME transaction should commit
|
||||
nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
|
||||
if (widget) {
|
||||
IMEState newState = GetNewIMEState(sPresContext, nullptr);
|
||||
InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
|
||||
InputContextAction::LOST_FOCUS);
|
||||
SetIMEState(newState, nullptr, widget, action);
|
||||
}
|
||||
|
||||
NS_IF_RELEASE(sContent);
|
||||
sPresContext = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
IMEStateManager::OnChangeFocus(nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
InputContextAction::Cause aCause)
|
||||
{
|
||||
InputContextAction action(aCause);
|
||||
return OnChangeFocusInternal(aPresContext, aContent, action);
|
||||
}
|
||||
|
||||
nsresult
|
||||
IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
InputContextAction aAction)
|
||||
{
|
||||
bool focusActuallyChanging =
|
||||
(sContent != aContent || sPresContext != aPresContext);
|
||||
|
||||
nsCOMPtr<nsIWidget> oldWidget =
|
||||
sPresContext ? sPresContext->GetRootWidget() : nullptr;
|
||||
if (oldWidget && focusActuallyChanging) {
|
||||
// If we're deactivating, we shouldn't commit composition forcibly because
|
||||
// the user may want to continue the composition.
|
||||
if (aPresContext) {
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
|
||||
}
|
||||
}
|
||||
|
||||
if (sActiveIMEContentObserver &&
|
||||
(aPresContext || !sActiveIMEContentObserver->KeepAliveDuringDeactive()) &&
|
||||
!sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
|
||||
DestroyTextStateManager();
|
||||
}
|
||||
|
||||
if (!aPresContext) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget =
|
||||
(sPresContext == aPresContext) ? oldWidget.get() :
|
||||
aPresContext->GetRootWidget();
|
||||
if (!widget) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IMEState newState = GetNewIMEState(aPresContext, aContent);
|
||||
if (!focusActuallyChanging) {
|
||||
// actual focus isn't changing, but if IME enabled state is changing,
|
||||
// we should do it.
|
||||
InputContext context = widget->GetInputContext();
|
||||
if (context.mIMEState.mEnabled == newState.mEnabled) {
|
||||
// the enabled state isn't changing.
|
||||
return NS_OK;
|
||||
}
|
||||
aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
|
||||
|
||||
// Even if focus isn't changing actually, we should commit current
|
||||
// composition here since the IME state is changing.
|
||||
if (sPresContext && oldWidget && !focusActuallyChanging) {
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
|
||||
}
|
||||
} else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
|
||||
// If aContent isn't null or aContent is null but editable, somebody gets
|
||||
// focus.
|
||||
bool gotFocus = aContent || (newState.mEnabled == IMEState::ENABLED);
|
||||
aAction.mFocusChange =
|
||||
gotFocus ? InputContextAction::GOT_FOCUS : InputContextAction::LOST_FOCUS;
|
||||
}
|
||||
|
||||
// Update IME state for new focus widget
|
||||
SetIMEState(newState, aContent, widget, aAction);
|
||||
|
||||
sPresContext = aPresContext;
|
||||
if (sContent != aContent) {
|
||||
NS_IF_RELEASE(sContent);
|
||||
NS_IF_ADDREF(sContent = aContent);
|
||||
}
|
||||
|
||||
// Don't call CreateIMEContentObserver() here, it should be called from
|
||||
// focus event handler of editor.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
IMEStateManager::OnInstalledMenuKeyboardListener(bool aInstalling)
|
||||
{
|
||||
sInstalledMenuKeyboardListener = aInstalling;
|
||||
|
||||
InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
|
||||
aInstalling ? InputContextAction::MENU_GOT_PSEUDO_FOCUS :
|
||||
InputContextAction::MENU_LOST_PSEUDO_FOCUS);
|
||||
OnChangeFocusInternal(sPresContext, sContent, action);
|
||||
}
|
||||
|
||||
void
|
||||
IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
nsIDOMMouseEvent* aMouseEvent)
|
||||
{
|
||||
if (sPresContext != aPresContext || sContent != aContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = aPresContext->GetRootWidget();
|
||||
NS_ENSURE_TRUE_VOID(widget);
|
||||
|
||||
bool isTrusted;
|
||||
nsresult rv = aMouseEvent->GetIsTrusted(&isTrusted);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (!isTrusted) {
|
||||
return; // ignore untrusted event.
|
||||
}
|
||||
|
||||
int16_t button;
|
||||
rv = aMouseEvent->GetButton(&button);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (button != 0) {
|
||||
return; // not a left click event.
|
||||
}
|
||||
|
||||
int32_t clickCount;
|
||||
rv = aMouseEvent->GetDetail(&clickCount);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (clickCount != 1) {
|
||||
return; // should notify only first click event.
|
||||
}
|
||||
|
||||
InputContextAction action(InputContextAction::CAUSE_MOUSE,
|
||||
InputContextAction::FOCUS_NOT_CHANGED);
|
||||
IMEState newState = GetNewIMEState(aPresContext, aContent);
|
||||
SetIMEState(newState, aContent, widget, action);
|
||||
}
|
||||
|
||||
void
|
||||
IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
if (sPresContext != aPresContext || sContent != aContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the IMEContentObserver instance isn't managing the editor actually,
|
||||
// we need to recreate the instance.
|
||||
if (sActiveIMEContentObserver) {
|
||||
if (sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
|
||||
return;
|
||||
}
|
||||
DestroyTextStateManager();
|
||||
}
|
||||
|
||||
CreateIMEContentObserver();
|
||||
}
|
||||
|
||||
void
|
||||
IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
if (!sPresContext) {
|
||||
NS_WARNING("ISM doesn't know which editor has focus");
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
|
||||
if (!widget) {
|
||||
NS_WARNING("focused widget is not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the IMEContentObserver instance isn't managing the editor's current
|
||||
// editable root content, the editor frame might be reframed. We should
|
||||
// recreate the instance at that time.
|
||||
bool createTextStateManager =
|
||||
(!sActiveIMEContentObserver ||
|
||||
!sActiveIMEContentObserver->IsManaging(sPresContext, aContent));
|
||||
|
||||
bool updateIMEState =
|
||||
(widget->GetInputContext().mIMEState.mEnabled != aNewIMEState.mEnabled);
|
||||
|
||||
if (updateIMEState) {
|
||||
// commit current composition before modifying IME state.
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, widget);
|
||||
}
|
||||
|
||||
if (createTextStateManager) {
|
||||
DestroyTextStateManager();
|
||||
}
|
||||
|
||||
if (updateIMEState) {
|
||||
InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
|
||||
InputContextAction::FOCUS_NOT_CHANGED);
|
||||
SetIMEState(aNewIMEState, aContent, widget, action);
|
||||
}
|
||||
|
||||
if (createTextStateManager) {
|
||||
CreateIMEContentObserver();
|
||||
}
|
||||
}
|
||||
|
||||
IMEState
|
||||
IMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
// On Printing or Print Preview, we don't need IME.
|
||||
if (aPresContext->Type() == nsPresContext::eContext_PrintPreview ||
|
||||
aPresContext->Type() == nsPresContext::eContext_Print) {
|
||||
return IMEState(IMEState::DISABLED);
|
||||
}
|
||||
|
||||
if (sInstalledMenuKeyboardListener) {
|
||||
return IMEState(IMEState::DISABLED);
|
||||
}
|
||||
|
||||
if (!aContent) {
|
||||
// Even if there are no focused content, the focused document might be
|
||||
// editable, such case is design mode.
|
||||
nsIDocument* doc = aPresContext->Document();
|
||||
if (doc && doc->HasFlag(NODE_IS_EDITABLE)) {
|
||||
return IMEState(IMEState::ENABLED);
|
||||
}
|
||||
return IMEState(IMEState::DISABLED);
|
||||
}
|
||||
|
||||
return aContent->GetDesiredIMEState();
|
||||
}
|
||||
|
||||
// Helper class, used for IME enabled state change notification
|
||||
class IMEEnabledStateChangedEvent : public nsRunnable {
|
||||
public:
|
||||
IMEEnabledStateChangedEvent(uint32_t aState)
|
||||
: mState(aState)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
services::GetObserverService();
|
||||
if (observerService) {
|
||||
nsAutoString state;
|
||||
state.AppendInt(mState);
|
||||
observerService->NotifyObservers(nullptr, "ime-enabled-state-changed",
|
||||
state.get());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t mState;
|
||||
};
|
||||
|
||||
void
|
||||
IMEStateManager::SetIMEState(const IMEState& aState,
|
||||
nsIContent* aContent,
|
||||
nsIWidget* aWidget,
|
||||
InputContextAction aAction)
|
||||
{
|
||||
NS_ENSURE_TRUE_VOID(aWidget);
|
||||
|
||||
InputContext oldContext = aWidget->GetInputContext();
|
||||
|
||||
InputContext context;
|
||||
context.mIMEState = aState;
|
||||
|
||||
if (aContent && aContent->GetNameSpaceID() == kNameSpaceID_XHTML &&
|
||||
(aContent->Tag() == nsGkAtoms::input ||
|
||||
aContent->Tag() == nsGkAtoms::textarea)) {
|
||||
if (aContent->Tag() != nsGkAtoms::textarea) {
|
||||
// <input type=number> has an anonymous <input type=text> descendant
|
||||
// that gets focus whenever anyone tries to focus the number control. We
|
||||
// need to check if aContent is one of those anonymous text controls and,
|
||||
// if so, use the number control instead:
|
||||
nsIContent* content = aContent;
|
||||
HTMLInputElement* inputElement =
|
||||
HTMLInputElement::FromContentOrNull(aContent);
|
||||
if (inputElement) {
|
||||
HTMLInputElement* ownerNumberControl =
|
||||
inputElement->GetOwnerNumberControl();
|
||||
if (ownerNumberControl) {
|
||||
content = ownerNumberControl; // an <input type=number>
|
||||
}
|
||||
}
|
||||
content->GetAttr(kNameSpaceID_None, nsGkAtoms::type,
|
||||
context.mHTMLInputType);
|
||||
} else {
|
||||
context.mHTMLInputType.Assign(nsGkAtoms::textarea->GetUTF16String());
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("dom.forms.inputmode", false)) {
|
||||
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::inputmode,
|
||||
context.mHTMLInputInputmode);
|
||||
}
|
||||
|
||||
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint,
|
||||
context.mActionHint);
|
||||
|
||||
// if we don't have an action hint and return won't submit the form use "next"
|
||||
if (context.mActionHint.IsEmpty() && aContent->Tag() == nsGkAtoms::input) {
|
||||
bool willSubmit = false;
|
||||
nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent));
|
||||
mozilla::dom::Element* formElement = control->GetFormElement();
|
||||
nsCOMPtr<nsIForm> form;
|
||||
if (control) {
|
||||
// is this a form and does it have a default submit element?
|
||||
if ((form = do_QueryInterface(formElement)) &&
|
||||
form->GetDefaultSubmitElement()) {
|
||||
willSubmit = true;
|
||||
// is this an html form and does it only have a single text input element?
|
||||
} else if (formElement && formElement->Tag() == nsGkAtoms::form &&
|
||||
formElement->IsHTML() &&
|
||||
!static_cast<dom::HTMLFormElement*>(formElement)->
|
||||
ImplicitSubmissionIsDisabled()) {
|
||||
willSubmit = true;
|
||||
}
|
||||
}
|
||||
context.mActionHint.Assign(
|
||||
willSubmit ? (control->GetType() == NS_FORM_INPUT_SEARCH ?
|
||||
NS_LITERAL_STRING("search") : NS_LITERAL_STRING("go")) :
|
||||
(formElement ?
|
||||
NS_LITERAL_STRING("next") : EmptyString()));
|
||||
}
|
||||
}
|
||||
|
||||
// XXX I think that we should use nsContentUtils::IsCallerChrome() instead
|
||||
// of the process type.
|
||||
if (aAction.mCause == InputContextAction::CAUSE_UNKNOWN &&
|
||||
XRE_GetProcessType() != GeckoProcessType_Content) {
|
||||
aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME;
|
||||
}
|
||||
|
||||
aWidget->SetInputContext(context, aAction);
|
||||
if (oldContext.mIMEState.mEnabled == context.mIMEState.mEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new IMEEnabledStateChangedEvent(context.mIMEState.mEnabled));
|
||||
}
|
||||
|
||||
void
|
||||
IMEStateManager::EnsureTextCompositionArray()
|
||||
{
|
||||
if (sTextCompositions) {
|
||||
return;
|
||||
}
|
||||
sTextCompositions = new TextCompositionArray();
|
||||
}
|
||||
|
||||
void
|
||||
IMEStateManager::DispatchCompositionEvent(nsINode* aEventTargetNode,
|
||||
nsPresContext* aPresContext,
|
||||
WidgetEvent* aEvent,
|
||||
nsEventStatus* aStatus,
|
||||
nsDispatchingCallback* aCallBack)
|
||||
{
|
||||
MOZ_ASSERT(aEvent->eventStructType == NS_COMPOSITION_EVENT ||
|
||||
aEvent->eventStructType == NS_TEXT_EVENT);
|
||||
if (!aEvent->mFlags.mIsTrusted || aEvent->mFlags.mPropagationStopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureTextCompositionArray();
|
||||
|
||||
WidgetGUIEvent* GUIEvent = aEvent->AsGUIEvent();
|
||||
|
||||
nsRefPtr<TextComposition> composition =
|
||||
sTextCompositions->GetCompositionFor(GUIEvent->widget);
|
||||
if (!composition) {
|
||||
MOZ_ASSERT(GUIEvent->message == NS_COMPOSITION_START);
|
||||
composition = new TextComposition(aPresContext, aEventTargetNode, GUIEvent);
|
||||
sTextCompositions->AppendElement(composition);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
MOZ_ASSERT(GUIEvent->message != NS_COMPOSITION_START);
|
||||
}
|
||||
#endif // #ifdef DEBUG
|
||||
|
||||
// Dispatch the event on composing target.
|
||||
composition->DispatchEvent(GUIEvent, aStatus, aCallBack);
|
||||
|
||||
// WARNING: the |composition| might have been destroyed already.
|
||||
|
||||
// Remove the ended composition from the array.
|
||||
if (aEvent->message == NS_COMPOSITION_END) {
|
||||
TextCompositionArray::index_type i =
|
||||
sTextCompositions->IndexOf(GUIEvent->widget);
|
||||
if (i != TextCompositionArray::NoIndex) {
|
||||
sTextCompositions->ElementAt(i)->Destroy();
|
||||
sTextCompositions->RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IMEStateManager::NotifyIME(IMEMessage aMessage,
|
||||
nsIWidget* aWidget)
|
||||
{
|
||||
NS_ENSURE_TRUE(aWidget, NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsRefPtr<TextComposition> composition;
|
||||
if (sTextCompositions) {
|
||||
composition = sTextCompositions->GetCompositionFor(aWidget);
|
||||
}
|
||||
if (!composition || !composition->IsSynthesizedForTests()) {
|
||||
switch (aMessage) {
|
||||
case NOTIFY_IME_OF_CURSOR_POS_CHANGED:
|
||||
return aWidget->NotifyIME(IMENotification(aMessage));
|
||||
case REQUEST_TO_COMMIT_COMPOSITION:
|
||||
case REQUEST_TO_CANCEL_COMPOSITION:
|
||||
case NOTIFY_IME_OF_COMPOSITION_UPDATE:
|
||||
return composition ?
|
||||
aWidget->NotifyIME(IMENotification(aMessage)) : NS_OK;
|
||||
default:
|
||||
MOZ_CRASH("Unsupported notification");
|
||||
}
|
||||
MOZ_CRASH(
|
||||
"Failed to handle the notification for non-synthesized composition");
|
||||
}
|
||||
|
||||
// If the composition is synthesized events for automated tests, we should
|
||||
// dispatch composition events for emulating the native composition behavior.
|
||||
// NOTE: The dispatched events are discarded if it's not safe to run script.
|
||||
switch (aMessage) {
|
||||
case REQUEST_TO_COMMIT_COMPOSITION: {
|
||||
nsCOMPtr<nsIWidget> widget(aWidget);
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
if (!composition->LastData().IsEmpty()) {
|
||||
WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget);
|
||||
textEvent.theText = composition->LastData();
|
||||
textEvent.mFlags.mIsSynthesizedForTests = true;
|
||||
widget->DispatchEvent(&textEvent, status);
|
||||
if (widget->Destroyed()) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
status = nsEventStatus_eIgnore;
|
||||
WidgetCompositionEvent endEvent(true, NS_COMPOSITION_END, widget);
|
||||
endEvent.data = composition->LastData();
|
||||
endEvent.mFlags.mIsSynthesizedForTests = true;
|
||||
widget->DispatchEvent(&endEvent, status);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case REQUEST_TO_CANCEL_COMPOSITION: {
|
||||
nsCOMPtr<nsIWidget> widget(aWidget);
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
if (!composition->LastData().IsEmpty()) {
|
||||
WidgetCompositionEvent updateEvent(true, NS_COMPOSITION_UPDATE, widget);
|
||||
updateEvent.data = composition->LastData();
|
||||
updateEvent.mFlags.mIsSynthesizedForTests = true;
|
||||
widget->DispatchEvent(&updateEvent, status);
|
||||
if (widget->Destroyed()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
status = nsEventStatus_eIgnore;
|
||||
WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget);
|
||||
textEvent.theText = composition->LastData();
|
||||
textEvent.mFlags.mIsSynthesizedForTests = true;
|
||||
widget->DispatchEvent(&textEvent, status);
|
||||
if (widget->Destroyed()) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
status = nsEventStatus_eIgnore;
|
||||
WidgetCompositionEvent endEvent(true, NS_COMPOSITION_END, widget);
|
||||
endEvent.data = composition->LastData();
|
||||
endEvent.mFlags.mIsSynthesizedForTests = true;
|
||||
widget->DispatchEvent(&endEvent, status);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
default:
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IMEStateManager::NotifyIME(IMEMessage aMessage,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
NS_ENSURE_TRUE(aPresContext, NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsIWidget* widget = aPresContext->GetRootWidget();
|
||||
if (!widget) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return NotifyIME(aMessage, widget);
|
||||
}
|
||||
|
||||
bool
|
||||
IMEStateManager::IsEditable(nsINode* node)
|
||||
{
|
||||
if (node->IsEditable()) {
|
||||
return true;
|
||||
}
|
||||
// |node| might be readwrite (for example, a text control)
|
||||
if (node->IsElement() &&
|
||||
node->AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsINode*
|
||||
IMEStateManager::GetRootEditableNode(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
if (aContent) {
|
||||
nsINode* root = nullptr;
|
||||
nsINode* node = aContent;
|
||||
while (node && IsEditable(node)) {
|
||||
root = node;
|
||||
node = node->GetParentNode();
|
||||
}
|
||||
return root;
|
||||
}
|
||||
if (aPresContext) {
|
||||
nsIDocument* document = aPresContext->Document();
|
||||
if (document && document->IsEditable()) {
|
||||
return document;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
IMEStateManager::IsEditableIMEState(nsIWidget* aWidget)
|
||||
{
|
||||
switch (aWidget->GetInputContext().mIMEState.mEnabled) {
|
||||
case IMEState::ENABLED:
|
||||
case IMEState::PASSWORD:
|
||||
return true;
|
||||
case IMEState::PLUGIN:
|
||||
case IMEState::DISABLED:
|
||||
return false;
|
||||
default:
|
||||
MOZ_CRASH("Unknown IME enable state");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IMEStateManager::DestroyTextStateManager()
|
||||
{
|
||||
if (!sActiveIMEContentObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<IMEContentObserver> tsm;
|
||||
tsm.swap(sActiveIMEContentObserver);
|
||||
tsm->Destroy();
|
||||
}
|
||||
|
||||
void
|
||||
IMEStateManager::CreateIMEContentObserver()
|
||||
{
|
||||
if (sActiveIMEContentObserver) {
|
||||
NS_WARNING("text state observer has been there already");
|
||||
MOZ_ASSERT(sActiveIMEContentObserver->IsManaging(sPresContext, sContent));
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
|
||||
if (!widget) {
|
||||
return; // Sometimes, there are no widgets.
|
||||
}
|
||||
|
||||
// If it's not text ediable, we don't need to create IMEContentObserver.
|
||||
if (!IsEditableIMEState(widget)) {
|
||||
return;
|
||||
}
|
||||
|
||||
static bool sInitializeIsTestingIME = true;
|
||||
if (sInitializeIsTestingIME) {
|
||||
Preferences::AddBoolVarCache(&sIsTestingIME, "test.IME", false);
|
||||
sInitializeIsTestingIME = false;
|
||||
}
|
||||
|
||||
sActiveIMEContentObserver = new IMEContentObserver();
|
||||
NS_ADDREF(sActiveIMEContentObserver);
|
||||
|
||||
// IMEContentObserver::Init() might create another IMEContentObserver
|
||||
// instance. So, sActiveIMEContentObserver would be replaced with new one.
|
||||
// We should hold the current instance here.
|
||||
nsRefPtr<IMEContentObserver> kungFuDeathGrip(sActiveIMEContentObserver);
|
||||
sActiveIMEContentObserver->Init(widget, sPresContext, sContent);
|
||||
}
|
||||
|
||||
nsresult
|
||||
IMEStateManager::GetFocusSelectionAndRoot(nsISelection** aSelection,
|
||||
nsIContent** aRootContent)
|
||||
{
|
||||
if (!sActiveIMEContentObserver) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return sActiveIMEContentObserver->GetSelectionAndRoot(aSelection,
|
||||
aRootContent);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<TextComposition>
|
||||
IMEStateManager::GetTextCompositionFor(nsIWidget* aWidget)
|
||||
{
|
||||
if (!sTextCompositions) {
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<TextComposition> textComposition =
|
||||
sTextCompositions->GetCompositionFor(aWidget);
|
||||
return textComposition.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<TextComposition>
|
||||
IMEStateManager::GetTextCompositionFor(WidgetGUIEvent* aEvent)
|
||||
{
|
||||
MOZ_ASSERT(aEvent->AsCompositionEvent() || aEvent->AsTextEvent(),
|
||||
"aEvent has to be WidgetCompositionEvent or WidgetTextEvent");
|
||||
return GetTextCompositionFor(aEvent->widget);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -3,8 +3,8 @@
|
|||
* 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 nsIMEStateManager_h__
|
||||
#define nsIMEStateManager_h__
|
||||
#ifndef mozilla_IMEStateManager_h_
|
||||
#define mozilla_IMEStateManager_h_
|
||||
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "nsIWidget.h"
|
||||
|
@ -15,26 +15,26 @@ class nsIDOMMouseEvent;
|
|||
class nsINode;
|
||||
class nsPIDOMWindow;
|
||||
class nsPresContext;
|
||||
class nsTextStateManager;
|
||||
class nsISelection;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class IMEContentObserver;
|
||||
class TextCompositionArray;
|
||||
class TextComposition;
|
||||
} // namespace mozilla
|
||||
|
||||
/*
|
||||
* IME state manager
|
||||
/**
|
||||
* IMEStateManager manages InputContext (e.g., active editor type, IME enabled
|
||||
* state and IME open state) of nsIWidget instances, manages IMEContentObserver
|
||||
* and provides useful API for IME.
|
||||
*/
|
||||
|
||||
class nsIMEStateManager
|
||||
class IMEStateManager
|
||||
{
|
||||
friend class nsTextStateManager;
|
||||
protected:
|
||||
typedef mozilla::widget::IMEMessage IMEMessage;
|
||||
typedef mozilla::widget::IMEState IMEState;
|
||||
typedef mozilla::widget::InputContext InputContext;
|
||||
typedef mozilla::widget::InputContextAction InputContextAction;
|
||||
typedef widget::IMEMessage IMEMessage;
|
||||
typedef widget::IMEState IMEState;
|
||||
typedef widget::InputContext InputContext;
|
||||
typedef widget::InputContextAction InputContextAction;
|
||||
|
||||
public:
|
||||
static void Shutdown();
|
||||
|
@ -92,14 +92,14 @@ public:
|
|||
*/
|
||||
static void DispatchCompositionEvent(nsINode* aEventTargetNode,
|
||||
nsPresContext* aPresContext,
|
||||
mozilla::WidgetEvent* aEvent,
|
||||
WidgetEvent* aEvent,
|
||||
nsEventStatus* aStatus,
|
||||
nsDispatchingCallback* aCallBack);
|
||||
|
||||
/**
|
||||
* Get TextComposition from widget.
|
||||
*/
|
||||
static already_AddRefed<mozilla::TextComposition>
|
||||
static already_AddRefed<TextComposition>
|
||||
GetTextCompositionFor(nsIWidget* aWidget);
|
||||
|
||||
/**
|
||||
|
@ -108,8 +108,8 @@ public:
|
|||
* @param aEvent Should be a composition event or a text event which is
|
||||
* being dispatched.
|
||||
*/
|
||||
static already_AddRefed<mozilla::TextComposition>
|
||||
GetTextCompositionFor(mozilla::WidgetGUIEvent* aEvent);
|
||||
static already_AddRefed<TextComposition>
|
||||
GetTextCompositionFor(WidgetGUIEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Send a notification to IME. It depends on the IME or platform spec what
|
||||
|
@ -118,6 +118,10 @@ public:
|
|||
static nsresult NotifyIME(IMEMessage aMessage, nsIWidget* aWidget);
|
||||
static nsresult NotifyIME(IMEMessage aMessage, nsPresContext* aPresContext);
|
||||
|
||||
static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
|
||||
nsIContent* aContent);
|
||||
static bool IsTestingIME() { return sIsTestingIME; }
|
||||
|
||||
protected:
|
||||
static nsresult OnChangeFocusInternal(nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
|
@ -130,12 +134,10 @@ protected:
|
|||
nsIContent* aContent);
|
||||
|
||||
static void EnsureTextCompositionArray();
|
||||
static void CreateTextStateManager();
|
||||
static void CreateIMEContentObserver();
|
||||
static void DestroyTextStateManager();
|
||||
|
||||
static bool IsEditable(nsINode* node);
|
||||
static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
|
||||
nsIContent* aContent);
|
||||
|
||||
static bool IsEditableIMEState(nsIWidget* aWidget);
|
||||
|
||||
|
@ -144,13 +146,15 @@ protected:
|
|||
static bool sInstalledMenuKeyboardListener;
|
||||
static bool sIsTestingIME;
|
||||
|
||||
static nsTextStateManager* sTextStateObserver;
|
||||
static IMEContentObserver* sActiveIMEContentObserver;
|
||||
|
||||
// All active compositions in the process are stored by this array.
|
||||
// When you get an item of this array and use it, please be careful.
|
||||
// The instances in this array can be destroyed automatically if you do
|
||||
// something to cause committing or canceling the composition.
|
||||
static mozilla::TextCompositionArray* sTextCompositions;
|
||||
static TextCompositionArray* sTextCompositions;
|
||||
};
|
||||
|
||||
#endif // nsIMEStateManager_h__
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_IMEStateManager_h_
|
|
@ -10,9 +10,9 @@
|
|||
#include "nsEventDispatcher.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIMEStateManager.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/MiscEvents.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
|
||||
|
@ -145,7 +145,7 @@ nsresult
|
|||
TextComposition::NotifyIME(IMEMessage aMessage)
|
||||
{
|
||||
NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
|
||||
return nsIMEStateManager::NotifyIME(aMessage, mPresContext);
|
||||
return IMEStateManager::NotifyIME(aMessage, mPresContext);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -231,7 +231,7 @@ TextComposition::CompositionEventDispatcher::Run()
|
|||
handler.OnQuerySelectedText(&selectedText);
|
||||
NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
|
||||
compStart.data = selectedText.mReply.mString;
|
||||
nsIMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
|
||||
IMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
|
||||
&compStart, &status, nullptr);
|
||||
break;
|
||||
}
|
||||
|
@ -239,14 +239,14 @@ TextComposition::CompositionEventDispatcher::Run()
|
|||
case NS_COMPOSITION_END: {
|
||||
WidgetCompositionEvent compEvent(true, mEventMessage, mWidget);
|
||||
compEvent.data = mData;
|
||||
nsIMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
|
||||
IMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
|
||||
&compEvent, &status, nullptr);
|
||||
break;
|
||||
}
|
||||
case NS_TEXT_TEXT: {
|
||||
WidgetTextEvent textEvent(true, NS_TEXT_TEXT, mWidget);
|
||||
textEvent.theText = mData;
|
||||
nsIMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
|
||||
IMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
|
||||
&textEvent, &status, nullptr);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -20,10 +20,11 @@
|
|||
|
||||
class nsDispatchingCallback;
|
||||
class nsIEditor;
|
||||
class nsIMEStateManager;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class IMEStateManager;
|
||||
|
||||
/**
|
||||
* TextComposition represents a text composition. This class stores the
|
||||
* composition event target and its presContext. At dispatching the event via
|
||||
|
@ -32,7 +33,7 @@ namespace mozilla {
|
|||
|
||||
class TextComposition MOZ_FINAL
|
||||
{
|
||||
friend class ::nsIMEStateManager;
|
||||
friend class IMEStateManager;
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(TextComposition)
|
||||
|
||||
|
@ -71,7 +72,7 @@ public:
|
|||
bool MatchesNativeContext(nsIWidget* aWidget) const;
|
||||
|
||||
/**
|
||||
* This is called when nsIMEStateManager stops managing the instance.
|
||||
* This is called when IMEStateManager stops managing the instance.
|
||||
*/
|
||||
void Destroy();
|
||||
|
||||
|
@ -145,7 +146,7 @@ public:
|
|||
private:
|
||||
// This class holds nsPresContext weak. This instance shouldn't block
|
||||
// destroying it. When the presContext is being destroyed, it's notified to
|
||||
// nsIMEStateManager::OnDestroyPresContext(), and then, it destroy
|
||||
// IMEStateManager::OnDestroyPresContext(), and then, it destroy
|
||||
// this instance.
|
||||
nsPresContext* mPresContext;
|
||||
nsCOMPtr<nsINode> mNode;
|
||||
|
@ -252,7 +253,7 @@ private:
|
|||
* DispatchCompositionEventRunnable() dispatches a composition or text event
|
||||
* to the content. Be aware, if you use this method, nsPresShellEventCB
|
||||
* isn't used. That means that nsIFrame::HandleEvent() is never called.
|
||||
* WARNING: The instance which is managed by nsIMEStateManager may be
|
||||
* WARNING: The instance which is managed by IMEStateManager may be
|
||||
* destroyed by this method call.
|
||||
*
|
||||
* @param aEventMessage Must be one of composition event or text event.
|
||||
|
@ -270,7 +271,7 @@ private:
|
|||
* Managing with array is enough because only one composition is typically
|
||||
* there. Even if user switches native IME context, it's very rare that
|
||||
* second or more composition is started.
|
||||
* It's assumed that this is used by nsIMEStateManager for storing all active
|
||||
* It's assumed that this is used by IMEStateManager for storing all active
|
||||
* compositions in the process. If the instance is it, each TextComposition
|
||||
* in the array can be destroyed by calling some methods of itself.
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@ EXPORTS += [
|
|||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'IMEStateManager.h',
|
||||
'InternalMutationEvent.h',
|
||||
]
|
||||
|
||||
|
@ -77,6 +78,8 @@ UNIFIED_SOURCES += [
|
|||
'Event.cpp',
|
||||
'EventTarget.cpp',
|
||||
'FocusEvent.cpp',
|
||||
'IMEContentObserver.cpp',
|
||||
'IMEStateManager.cpp',
|
||||
'KeyboardEvent.cpp',
|
||||
'MessageEvent.cpp',
|
||||
'MouseEvent.cpp',
|
||||
|
@ -90,7 +93,6 @@ UNIFIED_SOURCES += [
|
|||
'nsEventDispatcher.cpp',
|
||||
'nsEventListenerManager.cpp',
|
||||
'nsEventListenerService.cpp',
|
||||
'nsIMEStateManager.cpp',
|
||||
'nsJSEventListener.cpp',
|
||||
'nsPaintRequest.cpp',
|
||||
'PointerEvent.cpp',
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
#include "nsISelectionPrivate.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsIMEStateManager.h"
|
||||
#include "nsIObjectFrame.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -1096,8 +1096,8 @@ nsContentEventHandler::OnSelectionEvent(WidgetSelectionEvent* aEvent)
|
|||
// Get selection to manipulate
|
||||
// XXX why do we need to get them from ISM? This method should work fine
|
||||
// without ISM.
|
||||
nsresult rv = nsIMEStateManager::
|
||||
GetFocusSelectionAndRoot(getter_AddRefs(mSelection),
|
||||
nsresult rv =
|
||||
IMEStateManager::GetFocusSelectionAndRoot(getter_AddRefs(mSelection),
|
||||
getter_AddRefs(mRootContent));
|
||||
if (rv != NS_ERROR_NOT_AVAILABLE) {
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -69,7 +69,7 @@ public:
|
|||
// FlatText means the text that is generated from DOM tree. The BR elements
|
||||
// are replaced to native linefeeds. Other elements are ignored.
|
||||
|
||||
// Get the offset in FlatText of the range. (also used by nsIMEStateManager)
|
||||
// Get the offset in FlatText of the range. (also used by IMEContentObserver)
|
||||
static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
|
||||
nsINode* aNode,
|
||||
int32_t aNodeOffset,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/MiscEvents.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
|
@ -17,7 +18,6 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsEventStateManager.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsIMEStateManager.h"
|
||||
#include "nsContentEventHandler.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsINodeInfo.h"
|
||||
|
@ -3765,7 +3765,7 @@ nsEventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent)
|
|||
void
|
||||
nsEventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext)
|
||||
{
|
||||
nsIMEStateManager::OnDestroyPresContext(aPresContext);
|
||||
IMEStateManager::OnDestroyPresContext(aPresContext);
|
||||
if (mHoverContent) {
|
||||
// Bug 70855: Presentation is going away, possibly for a reframe.
|
||||
// Reset the hover state so that if we're recreating the presentation,
|
||||
|
@ -5176,7 +5176,7 @@ nsEventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent
|
|||
element->LeaveLink(element->GetPresContext());
|
||||
}
|
||||
|
||||
nsIMEStateManager::OnRemoveContent(mPresContext, aContent);
|
||||
IMEStateManager::OnRemoveContent(mPresContext, aContent);
|
||||
|
||||
// inform the focus manager that the content is being removed. If this
|
||||
// content is focused, the focus will be removed without firing events.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -917,6 +917,24 @@ interface WebGLExtensionTextureHalfFloatLinear
|
|||
{
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface WebGLExtensionColorBufferFloat
|
||||
{
|
||||
const GLenum RGBA32F_EXT = 0x8814;
|
||||
const GLenum RGB32F_EXT = 0x8815;
|
||||
const GLenum FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT = 0x8211;
|
||||
const GLenum UNSIGNED_NORMALIZED_EXT = 0x8C17;
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface WebGLExtensionColorBufferHalfFloat
|
||||
{
|
||||
const GLenum RGBA16F_EXT = 0x881A;
|
||||
const GLenum RGB16F_EXT = 0x881B;
|
||||
const GLenum FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT = 0x8211;
|
||||
const GLenum UNSIGNED_NORMALIZED_EXT = 0x8C17;
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface WebGLExtensionVertexArray {
|
||||
const GLenum VERTEX_ARRAY_BINDING_OES = 0x85B5;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "mozFlushType.h" // for mozFlushType::Flush_Frames
|
||||
#include "mozISpellCheckingEngine.h"
|
||||
#include "mozInlineSpellChecker.h" // for mozInlineSpellChecker
|
||||
#include "mozilla/IMEStateManager.h" // for IMEStateManager
|
||||
#include "mozilla/Preferences.h" // for Preferences
|
||||
#include "mozilla/Selection.h" // for Selection, etc
|
||||
#include "mozilla/Services.h" // for GetObserverService
|
||||
|
@ -75,7 +76,6 @@
|
|||
#include "nsIFrame.h" // for nsIFrame
|
||||
#include "nsIHTMLDocument.h" // for nsIHTMLDocument
|
||||
#include "nsIInlineSpellChecker.h" // for nsIInlineSpellChecker, etc
|
||||
#include "nsIMEStateManager.h" // for nsIMEStateManager
|
||||
#include "nsNameSpaceManager.h" // for kNameSpaceID_None, etc
|
||||
#include "nsINode.h" // for nsINode, etc
|
||||
#include "nsIObserverService.h" // for nsIObserverService
|
||||
|
@ -315,7 +315,7 @@ nsEditor::PostCreate()
|
|||
rv = GetPreferredIMEState(&newState);
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
nsCOMPtr<nsIContent> content = GetFocusedContentForIME();
|
||||
nsIMEStateManager::UpdateIMEState(newState, content);
|
||||
IMEStateManager::UpdateIMEState(newState, content);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -496,7 +496,7 @@ nsEditor::SetFlags(uint32_t aFlags)
|
|||
// NOTE: When the enabled state isn't going to be modified, this method
|
||||
// is going to do nothing.
|
||||
nsCOMPtr<nsIContent> content = GetFocusedContentForIME();
|
||||
nsIMEStateManager::UpdateIMEState(newState, content);
|
||||
IMEStateManager::UpdateIMEState(newState, content);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2016,10 +2016,10 @@ nsEditor::EnsureComposition(mozilla::WidgetGUIEvent* aEvent)
|
|||
return;
|
||||
}
|
||||
// The compositionstart event must cause creating new TextComposition
|
||||
// instance at being dispatched by nsIMEStateManager.
|
||||
mComposition = nsIMEStateManager::GetTextCompositionFor(aEvent);
|
||||
// instance at being dispatched by IMEStateManager.
|
||||
mComposition = IMEStateManager::GetTextCompositionFor(aEvent);
|
||||
if (!mComposition) {
|
||||
MOZ_CRASH("nsIMEStateManager doesn't return proper composition");
|
||||
MOZ_CRASH("IMEStateManager doesn't return proper composition");
|
||||
}
|
||||
mComposition->StartHandlingComposition(this);
|
||||
}
|
||||
|
@ -2095,10 +2095,10 @@ nsEditor::ForceCompositionEnd()
|
|||
// Linux. Currently, nsGtkIMModule can know the timing of the cursor move,
|
||||
// so, the latter meaning should be gone.
|
||||
// XXX This may commit a composition in another editor.
|
||||
return nsIMEStateManager::NotifyIME(NOTIFY_IME_OF_CURSOR_POS_CHANGED, pc);
|
||||
return IMEStateManager::NotifyIME(NOTIFY_IME_OF_CURSOR_POS_CHANGED, pc);
|
||||
}
|
||||
|
||||
return nsIMEStateManager::NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, pc);
|
||||
return IMEStateManager::NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, pc);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -770,7 +770,7 @@ public:
|
|||
// Get the focused content, if we're focused. Returns null otherwise.
|
||||
virtual already_AddRefed<nsIContent> GetFocusedContent();
|
||||
|
||||
// Get the focused content for the argument of some nsIMEStateManager's
|
||||
// Get the focused content for the argument of some IMEStateManager's
|
||||
// methods.
|
||||
virtual already_AddRefed<nsIContent> GetFocusedContentForIME();
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* 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 "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/IMEStateManager.h" // for IMEStateManager
|
||||
#include "mozilla/Preferences.h" // for Preferences
|
||||
#include "mozilla/TextEvents.h" // for WidgetCompositionEvent
|
||||
#include "mozilla/dom/Element.h" // for Element
|
||||
|
@ -38,7 +39,6 @@
|
|||
#include "nsIFocusManager.h" // for nsIFocusManager
|
||||
#include "nsIFormControl.h" // for nsIFormControl, etc
|
||||
#include "nsIHTMLEditor.h" // for nsIHTMLEditor
|
||||
#include "nsIMEStateManager.h" // for nsIMEStateManager
|
||||
#include "nsINativeKeyBindings.h" // for nsINativeKeyBindings
|
||||
#include "nsINode.h" // for nsINode, ::NODE_IS_EDITABLE, etc
|
||||
#include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc
|
||||
|
@ -570,7 +570,7 @@ nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
|
|||
nsPresContext* presContext =
|
||||
presShell ? presShell->GetPresContext() : nullptr;
|
||||
if (presContext && currentDoc) {
|
||||
nsIMEStateManager::OnClickInEditor(presContext,
|
||||
IMEStateManager::OnClickInEditor(presContext,
|
||||
currentDoc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent,
|
||||
mouseEvent);
|
||||
}
|
||||
|
@ -954,7 +954,7 @@ nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
|
|||
nsCOMPtr<nsIPresShell> ps = GetPresShell();
|
||||
NS_ENSURE_TRUE(ps, NS_OK);
|
||||
nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContentForIME();
|
||||
nsIMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent);
|
||||
IMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -86,6 +86,9 @@ static const char *sExtensionNames[] = {
|
|||
"GL_OES_texture_half_float",
|
||||
"GL_OES_texture_half_float_linear",
|
||||
"GL_NV_half_float",
|
||||
"GL_EXT_color_buffer_float",
|
||||
"GL_EXT_color_buffer_half_float",
|
||||
"GL_ARB_color_buffer_float",
|
||||
"GL_EXT_unpack_subimage",
|
||||
"GL_OES_standard_derivatives",
|
||||
"GL_EXT_texture_filter_anisotropic",
|
||||
|
|
|
@ -90,6 +90,7 @@ MOZ_BEGIN_ENUM_CLASS(GLFeature)
|
|||
element_index_uint,
|
||||
ES2_compatibility,
|
||||
ES3_compatibility,
|
||||
frag_color_float,
|
||||
frag_depth,
|
||||
framebuffer_blit,
|
||||
framebuffer_multisample,
|
||||
|
@ -102,6 +103,8 @@ MOZ_BEGIN_ENUM_CLASS(GLFeature)
|
|||
occlusion_query2,
|
||||
packed_depth_stencil,
|
||||
query_objects,
|
||||
renderbuffer_color_float,
|
||||
renderbuffer_color_half_float,
|
||||
robustness,
|
||||
sRGB,
|
||||
standard_derivatives,
|
||||
|
@ -365,6 +368,9 @@ public:
|
|||
OES_texture_half_float,
|
||||
OES_texture_half_float_linear,
|
||||
NV_half_float,
|
||||
EXT_color_buffer_float,
|
||||
EXT_color_buffer_half_float,
|
||||
ARB_color_buffer_float,
|
||||
EXT_unpack_subimage,
|
||||
OES_standard_derivatives,
|
||||
EXT_texture_filter_anisotropic,
|
||||
|
|
|
@ -111,6 +111,18 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
|||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
// Removes clamping for float color outputs from frag shaders.
|
||||
"frag_color_float",
|
||||
300, // OpenGL version
|
||||
300, // OpenGL ES version
|
||||
{
|
||||
GLContext::ARB_color_buffer_float,
|
||||
GLContext::EXT_color_buffer_float,
|
||||
GLContext::EXT_color_buffer_half_float,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"frag_depth",
|
||||
200, // OpenGL version
|
||||
|
@ -252,6 +264,26 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
|||
* (added in OpenGL ES 3.0)
|
||||
*/
|
||||
},
|
||||
{
|
||||
"renderbuffer_float",
|
||||
300, // OpenGL version
|
||||
300, // OpenGL ES version
|
||||
{
|
||||
GLContext::ARB_texture_float,
|
||||
GLContext::EXT_color_buffer_float,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"renderbuffer_half_float",
|
||||
300, // OpenGL version
|
||||
300, // OpenGL ES version
|
||||
{
|
||||
GLContext::ARB_texture_float,
|
||||
GLContext::EXT_color_buffer_half_float,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"robustness",
|
||||
0, // OpenGL version
|
||||
|
@ -282,7 +314,7 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
|||
},
|
||||
{
|
||||
"texture_float",
|
||||
310, // OpenGL version
|
||||
300, // OpenGL version
|
||||
300, // OpenGL ES version
|
||||
{
|
||||
GLContext::ARB_texture_float,
|
||||
|
@ -302,7 +334,7 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
|||
},
|
||||
{
|
||||
"texture_half_float",
|
||||
310, // OpenGL version
|
||||
300, // OpenGL version
|
||||
300, // OpenGL ES version
|
||||
{
|
||||
GLContext::ARB_half_float_pixel,
|
||||
|
|
|
@ -14,7 +14,8 @@ NS_IMPL_ISUPPORTS1(GfxTexturesReporter, nsIMemoryReporter)
|
|||
|
||||
int64_t GfxTexturesReporter::sAmount = 0;
|
||||
|
||||
static uint32_t GetBitsPerTexel(GLenum format, GLenum type)
|
||||
static uint32_t
|
||||
GetBitsPerTexel(GLenum format, GLenum type)
|
||||
{
|
||||
// If there is no defined format or type, we're not taking up any memory
|
||||
if (!format || !type) {
|
||||
|
@ -23,16 +24,16 @@ static uint32_t GetBitsPerTexel(GLenum format, GLenum type)
|
|||
|
||||
if (format == LOCAL_GL_DEPTH_COMPONENT) {
|
||||
if (type == LOCAL_GL_UNSIGNED_SHORT)
|
||||
return 2;
|
||||
return 2*8;
|
||||
else if (type == LOCAL_GL_UNSIGNED_INT)
|
||||
return 4;
|
||||
return 4*8;
|
||||
} else if (format == LOCAL_GL_DEPTH_STENCIL) {
|
||||
if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
|
||||
return 4;
|
||||
return 4*8;
|
||||
}
|
||||
|
||||
if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
|
||||
int multiplier = type == LOCAL_GL_FLOAT ? 32 : 8;
|
||||
uint32_t multiplier = type == LOCAL_GL_FLOAT ? 32 : 8;
|
||||
switch (format) {
|
||||
case LOCAL_GL_ALPHA:
|
||||
case LOCAL_GL_LUMINANCE:
|
||||
|
@ -64,7 +65,7 @@ static uint32_t GetBitsPerTexel(GLenum format, GLenum type)
|
|||
type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
|
||||
type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
|
||||
{
|
||||
return 16;
|
||||
return 2*8;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false);
|
||||
|
@ -75,8 +76,8 @@ static uint32_t GetBitsPerTexel(GLenum format, GLenum type)
|
|||
GfxTexturesReporter::UpdateAmount(MemoryUse action, GLenum format,
|
||||
GLenum type, uint16_t tileSize)
|
||||
{
|
||||
uint32_t bytesPerTexel = GetBitsPerTexel(format, type) / 8;
|
||||
int64_t bytes = (int64_t)(tileSize * tileSize * bytesPerTexel);
|
||||
int64_t bitsPerTexel = GetBitsPerTexel(format, type);
|
||||
int64_t bytes = int64_t(tileSize) * int64_t(tileSize) * bitsPerTexel/8;
|
||||
if (action == MemoryFreed) {
|
||||
sAmount -= bytes;
|
||||
} else {
|
||||
|
|
|
@ -132,6 +132,23 @@ enum SurfaceInitMode
|
|||
INIT_MODE_CLEAR
|
||||
};
|
||||
|
||||
/**
|
||||
* A base class for a platform-dependent helper for use by TextureHost.
|
||||
*/
|
||||
class CompositorBackendSpecificData : public RefCounted<CompositorBackendSpecificData>
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(CompositorBackendSpecificData)
|
||||
CompositorBackendSpecificData()
|
||||
{
|
||||
MOZ_COUNT_CTOR(CompositorBackendSpecificData);
|
||||
}
|
||||
virtual ~CompositorBackendSpecificData()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CompositorBackendSpecificData);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Common interface for compositor backends.
|
||||
*
|
||||
|
@ -459,6 +476,10 @@ public:
|
|||
return fillRatio;
|
||||
}
|
||||
|
||||
virtual CompositorBackendSpecificData* GetCompositorBackendSpecificData() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
|
||||
const gfx::Rect& aVisibleRect,
|
||||
|
|
|
@ -384,6 +384,7 @@ struct RemoteImageData {
|
|||
class ImageContainer : public SupportsWeakPtr<ImageContainer> {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer)
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(ImageContainer)
|
||||
|
||||
enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 };
|
||||
|
||||
|
|
|
@ -596,19 +596,12 @@ public:
|
|||
|
||||
bool IsInTransaction() const { return mInTransaction; }
|
||||
|
||||
virtual void AddRegionToClear(const nsIntRegion& aRegion)
|
||||
{
|
||||
mRegionToClear.Or(mRegionToClear, aRegion);
|
||||
}
|
||||
|
||||
protected:
|
||||
nsRefPtr<Layer> mRoot;
|
||||
gfx::UserData mUserData;
|
||||
bool mDestroyed;
|
||||
bool mSnapEffectiveTransforms;
|
||||
|
||||
nsIntRegion mRegionToClear;
|
||||
|
||||
// Print interesting information about this into aTo. Internally
|
||||
// used to implement Dump*() and Log*().
|
||||
virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
|
||||
|
@ -1342,7 +1335,6 @@ public:
|
|||
|
||||
virtual LayerRenderState GetRenderState() { return LayerRenderState(); }
|
||||
|
||||
|
||||
void Mutated()
|
||||
{
|
||||
mManager->Mutated(this);
|
||||
|
|
|
@ -182,7 +182,7 @@ private:
|
|||
bool IsPlaceholder(Tile aTile) const { return aTile == AsDerived().GetPlaceholderTile(); }
|
||||
};
|
||||
|
||||
class BasicTiledLayerBuffer;
|
||||
class ClientTiledLayerBuffer;
|
||||
class SurfaceDescriptorTiles;
|
||||
class ISurfaceAllocator;
|
||||
|
||||
|
@ -195,10 +195,10 @@ public:
|
|||
* Update the current retained layer with the updated layer data.
|
||||
* It is expected that the tiles described by aTiledDescriptor are all in the
|
||||
* ReadLock state, so that the locks can be adopted when recreating a
|
||||
* BasicTiledLayerBuffer locally. This lock will be retained until the buffer
|
||||
* ClientTiledLayerBuffer locally. This lock will be retained until the buffer
|
||||
* has completed uploading.
|
||||
*/
|
||||
virtual void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
virtual void UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
|
||||
|
||||
/**
|
||||
|
@ -292,6 +292,7 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
|
|||
// TODO: Add a tile pool to reduce new allocation
|
||||
int tileX = 0;
|
||||
int tileY = 0;
|
||||
int tilesMissing = 0;
|
||||
// Iterate over the new drawing bounds in steps of tiles.
|
||||
for (int32_t x = newBound.x; x < newBound.XMost(); tileX++) {
|
||||
// Compute tileRect(x,y,width,height) in layer space coordinate
|
||||
|
@ -336,6 +337,10 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
|
|||
// valid content because then we know we can safely recycle
|
||||
// with taking from a tile that has recyclable content.
|
||||
newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile());
|
||||
|
||||
if (aPaintRegion.Intersects(tileRect)) {
|
||||
tilesMissing++;
|
||||
}
|
||||
}
|
||||
|
||||
y += height;
|
||||
|
@ -349,6 +354,26 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
|
|||
mRetainedWidth = tileX;
|
||||
mRetainedHeight = tileY;
|
||||
|
||||
// Pass 1.5: Release excess tiles in oldRetainedTiles
|
||||
// Tiles in oldRetainedTiles that aren't in newRetainedTiles will be recycled
|
||||
// before creating new ones, but there could still be excess unnecessary
|
||||
// tiles. As tiles may not have a fixed memory cost (for example, due to
|
||||
// double-buffering), we should release these excess tiles first.
|
||||
int oldTileCount = 0;
|
||||
for (size_t i = 0; i < oldRetainedTiles.Length(); i++) {
|
||||
Tile oldTile = oldRetainedTiles[i];
|
||||
if (IsPlaceholder(oldTile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (oldTileCount >= tilesMissing) {
|
||||
oldRetainedTiles[i] = AsDerived().GetPlaceholderTile();
|
||||
AsDerived().ReleaseTile(oldTile);
|
||||
} else {
|
||||
oldTileCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ABORT_IF_FALSE(aNewValidRegion.Contains(aPaintRegion), "Painting a region outside the visible region");
|
||||
#ifdef DEBUG
|
||||
nsIntRegion oldAndPainted(oldValidRegion);
|
||||
|
@ -415,9 +440,15 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
|
|||
"index out of range");
|
||||
|
||||
Tile newTile = newRetainedTiles[index];
|
||||
|
||||
// Try to reuse a tile from the old retained tiles that had no partially
|
||||
// valid content.
|
||||
while (IsPlaceholder(newTile) && oldRetainedTiles.Length() > 0) {
|
||||
AsDerived().SwapTiles(newTile, oldRetainedTiles[oldRetainedTiles.Length()-1]);
|
||||
oldRetainedTiles.RemoveElementAt(oldRetainedTiles.Length()-1);
|
||||
if (!IsPlaceholder(newTile)) {
|
||||
oldTileCount--;
|
||||
}
|
||||
}
|
||||
|
||||
// We've done our best effort to recycle a tile but it can be null
|
||||
|
@ -438,13 +469,8 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
|
|||
x += width;
|
||||
}
|
||||
|
||||
// Throw away any tiles we didn't recycle
|
||||
// TODO: Add a tile pool
|
||||
while (oldRetainedTiles.Length() > 0) {
|
||||
Tile oldTile = oldRetainedTiles[oldRetainedTiles.Length()-1];
|
||||
oldRetainedTiles.RemoveElementAt(oldRetainedTiles.Length()-1);
|
||||
AsDerived().ReleaseTile(oldTile);
|
||||
}
|
||||
// At this point, oldTileCount should be zero
|
||||
NS_ABORT_IF_FALSE(oldTileCount == 0, "Failed to release old tiles");
|
||||
|
||||
mRetainedTiles = newRetainedTiles;
|
||||
mValidRegion = aNewValidRegion;
|
||||
|
|
|
@ -625,16 +625,6 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
|
|||
}
|
||||
|
||||
PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
|
||||
if (!mRegionToClear.IsEmpty()) {
|
||||
AutoSetOperator op(mTarget, gfxContext::OPERATOR_CLEAR);
|
||||
nsIntRegionRectIterator iter(mRegionToClear);
|
||||
const nsIntRect *r;
|
||||
while ((r = iter.Next())) {
|
||||
mTarget->NewPath();
|
||||
mTarget->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
|
||||
mTarget->Fill();
|
||||
}
|
||||
}
|
||||
if (mWidget) {
|
||||
FlashWidgetUpdateArea(mTarget);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,8 @@ class TextureClientX11
|
|||
return mFormat;
|
||||
}
|
||||
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
|
||||
|
||||
private:
|
||||
gfx::SurfaceFormat mFormat;
|
||||
gfx::IntSize mSize;
|
||||
|
|
|
@ -99,13 +99,6 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
|||
}
|
||||
}
|
||||
|
||||
TemporaryRef<BufferTextureClient>
|
||||
CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
|
||||
{
|
||||
return CompositableClient::CreateBufferTextureClient(aFormat,
|
||||
mTextureInfo.mTextureFlags | aFlags);
|
||||
}
|
||||
|
||||
CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder,
|
||||
TextureFlags aFlags)
|
||||
: CanvasClient(aLayerForwarder, aFlags)
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
TextureFlags aFlags);
|
||||
|
||||
CanvasClient(CompositableForwarder* aFwd, TextureFlags aFlags)
|
||||
: CompositableClient(aFwd)
|
||||
: CompositableClient(aFwd, aFlags)
|
||||
{
|
||||
mTextureInfo.mTextureFlags = aFlags;
|
||||
}
|
||||
|
@ -95,10 +95,6 @@ public:
|
|||
return CompositableClient::AddTextureClient(aTexture);
|
||||
}
|
||||
|
||||
virtual TemporaryRef<BufferTextureClient>
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT) MOZ_OVERRIDE;
|
||||
|
||||
virtual void OnDetach() MOZ_OVERRIDE
|
||||
{
|
||||
mBuffer = nullptr;
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/PLayerChild.h" // for PLayerChild
|
||||
#include "mozilla/layers/LayerTransactionChild.h"
|
||||
#include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
|
||||
#include "nsAString.h"
|
||||
#include "nsIWidget.h" // for nsIWidget
|
||||
#include "nsTArray.h" // for AutoInfallibleTArray
|
||||
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
|
||||
#include "TiledLayerBuffer.h"
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
#include "AndroidBridge.h"
|
||||
#endif
|
||||
|
@ -34,6 +36,11 @@ using namespace mozilla::gfx;
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
TextureClientPoolMember::TextureClientPoolMember(SurfaceFormat aFormat, TextureClientPool* aTexturePool)
|
||||
: mFormat(aFormat)
|
||||
, mTexturePool(aTexturePool)
|
||||
{}
|
||||
|
||||
ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
|
||||
: mPhase(PHASE_NONE)
|
||||
, mWidget(aWidget)
|
||||
|
@ -53,6 +60,8 @@ ClientLayerManager::~ClientLayerManager()
|
|||
mRoot = nullptr;
|
||||
|
||||
MOZ_COUNT_DTOR(ClientLayerManager);
|
||||
|
||||
mTexturePools.clear();
|
||||
}
|
||||
|
||||
int32_t
|
||||
|
@ -222,6 +231,11 @@ ClientLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
|
|||
} else {
|
||||
MakeSnapshotIfRequired();
|
||||
}
|
||||
|
||||
for (const TextureClientPoolMember* item = mTexturePools.getFirst();
|
||||
item; item = item->getNext()) {
|
||||
item->mTexturePool->ReturnDeferredClients();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -440,6 +454,26 @@ ClientLayerManager::SetIsFirstPaint()
|
|||
mForwarder->SetIsFirstPaint();
|
||||
}
|
||||
|
||||
TextureClientPool*
|
||||
ClientLayerManager::GetTexturePool(SurfaceFormat aFormat)
|
||||
{
|
||||
for (const TextureClientPoolMember* item = mTexturePools.getFirst();
|
||||
item; item = item->getNext()) {
|
||||
if (item->mFormat == aFormat) {
|
||||
return item->mTexturePool;
|
||||
}
|
||||
}
|
||||
|
||||
TextureClientPoolMember* texturePoolMember =
|
||||
new TextureClientPoolMember(aFormat,
|
||||
new TextureClientPool(aFormat, IntSize(TILEDLAYERBUFFER_TILE_SIZE,
|
||||
TILEDLAYERBUFFER_TILE_SIZE),
|
||||
mForwarder));
|
||||
mTexturePools.insertBack(texturePoolMember);
|
||||
|
||||
return texturePoolMember->mTexturePool;
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::ClearCachedResources(Layer* aSubtree)
|
||||
{
|
||||
|
@ -452,6 +486,10 @@ ClientLayerManager::ClearCachedResources(Layer* aSubtree)
|
|||
} else if (mRoot) {
|
||||
ClearLayer(mRoot);
|
||||
}
|
||||
for (const TextureClientPoolMember* item = mTexturePools.getFirst();
|
||||
item; item = item->getNext()) {
|
||||
item->mTexturePool->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Layers.h"
|
||||
#include "gfxContext.h" // for gfxContext
|
||||
#include "mozilla/Attributes.h" // for MOZ_OVERRIDE
|
||||
#include "mozilla/LinkedList.h" // For LinkedList
|
||||
#include "mozilla/WidgetUtils.h" // for ScreenRotation
|
||||
#include "mozilla/gfx/Rect.h" // for Rect
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
|
@ -32,6 +33,16 @@ class ClientThebesLayer;
|
|||
class CompositorChild;
|
||||
class ImageLayer;
|
||||
class PLayerChild;
|
||||
class TextureClientPool;
|
||||
|
||||
class TextureClientPoolMember
|
||||
: public LinkedListElement<TextureClientPoolMember> {
|
||||
public:
|
||||
TextureClientPoolMember(gfx::SurfaceFormat aFormat, TextureClientPool* aTexturePool);
|
||||
|
||||
gfx::SurfaceFormat mFormat;
|
||||
RefPtr<TextureClientPool> mTexturePool;
|
||||
};
|
||||
|
||||
class ClientLayerManager : public LayerManager
|
||||
{
|
||||
|
@ -96,6 +107,8 @@ public:
|
|||
|
||||
virtual void SetIsFirstPaint() MOZ_OVERRIDE;
|
||||
|
||||
TextureClientPool *GetTexturePool(gfx::SurfaceFormat aFormat);
|
||||
|
||||
// Drop cached resources and ask our shadow manager to do the same,
|
||||
// if we have one.
|
||||
virtual void ClearCachedResources(Layer* aSubtree = nullptr) MOZ_OVERRIDE;
|
||||
|
@ -214,6 +227,7 @@ private:
|
|||
bool mNeedsComposite;
|
||||
|
||||
RefPtr<ShadowLayerForwarder> mForwarder;
|
||||
LinkedList<TextureClientPoolMember> mTexturePools;
|
||||
};
|
||||
|
||||
class ClientLayer : public ShadowableLayer
|
||||
|
|
|
@ -172,7 +172,10 @@ ClientLayerManager::CreateThebesLayerWithHint(ThebesLayerCreationHint aHint)
|
|||
#ifdef MOZ_B2G
|
||||
aHint == SCROLLABLE &&
|
||||
#endif
|
||||
gfxPrefs::LayersTilesEnabled() && AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL) {
|
||||
gfxPrefs::LayersTilesEnabled() &&
|
||||
(AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL ||
|
||||
AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D9 ||
|
||||
AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D11)) {
|
||||
nsRefPtr<ClientTiledThebesLayer> layer =
|
||||
new ClientTiledThebesLayer(this);
|
||||
CREATE_SHADOW(Thebes);
|
||||
|
|
|
@ -37,6 +37,14 @@ ClientTiledThebesLayer::~ClientTiledThebesLayer()
|
|||
MOZ_COUNT_DTOR(ClientTiledThebesLayer);
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledThebesLayer::ClearCachedResources()
|
||||
{
|
||||
if (mContentClient) {
|
||||
mContentClient->ClearCachedResources();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
|
||||
{
|
||||
|
@ -189,7 +197,7 @@ ClientTiledThebesLayer::RenderLayer()
|
|||
callback, data);
|
||||
|
||||
ClientManager()->Hold(this);
|
||||
mContentClient->LockCopyAndWrite(TiledContentClient::TILED_BUFFER);
|
||||
mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -262,7 +270,7 @@ ClientTiledThebesLayer::RenderLayer()
|
|||
|
||||
if (updatedBuffer) {
|
||||
ClientManager()->Hold(this);
|
||||
mContentClient->LockCopyAndWrite(TiledContentClient::TILED_BUFFER);
|
||||
mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
|
||||
|
||||
// If there are low precision updates, mark the paint as unfinished and
|
||||
// request a repeat transaction.
|
||||
|
@ -331,7 +339,7 @@ ClientTiledThebesLayer::RenderLayer()
|
|||
// and the associated resources can be freed.
|
||||
if (updatedLowPrecision) {
|
||||
ClientManager()->Hold(this);
|
||||
mContentClient->LockCopyAndWrite(TiledContentClient::LOW_PRECISION_TILED_BUFFER);
|
||||
mContentClient->UseTiledLayerBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER);
|
||||
}
|
||||
|
||||
EndPaint(false);
|
||||
|
|
|
@ -63,6 +63,8 @@ public:
|
|||
|
||||
virtual void RenderLayer();
|
||||
|
||||
virtual void ClearCachedResources() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
ClientLayerManager* ClientManager()
|
||||
{
|
||||
|
|
|
@ -12,20 +12,9 @@
|
|||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "gfxASurface.h" // for gfxContentType
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/layers/TextureD3D9.h"
|
||||
#include "gfxWindowsPlatform.h" // for gfxWindowsPlatform
|
||||
#include "mozilla/layers/TextureD3D11.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#endif
|
||||
#ifdef MOZ_X11
|
||||
#include "mozilla/layers/TextureClientX11.h"
|
||||
#ifdef GL_PROVIDER_GLX
|
||||
#include "GLXLibrary.h"
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include <cutils/properties.h>
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
#include "mozilla/layers/TextureD3D9.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
@ -33,14 +22,15 @@ using namespace mozilla::gfx;
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
CompositableClient::CompositableClient(CompositableForwarder* aForwarder)
|
||||
CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
|
||||
TextureFlags aTextureFlags)
|
||||
: mCompositableChild(nullptr)
|
||||
, mForwarder(aForwarder)
|
||||
, mTextureFlags(aTextureFlags)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CompositableClient);
|
||||
}
|
||||
|
||||
|
||||
CompositableClient::~CompositableClient()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CompositableClient);
|
||||
|
@ -131,7 +121,7 @@ CompositableClient::CreateDeprecatedTextureClient(DeprecatedTextureClientType aD
|
|||
break;
|
||||
}
|
||||
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
|
||||
!GetForwarder()->ForwardsToDifferentProcess()) {
|
||||
GetForwarder()->IsSameProcess()) {
|
||||
// We can't use a d3d9 texture for an RGBA surface because we cannot get a DC for
|
||||
// for a gfxWindowsSurface.
|
||||
// We have to wait for the compositor thread to create a d3d9 device before we
|
||||
|
@ -181,117 +171,16 @@ TemporaryRef<BufferTextureClient>
|
|||
CompositableClient::CreateBufferTextureClient(SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
// XXX - Once bug 908196 is fixed, we can use gralloc textures here which will
|
||||
// improve performances of videos using SharedPlanarYCbCrImage on b2g.
|
||||
//#ifdef MOZ_WIDGET_GONK
|
||||
// {
|
||||
// RefPtr<BufferTextureClient> result = new GrallocTextureClientOGL(this,
|
||||
// aFormat,
|
||||
// aTextureFlags);
|
||||
// return result.forget();
|
||||
// }
|
||||
//#endif
|
||||
if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
|
||||
RefPtr<BufferTextureClient> result = new MemoryTextureClient(this, aFormat, aTextureFlags);
|
||||
return result.forget();
|
||||
return TextureClient::CreateBufferTextureClient(GetForwarder(), aFormat,
|
||||
aTextureFlags | mTextureFlags);
|
||||
}
|
||||
RefPtr<BufferTextureClient> result = new ShmemTextureClient(this, aFormat, aTextureFlags);
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
static bool
|
||||
DisableGralloc(SurfaceFormat aFormat)
|
||||
{
|
||||
if (aFormat == gfx::SurfaceFormat::A8) {
|
||||
return true;
|
||||
}
|
||||
#if ANDROID_VERSION <= 15
|
||||
static bool checkedDevice = false;
|
||||
static bool disableGralloc = false;
|
||||
|
||||
if (!checkedDevice) {
|
||||
char propValue[PROPERTY_VALUE_MAX];
|
||||
property_get("ro.product.device", propValue, "None");
|
||||
|
||||
if (strcmp("crespo",propValue) == 0) {
|
||||
NS_WARNING("Nexus S has issues with gralloc, falling back to shmem");
|
||||
disableGralloc = true;
|
||||
}
|
||||
|
||||
checkedDevice = true;
|
||||
}
|
||||
|
||||
if (disableGralloc) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
TemporaryRef<TextureClient>
|
||||
CompositableClient::CreateTextureClientForDrawing(SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
RefPtr<TextureClient> result;
|
||||
|
||||
#ifdef XP_WIN
|
||||
LayersBackend parentBackend = GetForwarder()->GetCompositorBackendType();
|
||||
if (parentBackend == LayersBackend::LAYERS_D3D11 && gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
|
||||
result = new TextureClientD3D11(aFormat, aTextureFlags);
|
||||
}
|
||||
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
|
||||
!GetForwarder()->ForwardsToDifferentProcess() &&
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
|
||||
if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
|
||||
result = new DIBTextureClientD3D9(aFormat, aTextureFlags);
|
||||
} else {
|
||||
result = new CairoTextureClientD3D9(aFormat, aTextureFlags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_X11
|
||||
LayersBackend parentBackend = GetForwarder()->GetCompositorBackendType();
|
||||
gfxSurfaceType type =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
|
||||
|
||||
if (parentBackend == LayersBackend::LAYERS_BASIC &&
|
||||
type == gfxSurfaceType::Xlib &&
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK))
|
||||
{
|
||||
result = new TextureClientX11(aFormat, aTextureFlags);
|
||||
}
|
||||
#ifdef GL_PROVIDER_GLX
|
||||
if (parentBackend == LayersBackend::LAYERS_OPENGL &&
|
||||
type == gfxSurfaceType::Xlib &&
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK) &&
|
||||
aFormat != SurfaceFormat::A8 &&
|
||||
gl::sGLXLibrary.UseTextureFromPixmap())
|
||||
{
|
||||
result = new TextureClientX11(aFormat, aTextureFlags);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (!DisableGralloc(aFormat)) {
|
||||
result = new GrallocTextureClientOGL(this, aFormat, aTextureFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Can't do any better than a buffer texture client.
|
||||
if (!result) {
|
||||
result = CreateBufferTextureClient(aFormat, aTextureFlags);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!result || result->AsTextureClientDrawTarget(),
|
||||
"Not a TextureClientDrawTarget?");
|
||||
return result;
|
||||
return TextureClient::CreateTextureClientForDrawing(GetForwarder(), aFormat,
|
||||
aTextureFlags | mTextureFlags);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -73,7 +73,7 @@ class CompositableClient : public AtomicRefCounted<CompositableClient>
|
|||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(CompositableClient)
|
||||
CompositableClient(CompositableForwarder* aForwarder);
|
||||
CompositableClient(CompositableForwarder* aForwarder, TextureFlags aFlags = 0);
|
||||
|
||||
virtual ~CompositableClient();
|
||||
|
||||
|
@ -85,7 +85,7 @@ public:
|
|||
CreateDeprecatedTextureClient(DeprecatedTextureClientType aDeprecatedTextureClientType,
|
||||
gfxContentType aContentType = gfxContentType::SENTINEL);
|
||||
|
||||
virtual TemporaryRef<BufferTextureClient>
|
||||
TemporaryRef<BufferTextureClient>
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
|
||||
|
||||
|
@ -143,9 +143,18 @@ public:
|
|||
*/
|
||||
virtual void OnDetach() {}
|
||||
|
||||
/**
|
||||
* Clear any resources that are not immediately necessary. This may be called
|
||||
* in low-memory conditions.
|
||||
*/
|
||||
virtual void ClearCachedResources() {}
|
||||
|
||||
protected:
|
||||
CompositableChild* mCompositableChild;
|
||||
CompositableForwarder* mForwarder;
|
||||
// Some layers may want to enforce some flags to all their textures
|
||||
// (like disallowing tiling)
|
||||
TextureFlags mTextureFlags;
|
||||
|
||||
friend class CompositableChild;
|
||||
};
|
||||
|
|
|
@ -82,8 +82,7 @@ ImageClient::CreateImageClient(CompositableType aCompositableHostType,
|
|||
ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags,
|
||||
CompositableType aType)
|
||||
: ImageClient(aFwd, aType)
|
||||
, mTextureFlags(aFlags)
|
||||
: ImageClient(aFwd, aFlags, aType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -310,12 +309,6 @@ ImageClientSingle::AddTextureClient(TextureClient* aTexture)
|
|||
return CompositableClient::AddTextureClient(aTexture);
|
||||
}
|
||||
|
||||
TemporaryRef<BufferTextureClient>
|
||||
ImageClientSingle::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
|
||||
{
|
||||
return CompositableClient::CreateBufferTextureClient(aFormat, mTextureFlags | aFlags);
|
||||
}
|
||||
|
||||
void
|
||||
ImageClientSingle::OnDetach()
|
||||
{
|
||||
|
@ -329,8 +322,9 @@ ImageClientBuffered::OnDetach()
|
|||
mBackBuffer = nullptr;
|
||||
}
|
||||
|
||||
ImageClient::ImageClient(CompositableForwarder* aFwd, CompositableType aType)
|
||||
: CompositableClient(aFwd)
|
||||
ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
|
||||
CompositableType aType)
|
||||
: CompositableClient(aFwd, aFlags)
|
||||
, mType(aType)
|
||||
, mLastPaintedImageSerial(0)
|
||||
{}
|
||||
|
@ -349,7 +343,7 @@ ImageClient::UpdatePictureRect(nsIntRect aRect)
|
|||
DeprecatedImageClientSingle::DeprecatedImageClientSingle(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags,
|
||||
CompositableType aType)
|
||||
: ImageClient(aFwd, aType)
|
||||
: ImageClient(aFwd, aFlags, aType)
|
||||
, mTextureInfo(aType)
|
||||
{
|
||||
mTextureInfo.mTextureFlags = aFlags;
|
||||
|
@ -482,7 +476,7 @@ DeprecatedImageClientSingle::Updated()
|
|||
|
||||
ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags)
|
||||
: ImageClient(aFwd, BUFFER_BRIDGE)
|
||||
: ImageClient(aFwd, aFlags, BUFFER_BRIDGE)
|
||||
, mAsyncContainerID(0)
|
||||
, mLayer(nullptr)
|
||||
{
|
||||
|
|
|
@ -67,7 +67,8 @@ public:
|
|||
virtual void FlushAllImages(bool aExceptFront) {}
|
||||
|
||||
protected:
|
||||
ImageClient(CompositableForwarder* aFwd, CompositableType aType);
|
||||
ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
|
||||
CompositableType aType);
|
||||
|
||||
CompositableType mType;
|
||||
int32_t mLastPaintedImageSerial;
|
||||
|
@ -90,10 +91,6 @@ public:
|
|||
|
||||
virtual bool AddTextureClient(TextureClient* aTexture) MOZ_OVERRIDE;
|
||||
|
||||
virtual TemporaryRef<BufferTextureClient>
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT) MOZ_OVERRIDE;
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE;
|
||||
|
||||
virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat) MOZ_OVERRIDE;
|
||||
|
@ -105,9 +102,6 @@ protected:
|
|||
|
||||
protected:
|
||||
RefPtr<TextureClient> mFrontBuffer;
|
||||
// Some layers may want to enforce some flags to all their textures
|
||||
// (like disallowing tiling)
|
||||
TextureFlags mTextureFlags;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,25 @@
|
|||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "ImageContainer.h" // for PlanarYCbCrImage, etc
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/layers/TextureClientOGL.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/layers/TextureD3D9.h"
|
||||
#include "mozilla/layers/TextureD3D11.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#endif
|
||||
#ifdef MOZ_X11
|
||||
#include "mozilla/layers/TextureClientX11.h"
|
||||
#ifdef GL_PROVIDER_GLX
|
||||
#include "GLXLibrary.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include <cutils/properties.h>
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_ANDROID_OMTC
|
||||
# include "gfxReusableImageSurfaceWrapper.h"
|
||||
|
@ -193,6 +212,120 @@ TextureClient::GetIPDLActor()
|
|||
return mActor;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
static bool
|
||||
DisableGralloc(SurfaceFormat aFormat)
|
||||
{
|
||||
if (aFormat == gfx::SurfaceFormat::A8) {
|
||||
return true;
|
||||
}
|
||||
#if ANDROID_VERSION <= 15
|
||||
static bool checkedDevice = false;
|
||||
static bool disableGralloc = false;
|
||||
|
||||
if (!checkedDevice) {
|
||||
char propValue[PROPERTY_VALUE_MAX];
|
||||
property_get("ro.product.device", propValue, "None");
|
||||
|
||||
if (strcmp("crespo",propValue) == 0) {
|
||||
NS_WARNING("Nexus S has issues with gralloc, falling back to shmem");
|
||||
disableGralloc = true;
|
||||
}
|
||||
|
||||
checkedDevice = true;
|
||||
}
|
||||
|
||||
if (disableGralloc) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
TemporaryRef<TextureClient>
|
||||
TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
||||
SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
RefPtr<TextureClient> result;
|
||||
|
||||
#ifdef XP_WIN
|
||||
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
|
||||
if (parentBackend == LayersBackend::LAYERS_D3D11 && gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
|
||||
result = new TextureClientD3D11(aFormat, aTextureFlags);
|
||||
}
|
||||
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
|
||||
aAllocator->IsSameProcess() &&
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
|
||||
if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
|
||||
result = new DIBTextureClientD3D9(aFormat, aTextureFlags);
|
||||
} else {
|
||||
result = new CairoTextureClientD3D9(aFormat, aTextureFlags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_X11
|
||||
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
|
||||
gfxSurfaceType type =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
|
||||
|
||||
if (parentBackend == LayersBackend::LAYERS_BASIC &&
|
||||
type == gfxSurfaceType::Xlib &&
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK))
|
||||
{
|
||||
result = new TextureClientX11(aFormat, aTextureFlags);
|
||||
}
|
||||
#ifdef GL_PROVIDER_GLX
|
||||
if (parentBackend == LayersBackend::LAYERS_OPENGL &&
|
||||
type == gfxSurfaceType::Xlib &&
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK) &&
|
||||
aFormat != SurfaceFormat::A8 &&
|
||||
gl::sGLXLibrary.UseTextureFromPixmap())
|
||||
{
|
||||
result = new TextureClientX11(aFormat, aTextureFlags);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (!DisableGralloc(aFormat)) {
|
||||
result = new GrallocTextureClientOGL(aAllocator, aFormat, aTextureFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Can't do any better than a buffer texture client.
|
||||
if (!result) {
|
||||
result = CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!result || result->AsTextureClientDrawTarget(),
|
||||
"Not a TextureClientDrawTarget?");
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
TemporaryRef<BufferTextureClient>
|
||||
TextureClient::CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
|
||||
SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
|
||||
RefPtr<BufferTextureClient> result = new MemoryTextureClient(aAllocator, aFormat,
|
||||
aTextureFlags);
|
||||
return result.forget();
|
||||
}
|
||||
RefPtr<BufferTextureClient> result = new ShmemTextureClient(aAllocator, aFormat,
|
||||
aTextureFlags);
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
|
||||
class ShmemTextureClientData : public TextureClientData
|
||||
{
|
||||
public:
|
||||
|
@ -296,6 +429,30 @@ void TextureClient::ForceRemove()
|
|||
MarkInvalid();
|
||||
}
|
||||
|
||||
bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
|
||||
const gfx::IntRect* aRect,
|
||||
const gfx::IntPoint* aPoint)
|
||||
{
|
||||
MOZ_ASSERT(IsLocked());
|
||||
MOZ_ASSERT(aTarget->IsLocked());
|
||||
|
||||
if (!aTarget->AsTextureClientDrawTarget() || !AsTextureClientDrawTarget()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> destinationTarget = aTarget->AsTextureClientDrawTarget()->GetAsDrawTarget();
|
||||
RefPtr<DrawTarget> sourceTarget = AsTextureClientDrawTarget()->GetAsDrawTarget();
|
||||
RefPtr<gfx::SourceSurface> source = sourceTarget->Snapshot();
|
||||
destinationTarget->CopySurface(source,
|
||||
aRect ? *aRect : gfx::IntRect(gfx::IntPoint(0, 0), GetSize()),
|
||||
aPoint ? *aPoint : gfx::IntPoint(0, 0));
|
||||
destinationTarget = nullptr;
|
||||
source = nullptr;
|
||||
sourceTarget = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TextureClient::Finalize()
|
||||
{
|
||||
|
@ -339,12 +496,6 @@ ShmemTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor)
|
|||
return true;
|
||||
}
|
||||
|
||||
ISurfaceAllocator*
|
||||
ShmemTextureClient::GetAllocator() const
|
||||
{
|
||||
return mCompositable->GetForwarder();
|
||||
}
|
||||
|
||||
bool
|
||||
ShmemTextureClient::Allocate(uint32_t aSize)
|
||||
{
|
||||
|
@ -371,10 +522,10 @@ ShmemTextureClient::GetBufferSize() const
|
|||
return mShmem.Size<uint8_t>();
|
||||
}
|
||||
|
||||
ShmemTextureClient::ShmemTextureClient(CompositableClient* aCompositable,
|
||||
ShmemTextureClient::ShmemTextureClient(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureClient(aCompositable, aFormat, aFlags)
|
||||
: BufferTextureClient(aAllocator, aFormat, aFlags)
|
||||
, mAllocated(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ShmemTextureClient);
|
||||
|
@ -386,7 +537,7 @@ ShmemTextureClient::~ShmemTextureClient()
|
|||
if (ShouldDeallocateInDestructor()) {
|
||||
// if the buffer has never been shared we must deallocate it or ir would
|
||||
// leak.
|
||||
mCompositable->GetForwarder()->DeallocShmem(mShmem);
|
||||
GetAllocator()->DeallocShmem(mShmem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,10 +568,10 @@ MemoryTextureClient::Allocate(uint32_t aSize)
|
|||
return true;
|
||||
}
|
||||
|
||||
MemoryTextureClient::MemoryTextureClient(CompositableClient* aCompositable,
|
||||
MemoryTextureClient::MemoryTextureClient(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureClient(aCompositable, aFormat, aFlags)
|
||||
: BufferTextureClient(aAllocator, aFormat, aFlags)
|
||||
, mBuffer(nullptr)
|
||||
, mBufSize(0)
|
||||
{
|
||||
|
@ -438,11 +589,11 @@ MemoryTextureClient::~MemoryTextureClient()
|
|||
}
|
||||
}
|
||||
|
||||
BufferTextureClient::BufferTextureClient(CompositableClient* aCompositable,
|
||||
BufferTextureClient::BufferTextureClient(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags)
|
||||
: TextureClient(aFlags)
|
||||
, mCompositable(aCompositable)
|
||||
, mAllocator(aAllocator)
|
||||
, mFormat(aFormat)
|
||||
, mUsingFallbackDrawTarget(false)
|
||||
, mLocked(false)
|
||||
|
@ -451,6 +602,12 @@ BufferTextureClient::BufferTextureClient(CompositableClient* aCompositable,
|
|||
BufferTextureClient::~BufferTextureClient()
|
||||
{}
|
||||
|
||||
ISurfaceAllocator*
|
||||
BufferTextureClient::GetAllocator() const
|
||||
{
|
||||
return mAllocator;
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureClient::UpdateSurface(gfxASurface* aSurface)
|
||||
{
|
||||
|
|
|
@ -44,6 +44,7 @@ class PlanarYCbCrData;
|
|||
class Image;
|
||||
class PTextureChild;
|
||||
class TextureChild;
|
||||
class BufferTextureClient;
|
||||
|
||||
/**
|
||||
* TextureClient is the abstraction that allows us to share data between the
|
||||
|
@ -198,6 +199,16 @@ public:
|
|||
TextureClient(TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
|
||||
virtual ~TextureClient();
|
||||
|
||||
static TemporaryRef<BufferTextureClient>
|
||||
CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
static TemporaryRef<TextureClient>
|
||||
CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
virtual TextureClientSurface* AsTextureClientSurface() { return nullptr; }
|
||||
virtual TextureClientDrawTarget* AsTextureClientDrawTarget() { return nullptr; }
|
||||
virtual TextureClientYCbCr* AsTextureClientYCbCr() { return nullptr; }
|
||||
|
@ -214,6 +225,15 @@ public:
|
|||
|
||||
virtual bool IsLocked() const = 0;
|
||||
|
||||
/**
|
||||
* Copies a rectangle from this texture client to a position in aTarget.
|
||||
* It is assumed that the necessary locks are in place; so this should at
|
||||
* least have a read lock and aTarget should at least have a write lock.
|
||||
*/
|
||||
virtual bool CopyToTextureClient(TextureClient* aTarget,
|
||||
const gfx::IntRect* aRect,
|
||||
const gfx::IntPoint* aPoint);
|
||||
|
||||
/**
|
||||
* Returns true if this texture has a lock/unlock mechanism.
|
||||
* Textures that do not implement locking should be immutable or should
|
||||
|
@ -221,6 +241,13 @@ public:
|
|||
*/
|
||||
virtual bool ImplementsLocking() const { return false; }
|
||||
|
||||
/**
|
||||
* Indicates whether the TextureClient implementation is backed by an
|
||||
* in-memory buffer. The consequence of this is that locking the
|
||||
* TextureClient does not contend with locking the texture on the host side.
|
||||
*/
|
||||
virtual bool HasInternalBuffer() const = 0;
|
||||
|
||||
/**
|
||||
* Allocate and deallocate a TextureChild actor.
|
||||
*
|
||||
|
@ -355,7 +382,7 @@ class BufferTextureClient : public TextureClient
|
|||
, public TextureClientDrawTarget
|
||||
{
|
||||
public:
|
||||
BufferTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
|
||||
BufferTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags);
|
||||
|
||||
virtual ~BufferTextureClient();
|
||||
|
@ -411,9 +438,13 @@ public:
|
|||
|
||||
virtual size_t GetBufferSize() const = 0;
|
||||
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
ISurfaceAllocator* GetAllocator() const;
|
||||
|
||||
protected:
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
CompositableClient* mCompositable;
|
||||
RefPtr<ISurfaceAllocator> mAllocator;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
gfx::IntSize mSize;
|
||||
OpenMode mOpenMode;
|
||||
|
@ -428,7 +459,7 @@ protected:
|
|||
class ShmemTextureClient : public BufferTextureClient
|
||||
{
|
||||
public:
|
||||
ShmemTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
|
||||
ShmemTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags);
|
||||
|
||||
~ShmemTextureClient();
|
||||
|
@ -445,13 +476,12 @@ public:
|
|||
|
||||
virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
|
||||
|
||||
ISurfaceAllocator* GetAllocator() const;
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
mozilla::ipc::Shmem& GetShmem() { return mShmem; }
|
||||
|
||||
protected:
|
||||
mozilla::ipc::Shmem mShmem;
|
||||
RefPtr<ISurfaceAllocator> mAllocator;
|
||||
bool mAllocated;
|
||||
};
|
||||
|
||||
|
@ -463,7 +493,7 @@ protected:
|
|||
class MemoryTextureClient : public BufferTextureClient
|
||||
{
|
||||
public:
|
||||
MemoryTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat,
|
||||
MemoryTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags);
|
||||
|
||||
~MemoryTextureClient();
|
||||
|
@ -478,6 +508,8 @@ public:
|
|||
|
||||
virtual bool IsAllocated() const MOZ_OVERRIDE { return mBuffer != nullptr; }
|
||||
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* 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 "TextureClientPool.h"
|
||||
#include "CompositableClient.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
static void
|
||||
ShrinkCallback(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
static_cast<TextureClientPool*>(aClosure)->ShrinkToMinimumSize();
|
||||
}
|
||||
|
||||
TextureClientPool::TextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
|
||||
ISurfaceAllocator *aAllocator)
|
||||
: mFormat(aFormat)
|
||||
, mSize(aSize)
|
||||
, mOutstandingClients(0)
|
||||
, mSurfaceAllocator(aAllocator)
|
||||
{
|
||||
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
}
|
||||
|
||||
TemporaryRef<TextureClient>
|
||||
TextureClientPool::GetTextureClient()
|
||||
{
|
||||
mOutstandingClients++;
|
||||
|
||||
// Try to fetch a client from the pool
|
||||
RefPtr<TextureClient> textureClient;
|
||||
if (mTextureClients.size()) {
|
||||
textureClient = mTextureClients.top();
|
||||
mTextureClients.pop();
|
||||
return textureClient;
|
||||
}
|
||||
|
||||
// We're increasing the number of outstanding TextureClients without reusing a
|
||||
// client, we may need to free a deferred-return TextureClient.
|
||||
ShrinkToMaximumSize();
|
||||
|
||||
// No unused clients in the pool, create one
|
||||
if (gfxPrefs::ForceShmemTiles()) {
|
||||
textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator, mFormat, TEXTURE_IMMEDIATE_UPLOAD);
|
||||
} else {
|
||||
textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator, mFormat, TEXTURE_IMMEDIATE_UPLOAD);
|
||||
}
|
||||
textureClient->AsTextureClientDrawTarget()->AllocateForSurface(mSize, ALLOC_DEFAULT);
|
||||
|
||||
return textureClient;
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ReturnTextureClient(TextureClient *aClient)
|
||||
{
|
||||
if (!aClient) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mOutstandingClients);
|
||||
mOutstandingClients--;
|
||||
|
||||
// Add the client to the pool and shrink down if we're beyond our maximum size
|
||||
mTextureClients.push(aClient);
|
||||
ShrinkToMaximumSize();
|
||||
|
||||
// Kick off the pool shrinking timer if there are still more unused texture
|
||||
// clients than our desired minimum cache size.
|
||||
if (mTextureClients.size() > sMinCacheSize) {
|
||||
mTimer->InitWithFuncCallback(ShrinkCallback, this, sShrinkTimeout,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ReturnTextureClientDeferred(TextureClient *aClient)
|
||||
{
|
||||
mTextureClientsDeferred.push(aClient);
|
||||
ShrinkToMaximumSize();
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ShrinkToMaximumSize()
|
||||
{
|
||||
uint32_t totalClientsOutstanding = mTextureClients.size() + mOutstandingClients;
|
||||
|
||||
// We're over our desired maximum size, immediately shrink down to the
|
||||
// maximum, or zero if we have too many outstanding texture clients.
|
||||
// We cull from the deferred TextureClients first, as we can't reuse those
|
||||
// until they get returned.
|
||||
while (totalClientsOutstanding > sMaxTextureClients) {
|
||||
if (mTextureClientsDeferred.size()) {
|
||||
mOutstandingClients--;
|
||||
mTextureClientsDeferred.pop();
|
||||
} else {
|
||||
if (!mTextureClients.size()) {
|
||||
// Getting here means we're over our desired number of TextureClients
|
||||
// with none in the pool. This can happen for pathological cases, or
|
||||
// it could mean that sMaxTextureClients needs adjusting for whatever
|
||||
// device we're running on.
|
||||
break;
|
||||
}
|
||||
mTextureClients.pop();
|
||||
}
|
||||
totalClientsOutstanding--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ShrinkToMinimumSize()
|
||||
{
|
||||
while (mTextureClients.size() > sMinCacheSize) {
|
||||
mTextureClients.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::ReturnDeferredClients()
|
||||
{
|
||||
while (!mTextureClientsDeferred.empty()) {
|
||||
ReturnTextureClient(mTextureClientsDeferred.top());
|
||||
mTextureClientsDeferred.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientPool::Clear()
|
||||
{
|
||||
while (!mTextureClients.empty()) {
|
||||
mTextureClients.pop();
|
||||
}
|
||||
while (!mTextureClientsDeferred.empty()) {
|
||||
mOutstandingClients--;
|
||||
mTextureClientsDeferred.pop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* 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 MOZILLA_GFX_TEXTURECLIENTPOOL_H
|
||||
#define MOZILLA_GFX_TEXTURECLIENTPOOL_H
|
||||
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "TextureClient.h"
|
||||
#include "nsITimer.h"
|
||||
#include <stack>
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ISurfaceAllocator;
|
||||
|
||||
class TextureClientPool : public RefCounted<TextureClientPool>
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(TextureClientPool)
|
||||
TextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
|
||||
ISurfaceAllocator *aAllocator);
|
||||
|
||||
/**
|
||||
* Gets an allocated TextureClient of size and format that are determined
|
||||
* by the initialisation parameters given to the pool. This will either be
|
||||
* a cached client that was returned to the pool, or a newly allocated
|
||||
* client if one isn't available.
|
||||
*
|
||||
* All clients retrieved by this method should be returned using the return
|
||||
* functions, or reported lost so that the pool can manage its size correctly.
|
||||
*/
|
||||
TemporaryRef<TextureClient> GetTextureClient();
|
||||
|
||||
/**
|
||||
* Return a TextureClient that is no longer being used and is ready for
|
||||
* immediate re-use or destruction.
|
||||
*/
|
||||
void ReturnTextureClient(TextureClient *aClient);
|
||||
|
||||
/**
|
||||
* Return a TextureClient that is not yet ready to be reused, but will be
|
||||
* imminently.
|
||||
*/
|
||||
void ReturnTextureClientDeferred(TextureClient *aClient);
|
||||
|
||||
/**
|
||||
* Attempt to shrink the pool so that there are no more than
|
||||
* sMaxTextureClients clients outstanding.
|
||||
*/
|
||||
void ShrinkToMaximumSize();
|
||||
|
||||
/**
|
||||
* Attempt to shrink the pool so that there are no more than sMinCacheSize
|
||||
* unused clients.
|
||||
*/
|
||||
void ShrinkToMinimumSize();
|
||||
|
||||
/**
|
||||
* Return any clients to the pool that were previously returned in
|
||||
* ReturnTextureClientDeferred.
|
||||
*/
|
||||
void ReturnDeferredClients();
|
||||
|
||||
/**
|
||||
* Report that a client retrieved via GetTextureClient() has become
|
||||
* unusable, so that it will no longer be tracked.
|
||||
*/
|
||||
void ReportClientLost() { mOutstandingClients--; }
|
||||
|
||||
/**
|
||||
* Calling this will cause the pool to attempt to relinquish any unused
|
||||
* clients.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
// The time in milliseconds before the pool will be shrunk to the minimum
|
||||
// size after returning a client.
|
||||
static const uint32_t sShrinkTimeout = 1000;
|
||||
|
||||
// The minimum size of the pool (the number of tiles that will be kept after
|
||||
// shrinking).
|
||||
static const uint32_t sMinCacheSize = 0;
|
||||
|
||||
// The maximum number of texture clients managed by this pool that we want
|
||||
// to remain active.
|
||||
static const uint32_t sMaxTextureClients = 50;
|
||||
|
||||
gfx::SurfaceFormat mFormat;
|
||||
gfx::IntSize mSize;
|
||||
|
||||
uint32_t mOutstandingClients;
|
||||
|
||||
std::stack<RefPtr<TextureClient> > mTextureClients;
|
||||
std::stack<RefPtr<TextureClient> > mTextureClientsDeferred;
|
||||
nsRefPtr<nsITimer> mTimer;
|
||||
RefPtr<ISurfaceAllocator> mSurfaceAllocator;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* MOZILLA_GFX_TEXTURECLIENTPOOL_H */
|
|
@ -18,6 +18,7 @@
|
|||
#include "mozilla/gfx/Rect.h" // for Rect
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
|
||||
#include "TextureClientPool.h"
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
|
||||
#include "nsSize.h" // for nsIntSize
|
||||
|
@ -25,18 +26,23 @@
|
|||
#include "nsMathUtils.h" // for NS_roundf
|
||||
#include "gfx2DGlue.h"
|
||||
|
||||
// This is the minimum area that we deem reasonable to copy from the front buffer to the
|
||||
// back buffer on tile updates. If the valid region is smaller than this, we just
|
||||
// redraw it and save on the copy (and requisite surface-locking involved).
|
||||
#define MINIMUM_TILE_COPY_AREA ((TILEDLAYERBUFFER_TILE_SIZE * TILEDLAYERBUFFER_TILE_SIZE)/16)
|
||||
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
#include "cairo.h"
|
||||
#include <sstream>
|
||||
using mozilla::layers::Layer;
|
||||
static void DrawDebugOverlay(gfxASurface* imgSurf, int x, int y)
|
||||
static void DrawDebugOverlay(mozilla::gfx::DrawTarget* dt, int x, int y, int width, int height)
|
||||
{
|
||||
gfxContext c(imgSurf);
|
||||
gfxContext c(dt);
|
||||
|
||||
// Draw border
|
||||
c.NewPath();
|
||||
c.SetDeviceColor(gfxRGBA(0.0, 0.0, 0.0, 1.0));
|
||||
c.Rectangle(gfxRect(gfxPoint(0,0),imgSurf->GetSize()));
|
||||
c.Rectangle(gfxRect(0, 0, width, height));
|
||||
c.Stroke();
|
||||
|
||||
// Build tile description
|
||||
|
@ -79,28 +85,37 @@ namespace layers {
|
|||
TiledContentClient::TiledContentClient(ClientTiledThebesLayer* aThebesLayer,
|
||||
ClientLayerManager* aManager)
|
||||
: CompositableClient(aManager->AsShadowForwarder())
|
||||
, mTiledBuffer(aThebesLayer, aManager, &mSharedFrameMetricsHelper)
|
||||
, mLowPrecisionTiledBuffer(aThebesLayer, aManager, &mSharedFrameMetricsHelper)
|
||||
{
|
||||
MOZ_COUNT_CTOR(TiledContentClient);
|
||||
|
||||
// The preference is int in "thousands", so adjust:
|
||||
mTiledBuffer = ClientTiledLayerBuffer(aThebesLayer, this, aManager,
|
||||
&mSharedFrameMetricsHelper);
|
||||
mLowPrecisionTiledBuffer = ClientTiledLayerBuffer(aThebesLayer, this, aManager,
|
||||
&mSharedFrameMetricsHelper);
|
||||
|
||||
mLowPrecisionTiledBuffer.SetResolution(gfxPrefs::LowPrecisionResolution()/1000.f);
|
||||
}
|
||||
|
||||
void
|
||||
TiledContentClient::LockCopyAndWrite(TiledBufferType aType)
|
||||
TiledContentClient::ClearCachedResources()
|
||||
{
|
||||
BasicTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
|
||||
mTiledBuffer.DiscardBackBuffers();
|
||||
mLowPrecisionTiledBuffer.DiscardBackBuffers();
|
||||
}
|
||||
|
||||
void
|
||||
TiledContentClient::UseTiledLayerBuffer(TiledBufferType aType)
|
||||
{
|
||||
ClientTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
|
||||
? &mLowPrecisionTiledBuffer
|
||||
: &mTiledBuffer;
|
||||
|
||||
// Take an extra ReadLock on behalf of the TiledContentHost. This extra
|
||||
// reference will be adopted when the descriptor is opened by
|
||||
// BasicTiledLayerTile::OpenDescriptor.
|
||||
// Take a ReadLock on behalf of the TiledContentHost. This
|
||||
// reference will be adopted when the descriptor is opened in
|
||||
// TiledLayerBufferComposite.
|
||||
buffer->ReadLock();
|
||||
|
||||
mForwarder->PaintedTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
|
||||
mForwarder->UseTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
|
||||
buffer->ClearPaintedRegion();
|
||||
}
|
||||
|
||||
|
@ -229,10 +244,12 @@ SharedFrameMetricsHelper::AboutToCheckerboard(const FrameMetrics& aContentMetric
|
|||
return !aContentMetrics.mDisplayPort.Contains(aCompositorMetrics.CalculateCompositedRectInCssPixels() - aCompositorMetrics.mScrollOffset);
|
||||
}
|
||||
|
||||
BasicTiledLayerBuffer::BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
|
||||
ClientTiledLayerBuffer::ClientTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
|
||||
CompositableClient* aCompositableClient,
|
||||
ClientLayerManager* aManager,
|
||||
SharedFrameMetricsHelper* aHelper)
|
||||
: mThebesLayer(aThebesLayer)
|
||||
, mCompositableClient(aCompositableClient)
|
||||
, mManager(aManager)
|
||||
, mLastPaintOpaque(false)
|
||||
, mSharedFrameMetricsHelper(aHelper)
|
||||
|
@ -240,14 +257,14 @@ BasicTiledLayerBuffer::BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLaye
|
|||
}
|
||||
|
||||
bool
|
||||
BasicTiledLayerBuffer::HasFormatChanged() const
|
||||
ClientTiledLayerBuffer::HasFormatChanged() const
|
||||
{
|
||||
return mThebesLayer->CanUseOpaqueSurface() != mLastPaintOpaque;
|
||||
}
|
||||
|
||||
|
||||
gfxContentType
|
||||
BasicTiledLayerBuffer::GetContentType() const
|
||||
ClientTiledLayerBuffer::GetContentType() const
|
||||
{
|
||||
if (mThebesLayer->CanUseOpaqueSurface()) {
|
||||
return gfxContentType::COLOR;
|
||||
|
@ -256,54 +273,311 @@ BasicTiledLayerBuffer::GetContentType() const
|
|||
}
|
||||
}
|
||||
|
||||
gfxMemorySharedReadLock::gfxMemorySharedReadLock()
|
||||
: mReadCount(1)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxMemorySharedReadLock);
|
||||
}
|
||||
|
||||
gfxMemorySharedReadLock::~gfxMemorySharedReadLock()
|
||||
{
|
||||
MOZ_COUNT_DTOR(gfxMemorySharedReadLock);
|
||||
}
|
||||
|
||||
int32_t
|
||||
gfxMemorySharedReadLock::ReadLock()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(gfxMemorySharedReadLock);
|
||||
|
||||
return PR_ATOMIC_INCREMENT(&mReadCount);
|
||||
}
|
||||
|
||||
int32_t
|
||||
gfxMemorySharedReadLock::ReadUnlock()
|
||||
{
|
||||
int32_t readCount = PR_ATOMIC_DECREMENT(&mReadCount);
|
||||
NS_ASSERTION(readCount >= 0, "ReadUnlock called without ReadLock.");
|
||||
|
||||
return readCount;
|
||||
}
|
||||
|
||||
int32_t
|
||||
gfxMemorySharedReadLock::GetReadCount()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(gfxMemorySharedReadLock);
|
||||
return mReadCount;
|
||||
}
|
||||
|
||||
gfxShmSharedReadLock::gfxShmSharedReadLock(ISurfaceAllocator* aAllocator)
|
||||
: mAllocator(aAllocator)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxShmSharedReadLock);
|
||||
|
||||
if (mAllocator) {
|
||||
#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
|
||||
if (mAllocator->AllocUnsafeShmem(MOZ_ALIGN_WORD(sizeof(ShmReadLockInfo)),
|
||||
mozilla::ipc::SharedMemory::TYPE_BASIC, &mShmem)) {
|
||||
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
|
||||
info->readCount = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfxShmSharedReadLock::~gfxShmSharedReadLock()
|
||||
{
|
||||
MOZ_COUNT_DTOR(gfxShmSharedReadLock);
|
||||
}
|
||||
|
||||
int32_t
|
||||
gfxShmSharedReadLock::ReadLock() {
|
||||
NS_ASSERT_OWNINGTHREAD(gfxShmSharedReadLock);
|
||||
|
||||
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
|
||||
return PR_ATOMIC_INCREMENT(&info->readCount);
|
||||
}
|
||||
|
||||
int32_t
|
||||
gfxShmSharedReadLock::ReadUnlock() {
|
||||
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
|
||||
int32_t readCount = PR_ATOMIC_DECREMENT(&info->readCount);
|
||||
NS_ASSERTION(readCount >= 0, "ReadUnlock called without a ReadLock.");
|
||||
if (readCount <= 0) {
|
||||
mAllocator->DeallocShmem(mShmem);
|
||||
}
|
||||
return readCount;
|
||||
}
|
||||
|
||||
int32_t
|
||||
gfxShmSharedReadLock::GetReadCount() {
|
||||
NS_ASSERT_OWNINGTHREAD(gfxShmSharedReadLock);
|
||||
|
||||
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
|
||||
return info->readCount;
|
||||
}
|
||||
|
||||
// Placeholder
|
||||
TileClient::TileClient()
|
||||
: mBackBuffer(nullptr)
|
||||
, mFrontBuffer(nullptr)
|
||||
, mBackLock(nullptr)
|
||||
, mFrontLock(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
TileClient::TileClient(const TileClient& o)
|
||||
{
|
||||
mBackBuffer = o.mBackBuffer;
|
||||
mFrontBuffer = o.mFrontBuffer;
|
||||
mBackLock = o.mBackLock;
|
||||
mFrontLock = o.mFrontLock;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
mLastUpdate = o.mLastUpdate;
|
||||
#endif
|
||||
mManager = o.mManager;
|
||||
mInvalidFront = o.mInvalidFront;
|
||||
mInvalidBack = o.mInvalidBack;
|
||||
}
|
||||
|
||||
TileClient&
|
||||
TileClient::operator=(const TileClient& o)
|
||||
{
|
||||
if (this == &o) return *this;
|
||||
mBackBuffer = o.mBackBuffer;
|
||||
mFrontBuffer = o.mFrontBuffer;
|
||||
mBackLock = o.mBackLock;
|
||||
mFrontLock = o.mFrontLock;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
mLastUpdate = o.mLastUpdate;
|
||||
#endif
|
||||
mManager = o.mManager;
|
||||
mInvalidFront = o.mInvalidFront;
|
||||
mInvalidBack = o.mInvalidBack;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TileClient::Flip()
|
||||
{
|
||||
RefPtr<TextureClient> frontBuffer = mFrontBuffer;
|
||||
mFrontBuffer = mBackBuffer;
|
||||
mBackBuffer = frontBuffer;
|
||||
RefPtr<gfxSharedReadLock> frontLock = mFrontLock;
|
||||
mFrontLock = mBackLock;
|
||||
mBackLock = frontLock;
|
||||
nsIntRegion invalidFront = mInvalidFront;
|
||||
mInvalidFront = mInvalidBack;
|
||||
mInvalidBack = invalidFront;
|
||||
}
|
||||
|
||||
void
|
||||
TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
|
||||
bool aCanRerasterizeValidRegion)
|
||||
{
|
||||
if (mBackBuffer && mFrontBuffer) {
|
||||
const nsIntRect tileRect = nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
|
||||
|
||||
if (aDirtyRegion.Contains(tileRect)) {
|
||||
// The dirty region means that we no longer need the front buffer, so
|
||||
// discard it.
|
||||
DiscardFrontBuffer();
|
||||
} else {
|
||||
// Region that needs copying.
|
||||
nsIntRegion regionToCopy = mInvalidBack;
|
||||
|
||||
regionToCopy.Sub(regionToCopy, aDirtyRegion);
|
||||
|
||||
if (regionToCopy.IsEmpty() ||
|
||||
(aCanRerasterizeValidRegion &&
|
||||
regionToCopy.Area() < MINIMUM_TILE_COPY_AREA)) {
|
||||
// Just redraw it all.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mFrontBuffer->Lock(OPEN_READ)) {
|
||||
NS_WARNING("Failed to lock the tile's front buffer");
|
||||
return;
|
||||
}
|
||||
TextureClientAutoUnlock autoFront(mFrontBuffer);
|
||||
|
||||
if (!mBackBuffer->Lock(OPEN_WRITE)) {
|
||||
NS_WARNING("Failed to lock the tile's back buffer");
|
||||
return;
|
||||
}
|
||||
TextureClientAutoUnlock autoBack(mBackBuffer);
|
||||
|
||||
// Copy the bounding rect of regionToCopy. As tiles are quite small, it
|
||||
// is unlikely that we'd save much by copying each individual rect of the
|
||||
// region, but we can reevaluate this if it becomes an issue.
|
||||
const nsIntRect rectToCopy = regionToCopy.GetBounds();
|
||||
gfx::IntRect gfxRectToCopy(rectToCopy.x, rectToCopy.y, rectToCopy.width, rectToCopy.height);
|
||||
gfx::IntPoint gfxRectToCopyTopLeft = gfxRectToCopy.TopLeft();
|
||||
mFrontBuffer->CopyToTextureClient(mBackBuffer, &gfxRectToCopy, &gfxRectToCopyTopLeft);
|
||||
|
||||
mInvalidBack.SetEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TileClient::DiscardFrontBuffer()
|
||||
{
|
||||
if (mFrontBuffer) {
|
||||
MOZ_ASSERT(mFrontLock);
|
||||
mManager->GetTexturePool(mFrontBuffer->AsTextureClientDrawTarget()->GetFormat())->ReturnTextureClientDeferred(mFrontBuffer);
|
||||
mFrontLock->ReadUnlock();
|
||||
mFrontBuffer = nullptr;
|
||||
mFrontLock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TileClient::DiscardBackBuffer()
|
||||
{
|
||||
if (mBackBuffer) {
|
||||
MOZ_ASSERT(mBackLock);
|
||||
mManager->GetTexturePool(mBackBuffer->AsTextureClientDrawTarget()->GetFormat())->ReturnTextureClient(mBackBuffer);
|
||||
mBackLock->ReadUnlock();
|
||||
mBackBuffer = nullptr;
|
||||
mBackLock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TextureClient*
|
||||
TileClient::GetBackBuffer(const nsIntRegion& aDirtyRegion, TextureClientPool *aPool, bool *aCreatedTextureClient, bool aCanRerasterizeValidRegion)
|
||||
{
|
||||
// Try to re-use the front-buffer if possible
|
||||
if (mFrontBuffer &&
|
||||
mFrontBuffer->HasInternalBuffer() &&
|
||||
mFrontLock->GetReadCount() == 1) {
|
||||
// If we had a backbuffer we no longer care about it since we'll
|
||||
// re-use the front buffer.
|
||||
DiscardBackBuffer();
|
||||
Flip();
|
||||
return mBackBuffer;
|
||||
}
|
||||
|
||||
if (!mBackBuffer ||
|
||||
mBackLock->GetReadCount() > 1) {
|
||||
if (mBackBuffer) {
|
||||
// Our current back-buffer is still locked by the compositor. This can occur
|
||||
// when the client is producing faster than the compositor can consume. In
|
||||
// this case we just want to drop it and not return it to the pool.
|
||||
aPool->ReportClientLost();
|
||||
}
|
||||
mBackBuffer = aPool->GetTextureClient();
|
||||
// Create a lock for our newly created back-buffer.
|
||||
if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
|
||||
// If our compositor is in the same process, we can save some cycles by not
|
||||
// using shared memory.
|
||||
mBackLock = new gfxMemorySharedReadLock();
|
||||
} else {
|
||||
mBackLock = new gfxShmSharedReadLock(mManager->AsShadowForwarder());
|
||||
}
|
||||
*aCreatedTextureClient = true;
|
||||
mInvalidBack = nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
|
||||
}
|
||||
|
||||
ValidateBackBufferFromFront(aDirtyRegion, aCanRerasterizeValidRegion);
|
||||
|
||||
return mBackBuffer;
|
||||
}
|
||||
|
||||
TileDescriptor
|
||||
BasicTiledLayerTile::GetTileDescriptor()
|
||||
TileClient::GetTileDescriptor()
|
||||
{
|
||||
gfxReusableSurfaceWrapper* surface = GetSurface();
|
||||
switch (surface->GetType()) {
|
||||
case gfxReusableSurfaceWrapper::TYPE_IMAGE :
|
||||
return BasicTileDescriptor(uintptr_t(surface));
|
||||
|
||||
case gfxReusableSurfaceWrapper::TYPE_SHARED_IMAGE :
|
||||
return BasicShmTileDescriptor(static_cast<gfxReusableSharedImageSurfaceWrapper*>(surface)->GetShmem());
|
||||
|
||||
default :
|
||||
NS_NOTREACHED("Unhandled gfxReusableSurfaceWrapper type");
|
||||
if (IsPlaceholderTile()) {
|
||||
return PlaceholderTileDescriptor();
|
||||
}
|
||||
MOZ_ASSERT(mFrontLock);
|
||||
if (mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY) {
|
||||
// AddRef here and Release when receiving on the host side to make sure the
|
||||
// reference count doesn't go to zero before the host receives the message.
|
||||
// see TiledLayerBufferComposite::TiledLayerBufferComposite
|
||||
mFrontLock->AddRef();
|
||||
}
|
||||
return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(),
|
||||
mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY
|
||||
? TileLock(uintptr_t(mFrontLock.get()))
|
||||
: TileLock(static_cast<gfxShmSharedReadLock*>(mFrontLock.get())->GetShmem()));
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledLayerBuffer::ReadUnlock() {
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ BasicTiledLayerTile
|
||||
BasicTiledLayerTile::OpenDescriptor(ISurfaceAllocator *aAllocator, const TileDescriptor& aDesc)
|
||||
void
|
||||
ClientTiledLayerBuffer::ReadLock() {
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].ReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientTiledLayerBuffer::Release()
|
||||
{
|
||||
switch (aDesc.type()) {
|
||||
case TileDescriptor::TBasicShmTileDescriptor : {
|
||||
nsRefPtr<gfxReusableSurfaceWrapper> surface =
|
||||
gfxReusableSharedImageSurfaceWrapper::Open(
|
||||
aAllocator, aDesc.get_BasicShmTileDescriptor().reusableSurface());
|
||||
return BasicTiledLayerTile(
|
||||
new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].Release();
|
||||
}
|
||||
}
|
||||
|
||||
case TileDescriptor::TBasicTileDescriptor : {
|
||||
nsRefPtr<gfxReusableSurfaceWrapper> surface =
|
||||
reinterpret_cast<gfxReusableSurfaceWrapper*>(
|
||||
aDesc.get_BasicTileDescriptor().reusableSurface());
|
||||
surface->ReadUnlock();
|
||||
return BasicTiledLayerTile(
|
||||
new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
|
||||
}
|
||||
|
||||
default :
|
||||
NS_NOTREACHED("Unknown tile descriptor type!");
|
||||
return nullptr;
|
||||
void
|
||||
ClientTiledLayerBuffer::DiscardBackBuffers()
|
||||
{
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].DiscardBackBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceDescriptorTiles
|
||||
BasicTiledLayerBuffer::GetSurfaceDescriptorTiles()
|
||||
ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
|
||||
{
|
||||
InfallibleTArray<TileDescriptor> tiles;
|
||||
|
||||
|
@ -321,23 +595,8 @@ BasicTiledLayerBuffer::GetSurfaceDescriptorTiles()
|
|||
mResolution);
|
||||
}
|
||||
|
||||
/* static */ BasicTiledLayerBuffer
|
||||
BasicTiledLayerBuffer::OpenDescriptor(ISurfaceAllocator *aAllocator,
|
||||
const SurfaceDescriptorTiles& aDescriptor,
|
||||
SharedFrameMetricsHelper* aHelper)
|
||||
{
|
||||
return BasicTiledLayerBuffer(aAllocator,
|
||||
aDescriptor.validRegion(),
|
||||
aDescriptor.paintedRegion(),
|
||||
aDescriptor.tiles(),
|
||||
aDescriptor.retainedWidth(),
|
||||
aDescriptor.retainedHeight(),
|
||||
aDescriptor.resolution(),
|
||||
aHelper);
|
||||
}
|
||||
|
||||
void
|
||||
BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
|
@ -371,12 +630,11 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
|||
|
||||
const nsIntRect bounds = aPaintRegion.GetBounds();
|
||||
{
|
||||
PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferAlloc");
|
||||
PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferAlloc");
|
||||
gfxImageFormat format =
|
||||
gfxPlatform::GetPlatform()->OptimalFormatForContent(
|
||||
GetContentType());
|
||||
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
|
||||
mSinglePaintDrawTarget =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
|
||||
gfx::IntSize(ceilf(bounds.width * mResolution),
|
||||
|
@ -384,14 +642,6 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
|||
gfx::ImageFormatToSurfaceFormat(format));
|
||||
|
||||
ctxt = new gfxContext(mSinglePaintDrawTarget);
|
||||
} else {
|
||||
mSinglePaintBuffer = new gfxImageSurface(
|
||||
gfxIntSize(ceilf(bounds.width * mResolution),
|
||||
ceilf(bounds.height * mResolution)),
|
||||
format,
|
||||
!mThebesLayer->CanUseOpaqueSurface());
|
||||
ctxt = new gfxContext(mSinglePaintBuffer);
|
||||
}
|
||||
|
||||
mSinglePaintBufferOffset = nsIntPoint(bounds.x, bounds.y);
|
||||
}
|
||||
|
@ -404,7 +654,7 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
|||
}
|
||||
start = PR_IntervalNow();
|
||||
#endif
|
||||
PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferDraw");
|
||||
PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw");
|
||||
|
||||
mCallback(mThebesLayer, ctxt, aPaintRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), mCallbackData);
|
||||
}
|
||||
|
@ -424,7 +674,7 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
|||
start = PR_IntervalNow();
|
||||
#endif
|
||||
|
||||
PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesUpdate");
|
||||
PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesUpdate");
|
||||
Update(aNewValidRegion, aPaintRegion);
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
|
@ -437,102 +687,15 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
|||
mLastPaintOpaque = mThebesLayer->CanUseOpaqueSurface();
|
||||
mCallback = nullptr;
|
||||
mCallbackData = nullptr;
|
||||
mSinglePaintBuffer = nullptr;
|
||||
mSinglePaintDrawTarget = nullptr;
|
||||
}
|
||||
|
||||
BasicTiledLayerTile
|
||||
BasicTiledLayerBuffer::ValidateTileInternal(BasicTiledLayerTile aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRect& aDirtyRect)
|
||||
{
|
||||
if (aTile.IsPlaceholderTile()) {
|
||||
RefPtr<DeprecatedTextureClient> textureClient =
|
||||
new DeprecatedTextureClientTile(mManager->AsShadowForwarder(), TextureInfo(BUFFER_TILED));
|
||||
aTile.mDeprecatedTextureClient = static_cast<DeprecatedTextureClientTile*>(textureClient.get());
|
||||
}
|
||||
aTile.mDeprecatedTextureClient->EnsureAllocated(gfx::IntSize(GetTileLength(), GetTileLength()), GetContentType());
|
||||
gfxImageSurface* writableSurface = aTile.mDeprecatedTextureClient->LockImageSurface();
|
||||
// Bug 742100, this gfxContext really should live on the stack.
|
||||
nsRefPtr<gfxContext> ctxt;
|
||||
|
||||
RefPtr<gfx::DrawTarget> writableDrawTarget;
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
|
||||
// TODO: Instead of creating a gfxImageSurface to back the tile we should
|
||||
// create an offscreen DrawTarget. This would need to be shared cross-thread
|
||||
// and support copy on write semantics.
|
||||
gfx::SurfaceFormat format =
|
||||
gfx::ImageFormatToSurfaceFormat(writableSurface->Format());
|
||||
|
||||
writableDrawTarget =
|
||||
gfxPlatform::GetPlatform()->CreateDrawTargetForData(
|
||||
writableSurface->Data(),
|
||||
gfx::IntSize(writableSurface->Width(), writableSurface->Height()),
|
||||
writableSurface->Stride(),
|
||||
format);
|
||||
ctxt = new gfxContext(writableDrawTarget);
|
||||
} else {
|
||||
ctxt = new gfxContext(writableSurface);
|
||||
ctxt->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
}
|
||||
|
||||
gfxRect drawRect(aDirtyRect.x - aTileOrigin.x, aDirtyRect.y - aTileOrigin.y,
|
||||
aDirtyRect.width, aDirtyRect.height);
|
||||
|
||||
if (mSinglePaintBuffer || mSinglePaintDrawTarget) {
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
|
||||
gfx::Rect drawRect(aDirtyRect.x - aTileOrigin.x,
|
||||
aDirtyRect.y - aTileOrigin.y,
|
||||
aDirtyRect.width,
|
||||
aDirtyRect.height);
|
||||
drawRect.Scale(mResolution);
|
||||
|
||||
RefPtr<gfx::SourceSurface> source = mSinglePaintDrawTarget->Snapshot();
|
||||
writableDrawTarget->CopySurface(
|
||||
source,
|
||||
gfx::IntRect(NS_roundf((aDirtyRect.x - mSinglePaintBufferOffset.x) * mResolution),
|
||||
NS_roundf((aDirtyRect.y - mSinglePaintBufferOffset.y) * mResolution),
|
||||
drawRect.width,
|
||||
drawRect.height),
|
||||
gfx::IntPoint(NS_roundf(drawRect.x), NS_roundf(drawRect.y)));
|
||||
} else {
|
||||
gfxRect drawRect(aDirtyRect.x - aTileOrigin.x, aDirtyRect.y - aTileOrigin.y,
|
||||
aDirtyRect.width, aDirtyRect.height);
|
||||
drawRect.Scale(mResolution, mResolution);
|
||||
|
||||
ctxt->NewPath();
|
||||
ctxt->SetSource(mSinglePaintBuffer.get(),
|
||||
gfxPoint((mSinglePaintBufferOffset.x - aDirtyRect.x) * mResolution + drawRect.x,
|
||||
(mSinglePaintBufferOffset.y - aDirtyRect.y) * mResolution + drawRect.y));
|
||||
ctxt->SnappedRectangle(drawRect);
|
||||
ctxt->Fill();
|
||||
}
|
||||
} else {
|
||||
ctxt->NewPath();
|
||||
ctxt->Scale(mResolution, mResolution);
|
||||
ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
|
||||
nsIntPoint a = nsIntPoint(aTileOrigin.x, aTileOrigin.y);
|
||||
mCallback(mThebesLayer, ctxt,
|
||||
nsIntRegion(nsIntRect(a, nsIntSize(GetScaledTileLength(),
|
||||
GetScaledTileLength()))),
|
||||
DrawRegionClip::CLIP_NONE,
|
||||
nsIntRegion(), mCallbackData);
|
||||
}
|
||||
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
DrawDebugOverlay(writableSurface, aTileOrigin.x * mResolution,
|
||||
aTileOrigin.y * mResolution);
|
||||
#endif
|
||||
|
||||
return aTile;
|
||||
}
|
||||
|
||||
BasicTiledLayerTile
|
||||
BasicTiledLayerBuffer::ValidateTile(BasicTiledLayerTile aTile,
|
||||
TileClient
|
||||
ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRegion& aDirtyRegion)
|
||||
{
|
||||
PROFILER_LABEL("BasicTiledLayerBuffer", "ValidateTile");
|
||||
PROFILER_LABEL("ClientTiledLayerBuffer", "ValidateTile");
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (aDirtyRegion.IsComplex()) {
|
||||
|
@ -540,12 +703,140 @@ BasicTiledLayerBuffer::ValidateTile(BasicTiledLayerTile aTile,
|
|||
}
|
||||
#endif
|
||||
|
||||
if (aTile.IsPlaceholderTile()) {
|
||||
aTile.SetLayerManager(mManager);
|
||||
}
|
||||
|
||||
// Discard our front and backbuffers if our contents changed. In this case
|
||||
// the calling code will already have taken care of invalidating the entire
|
||||
// layer.
|
||||
if (HasFormatChanged()) {
|
||||
aTile.DiscardBackBuffer();
|
||||
aTile.DiscardFrontBuffer();
|
||||
}
|
||||
|
||||
bool createdTextureClient = false;
|
||||
nsIntRegion offsetDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
|
||||
bool usingSinglePaintBuffer = !!mSinglePaintDrawTarget;
|
||||
RefPtr<TextureClient> backBuffer =
|
||||
aTile.GetBackBuffer(offsetDirtyRegion,
|
||||
mManager->GetTexturePool(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType())),
|
||||
&createdTextureClient, !usingSinglePaintBuffer);
|
||||
|
||||
if (!backBuffer->Lock(OPEN_READ_WRITE)) {
|
||||
NS_WARNING("Failed to lock tile TextureClient for updating.");
|
||||
aTile.DiscardFrontBuffer();
|
||||
return aTile;
|
||||
}
|
||||
|
||||
// We must not keep a reference to the DrawTarget after it has been unlocked,
|
||||
// make sure these are null'd before unlocking as destruction of the context
|
||||
// may cause the target to be flushed.
|
||||
RefPtr<DrawTarget> drawTarget = backBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
|
||||
drawTarget->SetTransform(Matrix());
|
||||
|
||||
RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);
|
||||
|
||||
if (usingSinglePaintBuffer) {
|
||||
// XXX Perhaps we should just copy the bounding rectangle here?
|
||||
RefPtr<gfx::SourceSurface> source = mSinglePaintDrawTarget->Snapshot();
|
||||
nsIntRegionRectIterator it(aDirtyRegion);
|
||||
for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) {
|
||||
for (const nsIntRect* dirtyRect = it.Next(); dirtyRect != nullptr; dirtyRect = it.Next()) {
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr(" break into subrect %i, %i, %i, %i\n", rect->x, rect->y, rect->width, rect->height);
|
||||
printf_stderr(" break into subdirtyRect %i, %i, %i, %i\n",
|
||||
dirtyRect->x, dirtyRect->y, dirtyRect->width, dirtyRect->height);
|
||||
#endif
|
||||
aTile = ValidateTileInternal(aTile, aTileOrigin, *rect);
|
||||
gfx::Rect drawRect(dirtyRect->x - aTileOrigin.x,
|
||||
dirtyRect->y - aTileOrigin.y,
|
||||
dirtyRect->width,
|
||||
dirtyRect->height);
|
||||
drawRect.Scale(mResolution);
|
||||
|
||||
gfx::IntRect copyRect(NS_roundf((dirtyRect->x - mSinglePaintBufferOffset.x) * mResolution),
|
||||
NS_roundf((dirtyRect->y - mSinglePaintBufferOffset.y) * mResolution),
|
||||
drawRect.width,
|
||||
drawRect.height);
|
||||
gfx::IntPoint copyTarget(NS_roundf(drawRect.x), NS_roundf(drawRect.y));
|
||||
drawTarget->CopySurface(source, copyRect, copyTarget);
|
||||
|
||||
// Mark the newly updated area as invalid in the front buffer
|
||||
aTile.mInvalidFront.Or(aTile.mInvalidFront, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height));
|
||||
}
|
||||
|
||||
// The new buffer is now validated, remove the dirty region from it.
|
||||
aTile.mInvalidBack.Sub(nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE),
|
||||
offsetDirtyRegion);
|
||||
} else {
|
||||
// Area of the full tile...
|
||||
nsIntRegion tileRegion = nsIntRect(aTileOrigin.x, aTileOrigin.y, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
|
||||
|
||||
// Intersect this area with the portion that's dirty.
|
||||
tileRegion = tileRegion.Intersect(aDirtyRegion);
|
||||
|
||||
// Move invalid areas into layer space.
|
||||
aTile.mInvalidFront.MoveBy(aTileOrigin);
|
||||
aTile.mInvalidBack.MoveBy(aTileOrigin);
|
||||
|
||||
// Add the area that's going to be redrawn to the invalid area of the
|
||||
// front region.
|
||||
aTile.mInvalidFront.Or(aTile.mInvalidFront, tileRegion);
|
||||
|
||||
// Add invalid areas of the backbuffer to the area to redraw.
|
||||
tileRegion.Or(tileRegion, aTile.mInvalidBack);
|
||||
|
||||
// Move invalid areas back into tile space.
|
||||
aTile.mInvalidFront.MoveBy(-aTileOrigin);
|
||||
|
||||
// This will be validated now.
|
||||
aTile.mInvalidBack.SetEmpty();
|
||||
|
||||
nsIntRect bounds = tileRegion.GetBounds();
|
||||
bounds.ScaleRoundOut(mResolution, mResolution);
|
||||
bounds.MoveBy(-aTileOrigin);
|
||||
|
||||
if (GetContentType() != gfxContentType::COLOR) {
|
||||
drawTarget->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height));
|
||||
}
|
||||
|
||||
ctxt->NewPath();
|
||||
ctxt->Clip(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
|
||||
ctxt->Scale(mResolution, mResolution);
|
||||
ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
|
||||
mCallback(mThebesLayer, ctxt,
|
||||
tileRegion.GetBounds(),
|
||||
DrawRegionClip::CLIP_NONE,
|
||||
nsIntRegion(), mCallbackData);
|
||||
|
||||
}
|
||||
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
DrawDebugOverlay(drawTarget, aTileOrigin.x * mResolution,
|
||||
aTileOrigin.y * mResolution, GetTileLength(), GetTileLength());
|
||||
#endif
|
||||
|
||||
ctxt = nullptr;
|
||||
drawTarget = nullptr;
|
||||
|
||||
backBuffer->Unlock();
|
||||
|
||||
aTile.Flip();
|
||||
|
||||
if (createdTextureClient) {
|
||||
if (!mCompositableClient->AddTextureClient(backBuffer)) {
|
||||
NS_WARNING("Failed to add tile TextureClient.");
|
||||
aTile.DiscardFrontBuffer();
|
||||
aTile.DiscardBackBuffer();
|
||||
return aTile;
|
||||
}
|
||||
}
|
||||
|
||||
// Note, we don't call UpdatedTexture. The Updated function is called manually
|
||||
// by the TiledContentHost before composition.
|
||||
|
||||
if (backBuffer->HasInternalBuffer()) {
|
||||
// If our new buffer has an internal buffer, we don't want to keep another
|
||||
// TextureClient around unnecessarily, so discard the back-buffer.
|
||||
aTile.DiscardBackBuffer();
|
||||
}
|
||||
|
||||
return aTile;
|
||||
|
@ -576,7 +867,7 @@ TransformCompositionBounds(const ScreenRect& aCompositionBounds,
|
|||
}
|
||||
|
||||
bool
|
||||
BasicTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
|
||||
ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
|
||||
const nsIntRegion& aOldValidRegion,
|
||||
nsIntRegion& aRegionToPaint,
|
||||
BasicTiledLayerPaintData* aPaintData,
|
||||
|
@ -735,7 +1026,7 @@ BasicTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvali
|
|||
}
|
||||
|
||||
bool
|
||||
BasicTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion,
|
||||
ClientTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion,
|
||||
nsIntRegion& aInvalidRegion,
|
||||
const nsIntRegion& aOldValidRegion,
|
||||
BasicTiledLayerPaintData* aPaintData,
|
||||
|
|
|
@ -16,9 +16,14 @@
|
|||
#include "gfxTypes.h"
|
||||
#include "mozilla/Attributes.h" // for MOZ_OVERRIDE
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "mozilla/ipc/Shmem.h" // for Shmem
|
||||
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory
|
||||
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
|
||||
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
|
||||
#include "mozilla/layers/LayersMessages.h" // for TileDescriptor
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/TextureClientPool.h"
|
||||
#include "ClientLayerManager.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_DTOR
|
||||
|
@ -28,6 +33,8 @@
|
|||
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "gfxReusableSurfaceWrapper.h"
|
||||
#include "pratom.h" // For PR_ATOMIC_INCREMENT/DECREMENT
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
class gfxImageSurface;
|
||||
|
||||
|
@ -35,67 +42,186 @@ namespace mozilla {
|
|||
namespace layers {
|
||||
|
||||
class BasicTileDescriptor;
|
||||
class ClientTiledThebesLayer;
|
||||
class ClientLayerManager;
|
||||
|
||||
|
||||
// A class to help implement copy-on-write semantics for shared tiles.
|
||||
class gfxSharedReadLock : public AtomicRefCounted<gfxSharedReadLock> {
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(gfxSharedReadLock)
|
||||
virtual ~gfxSharedReadLock() {}
|
||||
|
||||
virtual int32_t ReadLock() = 0;
|
||||
virtual int32_t ReadUnlock() = 0;
|
||||
virtual int32_t GetReadCount() = 0;
|
||||
|
||||
enum gfxSharedReadLockType {
|
||||
TYPE_MEMORY,
|
||||
TYPE_SHMEM
|
||||
};
|
||||
virtual gfxSharedReadLockType GetType() = 0;
|
||||
|
||||
protected:
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
class gfxMemorySharedReadLock : public gfxSharedReadLock {
|
||||
public:
|
||||
gfxMemorySharedReadLock();
|
||||
|
||||
~gfxMemorySharedReadLock();
|
||||
|
||||
virtual int32_t ReadLock() MOZ_OVERRIDE;
|
||||
|
||||
virtual int32_t ReadUnlock() MOZ_OVERRIDE;
|
||||
|
||||
virtual int32_t GetReadCount() MOZ_OVERRIDE;
|
||||
|
||||
virtual gfxSharedReadLockType GetType() MOZ_OVERRIDE { return TYPE_MEMORY; }
|
||||
|
||||
private:
|
||||
int32_t mReadCount;
|
||||
};
|
||||
|
||||
class gfxShmSharedReadLock : public gfxSharedReadLock {
|
||||
private:
|
||||
struct ShmReadLockInfo {
|
||||
int32_t readCount;
|
||||
};
|
||||
|
||||
public:
|
||||
gfxShmSharedReadLock(ISurfaceAllocator* aAllocator);
|
||||
|
||||
~gfxShmSharedReadLock();
|
||||
|
||||
virtual int32_t ReadLock() MOZ_OVERRIDE;
|
||||
|
||||
virtual int32_t ReadUnlock() MOZ_OVERRIDE;
|
||||
|
||||
virtual int32_t GetReadCount() MOZ_OVERRIDE;
|
||||
|
||||
virtual gfxSharedReadLockType GetType() MOZ_OVERRIDE { return TYPE_SHMEM; }
|
||||
|
||||
mozilla::ipc::Shmem& GetShmem() { return mShmem; }
|
||||
|
||||
static already_AddRefed<gfxShmSharedReadLock>
|
||||
Open(mozilla::layers::ISurfaceAllocator* aAllocator, const mozilla::ipc::Shmem& aShmem)
|
||||
{
|
||||
nsRefPtr<gfxShmSharedReadLock> readLock = new gfxShmSharedReadLock(aAllocator, aShmem);
|
||||
return readLock.forget();
|
||||
}
|
||||
|
||||
private:
|
||||
gfxShmSharedReadLock(ISurfaceAllocator* aAllocator, const mozilla::ipc::Shmem& aShmem)
|
||||
: mAllocator(aAllocator)
|
||||
, mShmem(aShmem)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxShmSharedReadLock);
|
||||
}
|
||||
|
||||
ShmReadLockInfo* GetShmReadLockInfoPtr()
|
||||
{
|
||||
return reinterpret_cast<ShmReadLockInfo*>
|
||||
(mShmem.get<char>() + mShmem.Size<char>() - sizeof(ShmReadLockInfo));
|
||||
}
|
||||
|
||||
RefPtr<ISurfaceAllocator> mAllocator;
|
||||
mozilla::ipc::Shmem mShmem;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represent a single tile in tiled buffer. The buffer keeps tiles,
|
||||
* each tile keeps a reference to a texture client. The texture client
|
||||
* is backed by a gfxReusableSurfaceWrapper that implements a
|
||||
* copy-on-write mechanism while locked. The tile should be
|
||||
* locked before being sent to the compositor and unlocked
|
||||
* as soon as it is uploaded to prevent a copy.
|
||||
* each tile keeps a reference to a texture client and a read-lock. This
|
||||
* read-lock is used to help implement a copy-on-write mechanism. The tile
|
||||
* should be locked before being sent to the compositor. The compositor should
|
||||
* unlock the read-lock as soon as it has finished with the buffer in the
|
||||
* TextureHost to prevent more textures being created than is necessary.
|
||||
* Ideal place to store per tile debug information.
|
||||
*/
|
||||
struct BasicTiledLayerTile {
|
||||
RefPtr<DeprecatedTextureClientTile> mDeprecatedTextureClient;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
TimeStamp mLastUpdate;
|
||||
#endif
|
||||
|
||||
struct TileClient
|
||||
{
|
||||
// Placeholder
|
||||
BasicTiledLayerTile()
|
||||
: mDeprecatedTextureClient(nullptr)
|
||||
{}
|
||||
TileClient();
|
||||
|
||||
BasicTiledLayerTile(DeprecatedTextureClientTile* aTextureClient)
|
||||
: mDeprecatedTextureClient(aTextureClient)
|
||||
{}
|
||||
TileClient(const TileClient& o);
|
||||
|
||||
BasicTiledLayerTile(const BasicTiledLayerTile& o) {
|
||||
mDeprecatedTextureClient = o.mDeprecatedTextureClient;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
mLastUpdate = o.mLastUpdate;
|
||||
#endif
|
||||
}
|
||||
BasicTiledLayerTile& operator=(const BasicTiledLayerTile& o) {
|
||||
if (this == &o) return *this;
|
||||
mDeprecatedTextureClient = o.mDeprecatedTextureClient;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
mLastUpdate = o.mLastUpdate;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
bool operator== (const BasicTiledLayerTile& o) const {
|
||||
return mDeprecatedTextureClient == o.mDeprecatedTextureClient;
|
||||
}
|
||||
bool operator!= (const BasicTiledLayerTile& o) const {
|
||||
return mDeprecatedTextureClient != o.mDeprecatedTextureClient;
|
||||
TileClient& operator=(const TileClient& o);
|
||||
|
||||
bool operator== (const TileClient& o) const
|
||||
{
|
||||
return mFrontBuffer == o.mFrontBuffer;
|
||||
}
|
||||
|
||||
bool IsPlaceholderTile() { return mDeprecatedTextureClient == nullptr; }
|
||||
|
||||
void ReadUnlock() {
|
||||
GetSurface()->ReadUnlock();
|
||||
bool operator!= (const TileClient& o) const
|
||||
{
|
||||
return mFrontBuffer != o.mFrontBuffer;
|
||||
}
|
||||
void ReadLock() {
|
||||
GetSurface()->ReadLock();
|
||||
|
||||
void SetLayerManager(ClientLayerManager *aManager)
|
||||
{
|
||||
mManager = aManager;
|
||||
}
|
||||
|
||||
bool IsPlaceholderTile()
|
||||
{
|
||||
return mBackBuffer == nullptr && mFrontBuffer == nullptr;
|
||||
}
|
||||
|
||||
void ReadUnlock()
|
||||
{
|
||||
NS_ASSERTION(mFrontLock != nullptr, "ReadUnlock with no gfxSharedReadLock");
|
||||
mFrontLock->ReadUnlock();
|
||||
}
|
||||
|
||||
void ReadLock()
|
||||
{
|
||||
NS_ASSERTION(mFrontLock != nullptr, "ReadLock with no gfxSharedReadLock");
|
||||
mFrontLock->ReadLock();
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
DiscardFrontBuffer();
|
||||
DiscardBackBuffer();
|
||||
}
|
||||
|
||||
TileDescriptor GetTileDescriptor();
|
||||
static BasicTiledLayerTile OpenDescriptor(ISurfaceAllocator *aAllocator, const TileDescriptor& aDesc);
|
||||
|
||||
gfxReusableSurfaceWrapper* GetSurface() {
|
||||
return mDeprecatedTextureClient->GetReusableSurfaceWrapper();
|
||||
}
|
||||
/**
|
||||
* Swaps the front and back buffers.
|
||||
*/
|
||||
void Flip();
|
||||
|
||||
/**
|
||||
* Returns an unlocked TextureClient that can be used for writing new
|
||||
* data to the tile. This may flip the front-buffer to the back-buffer if
|
||||
* the front-buffer is still locked by the host, or does not have an
|
||||
* internal buffer (and so will always be locked).
|
||||
*/
|
||||
TextureClient* GetBackBuffer(const nsIntRegion& aDirtyRegion,
|
||||
TextureClientPool *aPool,
|
||||
bool *aCreatedTextureClient,
|
||||
bool aCanRerasterizeValidRegion);
|
||||
|
||||
void DiscardFrontBuffer();
|
||||
|
||||
void DiscardBackBuffer();
|
||||
|
||||
RefPtr<TextureClient> mBackBuffer;
|
||||
RefPtr<TextureClient> mFrontBuffer;
|
||||
RefPtr<gfxSharedReadLock> mBackLock;
|
||||
RefPtr<gfxSharedReadLock> mFrontLock;
|
||||
RefPtr<ClientLayerManager> mManager;
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
TimeStamp mLastUpdate;
|
||||
#endif
|
||||
nsIntRegion mInvalidFront;
|
||||
nsIntRegion mInvalidBack;
|
||||
|
||||
private:
|
||||
void ValidateBackBufferFromFront(const nsIntRegion &aDirtyRegion,
|
||||
bool aCanRerasterizeValidRegion);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -165,9 +291,6 @@ struct BasicTiledLayerPaintData {
|
|||
bool mPaintFinished : 1;
|
||||
};
|
||||
|
||||
class ClientTiledThebesLayer;
|
||||
class ClientLayerManager;
|
||||
|
||||
class SharedFrameMetricsHelper
|
||||
{
|
||||
public:
|
||||
|
@ -210,72 +333,45 @@ private:
|
|||
};
|
||||
|
||||
/**
|
||||
* Provide an instance of TiledLayerBuffer backed by image surfaces.
|
||||
* This buffer provides an implementation to ValidateTile using a
|
||||
* thebes callback and can support painting using a single paint buffer
|
||||
* which is much faster then painting directly into the tiles.
|
||||
* Provide an instance of TiledLayerBuffer backed by drawable TextureClients.
|
||||
* This buffer provides an implementation of ValidateTile using a
|
||||
* thebes callback and can support painting using a single paint buffer.
|
||||
* Whether a single paint buffer is used is controlled by
|
||||
* gfxPrefs::PerTileDrawing().
|
||||
*/
|
||||
class BasicTiledLayerBuffer
|
||||
: public TiledLayerBuffer<BasicTiledLayerBuffer, BasicTiledLayerTile>
|
||||
class ClientTiledLayerBuffer
|
||||
: public TiledLayerBuffer<ClientTiledLayerBuffer, TileClient>
|
||||
{
|
||||
friend class TiledLayerBuffer<BasicTiledLayerBuffer, BasicTiledLayerTile>;
|
||||
friend class TiledLayerBuffer<ClientTiledLayerBuffer, TileClient>;
|
||||
|
||||
public:
|
||||
BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
|
||||
ClientTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
|
||||
CompositableClient* aCompositableClient,
|
||||
ClientLayerManager* aManager,
|
||||
SharedFrameMetricsHelper* aHelper);
|
||||
BasicTiledLayerBuffer()
|
||||
ClientTiledLayerBuffer()
|
||||
: mThebesLayer(nullptr)
|
||||
, mCompositableClient(nullptr)
|
||||
, mManager(nullptr)
|
||||
, mLastPaintOpaque(false)
|
||||
, mSharedFrameMetricsHelper(nullptr)
|
||||
{}
|
||||
|
||||
BasicTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
const nsIntRegion& aValidRegion,
|
||||
const nsIntRegion& aPaintedRegion,
|
||||
const InfallibleTArray<TileDescriptor>& aTiles,
|
||||
int aRetainedWidth,
|
||||
int aRetainedHeight,
|
||||
float aResolution,
|
||||
SharedFrameMetricsHelper* aHelper)
|
||||
{
|
||||
mSharedFrameMetricsHelper = aHelper;
|
||||
mValidRegion = aValidRegion;
|
||||
mPaintedRegion = aPaintedRegion;
|
||||
mRetainedWidth = aRetainedWidth;
|
||||
mRetainedHeight = aRetainedHeight;
|
||||
mResolution = aResolution;
|
||||
|
||||
for(size_t i = 0; i < aTiles.Length(); i++) {
|
||||
if (aTiles[i].type() == TileDescriptor::TPlaceholderTileDescriptor) {
|
||||
mRetainedTiles.AppendElement(GetPlaceholderTile());
|
||||
} else {
|
||||
mRetainedTiles.AppendElement(BasicTiledLayerTile::OpenDescriptor(aAllocator, aTiles[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
LayerManager::DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
void ReadUnlock() {
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].ReadUnlock();
|
||||
}
|
||||
}
|
||||
void ReadUnlock();
|
||||
|
||||
void ReadLock() {
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].ReadLock();
|
||||
}
|
||||
}
|
||||
void ReadLock();
|
||||
|
||||
void Release();
|
||||
|
||||
void DiscardBackBuffers();
|
||||
|
||||
const CSSToScreenScale& GetFrameResolution() { return mFrameResolution; }
|
||||
|
||||
void SetFrameResolution(const CSSToScreenScale& aResolution) { mFrameResolution = aResolution; }
|
||||
|
||||
bool HasFormatChanged() const;
|
||||
|
@ -293,12 +389,8 @@ public:
|
|||
|
||||
SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
|
||||
|
||||
static BasicTiledLayerBuffer OpenDescriptor(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aDescriptor,
|
||||
SharedFrameMetricsHelper* aHelper);
|
||||
|
||||
protected:
|
||||
BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile,
|
||||
TileClient ValidateTile(TileClient aTile,
|
||||
const nsIntPoint& aTileRect,
|
||||
const nsIntRegion& dirtyRect);
|
||||
|
||||
|
@ -306,35 +398,29 @@ protected:
|
|||
// buffer and copy it out to the tiles instead of calling PaintThebes() on
|
||||
// each tile individually. Somewhat surprisingly, this turns out to be faster
|
||||
// on Android.
|
||||
bool UseSinglePaintBuffer() { return true; }
|
||||
bool UseSinglePaintBuffer() { return !gfxPrefs::PerTileDrawing(); }
|
||||
|
||||
void ReleaseTile(BasicTiledLayerTile aTile) { /* No-op. */ }
|
||||
void ReleaseTile(TileClient aTile) { aTile.Release(); }
|
||||
|
||||
void SwapTiles(BasicTiledLayerTile& aTileA, BasicTiledLayerTile& aTileB) {
|
||||
std::swap(aTileA, aTileB);
|
||||
}
|
||||
void SwapTiles(TileClient& aTileA, TileClient& aTileB) { std::swap(aTileA, aTileB); }
|
||||
|
||||
BasicTiledLayerTile GetPlaceholderTile() const { return BasicTiledLayerTile(); }
|
||||
TileClient GetPlaceholderTile() const { return TileClient(); }
|
||||
|
||||
private:
|
||||
gfxContentType GetContentType() const;
|
||||
ClientTiledThebesLayer* mThebesLayer;
|
||||
CompositableClient* mCompositableClient;
|
||||
ClientLayerManager* mManager;
|
||||
LayerManager::DrawThebesLayerCallback mCallback;
|
||||
void* mCallbackData;
|
||||
CSSToScreenScale mFrameResolution;
|
||||
bool mLastPaintOpaque;
|
||||
|
||||
// The buffer we use when UseSinglePaintBuffer() above is true.
|
||||
nsRefPtr<gfxImageSurface> mSinglePaintBuffer;
|
||||
// The DrawTarget we use when UseSinglePaintBuffer() above is true.
|
||||
RefPtr<gfx::DrawTarget> mSinglePaintDrawTarget;
|
||||
nsIntPoint mSinglePaintBufferOffset;
|
||||
SharedFrameMetricsHelper* mSharedFrameMetricsHelper;
|
||||
|
||||
BasicTiledLayerTile ValidateTileInternal(BasicTiledLayerTile aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRect& aDirtyRect);
|
||||
|
||||
/**
|
||||
* Calculates the region to update in a single progressive update transaction.
|
||||
* This employs some heuristics to update the most 'sensible' region to
|
||||
|
@ -374,6 +460,9 @@ public:
|
|||
~TiledContentClient()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TiledContentClient);
|
||||
|
||||
mTiledBuffer.Release();
|
||||
mLowPrecisionTiledBuffer.Release();
|
||||
}
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
|
||||
|
@ -381,16 +470,18 @@ public:
|
|||
return TextureInfo(BUFFER_TILED);
|
||||
}
|
||||
|
||||
virtual void ClearCachedResources() MOZ_OVERRIDE;
|
||||
|
||||
enum TiledBufferType {
|
||||
TILED_BUFFER,
|
||||
LOW_PRECISION_TILED_BUFFER
|
||||
};
|
||||
void LockCopyAndWrite(TiledBufferType aType);
|
||||
void UseTiledLayerBuffer(TiledBufferType aType);
|
||||
|
||||
private:
|
||||
SharedFrameMetricsHelper mSharedFrameMetricsHelper;
|
||||
BasicTiledLayerBuffer mTiledBuffer;
|
||||
BasicTiledLayerBuffer mLowPrecisionTiledBuffer;
|
||||
ClientTiledLayerBuffer mTiledBuffer;
|
||||
ClientTiledLayerBuffer mLowPrecisionTiledBuffer;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -174,7 +174,9 @@ CompositableHost::Create(const TextureInfo& aTextureInfo)
|
|||
default:
|
||||
MOZ_CRASH("Unknown CompositableType");
|
||||
}
|
||||
if (result) {
|
||||
// We know that Tiled buffers don't use the compositable backend-specific
|
||||
// data, so don't bother creating it.
|
||||
if (result && aTextureInfo.mCompositableType != BUFFER_TILED) {
|
||||
RefPtr<CompositableBackendSpecificData> data = CreateCompositableBackendSpecificDataOGL();
|
||||
result->SetCompositableBackendSpecificData(data);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "nsDebug.h" // for NS_RUNTIMEABORT
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nscore.h" // for nsACString
|
||||
#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
|
||||
|
||||
|
@ -274,6 +275,7 @@ class TextureHost
|
|||
void Finalize();
|
||||
|
||||
friend class AtomicRefCountedWithFinalize<TextureHost>;
|
||||
|
||||
public:
|
||||
TextureHost(TextureFlags aFlags);
|
||||
|
||||
|
@ -426,6 +428,13 @@ public:
|
|||
virtual const char *Name() { return "TextureHost"; }
|
||||
virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
|
||||
|
||||
/**
|
||||
* Indicates whether the TextureHost implementation is backed by an
|
||||
* in-memory buffer. The consequence of this is that locking the
|
||||
* TextureHost does not contend with locking the texture on the client side.
|
||||
*/
|
||||
virtual bool HasInternalBuffer() const { return false; }
|
||||
|
||||
/**
|
||||
* Cast to a TextureHost for each backend.
|
||||
*/
|
||||
|
@ -461,6 +470,7 @@ public:
|
|||
~BufferTextureHost();
|
||||
|
||||
virtual uint8_t* GetBuffer() = 0;
|
||||
|
||||
virtual size_t GetBufferSize() = 0;
|
||||
|
||||
virtual void Updated(const nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE;
|
||||
|
@ -488,6 +498,8 @@ public:
|
|||
|
||||
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
protected:
|
||||
bool Upload(nsIntRegion *aRegion = nullptr);
|
||||
bool MaybeUpload(nsIntRegion *aRegion = nullptr);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
#include "nsRect.h" // for nsIntRect
|
||||
#include "nsSize.h" // for nsIntSize
|
||||
#include "mozilla/layers/TiledContentClient.h"
|
||||
|
||||
class gfxReusableSurfaceWrapper;
|
||||
|
||||
|
@ -24,39 +25,119 @@ namespace layers {
|
|||
|
||||
class Layer;
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
|
||||
const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aInvalidateRegion,
|
||||
const CSSToScreenScale& aResolution)
|
||||
TiledLayerBufferComposite::TiledLayerBufferComposite()
|
||||
: mFrameResolution(1.0)
|
||||
, mHasDoubleBufferedTiles(false)
|
||||
, mUninitialized(true)
|
||||
{}
|
||||
|
||||
TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aDescriptor,
|
||||
const nsIntRegion& aOldPaintedRegion)
|
||||
{
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr("Upload %i, %i, %i, %i\n", aInvalidateRegion.GetBounds().x, aInvalidateRegion.GetBounds().y, aInvalidateRegion.GetBounds().width, aInvalidateRegion.GetBounds().height);
|
||||
long start = PR_IntervalNow();
|
||||
#endif
|
||||
mUninitialized = false;
|
||||
mHasDoubleBufferedTiles = false;
|
||||
mValidRegion = aDescriptor.validRegion();
|
||||
mPaintedRegion = aDescriptor.paintedRegion();
|
||||
mRetainedWidth = aDescriptor.retainedWidth();
|
||||
mRetainedHeight = aDescriptor.retainedHeight();
|
||||
mResolution = aDescriptor.resolution();
|
||||
|
||||
mFrameResolution = aResolution;
|
||||
mMainMemoryTiledBuffer = aMainMemoryTiledBuffer;
|
||||
Update(aNewValidRegion, aInvalidateRegion);
|
||||
mMainMemoryTiledBuffer = nullptr;
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 10) {
|
||||
printf_stderr("Time to upload %i\n", PR_IntervalNow() - start);
|
||||
// Combine any valid content that wasn't already uploaded
|
||||
nsIntRegion oldPaintedRegion(aOldPaintedRegion);
|
||||
oldPaintedRegion.And(oldPaintedRegion, mValidRegion);
|
||||
mPaintedRegion.Or(mPaintedRegion, oldPaintedRegion);
|
||||
|
||||
const InfallibleTArray<TileDescriptor>& tiles = aDescriptor.tiles();
|
||||
for(size_t i = 0; i < tiles.Length(); i++) {
|
||||
RefPtr<TextureHost> texture;
|
||||
const TileDescriptor& tileDesc = tiles[i];
|
||||
switch (tileDesc.type()) {
|
||||
case TileDescriptor::TTexturedTileDescriptor : {
|
||||
texture = TextureHost::AsTextureHost(tileDesc.get_TexturedTileDescriptor().textureParent());
|
||||
const TileLock& ipcLock = tileDesc.get_TexturedTileDescriptor().sharedLock();
|
||||
nsRefPtr<gfxSharedReadLock> sharedLock;
|
||||
if (ipcLock.type() == TileLock::TShmem) {
|
||||
sharedLock = gfxShmSharedReadLock::Open(aAllocator, ipcLock.get_Shmem());
|
||||
} else {
|
||||
sharedLock = reinterpret_cast<gfxMemorySharedReadLock*>(ipcLock.get_uintptr_t());
|
||||
// The corresponding AddRef is in TiledClient::GetTileDescriptor
|
||||
sharedLock->Release();
|
||||
}
|
||||
MOZ_ASSERT(sharedLock);
|
||||
if (sharedLock) {
|
||||
mRetainedTiles.AppendElement(TileHost(sharedLock, texture));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_WARNING("Unrecognised tile descriptor type");
|
||||
// Fall through
|
||||
case TileDescriptor::TPlaceholderTileDescriptor :
|
||||
mRetainedTiles.AppendElement(GetPlaceholderTile());
|
||||
break;
|
||||
}
|
||||
if (texture && !texture->HasInternalBuffer()) {
|
||||
mHasDoubleBufferedTiles = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TiledTexture
|
||||
TiledLayerBufferComposite::ValidateTile(TiledTexture aTile,
|
||||
void
|
||||
TiledLayerBufferComposite::ReadUnlock()
|
||||
{
|
||||
if (!IsValid()) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
mRetainedTiles[i].ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::ReleaseTextureHosts()
|
||||
{
|
||||
if (!IsValid()) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
mRetainedTiles[i].mTextureHost = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::Upload()
|
||||
{
|
||||
if(!IsValid()) {
|
||||
return;
|
||||
}
|
||||
// The TextureClients were created with the TEXTURE_IMMEDIATE_UPLOAD flag,
|
||||
// so calling Update on all the texture hosts will perform the texture upload.
|
||||
Update(mValidRegion, mPaintedRegion);
|
||||
ClearPaintedRegion();
|
||||
}
|
||||
|
||||
TileHost
|
||||
TiledLayerBufferComposite::ValidateTile(TileHost aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRegion& aDirtyRect)
|
||||
{
|
||||
if (aTile.IsPlaceholderTile()) {
|
||||
NS_WARNING("Placeholder tile encountered in painted region");
|
||||
return aTile;
|
||||
}
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr("Upload tile %i, %i\n", aTileOrigin.x, aTileOrigin.y);
|
||||
long start = PR_IntervalNow();
|
||||
#endif
|
||||
|
||||
aTile.Validate(mMainMemoryTiledBuffer->GetTile(aTileOrigin).GetSurface(), mCompositor, GetTileLength());
|
||||
MOZ_ASSERT(aTile.mTextureHost->GetFlags() & TEXTURE_IMMEDIATE_UPLOAD);
|
||||
// We possibly upload the entire texture contents here. This is a purposeful
|
||||
// decision, as sub-image upload can often be slow and/or unreliable, but
|
||||
// we may want to reevaluate this in the future.
|
||||
// For !HasInternalBuffer() textures, this is likely a no-op.
|
||||
aTile.mTextureHost->Updated(nullptr);
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 1) {
|
||||
|
@ -66,6 +147,57 @@ TiledLayerBufferComposite::ValidateTile(TiledTexture aTile,
|
|||
return aTile;
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor)
|
||||
{
|
||||
if (!IsValid()) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
|
||||
mRetainedTiles[i].mTextureHost->SetCompositor(aCompositor);
|
||||
}
|
||||
}
|
||||
|
||||
TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo)
|
||||
: ContentHost(aTextureInfo)
|
||||
, mTiledBuffer(TiledLayerBufferComposite())
|
||||
, mLowPrecisionTiledBuffer(TiledLayerBufferComposite())
|
||||
, mOldTiledBuffer(TiledLayerBufferComposite())
|
||||
, mOldLowPrecisionTiledBuffer(TiledLayerBufferComposite())
|
||||
, mPendingUpload(false)
|
||||
, mPendingLowPrecisionUpload(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(TiledContentHost);
|
||||
}
|
||||
|
||||
TiledContentHost::~TiledContentHost()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TiledContentHost);
|
||||
|
||||
// Unlock any buffers that may still be locked. If we have a pending upload,
|
||||
// we will need to unlock the buffer that was about to be uploaded.
|
||||
// If a buffer that was being composited had double-buffered tiles, we will
|
||||
// need to unlock that buffer too.
|
||||
if (mPendingUpload) {
|
||||
mTiledBuffer.ReadUnlock();
|
||||
if (mOldTiledBuffer.HasDoubleBufferedTiles()) {
|
||||
mOldTiledBuffer.ReadUnlock();
|
||||
}
|
||||
} else if (mTiledBuffer.HasDoubleBufferedTiles()) {
|
||||
mTiledBuffer.ReadUnlock();
|
||||
}
|
||||
|
||||
if (mPendingLowPrecisionUpload) {
|
||||
mLowPrecisionTiledBuffer.ReadUnlock();
|
||||
if (mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
|
||||
mOldLowPrecisionTiledBuffer.ReadUnlock();
|
||||
}
|
||||
} else if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
|
||||
mLowPrecisionTiledBuffer.ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TiledContentHost::Attach(Layer* aLayer,
|
||||
Compositor* aCompositor,
|
||||
|
@ -76,70 +208,41 @@ TiledContentHost::Attach(Layer* aLayer,
|
|||
}
|
||||
|
||||
void
|
||||
TiledContentHost::PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aTiledDescriptor)
|
||||
{
|
||||
if (aTiledDescriptor.resolution() < 1) {
|
||||
mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor, nullptr);
|
||||
mLowPrecisionRegionToUpload.Or(mLowPrecisionRegionToUpload,
|
||||
mLowPrecisionMainMemoryTiledBuffer.GetPaintedRegion());
|
||||
mLowPrecisionMainMemoryTiledBuffer.ClearPaintedRegion();
|
||||
mPendingLowPrecisionUpload = true;
|
||||
if (mPendingLowPrecisionUpload) {
|
||||
mLowPrecisionTiledBuffer.ReadUnlock();
|
||||
} else {
|
||||
mPendingLowPrecisionUpload = true;
|
||||
// If the old buffer has double-buffered tiles, hang onto it so we can
|
||||
// unlock it after we've composited the new buffer.
|
||||
// We only need to hang onto the locks, but not the textures.
|
||||
// Releasing the textures here can help prevent a memory spike in the
|
||||
// situation that the client starts rendering new content before we get
|
||||
// to composite the new buffer.
|
||||
if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
|
||||
mOldLowPrecisionTiledBuffer = mLowPrecisionTiledBuffer;
|
||||
mOldLowPrecisionTiledBuffer.ReleaseTextureHosts();
|
||||
}
|
||||
}
|
||||
mLowPrecisionTiledBuffer =
|
||||
TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
|
||||
mLowPrecisionTiledBuffer.GetPaintedRegion());
|
||||
} else {
|
||||
if (mPendingUpload) {
|
||||
mTiledBuffer.ReadUnlock();
|
||||
} else {
|
||||
mMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor, nullptr);
|
||||
mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetPaintedRegion());
|
||||
mMainMemoryTiledBuffer.ClearPaintedRegion();
|
||||
mPendingUpload = true;
|
||||
if (mTiledBuffer.HasDoubleBufferedTiles()) {
|
||||
mOldTiledBuffer = mTiledBuffer;
|
||||
mOldTiledBuffer.ReleaseTextureHosts();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TiledContentHost::ProcessLowPrecisionUploadQueue()
|
||||
{
|
||||
if (!mPendingLowPrecisionUpload) {
|
||||
return;
|
||||
mTiledBuffer = TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
|
||||
mTiledBuffer.GetPaintedRegion());
|
||||
}
|
||||
|
||||
mLowPrecisionRegionToUpload.And(mLowPrecisionRegionToUpload,
|
||||
mLowPrecisionMainMemoryTiledBuffer.GetValidRegion());
|
||||
mLowPrecisionVideoMemoryTiledBuffer.SetResolution(
|
||||
mLowPrecisionMainMemoryTiledBuffer.GetResolution());
|
||||
// It's assumed that the video memory tiled buffer has an up-to-date
|
||||
// frame resolution. As it's always updated first when zooming, this
|
||||
// should always be true.
|
||||
mLowPrecisionVideoMemoryTiledBuffer.Upload(&mLowPrecisionMainMemoryTiledBuffer,
|
||||
mLowPrecisionMainMemoryTiledBuffer.GetValidRegion(),
|
||||
mLowPrecisionRegionToUpload,
|
||||
mVideoMemoryTiledBuffer.GetFrameResolution());
|
||||
nsIntRegion validRegion = mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion();
|
||||
|
||||
mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer();
|
||||
mLowPrecisionRegionToUpload = nsIntRegion();
|
||||
mPendingLowPrecisionUpload = false;
|
||||
}
|
||||
|
||||
void
|
||||
TiledContentHost::ProcessUploadQueue(nsIntRegion* aNewValidRegion,
|
||||
TiledLayerProperties* aLayerProperties)
|
||||
{
|
||||
if (!mPendingUpload)
|
||||
return;
|
||||
|
||||
// If we coalesce uploads while the layers' valid region is changing we will
|
||||
// end up trying to upload area outside of the valid region. (bug 756555)
|
||||
mRegionToUpload.And(mRegionToUpload, mMainMemoryTiledBuffer.GetValidRegion());
|
||||
|
||||
mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer,
|
||||
mMainMemoryTiledBuffer.GetValidRegion(),
|
||||
mRegionToUpload, aLayerProperties->mEffectiveResolution);
|
||||
|
||||
*aNewValidRegion = mVideoMemoryTiledBuffer.GetValidRegion();
|
||||
|
||||
// Release all the tiles by replacing the tile buffer with an empty
|
||||
// tiled buffer.
|
||||
mMainMemoryTiledBuffer = BasicTiledLayerBuffer();
|
||||
mRegionToUpload = nsIntRegion();
|
||||
mPendingUpload = false;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -153,24 +256,51 @@ TiledContentHost::Composite(EffectChain& aEffectChain,
|
|||
{
|
||||
MOZ_ASSERT(aLayerProperties, "aLayerProperties required for TiledContentHost");
|
||||
|
||||
// note that ProcessUploadQueue updates the valid region which is then used by
|
||||
// the RenderLayerBuffer calls below and then sent back to the layer.
|
||||
ProcessUploadQueue(&aLayerProperties->mValidRegion, aLayerProperties);
|
||||
ProcessLowPrecisionUploadQueue();
|
||||
|
||||
// Render valid tiles.
|
||||
nsIntRect visibleRect = aVisibleRegion->GetBounds();
|
||||
|
||||
RenderLayerBuffer(mLowPrecisionVideoMemoryTiledBuffer,
|
||||
mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion(), aEffectChain, aOpacity,
|
||||
if (mPendingUpload) {
|
||||
mTiledBuffer.SetCompositor(mCompositor);
|
||||
mTiledBuffer.Upload();
|
||||
|
||||
// For a single-buffered tiled buffer, Upload will upload the shared memory
|
||||
// surface to texture memory and we no longer need to read from them.
|
||||
if (!mTiledBuffer.HasDoubleBufferedTiles()) {
|
||||
mTiledBuffer.ReadUnlock();
|
||||
}
|
||||
}
|
||||
if (mPendingLowPrecisionUpload) {
|
||||
mLowPrecisionTiledBuffer.SetCompositor(mCompositor);
|
||||
mLowPrecisionTiledBuffer.Upload();
|
||||
|
||||
if (!mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
|
||||
mLowPrecisionTiledBuffer.ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
RenderLayerBuffer(mLowPrecisionTiledBuffer,
|
||||
mLowPrecisionTiledBuffer.GetValidRegion(), aEffectChain, aOpacity,
|
||||
aFilter, aClipRect, aLayerProperties->mValidRegion, visibleRect, aTransform);
|
||||
RenderLayerBuffer(mVideoMemoryTiledBuffer, aLayerProperties->mValidRegion, aEffectChain, aOpacity,
|
||||
RenderLayerBuffer(mTiledBuffer, aLayerProperties->mValidRegion, aEffectChain, aOpacity,
|
||||
aFilter, aClipRect, nsIntRegion(), visibleRect, aTransform);
|
||||
|
||||
// Now release the old buffer if it had double-buffered tiles, as we can
|
||||
// guarantee that they're no longer on the screen (and so any locks that may
|
||||
// have been held have been released).
|
||||
if (mPendingUpload && mOldTiledBuffer.HasDoubleBufferedTiles()) {
|
||||
mOldTiledBuffer.ReadUnlock();
|
||||
mOldTiledBuffer = TiledLayerBufferComposite();
|
||||
}
|
||||
if (mPendingLowPrecisionUpload && mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
|
||||
mOldLowPrecisionTiledBuffer.ReadUnlock();
|
||||
mOldLowPrecisionTiledBuffer = TiledLayerBufferComposite();
|
||||
}
|
||||
mPendingUpload = mPendingLowPrecisionUpload = false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TiledContentHost::RenderTile(const TiledTexture& aTile,
|
||||
TiledContentHost::RenderTile(const TileHost& aTile,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
|
@ -180,19 +310,38 @@ TiledContentHost::RenderTile(const TiledTexture& aTile,
|
|||
const nsIntPoint& aTextureOffset,
|
||||
const nsIntSize& aTextureBounds)
|
||||
{
|
||||
MOZ_ASSERT(aTile.mDeprecatedTextureHost, "Trying to render a placeholder tile?");
|
||||
if (aTile.IsPlaceholderTile()) {
|
||||
// This shouldn't ever happen, but let's fail semi-gracefully. No need
|
||||
// to warn, the texture update would have already caught this.
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRect screenBounds = aScreenRegion.GetBounds();
|
||||
Matrix mat = aTransform.As2D();
|
||||
Rect quad(screenBounds.x, screenBounds.y, screenBounds.width, screenBounds.height);
|
||||
quad = mat.TransformBounds(quad);
|
||||
|
||||
if (!quad.Intersects(aClipRect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLockTextureHost autoLock(aTile.mTextureHost);
|
||||
if (autoLock.Failed()) {
|
||||
NS_WARNING("Failed to lock tile");
|
||||
return;
|
||||
}
|
||||
RefPtr<NewTextureSource> source = aTile.mTextureHost->GetTextureSources();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<TexturedEffect> effect =
|
||||
CreateTexturedEffect(aTile.mDeprecatedTextureHost, aFilter);
|
||||
CreateTexturedEffect(aTile.mTextureHost->GetFormat(), source, aFilter);
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aTile.mDeprecatedTextureHost->Lock()) {
|
||||
aEffectChain.mPrimaryEffect = effect;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRegionRectIterator it(aScreenRegion);
|
||||
for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) {
|
||||
|
@ -208,8 +357,6 @@ TiledContentHost::RenderTile(const TiledTexture& aTile,
|
|||
}
|
||||
mCompositor->DrawDiagnostics(DIAGNOSTIC_CONTENT|DIAGNOSTIC_TILE,
|
||||
aScreenRegion, aClipRect, aTransform);
|
||||
|
||||
aTile.mDeprecatedTextureHost->Unlock();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -231,9 +378,9 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
|||
gfx::Size layerScale(1, 1);
|
||||
// We assume that the current frame resolution is the one used in our primary
|
||||
// layer buffer. Compensate for a changing frame resolution.
|
||||
if (aLayerBuffer.GetFrameResolution() != mVideoMemoryTiledBuffer.GetFrameResolution()) {
|
||||
if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) {
|
||||
const CSSToScreenScale& layerResolution = aLayerBuffer.GetFrameResolution();
|
||||
const CSSToScreenScale& localResolution = mVideoMemoryTiledBuffer.GetFrameResolution();
|
||||
const CSSToScreenScale& localResolution = mTiledBuffer.GetFrameResolution();
|
||||
layerScale.width = layerScale.height = layerResolution.scale / localResolution.scale;
|
||||
aVisibleRect.ScaleRoundOut(layerScale.width, layerScale.height);
|
||||
}
|
||||
|
@ -257,7 +404,7 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
|||
h = aVisibleRect.y + aVisibleRect.height - y;
|
||||
}
|
||||
|
||||
TiledTexture tileTexture = aLayerBuffer.
|
||||
TileHost tileTexture = aLayerBuffer.
|
||||
GetTile(nsIntPoint(aLayerBuffer.RoundDownToTileEdge(x),
|
||||
aLayerBuffer.RoundDownToTileEdge(y)));
|
||||
if (tileTexture != aLayerBuffer.GetPlaceholderTile()) {
|
||||
|
@ -292,23 +439,6 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
|||
rect, aClipRect, aTransform);
|
||||
}
|
||||
|
||||
void
|
||||
TiledTexture::Validate(gfxReusableSurfaceWrapper* aReusableSurface, Compositor* aCompositor, uint16_t aSize)
|
||||
{
|
||||
TextureFlags flags = 0;
|
||||
if (!mDeprecatedTextureHost) {
|
||||
// convert placeholder tile to a real tile
|
||||
mDeprecatedTextureHost = DeprecatedTextureHost::CreateDeprecatedTextureHost(SurfaceDescriptor::Tnull_t,
|
||||
TEXTURE_HOST_TILED,
|
||||
flags,
|
||||
nullptr);
|
||||
mDeprecatedTextureHost->SetCompositor(aCompositor);
|
||||
flags |= TEXTURE_NEW_TILE;
|
||||
}
|
||||
|
||||
mDeprecatedTextureHost->Update(aReusableSurface, flags, gfx::IntSize(aSize, aSize));
|
||||
}
|
||||
|
||||
void
|
||||
TiledContentHost::PrintInfo(nsACString& aTo, const char* aPrefix)
|
||||
{
|
||||
|
@ -327,15 +457,19 @@ TiledContentHost::Dump(FILE* aFile,
|
|||
aFile = stderr;
|
||||
}
|
||||
|
||||
TiledLayerBufferComposite::Iterator it = mVideoMemoryTiledBuffer.TilesBegin();
|
||||
TiledLayerBufferComposite::Iterator stop = mVideoMemoryTiledBuffer.TilesEnd();
|
||||
TiledLayerBufferComposite::Iterator it = mTiledBuffer.TilesBegin();
|
||||
TiledLayerBufferComposite::Iterator stop = mTiledBuffer.TilesEnd();
|
||||
if (aDumpHtml) {
|
||||
fprintf_stderr(aFile, "<ul>");
|
||||
}
|
||||
for (;it != stop; ++it) {
|
||||
fprintf_stderr(aFile, "%s", aPrefix);
|
||||
fprintf_stderr(aFile, aDumpHtml ? "<li> <a href=" : "Tile ");
|
||||
DumpDeprecatedTextureHost(aFile, it->mDeprecatedTextureHost);
|
||||
if (it->IsPlaceholderTile()) {
|
||||
fprintf_stderr(aFile, "empty tile");
|
||||
} else {
|
||||
DumpTextureHost(aFile, it->mTextureHost);
|
||||
}
|
||||
fprintf_stderr(aFile, aDumpHtml ? " >Tile</a></li>" : " ");
|
||||
}
|
||||
if (aDumpHtml) {
|
||||
|
|
|
@ -47,132 +47,138 @@ class TiledThebesLayerComposite;
|
|||
struct EffectChain;
|
||||
|
||||
|
||||
class TiledTexture {
|
||||
class TileHost {
|
||||
public:
|
||||
// Constructs a placeholder TiledTexture. See the comments above
|
||||
// Constructs a placeholder TileHost. See the comments above
|
||||
// TiledLayerBuffer for more information on what this is used for;
|
||||
// essentially, this is a sentinel used to represent an invalid or blank
|
||||
// tile.
|
||||
TiledTexture()
|
||||
: mDeprecatedTextureHost(nullptr)
|
||||
TileHost()
|
||||
: mSharedLock(nullptr)
|
||||
, mTextureHost(nullptr)
|
||||
{}
|
||||
|
||||
// Constructs a TiledTexture from a DeprecatedTextureHost.
|
||||
TiledTexture(DeprecatedTextureHost* aDeprecatedTextureHost)
|
||||
: mDeprecatedTextureHost(aDeprecatedTextureHost)
|
||||
// Constructs a TileHost from a gfxSharedReadLock and TextureHost.
|
||||
TileHost(gfxSharedReadLock* aSharedLock,
|
||||
TextureHost* aTextureHost)
|
||||
: mSharedLock(aSharedLock)
|
||||
, mTextureHost(aTextureHost)
|
||||
{}
|
||||
|
||||
TiledTexture(const TiledTexture& o) {
|
||||
mDeprecatedTextureHost = o.mDeprecatedTextureHost;
|
||||
TileHost(const TileHost& o) {
|
||||
mTextureHost = o.mTextureHost;
|
||||
mSharedLock = o.mSharedLock;
|
||||
}
|
||||
TiledTexture& operator=(const TiledTexture& o) {
|
||||
TileHost& operator=(const TileHost& o) {
|
||||
if (this == &o) {
|
||||
return *this;
|
||||
}
|
||||
mDeprecatedTextureHost = o.mDeprecatedTextureHost;
|
||||
mTextureHost = o.mTextureHost;
|
||||
mSharedLock = o.mSharedLock;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Validate(gfxReusableSurfaceWrapper* aReusableSurface, Compositor* aCompositor, uint16_t aSize);
|
||||
|
||||
bool operator== (const TiledTexture& o) const {
|
||||
if (!mDeprecatedTextureHost || !o.mDeprecatedTextureHost) {
|
||||
return mDeprecatedTextureHost == o.mDeprecatedTextureHost;
|
||||
bool operator== (const TileHost& o) const {
|
||||
return mTextureHost == o.mTextureHost;
|
||||
}
|
||||
return *mDeprecatedTextureHost == *o.mDeprecatedTextureHost;
|
||||
}
|
||||
bool operator!= (const TiledTexture& o) const {
|
||||
if (!mDeprecatedTextureHost || !o.mDeprecatedTextureHost) {
|
||||
return mDeprecatedTextureHost != o.mDeprecatedTextureHost;
|
||||
}
|
||||
return *mDeprecatedTextureHost != *o.mDeprecatedTextureHost;
|
||||
bool operator!= (const TileHost& o) const {
|
||||
return mTextureHost != o.mTextureHost;
|
||||
}
|
||||
|
||||
RefPtr<DeprecatedTextureHost> mDeprecatedTextureHost;
|
||||
bool IsPlaceholderTile() const { return mTextureHost == nullptr; }
|
||||
|
||||
void ReadUnlock() {
|
||||
// Warn if we have a texture host, but no corresponding lock.
|
||||
NS_WARN_IF_FALSE(mTextureHost == nullptr || mSharedLock != nullptr,
|
||||
"ReadUnlock with no gfxSharedReadLock");
|
||||
if (mSharedLock) {
|
||||
mSharedLock->ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<gfxSharedReadLock> mSharedLock;
|
||||
RefPtr<TextureHost> mTextureHost;
|
||||
};
|
||||
|
||||
class TiledLayerBufferComposite
|
||||
: public TiledLayerBuffer<TiledLayerBufferComposite, TiledTexture>
|
||||
: public TiledLayerBuffer<TiledLayerBufferComposite, TileHost>
|
||||
{
|
||||
friend class TiledLayerBuffer<TiledLayerBufferComposite, TiledTexture>;
|
||||
friend class TiledLayerBuffer<TiledLayerBufferComposite, TileHost>;
|
||||
|
||||
public:
|
||||
typedef TiledLayerBuffer<TiledLayerBufferComposite, TiledTexture>::Iterator Iterator;
|
||||
TiledLayerBufferComposite()
|
||||
: mCompositor(nullptr)
|
||||
{}
|
||||
typedef TiledLayerBuffer<TiledLayerBufferComposite, TileHost>::Iterator Iterator;
|
||||
|
||||
void Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
|
||||
const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aInvalidateRegion,
|
||||
const CSSToScreenScale& aResolution);
|
||||
TiledLayerBufferComposite();
|
||||
TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aDescriptor,
|
||||
const nsIntRegion& aOldPaintedRegion);
|
||||
|
||||
TiledTexture GetPlaceholderTile() const { return TiledTexture(); }
|
||||
TileHost GetPlaceholderTile() const { return TileHost(); }
|
||||
|
||||
// Stores the absolute resolution of the containing frame, calculated
|
||||
// by the sum of the resolutions of all parent layers' FrameMetrics.
|
||||
const CSSToScreenScale& GetFrameResolution() { return mFrameResolution; }
|
||||
|
||||
void SetCompositor(Compositor* aCompositor)
|
||||
{
|
||||
mCompositor = aCompositor;
|
||||
}
|
||||
void ReadUnlock();
|
||||
|
||||
void ReleaseTextureHosts();
|
||||
|
||||
/**
|
||||
* This will synchronously upload any necessary texture contents, making the
|
||||
* sources immediately available for compositing. For texture hosts that
|
||||
* don't have an internal buffer, this is unlikely to actually do anything.
|
||||
*/
|
||||
void Upload();
|
||||
|
||||
void SetCompositor(Compositor* aCompositor);
|
||||
|
||||
bool HasDoubleBufferedTiles() { return mHasDoubleBufferedTiles; }
|
||||
|
||||
bool IsValid() const { return !mUninitialized; }
|
||||
|
||||
protected:
|
||||
TiledTexture ValidateTile(TiledTexture aTile,
|
||||
TileHost ValidateTile(TileHost aTile,
|
||||
const nsIntPoint& aTileRect,
|
||||
const nsIntRegion& dirtyRect);
|
||||
|
||||
// do nothing, the desctructor in the texture host takes care of releasing resources
|
||||
void ReleaseTile(TiledTexture aTile) {}
|
||||
void ReleaseTile(TileHost aTile) {}
|
||||
|
||||
void SwapTiles(TiledTexture& aTileA, TiledTexture& aTileB) {
|
||||
std::swap(aTileA, aTileB);
|
||||
}
|
||||
void SwapTiles(TileHost& aTileA, TileHost& aTileB) { std::swap(aTileA, aTileB); }
|
||||
|
||||
private:
|
||||
Compositor* mCompositor;
|
||||
const BasicTiledLayerBuffer* mMainMemoryTiledBuffer;
|
||||
CSSToScreenScale mFrameResolution;
|
||||
bool mHasDoubleBufferedTiles;
|
||||
bool mUninitialized;
|
||||
};
|
||||
|
||||
/**
|
||||
* ContentHost for tiled Thebes layers. Since tiled layers are special snow
|
||||
* flakes, we don't call UpdateThebes or AddTextureHost, etc. We do call Composite
|
||||
* in the usual way though.
|
||||
*
|
||||
* There is no corresponding content client - on the client side we use a
|
||||
* BasicTiledLayerBuffer owned by a BasicTiledThebesLayer. On the host side, we
|
||||
* just use a regular ThebesLayerComposite, but with a tiled content host.
|
||||
* flakes, we have a unique update process. All the textures that back the
|
||||
* tiles are added in the usual way, but Updated is called on the host side
|
||||
* in response to a message that describes the transaction for every tile.
|
||||
* Composition happens in the normal way.
|
||||
*
|
||||
* TiledContentHost has a TiledLayerBufferComposite which keeps hold of the tiles.
|
||||
* Each tile has a reference to a texture host. During the layers transaction, we
|
||||
* receive a copy of the client-side tile buffer (PaintedTiledLayerBuffer). This is
|
||||
* copied into the main memory tile buffer and then deleted. Copying copies tiles,
|
||||
* but we only copy references to the underlying texture clients.
|
||||
* receive a list of descriptors for the client-side tile buffer tiles
|
||||
* (UseTiledLayerBuffer). If we receive two transactions before a composition,
|
||||
* we immediately unlock and discard the unused buffer.
|
||||
*
|
||||
* When the content host is composited, we first upload any pending tiles
|
||||
* (Process*UploadQueue), then render (RenderLayerBuffer). The former calls Validate
|
||||
* on the tile (via ValidateTile and Update), that calls Update on the texture host,
|
||||
* which works as for regular texture hosts. Rendering takes us to RenderTile which
|
||||
* When the content host is composited, we first validate the TiledLayerBuffer
|
||||
* (Upload), which calls Updated on each tile's texture host to make sure the
|
||||
* texture data has been uploaded. For single-buffered tiles, we unlock at this
|
||||
* point, for double-buffered tiles we unlock and discard the last composited
|
||||
* buffer after compositing a new one. Rendering takes us to RenderTile which
|
||||
* is similar to Composite for non-tiled ContentHosts.
|
||||
*/
|
||||
class TiledContentHost : public ContentHost,
|
||||
public TiledLayerComposer
|
||||
{
|
||||
public:
|
||||
TiledContentHost(const TextureInfo& aTextureInfo)
|
||||
: ContentHost(aTextureInfo)
|
||||
, mPendingUpload(false)
|
||||
, mPendingLowPrecisionUpload(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(TiledContentHost);
|
||||
}
|
||||
TiledContentHost(const TextureInfo& aTextureInfo);
|
||||
|
||||
~TiledContentHost()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TiledContentHost);
|
||||
}
|
||||
~TiledContentHost();
|
||||
|
||||
virtual LayerRenderState GetRenderState() MOZ_OVERRIDE
|
||||
{
|
||||
|
@ -191,14 +197,14 @@ public:
|
|||
|
||||
const nsIntRegion& GetValidLowPrecisionRegion() const
|
||||
{
|
||||
return mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion();
|
||||
return mLowPrecisionTiledBuffer.GetValidRegion();
|
||||
}
|
||||
|
||||
void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
void UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aTiledDescriptor);
|
||||
|
||||
// Renders a single given tile.
|
||||
void RenderTile(const TiledTexture& aTile,
|
||||
void RenderTile(const TileHost& aTile,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
|
@ -228,13 +234,6 @@ public:
|
|||
MOZ_CRASH("Does nothing");
|
||||
}
|
||||
|
||||
virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE
|
||||
{
|
||||
CompositableHost::SetCompositor(aCompositor);
|
||||
mVideoMemoryTiledBuffer.SetCompositor(aCompositor);
|
||||
mLowPrecisionVideoMemoryTiledBuffer.SetCompositor(aCompositor);
|
||||
}
|
||||
|
||||
virtual void Attach(Layer* aLayer,
|
||||
Compositor* aCompositor,
|
||||
AttachFlags aFlags = NO_FLAGS) MOZ_OVERRIDE;
|
||||
|
@ -248,10 +247,6 @@ public:
|
|||
virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
|
||||
|
||||
private:
|
||||
void ProcessUploadQueue(nsIntRegion* aNewValidRegion,
|
||||
TiledLayerProperties* aLayerProperties);
|
||||
void ProcessLowPrecisionUploadQueue();
|
||||
|
||||
void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
||||
const nsIntRegion& aValidRegion,
|
||||
EffectChain& aEffectChain,
|
||||
|
@ -264,12 +259,10 @@ private:
|
|||
|
||||
void EnsureTileStore() {}
|
||||
|
||||
nsIntRegion mRegionToUpload;
|
||||
nsIntRegion mLowPrecisionRegionToUpload;
|
||||
BasicTiledLayerBuffer mMainMemoryTiledBuffer;
|
||||
BasicTiledLayerBuffer mLowPrecisionMainMemoryTiledBuffer;
|
||||
TiledLayerBufferComposite mVideoMemoryTiledBuffer;
|
||||
TiledLayerBufferComposite mLowPrecisionVideoMemoryTiledBuffer;
|
||||
TiledLayerBufferComposite mTiledBuffer;
|
||||
TiledLayerBufferComposite mLowPrecisionTiledBuffer;
|
||||
TiledLayerBufferComposite mOldTiledBuffer;
|
||||
TiledLayerBufferComposite mOldLowPrecisionTiledBuffer;
|
||||
bool mPendingUpload : 1;
|
||||
bool mPendingLowPrecisionUpload : 1;
|
||||
};
|
||||
|
|
|
@ -709,30 +709,6 @@ LayerManagerD3D10::Render(EndTransactionFlags aFlags)
|
|||
|
||||
static_cast<LayerD3D10*>(mRoot->ImplData())->RenderLayer();
|
||||
|
||||
if (!mRegionToClear.IsEmpty()) {
|
||||
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
gfx::Matrix4x4 transform;
|
||||
effect()->GetVariableByName("mLayerTransform")->SetRawValue(&transform, 0, 64);
|
||||
effect()->GetVariableByName("fLayerColor")->AsVector()->SetFloatVector(color);
|
||||
|
||||
ID3D10EffectTechnique *technique = effect()->GetTechniqueByName("RenderClearLayer");
|
||||
|
||||
nsIntRegionRectIterator iter(mRegionToClear);
|
||||
const nsIntRect *r;
|
||||
while ((r = iter.Next())) {
|
||||
effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
|
||||
ShaderConstantRectD3D10(
|
||||
(float)r->x,
|
||||
(float)r->y,
|
||||
(float)r->width,
|
||||
(float)r->height)
|
||||
);
|
||||
|
||||
technique->GetPassByIndex(0)->Apply(0);
|
||||
device()->Draw(4, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// See bug 630197 - we have some reasons to believe if an earlier call
|
||||
// returned an error, the upcoming present call may raise an exception.
|
||||
// This will check if any of the calls done recently has returned an error
|
||||
|
|
|
@ -448,18 +448,6 @@ technique10 RenderSolidColorLayer
|
|||
}
|
||||
}
|
||||
|
||||
technique10 RenderClearLayer
|
||||
{
|
||||
pass P0
|
||||
{
|
||||
SetRasterizerState( LayerRast );
|
||||
SetBlendState( NoBlendDual, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
||||
SetVertexShader( CompileShader( vs_4_0_level_9_3, LayerQuadVS() ) );
|
||||
SetGeometryShader( NULL );
|
||||
SetPixelShader( CompileShader( ps_4_0_level_9_3, SolidColorShader() ) );
|
||||
}
|
||||
}
|
||||
|
||||
technique10 PrepareAlphaExtractionTextures
|
||||
{
|
||||
pass P0
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -45,6 +45,8 @@ public:
|
|||
|
||||
virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
|
||||
|
||||
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
|
||||
|
||||
virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
|
||||
|
|
|
@ -261,25 +261,6 @@ LayerManagerD3D9::Render()
|
|||
|
||||
static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer();
|
||||
|
||||
if (!mRegionToClear.IsEmpty()) {
|
||||
D3DRECT* rects = new D3DRECT[mRegionToClear.GetNumRects()];
|
||||
nsIntRegionRectIterator iter(mRegionToClear);
|
||||
const nsIntRect *r;
|
||||
size_t i = 0;
|
||||
while ((r = iter.Next())) {
|
||||
rects[i].x1 = r->x;
|
||||
rects[i].y1 = r->y;
|
||||
rects[i].x2 = r->x + r->width;
|
||||
rects[i].y2 = r->y + r->height;
|
||||
i++;
|
||||
}
|
||||
|
||||
device()->Clear(i, rects, D3DCLEAR_TARGET,
|
||||
0x00000000, 0, 0);
|
||||
|
||||
delete [] rects;
|
||||
}
|
||||
|
||||
device()->EndScene();
|
||||
|
||||
if (!mTarget) {
|
||||
|
|
|
@ -219,6 +219,8 @@ public:
|
|||
virtual bool AllocateForSurface(gfx::IntSize aSize,
|
||||
TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
private:
|
||||
RefPtr<IDirect3DTexture9> mTexture;
|
||||
nsRefPtr<IDirect3DSurface9> mD3D9Surface;
|
||||
|
@ -271,6 +273,8 @@ public:
|
|||
virtual bool AllocateForSurface(gfx::IntSize aSize,
|
||||
TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
protected:
|
||||
nsRefPtr<gfxWindowsSurface> mSurface;
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
|
@ -353,6 +357,8 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
protected:
|
||||
TextureHostD3D9(TextureFlags aFlags);
|
||||
IDirect3DDevice9* GetDevice();
|
||||
|
|
|
@ -28,7 +28,7 @@ class SurfaceDescriptor;
|
|||
class SurfaceDescriptorTiles;
|
||||
class ThebesBufferData;
|
||||
class DeprecatedTextureClient;
|
||||
class BasicTiledLayerBuffer;
|
||||
class ClientTiledLayerBuffer;
|
||||
class PTextureChild;
|
||||
|
||||
/**
|
||||
|
@ -49,7 +49,6 @@ public:
|
|||
|
||||
CompositableForwarder()
|
||||
: mSerial(++sSerialCounter)
|
||||
, mMultiProcess(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
|
@ -92,7 +91,11 @@ public:
|
|||
*/
|
||||
virtual void DestroyThebesBuffer(CompositableClient* aCompositable) = 0;
|
||||
|
||||
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
|
||||
/**
|
||||
* Tell the CompositableHost on the compositor side what TiledLayerBuffer to
|
||||
* use for the next composition.
|
||||
*/
|
||||
virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
|
||||
const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
|
||||
|
||||
/**
|
||||
|
@ -222,7 +225,7 @@ public:
|
|||
* We only don't allow changing the backend type at runtime so this value can
|
||||
* be queried once and will not change until Gecko is restarted.
|
||||
*/
|
||||
LayersBackend GetCompositorBackendType() const
|
||||
virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE
|
||||
{
|
||||
return mTextureFactoryIdentifier.mParentBackend;
|
||||
}
|
||||
|
@ -237,11 +240,6 @@ public:
|
|||
return mTextureFactoryIdentifier.mSupportsPartialUploads;
|
||||
}
|
||||
|
||||
bool ForwardsToDifferentProcess() const
|
||||
{
|
||||
return mMultiProcess;
|
||||
}
|
||||
|
||||
const TextureFactoryIdentifier& GetTextureFactoryIdentifier() const
|
||||
{
|
||||
return mTextureFactoryIdentifier;
|
||||
|
@ -254,7 +252,6 @@ protected:
|
|||
nsTArray<RefPtr<TextureClient> > mTexturesToRemove;
|
||||
const int32_t mSerial;
|
||||
static mozilla::Atomic<int32_t> sSerialCounter;
|
||||
bool mMultiProcess;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class BasicTiledLayerBuffer;
|
||||
class ClientTiledLayerBuffer;
|
||||
class Compositor;
|
||||
|
||||
template<typename T>
|
||||
|
@ -224,9 +224,9 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
|||
compositable->SetPictureRect(op.picture());
|
||||
break;
|
||||
}
|
||||
case CompositableOperation::TOpPaintTiledLayerBuffer: {
|
||||
case CompositableOperation::TOpUseTiledLayerBuffer: {
|
||||
MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
|
||||
const OpPaintTiledLayerBuffer& op = aEdit.get_OpPaintTiledLayerBuffer();
|
||||
const OpUseTiledLayerBuffer& op = aEdit.get_OpUseTiledLayerBuffer();
|
||||
CompositableParent* compositableParent = static_cast<CompositableParent*>(op.compositableParent());
|
||||
CompositableHost* compositable =
|
||||
compositableParent->GetCompositableHost();
|
||||
|
@ -235,7 +235,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
|||
NS_ASSERTION(tileComposer, "compositable is not a tile composer");
|
||||
|
||||
const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor();
|
||||
tileComposer->PaintedTiledLayerBuffer(this, tileDesc);
|
||||
tileComposer->UseTiledLayerBuffer(this, tileDesc);
|
||||
break;
|
||||
}
|
||||
case CompositableOperation::TOpRemoveTexture: {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/RefPtr.h"
|
||||
#include "nsIMemoryReporter.h" // for nsIMemoryReporter
|
||||
#include "mozilla/Atomics.h" // for Atomic
|
||||
#include "LayersTypes.h"
|
||||
|
||||
/*
|
||||
* FIXME [bjacob] *** PURE CRAZYNESS WARNING ***
|
||||
|
@ -79,6 +80,16 @@ public:
|
|||
MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator)
|
||||
ISurfaceAllocator() {}
|
||||
|
||||
/**
|
||||
* Returns the type of backend that is used off the main thread.
|
||||
* We only don't allow changing the backend type at runtime so this value can
|
||||
* be queried once and will not change until Gecko is restarted.
|
||||
*
|
||||
* XXX - With e10s this may not be true anymore. we can have accelerated widgets
|
||||
* and non-accelerated widgets (small popups, etc.)
|
||||
*/
|
||||
virtual LayersBackend GetCompositorBackendType() const = 0;
|
||||
|
||||
/**
|
||||
* Allocate shared memory that can be accessed by only one process at a time.
|
||||
* Ownership of this memory is passed when the memory is sent in an IPDL
|
||||
|
|
|
@ -32,7 +32,7 @@ class Shmem;
|
|||
|
||||
namespace layers {
|
||||
|
||||
class BasicTiledLayerBuffer;
|
||||
class ClientTiledLayerBuffer;
|
||||
class ImageClient;
|
||||
class ImageContainer;
|
||||
class ImageBridgeParent;
|
||||
|
@ -280,7 +280,7 @@ public:
|
|||
|
||||
virtual void RemoveTexture(TextureClient* aTexture) MOZ_OVERRIDE;
|
||||
|
||||
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
|
||||
virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
|
||||
const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE
|
||||
{
|
||||
NS_RUNTIMEABORT("should not be called");
|
||||
|
|
|
@ -58,6 +58,12 @@ ImageBridgeParent::~ImageBridgeParent()
|
|||
}
|
||||
}
|
||||
|
||||
LayersBackend
|
||||
ImageBridgeParent::GetCompositorBackendType() const
|
||||
{
|
||||
return Compositor::GetBackend();
|
||||
}
|
||||
|
||||
void
|
||||
ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
|
|
|
@ -42,6 +42,8 @@ public:
|
|||
ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport);
|
||||
~ImageBridgeParent();
|
||||
|
||||
virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
static PImageBridgeParent*
|
||||
|
|
|
@ -174,6 +174,12 @@ LayerTransactionParent::Destroy()
|
|||
}
|
||||
}
|
||||
|
||||
LayersBackend
|
||||
LayerTransactionParent::GetCompositorBackendType() const
|
||||
{
|
||||
return mLayerManager->GetBackendType();
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
bool
|
||||
LayerTransactionParent::RecvUpdateNoSwap(const InfallibleTArray<Edit>& cset,
|
||||
|
|
|
@ -75,6 +75,8 @@ public:
|
|||
PLayerTransactionParent::DeallocShmem(aShmem);
|
||||
}
|
||||
|
||||
virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
|
||||
|
||||
virtual bool IsSameProcess() const MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -255,8 +255,34 @@ struct OpRaiseToTopChild { PLayer container; PLayer childLayer; };
|
|||
|
||||
struct OpSetDiagnosticTypes { DiagnosticTypes diagnostics; };
|
||||
|
||||
// Paint (buffer update)
|
||||
struct OpPaintTiledLayerBuffer {
|
||||
union TileLock {
|
||||
Shmem;
|
||||
uintptr_t;
|
||||
};
|
||||
|
||||
struct TexturedTileDescriptor {
|
||||
PTexture texture;
|
||||
TileLock sharedLock;
|
||||
};
|
||||
|
||||
struct PlaceholderTileDescriptor {
|
||||
};
|
||||
|
||||
union TileDescriptor {
|
||||
TexturedTileDescriptor;
|
||||
PlaceholderTileDescriptor;
|
||||
};
|
||||
|
||||
struct SurfaceDescriptorTiles {
|
||||
nsIntRegion validRegion;
|
||||
nsIntRegion paintedRegion;
|
||||
TileDescriptor[] tiles;
|
||||
int retainedWidth;
|
||||
int retainedHeight;
|
||||
float resolution;
|
||||
};
|
||||
|
||||
struct OpUseTiledLayerBuffer {
|
||||
PCompositable compositable;
|
||||
SurfaceDescriptorTiles tileLayerDescriptor;
|
||||
};
|
||||
|
@ -349,7 +375,7 @@ union CompositableOperation {
|
|||
OpPaintTextureRegion;
|
||||
OpPaintTextureIncremental;
|
||||
|
||||
OpPaintTiledLayerBuffer;
|
||||
OpUseTiledLayerBuffer;
|
||||
|
||||
OpRemoveTexture;
|
||||
|
||||
|
|
|
@ -56,32 +56,6 @@ struct SharedTextureDescriptor {
|
|||
bool inverted;
|
||||
};
|
||||
|
||||
struct BasicShmTileDescriptor {
|
||||
Shmem reusableSurface;
|
||||
};
|
||||
|
||||
struct BasicTileDescriptor {
|
||||
uintptr_t reusableSurface;
|
||||
};
|
||||
|
||||
struct PlaceholderTileDescriptor {
|
||||
};
|
||||
|
||||
union TileDescriptor {
|
||||
BasicTileDescriptor;
|
||||
BasicShmTileDescriptor;
|
||||
PlaceholderTileDescriptor;
|
||||
};
|
||||
|
||||
struct SurfaceDescriptorTiles {
|
||||
nsIntRegion validRegion;
|
||||
nsIntRegion paintedRegion;
|
||||
TileDescriptor[] tiles;
|
||||
int retainedWidth;
|
||||
int retainedHeight;
|
||||
float resolution;
|
||||
};
|
||||
|
||||
struct NewSurfaceDescriptorGralloc {
|
||||
PGrallocBuffer buffer;
|
||||
/**
|
||||
|
|
|
@ -49,7 +49,7 @@ class Shmem;
|
|||
|
||||
namespace layers {
|
||||
|
||||
class BasicTiledLayerBuffer;
|
||||
class ClientTiledLayerBuffer;
|
||||
|
||||
typedef nsTArray<SurfaceDescriptor> BufferArray;
|
||||
typedef std::vector<Edit> EditVector;
|
||||
|
@ -177,7 +177,6 @@ void
|
|||
CompositableForwarder::IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier)
|
||||
{
|
||||
mTextureFactoryIdentifier = aIdentifier;
|
||||
mMultiProcess = aIdentifier.mParentProcessId != XRE_GetProcessType();
|
||||
}
|
||||
|
||||
ShadowLayerForwarder::ShadowLayerForwarder()
|
||||
|
@ -327,10 +326,10 @@ ShadowLayerForwarder::CheckSurfaceDescriptor(const SurfaceDescriptor* aDescripto
|
|||
#endif
|
||||
|
||||
void
|
||||
ShadowLayerForwarder::PaintedTiledLayerBuffer(CompositableClient* aCompositable,
|
||||
ShadowLayerForwarder::UseTiledLayerBuffer(CompositableClient* aCompositable,
|
||||
const SurfaceDescriptorTiles& aTileLayerDescriptor)
|
||||
{
|
||||
mTxn->AddNoSwapPaint(OpPaintTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(),
|
||||
mTxn->AddNoSwapPaint(OpUseTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(),
|
||||
aTileLayerDescriptor));
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class gfxASurface;
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class BasicTiledLayerBuffer;
|
||||
class ClientTiledLayerBuffer;
|
||||
class CanvasClient;
|
||||
class CanvasLayerComposite;
|
||||
class CanvasSurface;
|
||||
|
@ -255,13 +255,9 @@ public:
|
|||
ShadowableLayer* aMaskLayer);
|
||||
|
||||
/**
|
||||
* Notify the compositor that a tiled layer buffer has changed
|
||||
* that needs to be synced to the shadow retained copy. The tiled
|
||||
* layer buffer will operate directly on the shadow retained buffer
|
||||
* and is free to choose it's own internal representation (double buffering,
|
||||
* copy on write, tiling).
|
||||
* See CompositableForwarder::UseTiledLayerBuffer
|
||||
*/
|
||||
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
|
||||
virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
|
||||
const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE;
|
||||
|
||||
/**
|
||||
|
|
|
@ -106,6 +106,7 @@ EXPORTS.mozilla.layers += [
|
|||
'client/ContentClient.h',
|
||||
'client/ImageClient.h',
|
||||
'client/TextureClient.h',
|
||||
'client/TextureClientPool.h',
|
||||
'client/TiledContentClient.h',
|
||||
'composite/APZCTreeManager.h',
|
||||
'composite/AsyncCompositionManager.h',
|
||||
|
@ -234,6 +235,7 @@ UNIFIED_SOURCES += [
|
|||
'client/ContentClient.cpp',
|
||||
'client/ImageClient.cpp',
|
||||
'client/TextureClient.cpp',
|
||||
'client/TextureClientPool.cpp',
|
||||
'client/TiledContentClient.cpp',
|
||||
'composite/APZCTreeManager.cpp',
|
||||
'composite/AsyncCompositionManager.cpp',
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#if MOZ_ANDROID_OMTC
|
||||
#include "TexturePoolOGL.h"
|
||||
#endif
|
||||
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
|
||||
|
@ -136,6 +137,72 @@ DrawQuads(GLContext *aGLContext,
|
|||
aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
CompositorOGLGonkBackendSpecificData::CompositorOGLGonkBackendSpecificData(CompositorOGL* aCompositor)
|
||||
: mCompositor(aCompositor)
|
||||
{
|
||||
}
|
||||
|
||||
CompositorOGLGonkBackendSpecificData::~CompositorOGLGonkBackendSpecificData()
|
||||
{
|
||||
// Delete all textures by calling EndFrame twice
|
||||
gl()->MakeCurrent();
|
||||
EndFrame();
|
||||
EndFrame();
|
||||
}
|
||||
|
||||
GLContext*
|
||||
CompositorOGLGonkBackendSpecificData::gl() const
|
||||
{
|
||||
return mCompositor->gl();
|
||||
}
|
||||
|
||||
GLuint
|
||||
CompositorOGLGonkBackendSpecificData::GetTexture()
|
||||
{
|
||||
GLuint texture = 0;
|
||||
|
||||
if (!mUnusedTextures.IsEmpty()) {
|
||||
// Try to reuse one from the unused pile first
|
||||
texture = mUnusedTextures[0];
|
||||
mUnusedTextures.RemoveElementAt(0);
|
||||
} else if (gl()->MakeCurrent()) {
|
||||
// There isn't one to reuse, create one.
|
||||
gl()->fGenTextures(1, &texture);
|
||||
}
|
||||
|
||||
if (texture) {
|
||||
mCreatedTextures.AppendElement(texture);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGLGonkBackendSpecificData::EndFrame()
|
||||
{
|
||||
gl()->MakeCurrent();
|
||||
|
||||
// Some platforms have issues unlocking Gralloc buffers even when they're
|
||||
// rebound.
|
||||
if (gfxPrefs::OverzealousGrallocUnlocking()) {
|
||||
mUnusedTextures.AppendElements(mCreatedTextures);
|
||||
mCreatedTextures.Clear();
|
||||
}
|
||||
|
||||
// Delete unused textures
|
||||
for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
|
||||
GLuint texture = mUnusedTextures[i];
|
||||
gl()->fDeleteTextures(1, &texture);
|
||||
}
|
||||
mUnusedTextures.Clear();
|
||||
|
||||
// Move all created textures into the unused pile
|
||||
mUnusedTextures.AppendElements(mCreatedTextures);
|
||||
mCreatedTextures.Clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
|
||||
int aSurfaceHeight, bool aUseExternalSurfaceSize)
|
||||
: mWidget(aWidget)
|
||||
|
@ -1299,6 +1366,12 @@ CompositorOGL::EndFrame()
|
|||
|
||||
mCurrentRenderTarget = nullptr;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (mCompositorBackendSpecificData) {
|
||||
static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositorBackendSpecificData.get())->EndFrame();
|
||||
}
|
||||
#endif
|
||||
|
||||
mGLContext->SwapBuffers();
|
||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
@ -1407,6 +1480,17 @@ CompositorOGL::Resume()
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
CompositorBackendSpecificData*
|
||||
CompositorOGL::GetCompositorBackendSpecificData()
|
||||
{
|
||||
if (!mCompositorBackendSpecificData) {
|
||||
mCompositorBackendSpecificData = new CompositorOGLGonkBackendSpecificData(this);
|
||||
}
|
||||
return mCompositorBackendSpecificData;
|
||||
}
|
||||
#endif
|
||||
|
||||
TemporaryRef<DataTextureSource>
|
||||
CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
|
||||
{
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
#include "nsXULAppAPI.h" // for XRE_GetProcessType
|
||||
#include "nscore.h" // for NS_IMETHOD
|
||||
#include "VBOArena.h" // for gl::VBOArena
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include <ui/GraphicBuffer.h>
|
||||
#endif
|
||||
|
||||
class gfx3DMatrix;
|
||||
class nsIWidget;
|
||||
|
@ -159,6 +162,10 @@ public:
|
|||
|
||||
virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
virtual CompositorBackendSpecificData* GetCompositorBackendSpecificData() MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
GLContext* gl() const { return mGLContext; }
|
||||
gfx::SurfaceFormat GetFBOFormat() const {
|
||||
return gfx::SurfaceFormat::R8G8B8A8;
|
||||
|
@ -313,8 +320,32 @@ private:
|
|||
* FlipY for the y-flipping calculation.
|
||||
*/
|
||||
GLint mHeight;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
RefPtr<CompositorBackendSpecificData> mCompositorBackendSpecificData;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
class CompositorOGLGonkBackendSpecificData : public CompositorBackendSpecificData
|
||||
{
|
||||
public:
|
||||
CompositorOGLGonkBackendSpecificData(CompositorOGL* aCompositor);
|
||||
virtual ~CompositorOGLGonkBackendSpecificData();
|
||||
|
||||
GLuint GetTexture();
|
||||
void EndFrame();
|
||||
|
||||
private:
|
||||
gl::GLContext* gl() const;
|
||||
|
||||
RefPtr<CompositorOGL> mCompositor;
|
||||
|
||||
nsTArray<GLuint> mCreatedTextures;
|
||||
nsTArray<GLuint> mUnusedTextures;
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
#include "mozilla/layers/CompositableClient.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
|
||||
|
@ -95,28 +94,16 @@ GrallocTextureClientOGL::GrallocTextureClientOGL(GrallocBufferActor* aActor,
|
|||
gfx::IntSize aSize,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureClient(nullptr, gfx::SurfaceFormat::UNKNOWN, aFlags)
|
||||
, mAllocator(nullptr)
|
||||
, mMappedBuffer(nullptr)
|
||||
{
|
||||
InitWith(aActor, aSize);
|
||||
MOZ_COUNT_CTOR(GrallocTextureClientOGL);
|
||||
}
|
||||
|
||||
GrallocTextureClientOGL::GrallocTextureClientOGL(CompositableClient* aCompositable,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureClient(aCompositable, aFormat, aFlags)
|
||||
, mAllocator(nullptr)
|
||||
, mMappedBuffer(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GrallocTextureClientOGL);
|
||||
}
|
||||
|
||||
GrallocTextureClientOGL::GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureClient(nullptr, aFormat, aFlags)
|
||||
, mAllocator(aAllocator)
|
||||
: BufferTextureClient(aAllocator, aFormat, aFlags)
|
||||
, mMappedBuffer(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GrallocTextureClientOGL);
|
||||
|
@ -457,15 +444,6 @@ GrallocTextureClientOGL::GetBufferSize() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
ISurfaceAllocator*
|
||||
GrallocTextureClientOGL::GetAllocator()
|
||||
{
|
||||
MOZ_ASSERT(mCompositable || mAllocator);
|
||||
return mCompositable ?
|
||||
mCompositable->GetForwarder() :
|
||||
mAllocator;
|
||||
}
|
||||
|
||||
} // namesapace layers
|
||||
} // namesapace mozilla
|
||||
|
||||
|
|
|
@ -37,9 +37,6 @@ public:
|
|||
GrallocTextureClientOGL(GrallocBufferActor* aActor,
|
||||
gfx::IntSize aSize,
|
||||
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
|
||||
GrallocTextureClientOGL(CompositableClient* aCompositable,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
|
||||
GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
|
||||
|
@ -52,6 +49,8 @@ public:
|
|||
|
||||
virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
|
||||
|
||||
virtual bool IsAllocated() const MOZ_OVERRIDE;
|
||||
|
||||
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
|
||||
|
@ -107,8 +106,6 @@ public:
|
|||
void SetGraphicBufferLocked(GraphicBufferLocked* aBufferLocked);
|
||||
|
||||
protected:
|
||||
ISurfaceAllocator* GetAllocator();
|
||||
|
||||
/**
|
||||
* Unfortunately, until bug 879681 is fixed we need to use a GrallocBufferActor.
|
||||
*/
|
||||
|
@ -118,8 +115,6 @@ protected:
|
|||
|
||||
android::sp<android::GraphicBuffer> mGraphicBuffer;
|
||||
|
||||
RefPtr<ISurfaceAllocator> mAllocator;
|
||||
|
||||
/**
|
||||
* Points to a mapped gralloc buffer between calls to lock and unlock.
|
||||
* Should be null outside of the lock-unlock pair.
|
||||
|
|
|
@ -104,7 +104,8 @@ GrallocTextureSourceOGL::~GrallocTextureSourceOGL()
|
|||
mCompositor = nullptr;
|
||||
}
|
||||
|
||||
void GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit)
|
||||
void
|
||||
GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit)
|
||||
{
|
||||
/*
|
||||
* The job of this function is to ensure that the texture is tied to the
|
||||
|
@ -125,17 +126,46 @@ void GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit)
|
|||
|
||||
gl()->fActiveTexture(aTextureUnit);
|
||||
gl()->fBindTexture(textureTarget, tex);
|
||||
|
||||
if (mCompositableBackendData) {
|
||||
// There are two paths for locking/unlocking - if mCompositableBackendData is
|
||||
// set, we use the texture on there, otherwise we use
|
||||
// CompositorBackendSpecificData from the compositor and bind the EGLImage
|
||||
// only in Lock().
|
||||
if (!mEGLImage) {
|
||||
mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
|
||||
}
|
||||
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
|
||||
}
|
||||
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void GrallocTextureSourceOGL::Lock()
|
||||
{
|
||||
if (mCompositableBackendData) return;
|
||||
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
CompositorOGLGonkBackendSpecificData* backendData =
|
||||
static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositor->GetCompositorBackendSpecificData());
|
||||
mTexture = backendData->GetTexture();
|
||||
|
||||
GLuint textureTarget = GetTextureTarget();
|
||||
|
||||
gl()->MakeCurrent();
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
gl()->fBindTexture(textureTarget, mTexture);
|
||||
if (!mEGLImage) {
|
||||
mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
|
||||
}
|
||||
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureSourceOGL::IsValid() const
|
||||
{
|
||||
return !!gl() && !!mGraphicBuffer.get();
|
||||
return !!gl() && !!mGraphicBuffer.get() && (!!mCompositor || !!mCompositableBackendData);
|
||||
}
|
||||
|
||||
gl::GLContext*
|
||||
|
@ -178,7 +208,7 @@ GrallocTextureSourceOGL::GetFormat() const {
|
|||
void
|
||||
GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
|
||||
{
|
||||
if (!aBackendData || !mGraphicBuffer.get()) {
|
||||
if (!aBackendData) {
|
||||
mCompositableBackendData = nullptr;
|
||||
DeallocateDeviceData();
|
||||
return;
|
||||
|
@ -285,7 +315,11 @@ GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor)
|
|||
bool
|
||||
GrallocTextureHostOGL::Lock()
|
||||
{
|
||||
return IsValid();
|
||||
if (IsValid()) {
|
||||
mTextureSource->Lock();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -384,10 +418,14 @@ GrallocTextureSourceOGL::GetAsSurface() {
|
|||
GLuint
|
||||
GrallocTextureSourceOGL::GetGLTexture()
|
||||
{
|
||||
if (mCompositableBackendData) {
|
||||
mCompositableBackendData->SetCompositor(mCompositor);
|
||||
return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture();
|
||||
}
|
||||
|
||||
return mTexture;
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
|
||||
{
|
||||
|
|
|
@ -62,10 +62,13 @@ public:
|
|||
|
||||
GLuint GetGLTexture();
|
||||
|
||||
void Lock();
|
||||
|
||||
protected:
|
||||
CompositorOGL* mCompositor;
|
||||
android::sp<android::GraphicBuffer> mGraphicBuffer;
|
||||
EGLImage mEGLImage;
|
||||
GLuint mTexture;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
bool mNeedsReset;
|
||||
};
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
|
||||
virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
|
||||
|
||||
protected:
|
||||
RefPtr<MacIOSurface> mSurface;
|
||||
bool mIsLocked;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче