This commit is contained in:
Phil Ringnalda 2014-03-08 17:39:51 -08:00
Родитель 8a9bf40748 f745bb2ae1
Коммит 3b52fd5e83
176 изменённых файлов: 11468 добавлений и 9351 удалений

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

@ -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,23 +231,24 @@ 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));
// if we found something, return its native accessible.
if (deepestFoundChild) {
mozAccessible *nativeChild = GetNativeFromGeckoAccessible(deepestFoundChild);
Accessible* child = mGeckoAccessible->ChildAtPoint(geckoPoint.x, geckoPoint.y,
Accessible::eDeepestChild);
if (child) {
mozAccessible* nativeChild = GetNativeFromGeckoAccessible(child);
if (nativeChild)
return GetClosestInterestingAccessible(nativeChild);
}
// if we didn't find anything, return ourself (or the first unignored ancestor).
return GetClosestInterestingAccessible(self);
}
@ -379,20 +371,17 @@ GetClosestInterestingAccessible(id anObject)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
int32_t x, y, width, height;
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;
if (!mGeckoAccessible)
return nil;
int32_t x = 0, y = 0, width = 0, height = 0;
mGeckoAccessible->GetBounds(&x, &y, &width, &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];
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
@ -402,9 +391,15 @@ GetClosestInterestingAccessible(id anObject)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
int32_t x, y, width, height;
mGeckoAccessible->GetBounds (&x, &y, &width, &height);
return [NSValue valueWithSize:NSMakeSize (width, height)];
if (!mGeckoAccessible)
return nil;
int32_t x = 0, y = 0, width = 0, height = 0;
mGeckoAccessible->GetBounds (&x, &y, &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()
{
mManager->RemovedFromDocumentInternal(mElement, mDoc);
// 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:
bytesPerPixel = 1 * channels;
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())
realType = LOCAL_GL_HALF_FLOAT;
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) {

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

@ -95,13 +95,13 @@ WebGLRenderbuffer::MemoryUsage() const {
int64_t primarySize = 0;
switch (primaryFormat) {
case LOCAL_GL_STENCIL_INDEX8:
primarySize = 1 * pixels;
primarySize = 1*pixels;
break;
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGB5_A1:
case LOCAL_GL_RGB565:
case LOCAL_GL_DEPTH_COMPONENT16:
primarySize = 2 * pixels;
primarySize = 2*pixels;
break;
case LOCAL_GL_RGB8:
case LOCAL_GL_DEPTH_COMPONENT24:
@ -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,8 +56,8 @@ 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(),
"write more data > EBML_BUFFER_SIZE");
MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(),
"write more data > EBML_BUFFER_SIZE");
mClusterBuffs.AppendElement();
mClusterBuffs.LastElement().SetLength(ebml.offset);
memcpy(mClusterBuffs.LastElement().Elements(), ebml.buf, ebml.offset);
@ -117,8 +117,8 @@ 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(),
"write more data > EBML_BUFFER_SIZE");
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,8 +933,8 @@ nsFocusManager::WindowHidden(nsIDOMWindow* aWindow)
nsPresContext* focusedPresContext =
presShell ? presShell->GetPresContext() : nullptr;
nsIMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
GetFocusMoveActionCause(0));
IMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
GetFocusMoveActionCause(0));
if (presShell) {
SetCaretVisible(presShell, false, nullptr);
}
@ -1529,8 +1529,8 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
nsPresContext* focusedPresContext =
mActiveWindow ? presShell->GetPresContext() : nullptr;
nsIMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
GetFocusMoveActionCause(0));
IMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
GetFocusMoveActionCause(0));
// now adjust the actual focus, by clearing the fields in the focus manager
// and in the window.
@ -1746,12 +1746,12 @@ 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,
GetFocusMoveActionCause(aFlags));
IMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr,
GetFocusMoveActionCause(aFlags));
}
if (doc)
SendFocusOrBlurEvent(NS_FOCUS_CONTENT, presShell, doc,
@ -1796,8 +1796,8 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
}
}
nsIMEStateManager::OnChangeFocus(presContext, aContent,
GetFocusMoveActionCause(aFlags));
IMEStateManager::OnChangeFocus(presContext, aContent,
GetFocusMoveActionCause(aFlags));
// as long as this focus wasn't because a window was raised, update the
// commands
@ -1810,8 +1810,8 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
aContent, aFlags & FOCUSMETHOD_MASK,
aWindowRaised, isRefocus);
} else {
nsIMEStateManager::OnChangeFocus(presContext, nullptr,
GetFocusMoveActionCause(aFlags));
IMEStateManager::OnChangeFocus(presContext, nullptr,
GetFocusMoveActionCause(aFlags));
if (!aWindowRaised) {
aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
}
@ -1834,8 +1834,8 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
}
nsPresContext* presContext = presShell->GetPresContext();
nsIMEStateManager::OnChangeFocus(presContext, nullptr,
GetFocusMoveActionCause(aFlags));
IMEStateManager::OnChangeFocus(presContext, nullptr,
GetFocusMoveActionCause(aFlags));
if (!aWindowRaised)
aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));

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

@ -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,23 +231,23 @@ TextComposition::CompositionEventDispatcher::Run()
handler.OnQuerySelectedText(&selectedText);
NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
compStart.data = selectedText.mReply.mString;
nsIMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
&compStart, &status, nullptr);
IMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
&compStart, &status, nullptr);
break;
}
case NS_COMPOSITION_UPDATE:
case NS_COMPOSITION_END: {
WidgetCompositionEvent compEvent(true, mEventMessage, mWidget);
compEvent.data = mData;
nsIMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
&compEvent, &status, nullptr);
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,
&textEvent, &status, nullptr);
IMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
&textEvent, &status, nullptr);
break;
}
default:

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

@ -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,9 +1096,9 @@ 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),
getter_AddRefs(mRootContent));
nsresult rv =
IMEStateManager::GetFocusSelectionAndRoot(getter_AddRefs(mSelection),
getter_AddRefs(mRootContent));
if (rv != NS_ERROR_NOT_AVAILABLE) {
NS_ENSURE_SUCCESS(rv, rv);
} else {

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

@ -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,11 +195,11 @@ 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,
const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
virtual void UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
/**
* If some part of the buffer is being rendered at a lower precision, this
@ -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();
}
RefPtr<BufferTextureClient> result = new ShmemTextureClient(this, aFormat, aTextureFlags);
return result.forget();
return TextureClient::CreateBufferTextureClient(GetForwarder(), aFormat,
aTextureFlags | mTextureFlags);
}
#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
}
}
TileDescriptor
BasicTiledLayerTile::GetTileDescriptor()
gfxMemorySharedReadLock::gfxMemorySharedReadLock()
: mReadCount(1)
{
gfxReusableSurfaceWrapper* surface = GetSurface();
switch (surface->GetType()) {
case gfxReusableSurfaceWrapper::TYPE_IMAGE :
return BasicTileDescriptor(uintptr_t(surface));
MOZ_COUNT_CTOR(gfxMemorySharedReadLock);
}
case gfxReusableSurfaceWrapper::TYPE_SHARED_IMAGE :
return BasicShmTileDescriptor(static_cast<gfxReusableSharedImageSurfaceWrapper*>(surface)->GetShmem());
gfxMemorySharedReadLock::~gfxMemorySharedReadLock()
{
MOZ_COUNT_DTOR(gfxMemorySharedReadLock);
}
default :
NS_NOTREACHED("Unhandled gfxReusableSurfaceWrapper type");
return PlaceholderTileDescriptor();
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;
}
}
}
/* static */ BasicTiledLayerTile
BasicTiledLayerTile::OpenDescriptor(ISurfaceAllocator *aAllocator, const TileDescriptor& aDesc)
gfxShmSharedReadLock::~gfxShmSharedReadLock()
{
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));
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;
}
case TileDescriptor::TBasicTileDescriptor : {
nsRefPtr<gfxReusableSurfaceWrapper> surface =
reinterpret_cast<gfxReusableSurfaceWrapper*>(
aDesc.get_BasicTileDescriptor().reusableSurface());
surface->ReadUnlock();
return BasicTiledLayerTile(
new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
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);
}
default :
NS_NOTREACHED("Unknown tile descriptor type!");
return nullptr;
ValidateBackBufferFromFront(aDirtyRegion, aCanRerasterizeValidRegion);
return mBackBuffer;
}
TileDescriptor
TileClient::GetTileDescriptor()
{
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();
}
}
void
ClientTiledLayerBuffer::ReadLock() {
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
mRetainedTiles[i].ReadLock();
}
}
void
ClientTiledLayerBuffer::Release()
{
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
mRetainedTiles[i].Release();
}
}
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,27 +630,18 @@ 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),
ceilf(bounds.height * mResolution)),
gfx::ImageFormatToSurfaceFormat(format));
mSinglePaintDrawTarget =
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
gfx::IntSize(ceilf(bounds.width * mResolution),
ceilf(bounds.height * mResolution)),
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);
}
ctxt = new gfxContext(mSinglePaintDrawTarget);
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
nsIntRegionRectIterator it(aDirtyRegion);
for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) {
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* 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,
ClientLayerManager* aManager,
SharedFrameMetricsHelper* aHelper);
BasicTiledLayerBuffer()
ClientTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
CompositableClient* aCompositableClient,
ClientLayerManager* aManager,
SharedFrameMetricsHelper* aHelper);
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,48 +389,38 @@ public:
SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
static BasicTiledLayerBuffer OpenDescriptor(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aDescriptor,
SharedFrameMetricsHelper* aHelper);
protected:
BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile,
const nsIntPoint& aTileRect,
const nsIntRegion& dirtyRect);
TileClient ValidateTile(TileClient aTile,
const nsIntPoint& aTileRect,
const nsIntRegion& dirtyRect);
// If this returns true, we perform the paint operation into a single large
// 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)
{
#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
TiledLayerBufferComposite::TiledLayerBufferComposite()
: mFrameResolution(1.0)
, mHasDoubleBufferedTiles(false)
, mUninitialized(true)
{}
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);
TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aDescriptor,
const nsIntRegion& aOldPaintedRegion)
{
mUninitialized = false;
mHasDoubleBufferedTiles = false;
mValidRegion = aDescriptor.validRegion();
mPaintedRegion = aDescriptor.paintedRegion();
mRetainedWidth = aDescriptor.retainedWidth();
mRetainedHeight = aDescriptor.retainedHeight();
mResolution = aDescriptor.resolution();
// 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,72 +208,43 @@ TiledContentHost::Attach(Layer* aLayer,
}
void
TiledContentHost::PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aTiledDescriptor)
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 {
mMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor, nullptr);
mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetPaintedRegion());
mMainMemoryTiledBuffer.ClearPaintedRegion();
mPendingUpload = true;
if (mPendingUpload) {
mTiledBuffer.ReadUnlock();
} else {
mPendingUpload = true;
if (mTiledBuffer.HasDoubleBufferedTiles()) {
mOldTiledBuffer = mTiledBuffer;
mOldTiledBuffer.ReleaseTextureHosts();
}
}
mTiledBuffer = TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
mTiledBuffer.GetPaintedRegion());
}
}
void
TiledContentHost::ProcessLowPrecisionUploadQueue()
{
if (!mPendingLowPrecisionUpload) {
return;
}
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
TiledContentHost::Composite(EffectChain& aEffectChain,
float aOpacity,
@ -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;
}
aEffectChain.mPrimaryEffect = effect;
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) {

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

@ -45,134 +45,140 @@ class Layer;
class ThebesBufferData;
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;
}
return *mDeprecatedTextureHost == *o.mDeprecatedTextureHost;
bool operator== (const TileHost& o) const {
return mTextureHost == o.mTextureHost;
}
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,
const nsIntPoint& aTileRect,
const nsIntRegion& dirtyRect);
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,
const SurfaceDescriptorTiles& aTiledDescriptor);
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,8 +91,12 @@ public:
*/
virtual void DestroyThebesBuffer(CompositableClient* aCompositable) = 0;
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
/**
* Tell the CompositableHost on the compositor side what TiledLayerBuffer to
* use for the next composition.
*/
virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
/**
* Create a TextureChild/Parent pair as as well as the TextureHost on the parent side.
@ -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,8 +280,8 @@ public:
virtual void RemoveTexture(TextureClient* aTexture) MOZ_OVERRIDE;
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE
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,11 +326,11 @@ ShadowLayerForwarder::CheckSurfaceDescriptor(const SurfaceDescriptor* aDescripto
#endif
void
ShadowLayerForwarder::PaintedTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTileLayerDescriptor)
ShadowLayerForwarder::UseTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTileLayerDescriptor)
{
mTxn->AddNoSwapPaint(OpPaintTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(),
aTileLayerDescriptor));
mTxn->AddNoSwapPaint(OpUseTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(),
aTileLayerDescriptor));
}
void

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

@ -28,7 +28,7 @@ class gfxASurface;
namespace mozilla {
namespace layers {
class BasicTiledLayerBuffer;
class ClientTiledLayerBuffer;
class CanvasClient;
class CanvasLayerComposite;
class CanvasSurface;
@ -255,14 +255,10 @@ 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,
const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE;
virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE;
/**
* Notify the compositor that a compositable will be updated asynchronously

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

@ -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);
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
}
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,8 +418,12 @@ GrallocTextureSourceOGL::GetAsSurface() {
GLuint
GrallocTextureSourceOGL::GetGLTexture()
{
mCompositableBackendData->SetCompositor(mCompositor);
return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture();
if (mCompositableBackendData) {
mCompositableBackendData->SetCompositor(mCompositor);
return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture();
}
return mTexture;
}
void

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

@ -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;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше