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;
using namespace mozilla::a11y; 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 // returns the passed in object if it is not ignored. if it's ignored, will return
// the first unignored ancestor. // the first unignored ancestor.
static inline id static inline id
@ -240,19 +231,20 @@ GetClosestInterestingAccessible(id anObject)
if (!mGeckoAccessible) if (!mGeckoAccessible)
return nil; return nil;
// Convert from cocoa's coordinate system to gecko's. According to the docs // Convert the given screen-global point in the cocoa coordinate system (with
// the point we're given is guaranteed to be bottom-left screen coordinates. // origin in the bottom-left corner of the screen) into point in the Gecko
nsPoint geckoPoint; // coordinate system (with origin in a top-left screen point).
ConvertCocoaToGeckoPoint (point, geckoPoint); 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; Accessible* child = mGeckoAccessible->ChildAtPoint(geckoPoint.x, geckoPoint.y,
mGeckoAccessible->GetDeepestChildAtPoint((int32_t)geckoPoint.x, Accessible::eDeepestChild);
(int32_t)geckoPoint.y,
getter_AddRefs(deepestFoundChild));
// if we found something, return its native accessible. if (child) {
if (deepestFoundChild) { mozAccessible* nativeChild = GetNativeFromGeckoAccessible(child);
mozAccessible *nativeChild = GetNativeFromGeckoAccessible(deepestFoundChild);
if (nativeChild) if (nativeChild)
return GetClosestInterestingAccessible(nativeChild); return GetClosestInterestingAccessible(nativeChild);
} }
@ -379,19 +371,16 @@ GetClosestInterestingAccessible(id anObject)
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
int32_t x, y, width, height; if (!mGeckoAccessible)
return nil;
int32_t x = 0, y = 0, width = 0, height = 0;
mGeckoAccessible->GetBounds(&x, &y, &width, &height); mGeckoAccessible->GetBounds(&x, &y, &width, &height);
NSPoint p = NSMakePoint (x, y);
// The coords we get from Gecko are top-left screen coordinates. NSScreen* mainView = [[NSScreen screens] objectAtIndex:0];
// Cocoa wants us to return bottom-left screen coordinates. CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mainView);
// This involves two steps: NSPoint p = NSMakePoint(static_cast<CGFloat>(x) / scaleFactor,
// 1. Put the rect in the bottom-left coord space [mainView frame].size.height - static_cast<CGFloat>(y + height) / scaleFactor);
// 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;
return [NSValue valueWithPoint:p]; return [NSValue valueWithPoint:p];
@ -402,9 +391,15 @@ GetClosestInterestingAccessible(id anObject)
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
int32_t x, y, width, height; if (!mGeckoAccessible)
return nil;
int32_t x = 0, y = 0, width = 0, height = 0;
mGeckoAccessible->GetBounds (&x, &y, &width, &height); mGeckoAccessible->GetBounds (&x, &y, &width, &height);
return [NSValue valueWithSize:NSMakeSize (width, height)]; CGFloat scaleFactor =
nsCocoaUtils::GetBackingScaleFactor([[NSScreen screens] objectAtIndex:0]);
return [NSValue valueWithSize:NSMakeSize(static_cast<CGFloat>(width) / scaleFactor,
static_cast<CGFloat>(height) / scaleFactor)];
NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 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.use-buffer-pixmap", true);
pref("mozilla.widget.disable-native-theme", true); pref("mozilla.widget.disable-native-theme", true);
pref("layout.reflow.synthMouseMove", false); 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 Cross Process Mutex is not supported on Mac OS X so progressive
paint can not be enabled for B2G on Mac OS X desktop paint can not be enabled for B2G on Mac OS X desktop

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

@ -1226,7 +1226,7 @@ var diagnosticList = [
check: function(frames, symbols, meta) { check: function(frames, symbols, meta) {
return stepContains('PaintGradient', frames, symbols) 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 skip-if(Android) load 851353-1.html
load 863950.html load 863950.html
load 864448.html load 864448.html
load 930250.html
load 942979.html load 942979.html
load 978646.html load 978646.html

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

@ -1264,7 +1264,17 @@ public:
NS_IMETHOD Run() NS_IMETHOD Run()
{ {
// It may be the case that the element was removed from the
// DOM, causing this runnable to be created, then inserted back
// into the document before the this runnable had a chance to
// tear down the binding. Only tear down the binding if the element
// is still no longer in the DOM. nsXBLService::LoadBinding tears
// down the old binding if the element is inserted back into the
// DOM and loads a different binding.
if (!mElement->IsInDoc()) {
mManager->RemovedFromDocumentInternal(mElement, mDoc); mManager->RemovedFromDocumentInternal(mElement, mDoc);
}
return NS_OK; return NS_OK;
} }

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

@ -41,6 +41,7 @@
#include "mozilla/dom/TextDecoder.h" #include "mozilla/dom/TextDecoder.h"
#include "mozilla/dom/TouchEvent.h" #include "mozilla/dom/TouchEvent.h"
#include "mozilla/dom/ShadowRoot.h" #include "mozilla/dom/ShadowRoot.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/InternalMutationEvent.h" #include "mozilla/InternalMutationEvent.h"
#include "mozilla/Likely.h" #include "mozilla/Likely.h"
#include "mozilla/MouseEvents.h" #include "mozilla/MouseEvents.h"
@ -122,7 +123,6 @@
#include "nsILineBreaker.h" #include "nsILineBreaker.h"
#include "nsILoadContext.h" #include "nsILoadContext.h"
#include "nsILoadGroup.h" #include "nsILoadGroup.h"
#include "nsIMEStateManager.h"
#include "nsIMIMEService.h" #include "nsIMIMEService.h"
#include "nsINode.h" #include "nsINode.h"
#include "nsINodeInfo.h" #include "nsINodeInfo.h"
@ -4324,7 +4324,7 @@ nsContentUtils::DestroyAnonymousContent(nsCOMPtr<Element>* aElement)
void void
nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling) nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling)
{ {
nsIMEStateManager::OnInstalledMenuKeyboardListener(aInstalling); IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling);
} }
static bool SchemeIs(nsIURI* aURI, const char* aScheme) static bool SchemeIs(nsIURI* aURI, const char* aScheme)

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

@ -116,7 +116,6 @@ WebGLContext::WebGLContext()
mOptionsFrozen = false; mOptionsFrozen = false;
mActiveTexture = 0; mActiveTexture = 0;
mWebGLError = LOCAL_GL_NO_ERROR;
mPixelStoreFlipY = false; mPixelStoreFlipY = false;
mPixelStorePremultiplyAlpha = false; mPixelStorePremultiplyAlpha = false;
mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL; mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
@ -1289,7 +1288,7 @@ WebGLContext::RobustnessTimerCallback(nsITimer* timer)
true); true);
// Set all flags back to the state they were in before the context was // Set all flags back to the state they were in before the context was
// lost. // lost.
mContextLostErrorSet = false; mEmitContextLostErrorOnce = true;
mAllowRestore = true; mAllowRestore = true;
} }

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

@ -244,10 +244,6 @@ public:
// Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'. // Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
void ClearScreen(); 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; } bool MinCapabilityMode() const { return mMinCapability; }
void RobustnessTimerCallback(nsITimer* timer); void RobustnessTimerCallback(nsITimer* timer);
@ -852,7 +848,12 @@ protected:
void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array); void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
GLuint mActiveTexture; GLuint mActiveTexture;
// glGetError sources:
bool mEmitContextLostErrorOnce;
GLenum mWebGLError; GLenum mWebGLError;
GLenum mUnderlyingGLError;
GLenum GetAndFlushUnderlyingGLErrors();
// whether shader validation is supported // whether shader validation is supported
bool mShaderValidation; bool mShaderValidation;
@ -895,6 +896,7 @@ protected:
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// WebGL extensions (implemented in WebGLContextExtensions.cpp) // WebGL extensions (implemented in WebGLContextExtensions.cpp)
enum WebGLExtensionID { enum WebGLExtensionID {
EXT_color_buffer_half_float,
EXT_frag_depth, EXT_frag_depth,
EXT_sRGB, EXT_sRGB,
EXT_texture_filter_anisotropic, EXT_texture_filter_anisotropic,
@ -905,6 +907,7 @@ protected:
OES_texture_half_float, OES_texture_half_float,
OES_texture_half_float_linear, OES_texture_half_float_linear,
OES_vertex_array_object, OES_vertex_array_object,
WEBGL_color_buffer_float,
WEBGL_compressed_texture_atc, WEBGL_compressed_texture_atc,
WEBGL_compressed_texture_pvrtc, WEBGL_compressed_texture_pvrtc,
WEBGL_compressed_texture_s3tc, WEBGL_compressed_texture_s3tc,
@ -933,7 +936,6 @@ protected:
nsTArray<GLenum> mCompressedTextureFormats; nsTArray<GLenum> mCompressedTextureFormats;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// WebGL 2 specifics (implemented in WebGL2Context.cpp) // WebGL 2 specifics (implemented in WebGL2Context.cpp)

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

@ -485,10 +485,9 @@ WebGLContext::CheckedBufferData(GLenum target,
bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength(); bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength();
if (sizeChanges) { if (sizeChanges) {
UpdateWebGLErrorAndClearGLError(); GetAndFlushUnderlyingGLErrors();
gl->fBufferData(target, size, data, usage); gl->fBufferData(target, size, data, usage);
GLenum error = LOCAL_GL_NO_ERROR; GLenum error = GetAndFlushUnderlyingGLErrors();
UpdateWebGLErrorAndClearGLError(&error);
return error; return error;
} else { } else {
gl->fBufferData(target, size, data, usage); gl->fBufferData(target, size, data, usage);

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

@ -17,6 +17,7 @@ using namespace mozilla::gl;
// must match WebGLContext::WebGLExtensionID // must match WebGLContext::WebGLExtensionID
static const char *sExtensionNames[] = { static const char *sExtensionNames[] = {
"EXT_color_buffer_half_float",
"EXT_frag_depth", "EXT_frag_depth",
"EXT_sRGB", "EXT_sRGB",
"EXT_texture_filter_anisotropic", "EXT_texture_filter_anisotropic",
@ -27,6 +28,7 @@ static const char *sExtensionNames[] = {
"OES_texture_half_float", "OES_texture_half_float",
"OES_texture_half_float_linear", "OES_texture_half_float_linear",
"OES_vertex_array_object", "OES_vertex_array_object",
"WEBGL_color_buffer_float",
"WEBGL_compressed_texture_atc", "WEBGL_compressed_texture_atc",
"WEBGL_compressed_texture_pvrtc", "WEBGL_compressed_texture_pvrtc",
"WEBGL_compressed_texture_s3tc", "WEBGL_compressed_texture_s3tc",
@ -108,6 +110,10 @@ bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
gl->IsSupported(GLFeature::texture_half_float); gl->IsSupported(GLFeature::texture_half_float);
case OES_texture_half_float_linear: case OES_texture_half_float_linear:
return gl->IsSupported(GLFeature::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: case OES_vertex_array_object:
return WebGLExtensionVertexArray::IsSupported(this); return WebGLExtensionVertexArray::IsSupported(this);
case EXT_texture_filter_anisotropic: case EXT_texture_filter_anisotropic:
@ -286,6 +292,12 @@ WebGLContext::EnableExtension(WebGLExtensionID ext)
case OES_texture_half_float_linear: case OES_texture_half_float_linear:
obj = new WebGLExtensionTextureHalfFloatLinear(this); obj = new WebGLExtensionTextureHalfFloatLinear(this);
break; 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: case WEBGL_draw_buffers:
obj = new WebGLExtensionDrawBuffers(this); obj = new WebGLExtensionDrawBuffers(this);
break; break;

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

@ -538,13 +538,12 @@ WebGLContext::CopyTexImage2D(GLenum target,
} }
if (sizeMayChange) if (sizeMayChange)
UpdateWebGLErrorAndClearGLError(); GetAndFlushUnderlyingGLErrors();
CopyTexSubImage2D_base(target, level, internalformat, 0, 0, x, y, width, height, false); CopyTexSubImage2D_base(target, level, internalformat, 0, 0, x, y, width, height, false);
if (sizeMayChange) { if (sizeMayChange) {
GLenum error = LOCAL_GL_NO_ERROR; GLenum error = GetAndFlushUnderlyingGLErrors();
UpdateWebGLErrorAndClearGLError(&error);
if (error) { if (error) {
GenerateWarning("copyTexImage2D generated error %s", ErrorName(error)); GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
return; return;
@ -902,8 +901,7 @@ WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject); gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
GLenum error = LOCAL_GL_NO_ERROR; GetAndFlushUnderlyingGLErrors();
UpdateWebGLErrorAndClearGLError();
if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) { if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]); nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]);
@ -917,7 +915,7 @@ WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
} else { } else {
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW); 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); 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)); return JS::NumberValue(uint32_t(LOCAL_GL_RENDERBUFFER));
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
{
return WebGLObjectAsJSValue(cx, fba.Renderbuffer(), rv); 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)); return JS::NumberValue(uint32_t(LOCAL_GL_TEXTURE));
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
{
return WebGLObjectAsJSValue(cx, fba.Texture(), rv); return WebGLObjectAsJSValue(cx, fba.Texture(), rv);
}
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
return JS::Int32Value(fba.TexImageLevel()); 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(); GLenum face = fba.TexImageTarget();
if (face == LOCAL_GL_TEXTURE_2D) if (face == LOCAL_GL_TEXTURE_2D)
face = 0; face = 0;
return JS::Int32Value(face); 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); ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
@ -1499,19 +1574,53 @@ WebGLContext::CreateTexture()
return globj.forget(); return globj.forget();
} }
static GLenum
GetAndClearError(GLenum* errorVar)
{
MOZ_ASSERT(errorVar);
GLenum ret = *errorVar;
*errorVar = LOCAL_GL_NO_ERROR;
return ret;
}
GLenum GLenum
WebGLContext::GetError() WebGLContext::GetError()
{ {
if (mContextStatus == ContextNotLost) { /* WebGL 1.0: Section 5.14.3: Setting and getting state:
MakeContextCurrent(); * If the context's webgl context lost flag is set, returns
UpdateWebGLErrorAndClearGLError(); * CONTEXT_LOST_WEBGL the first time this method is called.
} else if (!mContextLostErrorSet) { * Afterward, returns NO_ERROR until the context has been
mWebGLError = LOCAL_GL_CONTEXT_LOST; * restored.
mContextLostErrorSet = true; *
* 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; GLenum err = GetAndClearError(&mWebGLError);
mWebGLError = LOCAL_GL_NO_ERROR; 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; return err;
} }
@ -2215,9 +2324,8 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
GLenum type, const Nullable<ArrayBufferView> &pixels, GLenum type, const Nullable<ArrayBufferView> &pixels,
ErrorResult& rv) ErrorResult& rv)
{ {
if (IsContextLost()) { if (IsContextLost())
return; return;
}
if (mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome()) { if (mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome()) {
GenerateWarning("readPixels: Not allowed"); GenerateWarning("readPixels: Not allowed");
@ -2255,20 +2363,34 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
int requiredDataType = 0; int requiredDataType = 0;
// Check the type param // Check the type param
bool isReadTypeValid = false;
bool isReadTypeFloat = false;
switch (type) { switch (type) {
case LOCAL_GL_UNSIGNED_BYTE: case LOCAL_GL_UNSIGNED_BYTE:
isReadTypeValid = true;
bytesPerPixel = 1*channels; bytesPerPixel = 1*channels;
requiredDataType = js::ArrayBufferView::TYPE_UINT8; requiredDataType = js::ArrayBufferView::TYPE_UINT8;
break; break;
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
case LOCAL_GL_UNSIGNED_SHORT_5_6_5: case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
isReadTypeValid = true;
bytesPerPixel = 2; bytesPerPixel = 2;
requiredDataType = js::ArrayBufferView::TYPE_UINT16; requiredDataType = js::ArrayBufferView::TYPE_UINT16;
break; break;
default: case LOCAL_GL_FLOAT:
return ErrorInvalidEnum("readPixels: Bad type"); 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()); 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); 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) // Check the format and type params to assure they are an acceptable pair (as per spec)
switch (format) { switch (format) {
case LOCAL_GL_RGBA: { case LOCAL_GL_RGBA: {
switch (type) { switch (type) {
case LOCAL_GL_UNSIGNED_BYTE: case LOCAL_GL_UNSIGNED_BYTE:
break; break;
case LOCAL_GL_FLOAT:
break;
default: default:
return ErrorInvalidOperation("readPixels: Invalid format/type pair"); return ErrorInvalidOperation("readPixels: Invalid format/type pair");
} }
@ -2431,6 +2566,20 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
rowp += 4; 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(); row += checked_alignedRowSize.value();
} }
} else { } else {
@ -2486,6 +2635,22 @@ WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei
break; break;
case LOCAL_GL_SRGB8_ALPHA8_EXT: case LOCAL_GL_SRGB8_ALPHA8_EXT:
break; 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: default:
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat); return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
} }
@ -2496,10 +2661,9 @@ WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei
height != mBoundRenderbuffer->Height() || height != mBoundRenderbuffer->Height() ||
internalformat != mBoundRenderbuffer->InternalFormat(); internalformat != mBoundRenderbuffer->InternalFormat();
if (sizeChanges) { if (sizeChanges) {
UpdateWebGLErrorAndClearGLError(); GetAndFlushUnderlyingGLErrors();
mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height); mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
GLenum error = LOCAL_GL_NO_ERROR; GLenum error = GetAndFlushUnderlyingGLErrors();
UpdateWebGLErrorAndClearGLError(&error);
if (error) { if (error) {
GenerateWarning("renderbufferStorage generated error %s", ErrorName(error)); GenerateWarning("renderbufferStorage generated error %s", ErrorName(error));
return; return;
@ -3632,12 +3796,11 @@ GLenum WebGLContext::CheckedTexImage2D(GLenum target,
} }
if (sizeMayChange) { if (sizeMayChange) {
UpdateWebGLErrorAndClearGLError(); GetAndFlushUnderlyingGLErrors();
gl->fTexImage2D(target, level, internalFormat, width, height, border, format, realType, data); gl->fTexImage2D(target, level, internalFormat, width, height, border, format, realType, data);
GLenum error = LOCAL_GL_NO_ERROR; GLenum error = GetAndFlushUnderlyingGLErrors();
UpdateWebGLErrorAndClearGLError(&error);
return error; return error;
} }
@ -3881,8 +4044,13 @@ WebGLContext::TexSubImage2D_base(GLenum target, GLint level,
// convert type for half float if not on GLES2 // convert type for half float if not on GLES2
GLenum realType = type; GLenum realType = type;
if (realType == LOCAL_GL_HALF_FLOAT_OES && !gl->IsGLES2()) if (realType == LOCAL_GL_HALF_FLOAT_OES) {
if (gl->IsSupported(gl::GLFeature::texture_half_float)) {
realType = LOCAL_GL_HALF_FLOAT; realType = LOCAL_GL_HALF_FLOAT;
} else {
MOZ_ASSERT(gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
}
}
if (actualSrcFormat == dstFormat && if (actualSrcFormat == dstFormat &&
srcPremultiplied == mPixelStorePremultiplyAlpha && srcPremultiplied == mPixelStorePremultiplyAlpha &&

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

@ -106,15 +106,12 @@ WebGLContext::GetImageSize(GLsizei height,
void void
WebGLContext::SynthesizeGLError(GLenum err) WebGLContext::SynthesizeGLError(GLenum err)
{ {
// If there is already a pending error, don't overwrite it; /* ES2 section 2.5 "GL Errors" states that implementations can have
// but if there isn't, then we need to check for a gl error * multiple 'flags', as errors might be caught in different parts of
// that may have occurred before this one and use that code * a distributed implementation.
// instead. * We're signing up as a distributed implementation here, with
* separate flags for WebGL and the underlying GLContext.
MakeContextCurrent(); */
UpdateWebGLErrorAndClearGLError();
if (!mWebGLError) if (!mWebGLError)
mWebGLError = err; mWebGLError = err;
} }
@ -234,14 +231,16 @@ WebGLContext::IsTextureFormatCompressed(GLenum format)
} }
} }
void GLenum
WebGLContext::UpdateWebGLErrorAndClearGLError(GLenum *currentGLError) WebGLContext::GetAndFlushUnderlyingGLErrors()
{ {
// get and clear GL error in ALL cases // Get and clear GL error in ALL cases.
GLenum error = gl->GetAndClearError(); GLenum error = gl->GetAndClearError();
if (currentGLError)
*currentGLError = error; // Only store in mUnderlyingGLError if is hasn't already recorded an
// only store in mWebGLError if is hasn't already recorded an error // error.
if (!mWebGLError) if (!mUnderlyingGLError)
mWebGLError = error; mUnderlyingGLError = error;
return error;
} }

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

@ -1586,7 +1586,9 @@ WebGLContext::InitAndValidateGL()
} }
mActiveTexture = 0; mActiveTexture = 0;
mEmitContextLostErrorOnce = true;
mWebGLError = LOCAL_GL_NO_ERROR; mWebGLError = LOCAL_GL_NO_ERROR;
mUnderlyingGLError = LOCAL_GL_NO_ERROR;
mBound2DTextures.Clear(); mBound2DTextures.Clear();
mBoundCubeMapTextures.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_ #ifndef WEBGLEXTENSIONS_H_
#define WEBGLEXTENSIONS_H_ #define WEBGLEXTENSIONS_H_
#include "jsapi.h"
#include "mozilla/Attributes.h"
#include "nsWrapperCache.h"
#include "WebGLObjectModel.h"
#include "WebGLTypes.h"
namespace mozilla { namespace mozilla {
class WebGLContext; class WebGLContext;
class WebGLShader;
class WebGLVertexArray;
class WebGLExtensionBase class WebGLExtensionBase
: public nsWrapperCache : public nsWrapperCache
@ -205,6 +213,30 @@ public:
DECL_WEBGL_EXTENSION_GOOP 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 class WebGLExtensionDrawBuffers
: public WebGLExtensionBase : public WebGLExtensionBase
{ {

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

@ -60,6 +60,35 @@ WebGLFramebuffer::Attachment::HasAlpha() const
return FormatHasAlpha(format); 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 void
WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level) WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level)
{ {

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

@ -53,6 +53,7 @@ public:
bool IsDeleteRequested() const; bool IsDeleteRequested() const;
bool HasAlpha() const; bool HasAlpha() const;
bool IsReadableFloat() const;
void SetTexImage(WebGLTexture* tex, GLenum target, GLint level); void SetTexImage(WebGLTexture* tex, GLenum target, GLint level);
void SetRenderbuffer(WebGLRenderbuffer* rb) { void SetRenderbuffer(WebGLRenderbuffer* rb) {

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

@ -113,6 +113,18 @@ WebGLRenderbuffer::MemoryUsage() const {
case LOCAL_GL_DEPTH_COMPONENT32: case LOCAL_GL_DEPTH_COMPONENT32:
primarySize = 4*pixels; primarySize = 4*pixels;
break; 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: default:
MOZ_ASSERT(false, "Unknown `primaryFormat`."); MOZ_ASSERT(false, "Unknown `primaryFormat`.");
break; break;

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

@ -49,8 +49,8 @@ int64_t
WebGLTexture::ImageInfo::MemoryUsage() const { WebGLTexture::ImageInfo::MemoryUsage() const {
if (mImageDataStatus == WebGLImageDataStatus::NoImageData) if (mImageDataStatus == WebGLImageDataStatus::NoImageData)
return 0; return 0;
int64_t texelSizeInBits = WebGLContext::GetBitsPerTexel(mInternalFormat, mType); int64_t bitsPerTexel = WebGLContext::GetBitsPerTexel(mInternalFormat, mType);
return int64_t(mWidth) * int64_t(mHeight) * texelSizeInBits / 8; return int64_t(mWidth) * int64_t(mHeight) * bitsPerTexel/8;
} }
int64_t int64_t
@ -451,13 +451,12 @@ WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level)
void *zeros = calloc(1, checked_byteLength.value()); void *zeros = calloc(1, checked_byteLength.value());
GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat); GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat);
mContext->UpdateWebGLErrorAndClearGLError(); mContext->GetAndFlushUnderlyingGLErrors();
mContext->gl->fTexImage2D(imageTarget, level, imageInfo.mInternalFormat, mContext->gl->fTexImage2D(imageTarget, level, imageInfo.mInternalFormat,
imageInfo.mWidth, imageInfo.mHeight, imageInfo.mWidth, imageInfo.mHeight,
0, format, imageInfo.mType, 0, format, imageInfo.mType,
zeros); zeros);
GLenum error = LOCAL_GL_NO_ERROR; GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
mContext->UpdateWebGLErrorAndClearGLError(&error);
free(zeros); free(zeros);
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData); SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);

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

@ -44,6 +44,8 @@ if CONFIG['MOZ_WEBGL']:
'WebGLContextVertices.cpp', 'WebGLContextVertices.cpp',
'WebGLElementArrayCache.cpp', 'WebGLElementArrayCache.cpp',
'WebGLExtensionBase.cpp', 'WebGLExtensionBase.cpp',
'WebGLExtensionColorBufferFloat.cpp',
'WebGLExtensionColorBufferHalfFloat.cpp',
'WebGLExtensionCompressedTextureATC.cpp', 'WebGLExtensionCompressedTextureATC.cpp',
'WebGLExtensionCompressedTexturePVRTC.cpp', 'WebGLExtensionCompressedTexturePVRTC.cpp',
'WebGLExtensionCompressedTextureS3TC.cpp', 'WebGLExtensionCompressedTextureS3TC.cpp',

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

@ -147,7 +147,7 @@ var files = [
frames: 33297, frames: 33297,
sampleRate: 48000, sampleRate: 48000,
duration: 0.693, duration: 0.693,
fuzzTolerance: 3, fuzzTolerance: 5,
fuzzToleranceMobile: 1388 fuzzToleranceMobile: 1388
}, },
// An ogg file, 48khz, stereo // An ogg file, 48khz, stereo

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

@ -56,7 +56,7 @@ void EbmlComposer::GenerateHeader()
} }
// The Recording length is unknow and ignore write the whole Segment element size // The Recording length is unknow and ignore write the whole Segment element size
} }
MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(), MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(),
"write more data > EBML_BUFFER_SIZE"); "write more data > EBML_BUFFER_SIZE");
mClusterBuffs.AppendElement(); mClusterBuffs.AppendElement();
mClusterBuffs.LastElement().SetLength(ebml.offset); mClusterBuffs.LastElement().SetLength(ebml.offset);
@ -117,7 +117,7 @@ EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame)
0, 0, (unsigned char*)aFrame->GetFrameData().Elements(), 0, 0, (unsigned char*)aFrame->GetFrameData().Elements(),
aFrame->GetFrameData().Length()); aFrame->GetFrameData().Length());
} }
MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + aFrame->GetFrameData().Length(), MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + aFrame->GetFrameData().Length(),
"write more data > EBML_BUFFER_SIZE"); "write more data > EBML_BUFFER_SIZE");
mClusterBuffs.LastElement().SetLength(ebml.offset); mClusterBuffs.LastElement().SetLength(ebml.offset);
} }

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

@ -24,7 +24,6 @@
#include "nsFrameTraversal.h" #include "nsFrameTraversal.h"
#include "nsEventDispatcher.h" #include "nsEventDispatcher.h"
#include "nsEventStateManager.h" #include "nsEventStateManager.h"
#include "nsIMEStateManager.h"
#include "nsIWebNavigation.h" #include "nsIWebNavigation.h"
#include "nsCaret.h" #include "nsCaret.h"
#include "nsIBaseWindow.h" #include "nsIBaseWindow.h"
@ -41,6 +40,7 @@
#include "mozilla/ContentEvents.h" #include "mozilla/ContentEvents.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/LookAndFeel.h" #include "mozilla/LookAndFeel.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/Services.h" #include "mozilla/Services.h"
@ -933,7 +933,7 @@ nsFocusManager::WindowHidden(nsIDOMWindow* aWindow)
nsPresContext* focusedPresContext = nsPresContext* focusedPresContext =
presShell ? presShell->GetPresContext() : nullptr; presShell ? presShell->GetPresContext() : nullptr;
nsIMEStateManager::OnChangeFocus(focusedPresContext, nullptr, IMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
GetFocusMoveActionCause(0)); GetFocusMoveActionCause(0));
if (presShell) { if (presShell) {
SetCaretVisible(presShell, false, nullptr); SetCaretVisible(presShell, false, nullptr);
@ -1529,7 +1529,7 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
nsPresContext* focusedPresContext = nsPresContext* focusedPresContext =
mActiveWindow ? presShell->GetPresContext() : nullptr; mActiveWindow ? presShell->GetPresContext() : nullptr;
nsIMEStateManager::OnChangeFocus(focusedPresContext, nullptr, IMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
GetFocusMoveActionCause(0)); GetFocusMoveActionCause(0));
// now adjust the actual focus, by clearing the fields in the focus manager // now adjust the actual focus, by clearing the fields in the focus manager
@ -1746,11 +1746,11 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
// document and then the window. // document and then the window.
if (aIsNewDocument) { if (aIsNewDocument) {
nsIDocument* doc = aWindow->GetExtantDoc(); 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 // the focused content is a designMode editor since any content won't
// receive focus event. // receive focus event.
if (doc && doc->HasFlag(NODE_IS_EDITABLE)) { if (doc && doc->HasFlag(NODE_IS_EDITABLE)) {
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr, IMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr,
GetFocusMoveActionCause(aFlags)); GetFocusMoveActionCause(aFlags));
} }
if (doc) if (doc)
@ -1796,7 +1796,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
} }
} }
nsIMEStateManager::OnChangeFocus(presContext, aContent, IMEStateManager::OnChangeFocus(presContext, aContent,
GetFocusMoveActionCause(aFlags)); GetFocusMoveActionCause(aFlags));
// as long as this focus wasn't because a window was raised, update the // as long as this focus wasn't because a window was raised, update the
@ -1810,7 +1810,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
aContent, aFlags & FOCUSMETHOD_MASK, aContent, aFlags & FOCUSMETHOD_MASK,
aWindowRaised, isRefocus); aWindowRaised, isRefocus);
} else { } else {
nsIMEStateManager::OnChangeFocus(presContext, nullptr, IMEStateManager::OnChangeFocus(presContext, nullptr,
GetFocusMoveActionCause(aFlags)); GetFocusMoveActionCause(aFlags));
if (!aWindowRaised) { if (!aWindowRaised) {
aWindow->UpdateCommands(NS_LITERAL_STRING("focus")); aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
@ -1834,7 +1834,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
} }
nsPresContext* presContext = presShell->GetPresContext(); nsPresContext* presContext = presShell->GetPresContext();
nsIMEStateManager::OnChangeFocus(presContext, nullptr, IMEStateManager::OnChangeFocus(presContext, nullptr,
GetFocusMoveActionCause(aFlags)); GetFocusMoveActionCause(aFlags));
if (!aWindowRaised) if (!aWindowRaised)

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

@ -24,11 +24,24 @@ using namespace mozilla;
StaticRefPtr<nsWindowMemoryReporter> sWindowReporter; 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() nsWindowMemoryReporter::nsWindowMemoryReporter()
: mCheckForGhostWindowsCallbackPending(false) : mLastCheckForGhostWindows(TimeStamp::NowLoRes()),
mCycleCollectorIsRunning(false),
mCheckTimerWaitingForCCEnd(false)
{ {
} }
nsWindowMemoryReporter::~nsWindowMemoryReporter()
{
KillCheckTimer();
}
NS_IMPL_ISUPPORTS3(nsWindowMemoryReporter, nsIMemoryReporter, nsIObserver, NS_IMPL_ISUPPORTS3(nsWindowMemoryReporter, nsIMemoryReporter, nsIObserver,
nsSupportsWeakReference) nsSupportsWeakReference)
@ -105,6 +118,10 @@ nsWindowMemoryReporter::Init()
/* weakRef = */ true); /* weakRef = */ true);
os->AddObserver(sWindowReporter, "after-minimize-memory-usage", os->AddObserver(sWindowReporter, "after-minimize-memory-usage",
/* weakRef = */ true); /* weakRef = */ true);
os->AddObserver(sWindowReporter, "cycle-collector-begin",
/* weakRef = */ true);
os->AddObserver(sWindowReporter, "cycle-collector-end",
/* weakRef = */ true);
} }
RegisterStrongMemoryReporter(new GhostWindowsReporter()); RegisterStrongMemoryReporter(new GhostWindowsReporter());
@ -608,6 +625,18 @@ nsWindowMemoryReporter::Observe(nsISupports *aSubject, const char *aTopic,
ObserveDOMWindowDetached(aSubject); ObserveDOMWindowDetached(aSubject);
} else if (!strcmp(aTopic, "after-minimize-memory-usage")) { } else if (!strcmp(aTopic, "after-minimize-memory-usage")) {
ObserveAfterMinimizeMemoryUsage(); 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 { } else {
MOZ_ASSERT(false); MOZ_ASSERT(false);
} }
@ -626,12 +655,44 @@ nsWindowMemoryReporter::ObserveDOMWindowDetached(nsISupports* aWindow)
mDetachedWindows.Put(weakWindow, TimeStamp()); mDetachedWindows.Put(weakWindow, TimeStamp());
if (!mCheckForGhostWindowsCallbackPending) { AsyncCheckForGhostWindows();
nsCOMPtr<nsIRunnable> runnable = }
NS_NewRunnableMethod(this,
&nsWindowMemoryReporter::CheckForGhostWindowsCallback); // static
NS_DispatchToCurrentThread(runnable); void
mCheckForGhostWindowsCallbackPending = true; 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); &minTimeStamp);
} }
void
nsWindowMemoryReporter::CheckForGhostWindowsCallback()
{
mCheckForGhostWindowsCallbackPending = false;
CheckForGhostWindows();
}
struct CheckForGhostWindowsEnumeratorData struct CheckForGhostWindowsEnumeratorData
{ {
nsTHashtable<nsCStringHashKey> *nonDetachedDomains; nsTHashtable<nsCStringHashKey> *nonDetachedDomains;
@ -808,6 +862,9 @@ nsWindowMemoryReporter::CheckForGhostWindows(
return; return;
} }
mLastCheckForGhostWindows = TimeStamp::NowLoRes();
KillCheckTimer();
nsTHashtable<nsCStringHashKey> nonDetachedWindowDomains; nsTHashtable<nsCStringHashKey> nonDetachedWindowDomains;
// Populate nonDetachedWindowDomains. // Populate nonDetachedWindowDomains.
@ -820,7 +877,7 @@ nsWindowMemoryReporter::CheckForGhostWindows(
// if it's not null. // if it's not null.
CheckForGhostWindowsEnumeratorData ghostEnumData = CheckForGhostWindowsEnumeratorData ghostEnumData =
{ &nonDetachedWindowDomains, aOutGhostIDs, tldService, { &nonDetachedWindowDomains, aOutGhostIDs, tldService,
GetGhostTimeout(), TimeStamp::Now() }; GetGhostTimeout(), mLastCheckForGhostWindows };
mDetachedWindows.Enumerate(CheckForGhostWindowsEnumerator, mDetachedWindows.Enumerate(CheckForGhostWindowsEnumerator,
&ghostEnumData); &ghostEnumData);
} }
@ -836,6 +893,15 @@ nsWindowMemoryReporter::GhostWindowsReporter::DistinguishedAmount()
return ghostWindows.Count(); return ghostWindows.Count();
} }
void
nsWindowMemoryReporter::KillCheckTimer()
{
if (mCheckTimer) {
mCheckTimer->Cancel();
mCheckTimer = nullptr;
}
}
#ifdef DEBUG #ifdef DEBUG
static PLDHashOperator static PLDHashOperator
UnlinkGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void *) UnlinkGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void *)

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

@ -9,6 +9,7 @@
#include "nsIMemoryReporter.h" #include "nsIMemoryReporter.h"
#include "nsIObserver.h" #include "nsIObserver.h"
#include "nsITimer.h"
#include "nsDataHashtable.h" #include "nsDataHashtable.h"
#include "nsWeakReference.h" #include "nsWeakReference.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
@ -139,6 +140,8 @@ public:
static void Init(); static void Init();
~nsWindowMemoryReporter();
#ifdef DEBUG #ifdef DEBUG
/** /**
* Unlink all known ghost windows, to enable investigating what caused them * Unlink all known ghost windows, to enable investigating what caused them
@ -187,13 +190,6 @@ private:
void ObserveDOMWindowDetached(nsISupports* aWindow); void ObserveDOMWindowDetached(nsISupports* aWindow);
void ObserveAfterMinimizeMemoryUsage(); 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 * Iterate over all weak window pointers in mDetachedWindows and update our
* accounting of which windows meet ghost criterion (2). * accounting of which windows meet ghost criterion (2).
@ -209,6 +205,19 @@ private:
*/ */
void CheckForGhostWindows(nsTHashtable<nsUint64HashKey> *aOutGhostIDs = nullptr); 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 * Maps a weak reference to a detached window (nsIWeakReference) to the time
* when we observed that the window met ghost criterion (2) above. * when we observed that the window met ghost criterion (2) above.
@ -222,9 +231,16 @@ private:
nsDataHashtable<nsISupportsHashKey, mozilla::TimeStamp> mDetachedWindows; 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__ #endif // nsWindowMemoryReporter_h__

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

@ -1342,6 +1342,16 @@ DOMInterfaces = {
'headerFile': 'WebGLExtensions.h' 'headerFile': 'WebGLExtensions.h'
}, },
'WebGLExtensionColorBufferFloat': {
'nativeType': 'mozilla::WebGLExtensionColorBufferFloat',
'headerFile': 'WebGLExtensions.h'
},
'WebGLExtensionColorBufferHalfFloat': {
'nativeType': 'mozilla::WebGLExtensionColorBufferHalfFloat',
'headerFile': 'WebGLExtensions.h'
},
'WebGLExtensionDrawBuffers': { 'WebGLExtensionDrawBuffers': {
'nativeType': 'mozilla::WebGLExtensionDrawBuffers', 'nativeType': 'mozilla::WebGLExtensionDrawBuffers',
'headerFile': 'WebGLExtensions.h' '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 * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsIMEStateManager_h__ #ifndef mozilla_IMEStateManager_h_
#define nsIMEStateManager_h__ #define mozilla_IMEStateManager_h_
#include "mozilla/EventForwards.h" #include "mozilla/EventForwards.h"
#include "nsIWidget.h" #include "nsIWidget.h"
@ -15,26 +15,26 @@ class nsIDOMMouseEvent;
class nsINode; class nsINode;
class nsPIDOMWindow; class nsPIDOMWindow;
class nsPresContext; class nsPresContext;
class nsTextStateManager;
class nsISelection; class nsISelection;
namespace mozilla { namespace mozilla {
class IMEContentObserver;
class TextCompositionArray; class TextCompositionArray;
class TextComposition; 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; typedef widget::IMEMessage IMEMessage;
protected: typedef widget::IMEState IMEState;
typedef mozilla::widget::IMEMessage IMEMessage; typedef widget::InputContext InputContext;
typedef mozilla::widget::IMEState IMEState; typedef widget::InputContextAction InputContextAction;
typedef mozilla::widget::InputContext InputContext;
typedef mozilla::widget::InputContextAction InputContextAction;
public: public:
static void Shutdown(); static void Shutdown();
@ -92,14 +92,14 @@ public:
*/ */
static void DispatchCompositionEvent(nsINode* aEventTargetNode, static void DispatchCompositionEvent(nsINode* aEventTargetNode,
nsPresContext* aPresContext, nsPresContext* aPresContext,
mozilla::WidgetEvent* aEvent, WidgetEvent* aEvent,
nsEventStatus* aStatus, nsEventStatus* aStatus,
nsDispatchingCallback* aCallBack); nsDispatchingCallback* aCallBack);
/** /**
* Get TextComposition from widget. * Get TextComposition from widget.
*/ */
static already_AddRefed<mozilla::TextComposition> static already_AddRefed<TextComposition>
GetTextCompositionFor(nsIWidget* aWidget); GetTextCompositionFor(nsIWidget* aWidget);
/** /**
@ -108,8 +108,8 @@ public:
* @param aEvent Should be a composition event or a text event which is * @param aEvent Should be a composition event or a text event which is
* being dispatched. * being dispatched.
*/ */
static already_AddRefed<mozilla::TextComposition> static already_AddRefed<TextComposition>
GetTextCompositionFor(mozilla::WidgetGUIEvent* aEvent); GetTextCompositionFor(WidgetGUIEvent* aEvent);
/** /**
* Send a notification to IME. It depends on the IME or platform spec what * 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, nsIWidget* aWidget);
static nsresult NotifyIME(IMEMessage aMessage, nsPresContext* aPresContext); static nsresult NotifyIME(IMEMessage aMessage, nsPresContext* aPresContext);
static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
nsIContent* aContent);
static bool IsTestingIME() { return sIsTestingIME; }
protected: protected:
static nsresult OnChangeFocusInternal(nsPresContext* aPresContext, static nsresult OnChangeFocusInternal(nsPresContext* aPresContext,
nsIContent* aContent, nsIContent* aContent,
@ -130,12 +134,10 @@ protected:
nsIContent* aContent); nsIContent* aContent);
static void EnsureTextCompositionArray(); static void EnsureTextCompositionArray();
static void CreateTextStateManager(); static void CreateIMEContentObserver();
static void DestroyTextStateManager(); static void DestroyTextStateManager();
static bool IsEditable(nsINode* node); static bool IsEditable(nsINode* node);
static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
nsIContent* aContent);
static bool IsEditableIMEState(nsIWidget* aWidget); static bool IsEditableIMEState(nsIWidget* aWidget);
@ -144,13 +146,15 @@ protected:
static bool sInstalledMenuKeyboardListener; static bool sInstalledMenuKeyboardListener;
static bool sIsTestingIME; static bool sIsTestingIME;
static nsTextStateManager* sTextStateObserver; static IMEContentObserver* sActiveIMEContentObserver;
// All active compositions in the process are stored by this array. // 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. // 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 // The instances in this array can be destroyed automatically if you do
// something to cause committing or canceling the composition. // 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 "nsEventDispatcher.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "nsIEditor.h" #include "nsIEditor.h"
#include "nsIMEStateManager.h"
#include "nsIPresShell.h" #include "nsIPresShell.h"
#include "nsPresContext.h" #include "nsPresContext.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/MiscEvents.h" #include "mozilla/MiscEvents.h"
#include "mozilla/TextEvents.h" #include "mozilla/TextEvents.h"
@ -145,7 +145,7 @@ nsresult
TextComposition::NotifyIME(IMEMessage aMessage) TextComposition::NotifyIME(IMEMessage aMessage)
{ {
NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE); NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
return nsIMEStateManager::NotifyIME(aMessage, mPresContext); return IMEStateManager::NotifyIME(aMessage, mPresContext);
} }
void void
@ -231,7 +231,7 @@ TextComposition::CompositionEventDispatcher::Run()
handler.OnQuerySelectedText(&selectedText); handler.OnQuerySelectedText(&selectedText);
NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text"); NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
compStart.data = selectedText.mReply.mString; compStart.data = selectedText.mReply.mString;
nsIMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext, IMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
&compStart, &status, nullptr); &compStart, &status, nullptr);
break; break;
} }
@ -239,14 +239,14 @@ TextComposition::CompositionEventDispatcher::Run()
case NS_COMPOSITION_END: { case NS_COMPOSITION_END: {
WidgetCompositionEvent compEvent(true, mEventMessage, mWidget); WidgetCompositionEvent compEvent(true, mEventMessage, mWidget);
compEvent.data = mData; compEvent.data = mData;
nsIMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext, IMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
&compEvent, &status, nullptr); &compEvent, &status, nullptr);
break; break;
} }
case NS_TEXT_TEXT: { case NS_TEXT_TEXT: {
WidgetTextEvent textEvent(true, NS_TEXT_TEXT, mWidget); WidgetTextEvent textEvent(true, NS_TEXT_TEXT, mWidget);
textEvent.theText = mData; textEvent.theText = mData;
nsIMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext, IMEStateManager::DispatchCompositionEvent(mEventTarget, mPresContext,
&textEvent, &status, nullptr); &textEvent, &status, nullptr);
break; break;
} }

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

@ -20,10 +20,11 @@
class nsDispatchingCallback; class nsDispatchingCallback;
class nsIEditor; class nsIEditor;
class nsIMEStateManager;
namespace mozilla { namespace mozilla {
class IMEStateManager;
/** /**
* TextComposition represents a text composition. This class stores the * TextComposition represents a text composition. This class stores the
* composition event target and its presContext. At dispatching the event via * composition event target and its presContext. At dispatching the event via
@ -32,7 +33,7 @@ namespace mozilla {
class TextComposition MOZ_FINAL class TextComposition MOZ_FINAL
{ {
friend class ::nsIMEStateManager; friend class IMEStateManager;
NS_INLINE_DECL_REFCOUNTING(TextComposition) NS_INLINE_DECL_REFCOUNTING(TextComposition)
@ -71,7 +72,7 @@ public:
bool MatchesNativeContext(nsIWidget* aWidget) const; 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(); void Destroy();
@ -145,7 +146,7 @@ public:
private: private:
// This class holds nsPresContext weak. This instance shouldn't block // This class holds nsPresContext weak. This instance shouldn't block
// destroying it. When the presContext is being destroyed, it's notified to // 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. // this instance.
nsPresContext* mPresContext; nsPresContext* mPresContext;
nsCOMPtr<nsINode> mNode; nsCOMPtr<nsINode> mNode;
@ -252,7 +253,7 @@ private:
* DispatchCompositionEventRunnable() dispatches a composition or text event * DispatchCompositionEventRunnable() dispatches a composition or text event
* to the content. Be aware, if you use this method, nsPresShellEventCB * to the content. Be aware, if you use this method, nsPresShellEventCB
* isn't used. That means that nsIFrame::HandleEvent() is never called. * 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. * destroyed by this method call.
* *
* @param aEventMessage Must be one of composition event or text event. * @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 * Managing with array is enough because only one composition is typically
* there. Even if user switches native IME context, it's very rare that * there. Even if user switches native IME context, it's very rare that
* second or more composition is started. * 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 * compositions in the process. If the instance is it, each TextComposition
* in the array can be destroyed by calling some methods of itself. * in the array can be destroyed by calling some methods of itself.
*/ */

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

@ -27,6 +27,7 @@ EXPORTS += [
] ]
EXPORTS.mozilla += [ EXPORTS.mozilla += [
'IMEStateManager.h',
'InternalMutationEvent.h', 'InternalMutationEvent.h',
] ]
@ -77,6 +78,8 @@ UNIFIED_SOURCES += [
'Event.cpp', 'Event.cpp',
'EventTarget.cpp', 'EventTarget.cpp',
'FocusEvent.cpp', 'FocusEvent.cpp',
'IMEContentObserver.cpp',
'IMEStateManager.cpp',
'KeyboardEvent.cpp', 'KeyboardEvent.cpp',
'MessageEvent.cpp', 'MessageEvent.cpp',
'MouseEvent.cpp', 'MouseEvent.cpp',
@ -90,7 +93,6 @@ UNIFIED_SOURCES += [
'nsEventDispatcher.cpp', 'nsEventDispatcher.cpp',
'nsEventListenerManager.cpp', 'nsEventListenerManager.cpp',
'nsEventListenerService.cpp', 'nsEventListenerService.cpp',
'nsIMEStateManager.cpp',
'nsJSEventListener.cpp', 'nsJSEventListener.cpp',
'nsPaintRequest.cpp', 'nsPaintRequest.cpp',
'PointerEvent.cpp', 'PointerEvent.cpp',

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

@ -24,9 +24,9 @@
#include "nsISelectionPrivate.h" #include "nsISelectionPrivate.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsLayoutUtils.h" #include "nsLayoutUtils.h"
#include "nsIMEStateManager.h"
#include "nsIObjectFrame.h" #include "nsIObjectFrame.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/TextEvents.h" #include "mozilla/TextEvents.h"
#include <algorithm> #include <algorithm>
@ -1096,8 +1096,8 @@ nsContentEventHandler::OnSelectionEvent(WidgetSelectionEvent* aEvent)
// Get selection to manipulate // Get selection to manipulate
// XXX why do we need to get them from ISM? This method should work fine // XXX why do we need to get them from ISM? This method should work fine
// without ISM. // without ISM.
nsresult rv = nsIMEStateManager:: nsresult rv =
GetFocusSelectionAndRoot(getter_AddRefs(mSelection), IMEStateManager::GetFocusSelectionAndRoot(getter_AddRefs(mSelection),
getter_AddRefs(mRootContent)); getter_AddRefs(mRootContent));
if (rv != NS_ERROR_NOT_AVAILABLE) { if (rv != NS_ERROR_NOT_AVAILABLE) {
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);

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

@ -69,7 +69,7 @@ public:
// FlatText means the text that is generated from DOM tree. The BR elements // FlatText means the text that is generated from DOM tree. The BR elements
// are replaced to native linefeeds. Other elements are ignored. // 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, static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
nsINode* aNode, nsINode* aNode,
int32_t aNodeOffset, int32_t aNodeOffset,

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

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/MiscEvents.h" #include "mozilla/MiscEvents.h"
#include "mozilla/MathAlgorithms.h" #include "mozilla/MathAlgorithms.h"
#include "mozilla/MouseEvents.h" #include "mozilla/MouseEvents.h"
@ -17,7 +18,6 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsEventStateManager.h" #include "nsEventStateManager.h"
#include "nsFocusManager.h" #include "nsFocusManager.h"
#include "nsIMEStateManager.h"
#include "nsContentEventHandler.h" #include "nsContentEventHandler.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "nsINodeInfo.h" #include "nsINodeInfo.h"
@ -3765,7 +3765,7 @@ nsEventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent)
void void
nsEventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext) nsEventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext)
{ {
nsIMEStateManager::OnDestroyPresContext(aPresContext); IMEStateManager::OnDestroyPresContext(aPresContext);
if (mHoverContent) { if (mHoverContent) {
// Bug 70855: Presentation is going away, possibly for a reframe. // Bug 70855: Presentation is going away, possibly for a reframe.
// Reset the hover state so that if we're recreating the presentation, // 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()); element->LeaveLink(element->GetPresContext());
} }
nsIMEStateManager::OnRemoveContent(mPresContext, aContent); IMEStateManager::OnRemoveContent(mPresContext, aContent);
// inform the focus manager that the content is being removed. If this // inform the focus manager that the content is being removed. If this
// content is focused, the focus will be removed without firing events. // 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] [NoInterfaceObject]
interface WebGLExtensionVertexArray { interface WebGLExtensionVertexArray {
const GLenum VERTEX_ARRAY_BINDING_OES = 0x85B5; const GLenum VERTEX_ARRAY_BINDING_OES = 0x85B5;

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

@ -25,6 +25,7 @@
#include "mozFlushType.h" // for mozFlushType::Flush_Frames #include "mozFlushType.h" // for mozFlushType::Flush_Frames
#include "mozISpellCheckingEngine.h" #include "mozISpellCheckingEngine.h"
#include "mozInlineSpellChecker.h" // for mozInlineSpellChecker #include "mozInlineSpellChecker.h" // for mozInlineSpellChecker
#include "mozilla/IMEStateManager.h" // for IMEStateManager
#include "mozilla/Preferences.h" // for Preferences #include "mozilla/Preferences.h" // for Preferences
#include "mozilla/Selection.h" // for Selection, etc #include "mozilla/Selection.h" // for Selection, etc
#include "mozilla/Services.h" // for GetObserverService #include "mozilla/Services.h" // for GetObserverService
@ -75,7 +76,6 @@
#include "nsIFrame.h" // for nsIFrame #include "nsIFrame.h" // for nsIFrame
#include "nsIHTMLDocument.h" // for nsIHTMLDocument #include "nsIHTMLDocument.h" // for nsIHTMLDocument
#include "nsIInlineSpellChecker.h" // for nsIInlineSpellChecker, etc #include "nsIInlineSpellChecker.h" // for nsIInlineSpellChecker, etc
#include "nsIMEStateManager.h" // for nsIMEStateManager
#include "nsNameSpaceManager.h" // for kNameSpaceID_None, etc #include "nsNameSpaceManager.h" // for kNameSpaceID_None, etc
#include "nsINode.h" // for nsINode, etc #include "nsINode.h" // for nsINode, etc
#include "nsIObserverService.h" // for nsIObserverService #include "nsIObserverService.h" // for nsIObserverService
@ -315,7 +315,7 @@ nsEditor::PostCreate()
rv = GetPreferredIMEState(&newState); rv = GetPreferredIMEState(&newState);
NS_ENSURE_SUCCESS(rv, NS_OK); NS_ENSURE_SUCCESS(rv, NS_OK);
nsCOMPtr<nsIContent> content = GetFocusedContentForIME(); nsCOMPtr<nsIContent> content = GetFocusedContentForIME();
nsIMEStateManager::UpdateIMEState(newState, content); IMEStateManager::UpdateIMEState(newState, content);
} }
return NS_OK; 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 // NOTE: When the enabled state isn't going to be modified, this method
// is going to do nothing. // is going to do nothing.
nsCOMPtr<nsIContent> content = GetFocusedContentForIME(); nsCOMPtr<nsIContent> content = GetFocusedContentForIME();
nsIMEStateManager::UpdateIMEState(newState, content); IMEStateManager::UpdateIMEState(newState, content);
} }
} }
@ -2016,10 +2016,10 @@ nsEditor::EnsureComposition(mozilla::WidgetGUIEvent* aEvent)
return; return;
} }
// The compositionstart event must cause creating new TextComposition // The compositionstart event must cause creating new TextComposition
// instance at being dispatched by nsIMEStateManager. // instance at being dispatched by IMEStateManager.
mComposition = nsIMEStateManager::GetTextCompositionFor(aEvent); mComposition = IMEStateManager::GetTextCompositionFor(aEvent);
if (!mComposition) { if (!mComposition) {
MOZ_CRASH("nsIMEStateManager doesn't return proper composition"); MOZ_CRASH("IMEStateManager doesn't return proper composition");
} }
mComposition->StartHandlingComposition(this); mComposition->StartHandlingComposition(this);
} }
@ -2095,10 +2095,10 @@ nsEditor::ForceCompositionEnd()
// Linux. Currently, nsGtkIMModule can know the timing of the cursor move, // Linux. Currently, nsGtkIMModule can know the timing of the cursor move,
// so, the latter meaning should be gone. // so, the latter meaning should be gone.
// XXX This may commit a composition in another editor. // 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 NS_IMETHODIMP

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

@ -770,7 +770,7 @@ public:
// Get the focused content, if we're focused. Returns null otherwise. // Get the focused content, if we're focused. Returns null otherwise.
virtual already_AddRefed<nsIContent> GetFocusedContent(); 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. // methods.
virtual already_AddRefed<nsIContent> GetFocusedContentForIME(); virtual already_AddRefed<nsIContent> GetFocusedContentForIME();

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

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/IMEStateManager.h" // for IMEStateManager
#include "mozilla/Preferences.h" // for Preferences #include "mozilla/Preferences.h" // for Preferences
#include "mozilla/TextEvents.h" // for WidgetCompositionEvent #include "mozilla/TextEvents.h" // for WidgetCompositionEvent
#include "mozilla/dom/Element.h" // for Element #include "mozilla/dom/Element.h" // for Element
@ -38,7 +39,6 @@
#include "nsIFocusManager.h" // for nsIFocusManager #include "nsIFocusManager.h" // for nsIFocusManager
#include "nsIFormControl.h" // for nsIFormControl, etc #include "nsIFormControl.h" // for nsIFormControl, etc
#include "nsIHTMLEditor.h" // for nsIHTMLEditor #include "nsIHTMLEditor.h" // for nsIHTMLEditor
#include "nsIMEStateManager.h" // for nsIMEStateManager
#include "nsINativeKeyBindings.h" // for nsINativeKeyBindings #include "nsINativeKeyBindings.h" // for nsINativeKeyBindings
#include "nsINode.h" // for nsINode, ::NODE_IS_EDITABLE, etc #include "nsINode.h" // for nsINode, ::NODE_IS_EDITABLE, etc
#include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc #include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc
@ -570,7 +570,7 @@ nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
nsPresContext* presContext = nsPresContext* presContext =
presShell ? presShell->GetPresContext() : nullptr; presShell ? presShell->GetPresContext() : nullptr;
if (presContext && currentDoc) { if (presContext && currentDoc) {
nsIMEStateManager::OnClickInEditor(presContext, IMEStateManager::OnClickInEditor(presContext,
currentDoc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent, currentDoc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent,
mouseEvent); mouseEvent);
} }
@ -954,7 +954,7 @@ nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
nsCOMPtr<nsIPresShell> ps = GetPresShell(); nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_OK); NS_ENSURE_TRUE(ps, NS_OK);
nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContentForIME(); nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContentForIME();
nsIMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent); IMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent);
return NS_OK; return NS_OK;
} }

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

@ -86,6 +86,9 @@ static const char *sExtensionNames[] = {
"GL_OES_texture_half_float", "GL_OES_texture_half_float",
"GL_OES_texture_half_float_linear", "GL_OES_texture_half_float_linear",
"GL_NV_half_float", "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_EXT_unpack_subimage",
"GL_OES_standard_derivatives", "GL_OES_standard_derivatives",
"GL_EXT_texture_filter_anisotropic", "GL_EXT_texture_filter_anisotropic",

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

@ -90,6 +90,7 @@ MOZ_BEGIN_ENUM_CLASS(GLFeature)
element_index_uint, element_index_uint,
ES2_compatibility, ES2_compatibility,
ES3_compatibility, ES3_compatibility,
frag_color_float,
frag_depth, frag_depth,
framebuffer_blit, framebuffer_blit,
framebuffer_multisample, framebuffer_multisample,
@ -102,6 +103,8 @@ MOZ_BEGIN_ENUM_CLASS(GLFeature)
occlusion_query2, occlusion_query2,
packed_depth_stencil, packed_depth_stencil,
query_objects, query_objects,
renderbuffer_color_float,
renderbuffer_color_half_float,
robustness, robustness,
sRGB, sRGB,
standard_derivatives, standard_derivatives,
@ -365,6 +368,9 @@ public:
OES_texture_half_float, OES_texture_half_float,
OES_texture_half_float_linear, OES_texture_half_float_linear,
NV_half_float, NV_half_float,
EXT_color_buffer_float,
EXT_color_buffer_half_float,
ARB_color_buffer_float,
EXT_unpack_subimage, EXT_unpack_subimage,
OES_standard_derivatives, OES_standard_derivatives,
EXT_texture_filter_anisotropic, EXT_texture_filter_anisotropic,

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

@ -111,6 +111,18 @@ static const FeatureInfo sFeatureInfoArr[] = {
GLContext::Extensions_End 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", "frag_depth",
200, // OpenGL version 200, // OpenGL version
@ -252,6 +264,26 @@ static const FeatureInfo sFeatureInfoArr[] = {
* (added in OpenGL ES 3.0) * (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", "robustness",
0, // OpenGL version 0, // OpenGL version
@ -282,7 +314,7 @@ static const FeatureInfo sFeatureInfoArr[] = {
}, },
{ {
"texture_float", "texture_float",
310, // OpenGL version 300, // OpenGL version
300, // OpenGL ES version 300, // OpenGL ES version
{ {
GLContext::ARB_texture_float, GLContext::ARB_texture_float,
@ -302,7 +334,7 @@ static const FeatureInfo sFeatureInfoArr[] = {
}, },
{ {
"texture_half_float", "texture_half_float",
310, // OpenGL version 300, // OpenGL version
300, // OpenGL ES version 300, // OpenGL ES version
{ {
GLContext::ARB_half_float_pixel, GLContext::ARB_half_float_pixel,

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

@ -14,7 +14,8 @@ NS_IMPL_ISUPPORTS1(GfxTexturesReporter, nsIMemoryReporter)
int64_t GfxTexturesReporter::sAmount = 0; 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 there is no defined format or type, we're not taking up any memory
if (!format || !type) { if (!format || !type) {
@ -23,16 +24,16 @@ static uint32_t GetBitsPerTexel(GLenum format, GLenum type)
if (format == LOCAL_GL_DEPTH_COMPONENT) { if (format == LOCAL_GL_DEPTH_COMPONENT) {
if (type == LOCAL_GL_UNSIGNED_SHORT) if (type == LOCAL_GL_UNSIGNED_SHORT)
return 2; return 2*8;
else if (type == LOCAL_GL_UNSIGNED_INT) else if (type == LOCAL_GL_UNSIGNED_INT)
return 4; return 4*8;
} else if (format == LOCAL_GL_DEPTH_STENCIL) { } else if (format == LOCAL_GL_DEPTH_STENCIL) {
if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT) if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
return 4; return 4*8;
} }
if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) { 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) { switch (format) {
case LOCAL_GL_ALPHA: case LOCAL_GL_ALPHA:
case LOCAL_GL_LUMINANCE: 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_5_5_1 ||
type == LOCAL_GL_UNSIGNED_SHORT_5_6_5) type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
{ {
return 16; return 2*8;
} }
MOZ_ASSERT(false); MOZ_ASSERT(false);
@ -75,8 +76,8 @@ static uint32_t GetBitsPerTexel(GLenum format, GLenum type)
GfxTexturesReporter::UpdateAmount(MemoryUse action, GLenum format, GfxTexturesReporter::UpdateAmount(MemoryUse action, GLenum format,
GLenum type, uint16_t tileSize) GLenum type, uint16_t tileSize)
{ {
uint32_t bytesPerTexel = GetBitsPerTexel(format, type) / 8; int64_t bitsPerTexel = GetBitsPerTexel(format, type);
int64_t bytes = (int64_t)(tileSize * tileSize * bytesPerTexel); int64_t bytes = int64_t(tileSize) * int64_t(tileSize) * bitsPerTexel/8;
if (action == MemoryFreed) { if (action == MemoryFreed) {
sAmount -= bytes; sAmount -= bytes;
} else { } else {

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

@ -132,6 +132,23 @@ enum SurfaceInitMode
INIT_MODE_CLEAR 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. * Common interface for compositor backends.
* *
@ -459,6 +476,10 @@ public:
return fillRatio; return fillRatio;
} }
virtual CompositorBackendSpecificData* GetCompositorBackendSpecificData() {
return nullptr;
}
protected: protected:
void DrawDiagnosticsInternal(DiagnosticFlags aFlags, void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
const gfx::Rect& aVisibleRect, const gfx::Rect& aVisibleRect,

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

@ -384,6 +384,7 @@ struct RemoteImageData {
class ImageContainer : public SupportsWeakPtr<ImageContainer> { class ImageContainer : public SupportsWeakPtr<ImageContainer> {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer) NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer)
public: public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(ImageContainer)
enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 }; enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 };

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

@ -596,19 +596,12 @@ public:
bool IsInTransaction() const { return mInTransaction; } bool IsInTransaction() const { return mInTransaction; }
virtual void AddRegionToClear(const nsIntRegion& aRegion)
{
mRegionToClear.Or(mRegionToClear, aRegion);
}
protected: protected:
nsRefPtr<Layer> mRoot; nsRefPtr<Layer> mRoot;
gfx::UserData mUserData; gfx::UserData mUserData;
bool mDestroyed; bool mDestroyed;
bool mSnapEffectiveTransforms; bool mSnapEffectiveTransforms;
nsIntRegion mRegionToClear;
// Print interesting information about this into aTo. Internally // Print interesting information about this into aTo. Internally
// used to implement Dump*() and Log*(). // used to implement Dump*() and Log*().
virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix); virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
@ -1342,7 +1335,6 @@ public:
virtual LayerRenderState GetRenderState() { return LayerRenderState(); } virtual LayerRenderState GetRenderState() { return LayerRenderState(); }
void Mutated() void Mutated()
{ {
mManager->Mutated(this); mManager->Mutated(this);

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

@ -182,7 +182,7 @@ private:
bool IsPlaceholder(Tile aTile) const { return aTile == AsDerived().GetPlaceholderTile(); } bool IsPlaceholder(Tile aTile) const { return aTile == AsDerived().GetPlaceholderTile(); }
}; };
class BasicTiledLayerBuffer; class ClientTiledLayerBuffer;
class SurfaceDescriptorTiles; class SurfaceDescriptorTiles;
class ISurfaceAllocator; class ISurfaceAllocator;
@ -195,10 +195,10 @@ public:
* Update the current retained layer with the updated layer data. * Update the current retained layer with the updated layer data.
* It is expected that the tiles described by aTiledDescriptor are all in the * 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 * 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. * has completed uploading.
*/ */
virtual void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator, virtual void UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aTiledDescriptor) = 0; const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
/** /**
@ -292,6 +292,7 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
// TODO: Add a tile pool to reduce new allocation // TODO: Add a tile pool to reduce new allocation
int tileX = 0; int tileX = 0;
int tileY = 0; int tileY = 0;
int tilesMissing = 0;
// Iterate over the new drawing bounds in steps of tiles. // Iterate over the new drawing bounds in steps of tiles.
for (int32_t x = newBound.x; x < newBound.XMost(); tileX++) { for (int32_t x = newBound.x; x < newBound.XMost(); tileX++) {
// Compute tileRect(x,y,width,height) in layer space coordinate // 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 // valid content because then we know we can safely recycle
// with taking from a tile that has recyclable content. // with taking from a tile that has recyclable content.
newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile()); newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile());
if (aPaintRegion.Intersects(tileRect)) {
tilesMissing++;
}
} }
y += height; y += height;
@ -349,6 +354,26 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
mRetainedWidth = tileX; mRetainedWidth = tileX;
mRetainedHeight = tileY; 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"); NS_ABORT_IF_FALSE(aNewValidRegion.Contains(aPaintRegion), "Painting a region outside the visible region");
#ifdef DEBUG #ifdef DEBUG
nsIntRegion oldAndPainted(oldValidRegion); nsIntRegion oldAndPainted(oldValidRegion);
@ -415,9 +440,15 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
"index out of range"); "index out of range");
Tile newTile = newRetainedTiles[index]; 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) { while (IsPlaceholder(newTile) && oldRetainedTiles.Length() > 0) {
AsDerived().SwapTiles(newTile, oldRetainedTiles[oldRetainedTiles.Length()-1]); AsDerived().SwapTiles(newTile, oldRetainedTiles[oldRetainedTiles.Length()-1]);
oldRetainedTiles.RemoveElementAt(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 // 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; x += width;
} }
// Throw away any tiles we didn't recycle // At this point, oldTileCount should be zero
// TODO: Add a tile pool NS_ABORT_IF_FALSE(oldTileCount == 0, "Failed to release old tiles");
while (oldRetainedTiles.Length() > 0) {
Tile oldTile = oldRetainedTiles[oldRetainedTiles.Length()-1];
oldRetainedTiles.RemoveElementAt(oldRetainedTiles.Length()-1);
AsDerived().ReleaseTile(oldTile);
}
mRetainedTiles = newRetainedTiles; mRetainedTiles = newRetainedTiles;
mValidRegion = aNewValidRegion; mValidRegion = aNewValidRegion;

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

@ -625,16 +625,6 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
} }
PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr); 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) { if (mWidget) {
FlashWidgetUpdateArea(mTarget); FlashWidgetUpdateArea(mTarget);
} }

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

@ -54,6 +54,8 @@ class TextureClientX11
return mFormat; return mFormat;
} }
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
private: private:
gfx::SurfaceFormat mFormat; gfx::SurfaceFormat mFormat;
gfx::IntSize mSize; 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, CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder,
TextureFlags aFlags) TextureFlags aFlags)
: CanvasClient(aLayerForwarder, aFlags) : CanvasClient(aLayerForwarder, aFlags)

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

@ -50,7 +50,7 @@ public:
TextureFlags aFlags); TextureFlags aFlags);
CanvasClient(CompositableForwarder* aFwd, TextureFlags aFlags) CanvasClient(CompositableForwarder* aFwd, TextureFlags aFlags)
: CompositableClient(aFwd) : CompositableClient(aFwd, aFlags)
{ {
mTextureInfo.mTextureFlags = aFlags; mTextureInfo.mTextureFlags = aFlags;
} }
@ -95,10 +95,6 @@ public:
return CompositableClient::AddTextureClient(aTexture); return CompositableClient::AddTextureClient(aTexture);
} }
virtual TemporaryRef<BufferTextureClient>
CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT) MOZ_OVERRIDE;
virtual void OnDetach() MOZ_OVERRIDE virtual void OnDetach() MOZ_OVERRIDE
{ {
mBuffer = nullptr; mBuffer = nullptr;

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

@ -20,10 +20,12 @@
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/PLayerChild.h" // for PLayerChild #include "mozilla/layers/PLayerChild.h" // for PLayerChild
#include "mozilla/layers/LayerTransactionChild.h" #include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
#include "nsAString.h" #include "nsAString.h"
#include "nsIWidget.h" // for nsIWidget #include "nsIWidget.h" // for nsIWidget
#include "nsTArray.h" // for AutoInfallibleTArray #include "nsTArray.h" // for AutoInfallibleTArray
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc #include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
#include "TiledLayerBuffer.h"
#ifdef MOZ_WIDGET_ANDROID #ifdef MOZ_WIDGET_ANDROID
#include "AndroidBridge.h" #include "AndroidBridge.h"
#endif #endif
@ -34,6 +36,11 @@ using namespace mozilla::gfx;
namespace mozilla { namespace mozilla {
namespace layers { namespace layers {
TextureClientPoolMember::TextureClientPoolMember(SurfaceFormat aFormat, TextureClientPool* aTexturePool)
: mFormat(aFormat)
, mTexturePool(aTexturePool)
{}
ClientLayerManager::ClientLayerManager(nsIWidget* aWidget) ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
: mPhase(PHASE_NONE) : mPhase(PHASE_NONE)
, mWidget(aWidget) , mWidget(aWidget)
@ -53,6 +60,8 @@ ClientLayerManager::~ClientLayerManager()
mRoot = nullptr; mRoot = nullptr;
MOZ_COUNT_DTOR(ClientLayerManager); MOZ_COUNT_DTOR(ClientLayerManager);
mTexturePools.clear();
} }
int32_t int32_t
@ -222,6 +231,11 @@ ClientLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
} else { } else {
MakeSnapshotIfRequired(); MakeSnapshotIfRequired();
} }
for (const TextureClientPoolMember* item = mTexturePools.getFirst();
item; item = item->getNext()) {
item->mTexturePool->ReturnDeferredClients();
}
} }
bool bool
@ -440,6 +454,26 @@ ClientLayerManager::SetIsFirstPaint()
mForwarder->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 void
ClientLayerManager::ClearCachedResources(Layer* aSubtree) ClientLayerManager::ClearCachedResources(Layer* aSubtree)
{ {
@ -452,6 +486,10 @@ ClientLayerManager::ClearCachedResources(Layer* aSubtree)
} else if (mRoot) { } else if (mRoot) {
ClearLayer(mRoot); ClearLayer(mRoot);
} }
for (const TextureClientPoolMember* item = mTexturePools.getFirst();
item; item = item->getNext()) {
item->mTexturePool->Clear();
}
} }
void void

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

@ -10,6 +10,7 @@
#include "Layers.h" #include "Layers.h"
#include "gfxContext.h" // for gfxContext #include "gfxContext.h" // for gfxContext
#include "mozilla/Attributes.h" // for MOZ_OVERRIDE #include "mozilla/Attributes.h" // for MOZ_OVERRIDE
#include "mozilla/LinkedList.h" // For LinkedList
#include "mozilla/WidgetUtils.h" // for ScreenRotation #include "mozilla/WidgetUtils.h" // for ScreenRotation
#include "mozilla/gfx/Rect.h" // for Rect #include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/CompositorTypes.h"
@ -32,6 +33,16 @@ class ClientThebesLayer;
class CompositorChild; class CompositorChild;
class ImageLayer; class ImageLayer;
class PLayerChild; 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 class ClientLayerManager : public LayerManager
{ {
@ -96,6 +107,8 @@ public:
virtual void SetIsFirstPaint() MOZ_OVERRIDE; virtual void SetIsFirstPaint() MOZ_OVERRIDE;
TextureClientPool *GetTexturePool(gfx::SurfaceFormat aFormat);
// Drop cached resources and ask our shadow manager to do the same, // Drop cached resources and ask our shadow manager to do the same,
// if we have one. // if we have one.
virtual void ClearCachedResources(Layer* aSubtree = nullptr) MOZ_OVERRIDE; virtual void ClearCachedResources(Layer* aSubtree = nullptr) MOZ_OVERRIDE;
@ -214,6 +227,7 @@ private:
bool mNeedsComposite; bool mNeedsComposite;
RefPtr<ShadowLayerForwarder> mForwarder; RefPtr<ShadowLayerForwarder> mForwarder;
LinkedList<TextureClientPoolMember> mTexturePools;
}; };
class ClientLayer : public ShadowableLayer class ClientLayer : public ShadowableLayer

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

@ -172,7 +172,10 @@ ClientLayerManager::CreateThebesLayerWithHint(ThebesLayerCreationHint aHint)
#ifdef MOZ_B2G #ifdef MOZ_B2G
aHint == SCROLLABLE && aHint == SCROLLABLE &&
#endif #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 = nsRefPtr<ClientTiledThebesLayer> layer =
new ClientTiledThebesLayer(this); new ClientTiledThebesLayer(this);
CREATE_SHADOW(Thebes); CREATE_SHADOW(Thebes);

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

@ -37,6 +37,14 @@ ClientTiledThebesLayer::~ClientTiledThebesLayer()
MOZ_COUNT_DTOR(ClientTiledThebesLayer); MOZ_COUNT_DTOR(ClientTiledThebesLayer);
} }
void
ClientTiledThebesLayer::ClearCachedResources()
{
if (mContentClient) {
mContentClient->ClearCachedResources();
}
}
void void
ClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs) ClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
{ {
@ -189,7 +197,7 @@ ClientTiledThebesLayer::RenderLayer()
callback, data); callback, data);
ClientManager()->Hold(this); ClientManager()->Hold(this);
mContentClient->LockCopyAndWrite(TiledContentClient::TILED_BUFFER); mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
return; return;
} }
@ -262,7 +270,7 @@ ClientTiledThebesLayer::RenderLayer()
if (updatedBuffer) { if (updatedBuffer) {
ClientManager()->Hold(this); 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 // If there are low precision updates, mark the paint as unfinished and
// request a repeat transaction. // request a repeat transaction.
@ -331,7 +339,7 @@ ClientTiledThebesLayer::RenderLayer()
// and the associated resources can be freed. // and the associated resources can be freed.
if (updatedLowPrecision) { if (updatedLowPrecision) {
ClientManager()->Hold(this); ClientManager()->Hold(this);
mContentClient->LockCopyAndWrite(TiledContentClient::LOW_PRECISION_TILED_BUFFER); mContentClient->UseTiledLayerBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER);
} }
EndPaint(false); EndPaint(false);

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

@ -63,6 +63,8 @@ public:
virtual void RenderLayer(); virtual void RenderLayer();
virtual void ClearCachedResources() MOZ_OVERRIDE;
private: private:
ClientLayerManager* ClientManager() ClientLayerManager* ClientManager()
{ {

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

@ -12,20 +12,9 @@
#include "mozilla/mozalloc.h" // for operator delete, etc #include "mozilla/mozalloc.h" // for operator delete, etc
#include "gfxASurface.h" // for gfxContentType #include "gfxASurface.h" // for gfxContentType
#ifdef XP_WIN #ifdef XP_WIN
#include "mozilla/layers/TextureD3D9.h" #include "gfxWindowsPlatform.h" // for gfxWindowsPlatform
#include "mozilla/layers/TextureD3D11.h" #include "mozilla/layers/TextureD3D11.h"
#include "gfxWindowsPlatform.h" #include "mozilla/layers/TextureD3D9.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 #endif
using namespace mozilla::gfx; using namespace mozilla::gfx;
@ -33,14 +22,15 @@ using namespace mozilla::gfx;
namespace mozilla { namespace mozilla {
namespace layers { namespace layers {
CompositableClient::CompositableClient(CompositableForwarder* aForwarder) CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
TextureFlags aTextureFlags)
: mCompositableChild(nullptr) : mCompositableChild(nullptr)
, mForwarder(aForwarder) , mForwarder(aForwarder)
, mTextureFlags(aTextureFlags)
{ {
MOZ_COUNT_CTOR(CompositableClient); MOZ_COUNT_CTOR(CompositableClient);
} }
CompositableClient::~CompositableClient() CompositableClient::~CompositableClient()
{ {
MOZ_COUNT_DTOR(CompositableClient); MOZ_COUNT_DTOR(CompositableClient);
@ -131,7 +121,7 @@ CompositableClient::CreateDeprecatedTextureClient(DeprecatedTextureClientType aD
break; break;
} }
if (parentBackend == LayersBackend::LAYERS_D3D9 && 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 // We can't use a d3d9 texture for an RGBA surface because we cannot get a DC for
// for a gfxWindowsSurface. // for a gfxWindowsSurface.
// We have to wait for the compositor thread to create a d3d9 device before we // 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, CompositableClient::CreateBufferTextureClient(SurfaceFormat aFormat,
TextureFlags aTextureFlags) TextureFlags aTextureFlags)
{ {
// XXX - Once bug 908196 is fixed, we can use gralloc textures here which will return TextureClient::CreateBufferTextureClient(GetForwarder(), aFormat,
// improve performances of videos using SharedPlanarYCbCrImage on b2g. aTextureFlags | mTextureFlags);
//#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();
}
#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> TemporaryRef<TextureClient>
CompositableClient::CreateTextureClientForDrawing(SurfaceFormat aFormat, CompositableClient::CreateTextureClientForDrawing(SurfaceFormat aFormat,
TextureFlags aTextureFlags) TextureFlags aTextureFlags)
{ {
RefPtr<TextureClient> result; return TextureClient::CreateTextureClientForDrawing(GetForwarder(), aFormat,
aTextureFlags | mTextureFlags);
#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;
} }
bool bool

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

@ -73,7 +73,7 @@ class CompositableClient : public AtomicRefCounted<CompositableClient>
{ {
public: public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(CompositableClient) MOZ_DECLARE_REFCOUNTED_TYPENAME(CompositableClient)
CompositableClient(CompositableForwarder* aForwarder); CompositableClient(CompositableForwarder* aForwarder, TextureFlags aFlags = 0);
virtual ~CompositableClient(); virtual ~CompositableClient();
@ -85,7 +85,7 @@ public:
CreateDeprecatedTextureClient(DeprecatedTextureClientType aDeprecatedTextureClientType, CreateDeprecatedTextureClient(DeprecatedTextureClientType aDeprecatedTextureClientType,
gfxContentType aContentType = gfxContentType::SENTINEL); gfxContentType aContentType = gfxContentType::SENTINEL);
virtual TemporaryRef<BufferTextureClient> TemporaryRef<BufferTextureClient>
CreateBufferTextureClient(gfx::SurfaceFormat aFormat, CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT); TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
@ -143,9 +143,18 @@ public:
*/ */
virtual void OnDetach() {} virtual void OnDetach() {}
/**
* Clear any resources that are not immediately necessary. This may be called
* in low-memory conditions.
*/
virtual void ClearCachedResources() {}
protected: protected:
CompositableChild* mCompositableChild; CompositableChild* mCompositableChild;
CompositableForwarder* mForwarder; CompositableForwarder* mForwarder;
// Some layers may want to enforce some flags to all their textures
// (like disallowing tiling)
TextureFlags mTextureFlags;
friend class CompositableChild; friend class CompositableChild;
}; };

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

@ -82,8 +82,7 @@ ImageClient::CreateImageClient(CompositableType aCompositableHostType,
ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd, ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd,
TextureFlags aFlags, TextureFlags aFlags,
CompositableType aType) CompositableType aType)
: ImageClient(aFwd, aType) : ImageClient(aFwd, aFlags, aType)
, mTextureFlags(aFlags)
{ {
} }
@ -310,12 +309,6 @@ ImageClientSingle::AddTextureClient(TextureClient* aTexture)
return CompositableClient::AddTextureClient(aTexture); return CompositableClient::AddTextureClient(aTexture);
} }
TemporaryRef<BufferTextureClient>
ImageClientSingle::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
{
return CompositableClient::CreateBufferTextureClient(aFormat, mTextureFlags | aFlags);
}
void void
ImageClientSingle::OnDetach() ImageClientSingle::OnDetach()
{ {
@ -329,8 +322,9 @@ ImageClientBuffered::OnDetach()
mBackBuffer = nullptr; mBackBuffer = nullptr;
} }
ImageClient::ImageClient(CompositableForwarder* aFwd, CompositableType aType) ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
: CompositableClient(aFwd) CompositableType aType)
: CompositableClient(aFwd, aFlags)
, mType(aType) , mType(aType)
, mLastPaintedImageSerial(0) , mLastPaintedImageSerial(0)
{} {}
@ -349,7 +343,7 @@ ImageClient::UpdatePictureRect(nsIntRect aRect)
DeprecatedImageClientSingle::DeprecatedImageClientSingle(CompositableForwarder* aFwd, DeprecatedImageClientSingle::DeprecatedImageClientSingle(CompositableForwarder* aFwd,
TextureFlags aFlags, TextureFlags aFlags,
CompositableType aType) CompositableType aType)
: ImageClient(aFwd, aType) : ImageClient(aFwd, aFlags, aType)
, mTextureInfo(aType) , mTextureInfo(aType)
{ {
mTextureInfo.mTextureFlags = aFlags; mTextureInfo.mTextureFlags = aFlags;
@ -482,7 +476,7 @@ DeprecatedImageClientSingle::Updated()
ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd, ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
TextureFlags aFlags) TextureFlags aFlags)
: ImageClient(aFwd, BUFFER_BRIDGE) : ImageClient(aFwd, aFlags, BUFFER_BRIDGE)
, mAsyncContainerID(0) , mAsyncContainerID(0)
, mLayer(nullptr) , mLayer(nullptr)
{ {

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

@ -67,7 +67,8 @@ public:
virtual void FlushAllImages(bool aExceptFront) {} virtual void FlushAllImages(bool aExceptFront) {}
protected: protected:
ImageClient(CompositableForwarder* aFwd, CompositableType aType); ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
CompositableType aType);
CompositableType mType; CompositableType mType;
int32_t mLastPaintedImageSerial; int32_t mLastPaintedImageSerial;
@ -90,10 +91,6 @@ public:
virtual bool AddTextureClient(TextureClient* aTexture) MOZ_OVERRIDE; 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 TextureInfo GetTextureInfo() const MOZ_OVERRIDE;
virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat) MOZ_OVERRIDE; virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat) MOZ_OVERRIDE;
@ -105,9 +102,6 @@ protected:
protected: protected:
RefPtr<TextureClient> mFrontBuffer; 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 "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "ImageContainer.h" // for PlanarYCbCrImage, etc #include "ImageContainer.h" // for PlanarYCbCrImage, etc
#include "mozilla/gfx/2D.h" #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 #ifdef MOZ_ANDROID_OMTC
# include "gfxReusableImageSurfaceWrapper.h" # include "gfxReusableImageSurfaceWrapper.h"
@ -193,6 +212,120 @@ TextureClient::GetIPDLActor()
return mActor; 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 class ShmemTextureClientData : public TextureClientData
{ {
public: public:
@ -296,6 +429,30 @@ void TextureClient::ForceRemove()
MarkInvalid(); 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 void
TextureClient::Finalize() TextureClient::Finalize()
{ {
@ -339,12 +496,6 @@ ShmemTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor)
return true; return true;
} }
ISurfaceAllocator*
ShmemTextureClient::GetAllocator() const
{
return mCompositable->GetForwarder();
}
bool bool
ShmemTextureClient::Allocate(uint32_t aSize) ShmemTextureClient::Allocate(uint32_t aSize)
{ {
@ -371,10 +522,10 @@ ShmemTextureClient::GetBufferSize() const
return mShmem.Size<uint8_t>(); return mShmem.Size<uint8_t>();
} }
ShmemTextureClient::ShmemTextureClient(CompositableClient* aCompositable, ShmemTextureClient::ShmemTextureClient(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat, gfx::SurfaceFormat aFormat,
TextureFlags aFlags) TextureFlags aFlags)
: BufferTextureClient(aCompositable, aFormat, aFlags) : BufferTextureClient(aAllocator, aFormat, aFlags)
, mAllocated(false) , mAllocated(false)
{ {
MOZ_COUNT_CTOR(ShmemTextureClient); MOZ_COUNT_CTOR(ShmemTextureClient);
@ -386,7 +537,7 @@ ShmemTextureClient::~ShmemTextureClient()
if (ShouldDeallocateInDestructor()) { if (ShouldDeallocateInDestructor()) {
// if the buffer has never been shared we must deallocate it or ir would // if the buffer has never been shared we must deallocate it or ir would
// leak. // leak.
mCompositable->GetForwarder()->DeallocShmem(mShmem); GetAllocator()->DeallocShmem(mShmem);
} }
} }
@ -417,10 +568,10 @@ MemoryTextureClient::Allocate(uint32_t aSize)
return true; return true;
} }
MemoryTextureClient::MemoryTextureClient(CompositableClient* aCompositable, MemoryTextureClient::MemoryTextureClient(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat, gfx::SurfaceFormat aFormat,
TextureFlags aFlags) TextureFlags aFlags)
: BufferTextureClient(aCompositable, aFormat, aFlags) : BufferTextureClient(aAllocator, aFormat, aFlags)
, mBuffer(nullptr) , mBuffer(nullptr)
, mBufSize(0) , mBufSize(0)
{ {
@ -438,11 +589,11 @@ MemoryTextureClient::~MemoryTextureClient()
} }
} }
BufferTextureClient::BufferTextureClient(CompositableClient* aCompositable, BufferTextureClient::BufferTextureClient(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat, gfx::SurfaceFormat aFormat,
TextureFlags aFlags) TextureFlags aFlags)
: TextureClient(aFlags) : TextureClient(aFlags)
, mCompositable(aCompositable) , mAllocator(aAllocator)
, mFormat(aFormat) , mFormat(aFormat)
, mUsingFallbackDrawTarget(false) , mUsingFallbackDrawTarget(false)
, mLocked(false) , mLocked(false)
@ -451,6 +602,12 @@ BufferTextureClient::BufferTextureClient(CompositableClient* aCompositable,
BufferTextureClient::~BufferTextureClient() BufferTextureClient::~BufferTextureClient()
{} {}
ISurfaceAllocator*
BufferTextureClient::GetAllocator() const
{
return mAllocator;
}
bool bool
BufferTextureClient::UpdateSurface(gfxASurface* aSurface) BufferTextureClient::UpdateSurface(gfxASurface* aSurface)
{ {

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

@ -44,6 +44,7 @@ class PlanarYCbCrData;
class Image; class Image;
class PTextureChild; class PTextureChild;
class TextureChild; class TextureChild;
class BufferTextureClient;
/** /**
* TextureClient is the abstraction that allows us to share data between the * TextureClient is the abstraction that allows us to share data between the
@ -198,6 +199,16 @@ public:
TextureClient(TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT); TextureClient(TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
virtual ~TextureClient(); 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 TextureClientSurface* AsTextureClientSurface() { return nullptr; }
virtual TextureClientDrawTarget* AsTextureClientDrawTarget() { return nullptr; } virtual TextureClientDrawTarget* AsTextureClientDrawTarget() { return nullptr; }
virtual TextureClientYCbCr* AsTextureClientYCbCr() { return nullptr; } virtual TextureClientYCbCr* AsTextureClientYCbCr() { return nullptr; }
@ -214,6 +225,15 @@ public:
virtual bool IsLocked() const = 0; 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. * Returns true if this texture has a lock/unlock mechanism.
* Textures that do not implement locking should be immutable or should * Textures that do not implement locking should be immutable or should
@ -221,6 +241,13 @@ public:
*/ */
virtual bool ImplementsLocking() const { return false; } 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. * Allocate and deallocate a TextureChild actor.
* *
@ -355,7 +382,7 @@ class BufferTextureClient : public TextureClient
, public TextureClientDrawTarget , public TextureClientDrawTarget
{ {
public: public:
BufferTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat, BufferTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
TextureFlags aFlags); TextureFlags aFlags);
virtual ~BufferTextureClient(); virtual ~BufferTextureClient();
@ -411,9 +438,13 @@ public:
virtual size_t GetBufferSize() const = 0; virtual size_t GetBufferSize() const = 0;
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
ISurfaceAllocator* GetAllocator() const;
protected: protected:
RefPtr<gfx::DrawTarget> mDrawTarget; RefPtr<gfx::DrawTarget> mDrawTarget;
CompositableClient* mCompositable; RefPtr<ISurfaceAllocator> mAllocator;
gfx::SurfaceFormat mFormat; gfx::SurfaceFormat mFormat;
gfx::IntSize mSize; gfx::IntSize mSize;
OpenMode mOpenMode; OpenMode mOpenMode;
@ -428,7 +459,7 @@ protected:
class ShmemTextureClient : public BufferTextureClient class ShmemTextureClient : public BufferTextureClient
{ {
public: public:
ShmemTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat, ShmemTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
TextureFlags aFlags); TextureFlags aFlags);
~ShmemTextureClient(); ~ShmemTextureClient();
@ -445,13 +476,12 @@ public:
virtual TextureClientData* DropTextureData() MOZ_OVERRIDE; virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
ISurfaceAllocator* GetAllocator() const; virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
mozilla::ipc::Shmem& GetShmem() { return mShmem; } mozilla::ipc::Shmem& GetShmem() { return mShmem; }
protected: protected:
mozilla::ipc::Shmem mShmem; mozilla::ipc::Shmem mShmem;
RefPtr<ISurfaceAllocator> mAllocator;
bool mAllocated; bool mAllocated;
}; };
@ -463,7 +493,7 @@ protected:
class MemoryTextureClient : public BufferTextureClient class MemoryTextureClient : public BufferTextureClient
{ {
public: public:
MemoryTextureClient(CompositableClient* aCompositable, gfx::SurfaceFormat aFormat, MemoryTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
TextureFlags aFlags); TextureFlags aFlags);
~MemoryTextureClient(); ~MemoryTextureClient();
@ -478,6 +508,8 @@ public:
virtual bool IsAllocated() const MOZ_OVERRIDE { return mBuffer != nullptr; } virtual bool IsAllocated() const MOZ_OVERRIDE { return mBuffer != nullptr; }
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
virtual TextureClientData* DropTextureData() MOZ_OVERRIDE; virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
protected: 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/gfx/Rect.h" // for Rect
#include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder #include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
#include "TextureClientPool.h"
#include "nsDebug.h" // for NS_ASSERTION #include "nsDebug.h" // for NS_ASSERTION
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc #include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
#include "nsSize.h" // for nsIntSize #include "nsSize.h" // for nsIntSize
@ -25,18 +26,23 @@
#include "nsMathUtils.h" // for NS_roundf #include "nsMathUtils.h" // for NS_roundf
#include "gfx2DGlue.h" #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 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
#include "cairo.h" #include "cairo.h"
#include <sstream> #include <sstream>
using mozilla::layers::Layer; 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 // Draw border
c.NewPath(); c.NewPath();
c.SetDeviceColor(gfxRGBA(0.0, 0.0, 0.0, 1.0)); 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(); c.Stroke();
// Build tile description // Build tile description
@ -79,28 +85,37 @@ namespace layers {
TiledContentClient::TiledContentClient(ClientTiledThebesLayer* aThebesLayer, TiledContentClient::TiledContentClient(ClientTiledThebesLayer* aThebesLayer,
ClientLayerManager* aManager) ClientLayerManager* aManager)
: CompositableClient(aManager->AsShadowForwarder()) : CompositableClient(aManager->AsShadowForwarder())
, mTiledBuffer(aThebesLayer, aManager, &mSharedFrameMetricsHelper)
, mLowPrecisionTiledBuffer(aThebesLayer, aManager, &mSharedFrameMetricsHelper)
{ {
MOZ_COUNT_CTOR(TiledContentClient); 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); mLowPrecisionTiledBuffer.SetResolution(gfxPrefs::LowPrecisionResolution()/1000.f);
} }
void 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 ? &mLowPrecisionTiledBuffer
: &mTiledBuffer; : &mTiledBuffer;
// Take an extra ReadLock on behalf of the TiledContentHost. This extra // Take a ReadLock on behalf of the TiledContentHost. This
// reference will be adopted when the descriptor is opened by // reference will be adopted when the descriptor is opened in
// BasicTiledLayerTile::OpenDescriptor. // TiledLayerBufferComposite.
buffer->ReadLock(); buffer->ReadLock();
mForwarder->PaintedTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles()); mForwarder->UseTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
buffer->ClearPaintedRegion(); buffer->ClearPaintedRegion();
} }
@ -229,10 +244,12 @@ SharedFrameMetricsHelper::AboutToCheckerboard(const FrameMetrics& aContentMetric
return !aContentMetrics.mDisplayPort.Contains(aCompositorMetrics.CalculateCompositedRectInCssPixels() - aCompositorMetrics.mScrollOffset); return !aContentMetrics.mDisplayPort.Contains(aCompositorMetrics.CalculateCompositedRectInCssPixels() - aCompositorMetrics.mScrollOffset);
} }
BasicTiledLayerBuffer::BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer, ClientTiledLayerBuffer::ClientTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
CompositableClient* aCompositableClient,
ClientLayerManager* aManager, ClientLayerManager* aManager,
SharedFrameMetricsHelper* aHelper) SharedFrameMetricsHelper* aHelper)
: mThebesLayer(aThebesLayer) : mThebesLayer(aThebesLayer)
, mCompositableClient(aCompositableClient)
, mManager(aManager) , mManager(aManager)
, mLastPaintOpaque(false) , mLastPaintOpaque(false)
, mSharedFrameMetricsHelper(aHelper) , mSharedFrameMetricsHelper(aHelper)
@ -240,14 +257,14 @@ BasicTiledLayerBuffer::BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLaye
} }
bool bool
BasicTiledLayerBuffer::HasFormatChanged() const ClientTiledLayerBuffer::HasFormatChanged() const
{ {
return mThebesLayer->CanUseOpaqueSurface() != mLastPaintOpaque; return mThebesLayer->CanUseOpaqueSurface() != mLastPaintOpaque;
} }
gfxContentType gfxContentType
BasicTiledLayerBuffer::GetContentType() const ClientTiledLayerBuffer::GetContentType() const
{ {
if (mThebesLayer->CanUseOpaqueSurface()) { if (mThebesLayer->CanUseOpaqueSurface()) {
return gfxContentType::COLOR; return gfxContentType::COLOR;
@ -256,54 +273,311 @@ BasicTiledLayerBuffer::GetContentType() const
} }
} }
gfxMemorySharedReadLock::gfxMemorySharedReadLock()
: mReadCount(1)
{
MOZ_COUNT_CTOR(gfxMemorySharedReadLock);
}
gfxMemorySharedReadLock::~gfxMemorySharedReadLock()
{
MOZ_COUNT_DTOR(gfxMemorySharedReadLock);
}
int32_t
gfxMemorySharedReadLock::ReadLock()
{
NS_ASSERT_OWNINGTHREAD(gfxMemorySharedReadLock);
return PR_ATOMIC_INCREMENT(&mReadCount);
}
int32_t
gfxMemorySharedReadLock::ReadUnlock()
{
int32_t readCount = PR_ATOMIC_DECREMENT(&mReadCount);
NS_ASSERTION(readCount >= 0, "ReadUnlock called without ReadLock.");
return readCount;
}
int32_t
gfxMemorySharedReadLock::GetReadCount()
{
NS_ASSERT_OWNINGTHREAD(gfxMemorySharedReadLock);
return mReadCount;
}
gfxShmSharedReadLock::gfxShmSharedReadLock(ISurfaceAllocator* aAllocator)
: mAllocator(aAllocator)
{
MOZ_COUNT_CTOR(gfxShmSharedReadLock);
if (mAllocator) {
#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
if (mAllocator->AllocUnsafeShmem(MOZ_ALIGN_WORD(sizeof(ShmReadLockInfo)),
mozilla::ipc::SharedMemory::TYPE_BASIC, &mShmem)) {
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
info->readCount = 1;
}
}
}
gfxShmSharedReadLock::~gfxShmSharedReadLock()
{
MOZ_COUNT_DTOR(gfxShmSharedReadLock);
}
int32_t
gfxShmSharedReadLock::ReadLock() {
NS_ASSERT_OWNINGTHREAD(gfxShmSharedReadLock);
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
return PR_ATOMIC_INCREMENT(&info->readCount);
}
int32_t
gfxShmSharedReadLock::ReadUnlock() {
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
int32_t readCount = PR_ATOMIC_DECREMENT(&info->readCount);
NS_ASSERTION(readCount >= 0, "ReadUnlock called without a ReadLock.");
if (readCount <= 0) {
mAllocator->DeallocShmem(mShmem);
}
return readCount;
}
int32_t
gfxShmSharedReadLock::GetReadCount() {
NS_ASSERT_OWNINGTHREAD(gfxShmSharedReadLock);
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
return info->readCount;
}
// Placeholder
TileClient::TileClient()
: mBackBuffer(nullptr)
, mFrontBuffer(nullptr)
, mBackLock(nullptr)
, mFrontLock(nullptr)
{
}
TileClient::TileClient(const TileClient& o)
{
mBackBuffer = o.mBackBuffer;
mFrontBuffer = o.mFrontBuffer;
mBackLock = o.mBackLock;
mFrontLock = o.mFrontLock;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
mManager = o.mManager;
mInvalidFront = o.mInvalidFront;
mInvalidBack = o.mInvalidBack;
}
TileClient&
TileClient::operator=(const TileClient& o)
{
if (this == &o) return *this;
mBackBuffer = o.mBackBuffer;
mFrontBuffer = o.mFrontBuffer;
mBackLock = o.mBackLock;
mFrontLock = o.mFrontLock;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
mManager = o.mManager;
mInvalidFront = o.mInvalidFront;
mInvalidBack = o.mInvalidBack;
return *this;
}
void
TileClient::Flip()
{
RefPtr<TextureClient> frontBuffer = mFrontBuffer;
mFrontBuffer = mBackBuffer;
mBackBuffer = frontBuffer;
RefPtr<gfxSharedReadLock> frontLock = mFrontLock;
mFrontLock = mBackLock;
mBackLock = frontLock;
nsIntRegion invalidFront = mInvalidFront;
mInvalidFront = mInvalidBack;
mInvalidBack = invalidFront;
}
void
TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
bool aCanRerasterizeValidRegion)
{
if (mBackBuffer && mFrontBuffer) {
const nsIntRect tileRect = nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
if (aDirtyRegion.Contains(tileRect)) {
// The dirty region means that we no longer need the front buffer, so
// discard it.
DiscardFrontBuffer();
} else {
// Region that needs copying.
nsIntRegion regionToCopy = mInvalidBack;
regionToCopy.Sub(regionToCopy, aDirtyRegion);
if (regionToCopy.IsEmpty() ||
(aCanRerasterizeValidRegion &&
regionToCopy.Area() < MINIMUM_TILE_COPY_AREA)) {
// Just redraw it all.
return;
}
if (!mFrontBuffer->Lock(OPEN_READ)) {
NS_WARNING("Failed to lock the tile's front buffer");
return;
}
TextureClientAutoUnlock autoFront(mFrontBuffer);
if (!mBackBuffer->Lock(OPEN_WRITE)) {
NS_WARNING("Failed to lock the tile's back buffer");
return;
}
TextureClientAutoUnlock autoBack(mBackBuffer);
// Copy the bounding rect of regionToCopy. As tiles are quite small, it
// is unlikely that we'd save much by copying each individual rect of the
// region, but we can reevaluate this if it becomes an issue.
const nsIntRect rectToCopy = regionToCopy.GetBounds();
gfx::IntRect gfxRectToCopy(rectToCopy.x, rectToCopy.y, rectToCopy.width, rectToCopy.height);
gfx::IntPoint gfxRectToCopyTopLeft = gfxRectToCopy.TopLeft();
mFrontBuffer->CopyToTextureClient(mBackBuffer, &gfxRectToCopy, &gfxRectToCopyTopLeft);
mInvalidBack.SetEmpty();
}
}
}
void
TileClient::DiscardFrontBuffer()
{
if (mFrontBuffer) {
MOZ_ASSERT(mFrontLock);
mManager->GetTexturePool(mFrontBuffer->AsTextureClientDrawTarget()->GetFormat())->ReturnTextureClientDeferred(mFrontBuffer);
mFrontLock->ReadUnlock();
mFrontBuffer = nullptr;
mFrontLock = nullptr;
}
}
void
TileClient::DiscardBackBuffer()
{
if (mBackBuffer) {
MOZ_ASSERT(mBackLock);
mManager->GetTexturePool(mBackBuffer->AsTextureClientDrawTarget()->GetFormat())->ReturnTextureClient(mBackBuffer);
mBackLock->ReadUnlock();
mBackBuffer = nullptr;
mBackLock = nullptr;
}
}
TextureClient*
TileClient::GetBackBuffer(const nsIntRegion& aDirtyRegion, TextureClientPool *aPool, bool *aCreatedTextureClient, bool aCanRerasterizeValidRegion)
{
// Try to re-use the front-buffer if possible
if (mFrontBuffer &&
mFrontBuffer->HasInternalBuffer() &&
mFrontLock->GetReadCount() == 1) {
// If we had a backbuffer we no longer care about it since we'll
// re-use the front buffer.
DiscardBackBuffer();
Flip();
return mBackBuffer;
}
if (!mBackBuffer ||
mBackLock->GetReadCount() > 1) {
if (mBackBuffer) {
// Our current back-buffer is still locked by the compositor. This can occur
// when the client is producing faster than the compositor can consume. In
// this case we just want to drop it and not return it to the pool.
aPool->ReportClientLost();
}
mBackBuffer = aPool->GetTextureClient();
// Create a lock for our newly created back-buffer.
if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
// If our compositor is in the same process, we can save some cycles by not
// using shared memory.
mBackLock = new gfxMemorySharedReadLock();
} else {
mBackLock = new gfxShmSharedReadLock(mManager->AsShadowForwarder());
}
*aCreatedTextureClient = true;
mInvalidBack = nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
}
ValidateBackBufferFromFront(aDirtyRegion, aCanRerasterizeValidRegion);
return mBackBuffer;
}
TileDescriptor TileDescriptor
BasicTiledLayerTile::GetTileDescriptor() TileClient::GetTileDescriptor()
{ {
gfxReusableSurfaceWrapper* surface = GetSurface(); if (IsPlaceholderTile()) {
switch (surface->GetType()) {
case gfxReusableSurfaceWrapper::TYPE_IMAGE :
return BasicTileDescriptor(uintptr_t(surface));
case gfxReusableSurfaceWrapper::TYPE_SHARED_IMAGE :
return BasicShmTileDescriptor(static_cast<gfxReusableSharedImageSurfaceWrapper*>(surface)->GetShmem());
default :
NS_NOTREACHED("Unhandled gfxReusableSurfaceWrapper type");
return PlaceholderTileDescriptor(); return PlaceholderTileDescriptor();
} }
MOZ_ASSERT(mFrontLock);
if (mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY) {
// AddRef here and Release when receiving on the host side to make sure the
// reference count doesn't go to zero before the host receives the message.
// see TiledLayerBufferComposite::TiledLayerBufferComposite
mFrontLock->AddRef();
}
return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(),
mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY
? TileLock(uintptr_t(mFrontLock.get()))
: TileLock(static_cast<gfxShmSharedReadLock*>(mFrontLock.get())->GetShmem()));
} }
void
ClientTiledLayerBuffer::ReadUnlock() {
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
mRetainedTiles[i].ReadUnlock();
}
}
/* static */ BasicTiledLayerTile void
BasicTiledLayerTile::OpenDescriptor(ISurfaceAllocator *aAllocator, const TileDescriptor& aDesc) ClientTiledLayerBuffer::ReadLock() {
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
mRetainedTiles[i].ReadLock();
}
}
void
ClientTiledLayerBuffer::Release()
{ {
switch (aDesc.type()) { for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
case TileDescriptor::TBasicShmTileDescriptor : { if (mRetainedTiles[i].IsPlaceholderTile()) continue;
nsRefPtr<gfxReusableSurfaceWrapper> surface = mRetainedTiles[i].Release();
gfxReusableSharedImageSurfaceWrapper::Open( }
aAllocator, aDesc.get_BasicShmTileDescriptor().reusableSurface());
return BasicTiledLayerTile(
new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
} }
case TileDescriptor::TBasicTileDescriptor : { void
nsRefPtr<gfxReusableSurfaceWrapper> surface = ClientTiledLayerBuffer::DiscardBackBuffers()
reinterpret_cast<gfxReusableSurfaceWrapper*>( {
aDesc.get_BasicTileDescriptor().reusableSurface()); for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
surface->ReadUnlock(); if (mRetainedTiles[i].IsPlaceholderTile()) continue;
return BasicTiledLayerTile( mRetainedTiles[i].DiscardBackBuffer();
new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
}
default :
NS_NOTREACHED("Unknown tile descriptor type!");
return nullptr;
} }
} }
SurfaceDescriptorTiles SurfaceDescriptorTiles
BasicTiledLayerBuffer::GetSurfaceDescriptorTiles() ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
{ {
InfallibleTArray<TileDescriptor> tiles; InfallibleTArray<TileDescriptor> tiles;
@ -321,23 +595,8 @@ BasicTiledLayerBuffer::GetSurfaceDescriptorTiles()
mResolution); 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 void
BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion, const nsIntRegion& aPaintRegion,
LayerManager::DrawThebesLayerCallback aCallback, LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData) void* aCallbackData)
@ -371,12 +630,11 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRect bounds = aPaintRegion.GetBounds(); const nsIntRect bounds = aPaintRegion.GetBounds();
{ {
PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferAlloc"); PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferAlloc");
gfxImageFormat format = gfxImageFormat format =
gfxPlatform::GetPlatform()->OptimalFormatForContent( gfxPlatform::GetPlatform()->OptimalFormatForContent(
GetContentType()); GetContentType());
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
mSinglePaintDrawTarget = mSinglePaintDrawTarget =
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
gfx::IntSize(ceilf(bounds.width * mResolution), gfx::IntSize(ceilf(bounds.width * mResolution),
@ -384,14 +642,6 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
gfx::ImageFormatToSurfaceFormat(format)); gfx::ImageFormatToSurfaceFormat(format));
ctxt = new gfxContext(mSinglePaintDrawTarget); ctxt = new gfxContext(mSinglePaintDrawTarget);
} else {
mSinglePaintBuffer = new gfxImageSurface(
gfxIntSize(ceilf(bounds.width * mResolution),
ceilf(bounds.height * mResolution)),
format,
!mThebesLayer->CanUseOpaqueSurface());
ctxt = new gfxContext(mSinglePaintBuffer);
}
mSinglePaintBufferOffset = nsIntPoint(bounds.x, bounds.y); mSinglePaintBufferOffset = nsIntPoint(bounds.x, bounds.y);
} }
@ -404,7 +654,7 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
} }
start = PR_IntervalNow(); start = PR_IntervalNow();
#endif #endif
PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferDraw"); PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw");
mCallback(mThebesLayer, ctxt, aPaintRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), mCallbackData); mCallback(mThebesLayer, ctxt, aPaintRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), mCallbackData);
} }
@ -424,7 +674,7 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
start = PR_IntervalNow(); start = PR_IntervalNow();
#endif #endif
PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesUpdate"); PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesUpdate");
Update(aNewValidRegion, aPaintRegion); Update(aNewValidRegion, aPaintRegion);
#ifdef GFX_TILEDLAYER_PREF_WARNINGS #ifdef GFX_TILEDLAYER_PREF_WARNINGS
@ -437,102 +687,15 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
mLastPaintOpaque = mThebesLayer->CanUseOpaqueSurface(); mLastPaintOpaque = mThebesLayer->CanUseOpaqueSurface();
mCallback = nullptr; mCallback = nullptr;
mCallbackData = nullptr; mCallbackData = nullptr;
mSinglePaintBuffer = nullptr;
mSinglePaintDrawTarget = nullptr; mSinglePaintDrawTarget = nullptr;
} }
BasicTiledLayerTile TileClient
BasicTiledLayerBuffer::ValidateTileInternal(BasicTiledLayerTile aTile, ClientTiledLayerBuffer::ValidateTile(TileClient 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,
const nsIntPoint& aTileOrigin, const nsIntPoint& aTileOrigin,
const nsIntRegion& aDirtyRegion) const nsIntRegion& aDirtyRegion)
{ {
PROFILER_LABEL("BasicTiledLayerBuffer", "ValidateTile"); PROFILER_LABEL("ClientTiledLayerBuffer", "ValidateTile");
#ifdef GFX_TILEDLAYER_PREF_WARNINGS #ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (aDirtyRegion.IsComplex()) { if (aDirtyRegion.IsComplex()) {
@ -540,12 +703,140 @@ BasicTiledLayerBuffer::ValidateTile(BasicTiledLayerTile aTile,
} }
#endif #endif
if (aTile.IsPlaceholderTile()) {
aTile.SetLayerManager(mManager);
}
// Discard our front and backbuffers if our contents changed. In this case
// the calling code will already have taken care of invalidating the entire
// layer.
if (HasFormatChanged()) {
aTile.DiscardBackBuffer();
aTile.DiscardFrontBuffer();
}
bool createdTextureClient = false;
nsIntRegion offsetDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
bool usingSinglePaintBuffer = !!mSinglePaintDrawTarget;
RefPtr<TextureClient> backBuffer =
aTile.GetBackBuffer(offsetDirtyRegion,
mManager->GetTexturePool(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType())),
&createdTextureClient, !usingSinglePaintBuffer);
if (!backBuffer->Lock(OPEN_READ_WRITE)) {
NS_WARNING("Failed to lock tile TextureClient for updating.");
aTile.DiscardFrontBuffer();
return aTile;
}
// We must not keep a reference to the DrawTarget after it has been unlocked,
// make sure these are null'd before unlocking as destruction of the context
// may cause the target to be flushed.
RefPtr<DrawTarget> drawTarget = backBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
drawTarget->SetTransform(Matrix());
RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);
if (usingSinglePaintBuffer) {
// XXX Perhaps we should just copy the bounding rectangle here?
RefPtr<gfx::SourceSurface> source = mSinglePaintDrawTarget->Snapshot();
nsIntRegionRectIterator it(aDirtyRegion); nsIntRegionRectIterator it(aDirtyRegion);
for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) { for (const nsIntRect* dirtyRect = it.Next(); dirtyRect != nullptr; dirtyRect = it.Next()) {
#ifdef GFX_TILEDLAYER_PREF_WARNINGS #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 #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; return aTile;
@ -576,7 +867,7 @@ TransformCompositionBounds(const ScreenRect& aCompositionBounds,
} }
bool bool
BasicTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion, ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
const nsIntRegion& aOldValidRegion, const nsIntRegion& aOldValidRegion,
nsIntRegion& aRegionToPaint, nsIntRegion& aRegionToPaint,
BasicTiledLayerPaintData* aPaintData, BasicTiledLayerPaintData* aPaintData,
@ -735,7 +1026,7 @@ BasicTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvali
} }
bool bool
BasicTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion, ClientTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion,
nsIntRegion& aInvalidRegion, nsIntRegion& aInvalidRegion,
const nsIntRegion& aOldValidRegion, const nsIntRegion& aOldValidRegion,
BasicTiledLayerPaintData* aPaintData, BasicTiledLayerPaintData* aPaintData,

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

@ -16,9 +16,14 @@
#include "gfxTypes.h" #include "gfxTypes.h"
#include "mozilla/Attributes.h" // for MOZ_OVERRIDE #include "mozilla/Attributes.h" // for MOZ_OVERRIDE
#include "mozilla/RefPtr.h" // for RefPtr #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/CompositableClient.h" // for CompositableClient
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc #include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
#include "mozilla/layers/LayersMessages.h" // for TileDescriptor
#include "mozilla/layers/TextureClient.h" #include "mozilla/layers/TextureClient.h"
#include "mozilla/layers/TextureClientPool.h"
#include "ClientLayerManager.h"
#include "mozilla/mozalloc.h" // for operator delete #include "mozilla/mozalloc.h" // for operator delete
#include "nsAutoPtr.h" // for nsRefPtr #include "nsAutoPtr.h" // for nsRefPtr
#include "nsISupportsImpl.h" // for MOZ_COUNT_DTOR #include "nsISupportsImpl.h" // for MOZ_COUNT_DTOR
@ -28,6 +33,8 @@
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc #include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
#include "mozilla/layers/ISurfaceAllocator.h" #include "mozilla/layers/ISurfaceAllocator.h"
#include "gfxReusableSurfaceWrapper.h" #include "gfxReusableSurfaceWrapper.h"
#include "pratom.h" // For PR_ATOMIC_INCREMENT/DECREMENT
#include "gfxPrefs.h"
class gfxImageSurface; class gfxImageSurface;
@ -35,67 +42,186 @@ namespace mozilla {
namespace layers { namespace layers {
class BasicTileDescriptor; 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, * Represent a single tile in tiled buffer. The buffer keeps tiles,
* each tile keeps a reference to a texture client. The texture client * each tile keeps a reference to a texture client and a read-lock. This
* is backed by a gfxReusableSurfaceWrapper that implements a * read-lock is used to help implement a copy-on-write mechanism. The tile
* copy-on-write mechanism while locked. The tile should be * should be locked before being sent to the compositor. The compositor should
* locked before being sent to the compositor and unlocked * unlock the read-lock as soon as it has finished with the buffer in the
* as soon as it is uploaded to prevent a copy. * TextureHost to prevent more textures being created than is necessary.
* Ideal place to store per tile debug information. * Ideal place to store per tile debug information.
*/ */
struct BasicTiledLayerTile { struct TileClient
RefPtr<DeprecatedTextureClientTile> mDeprecatedTextureClient; {
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
TimeStamp mLastUpdate;
#endif
// Placeholder // Placeholder
BasicTiledLayerTile() TileClient();
: mDeprecatedTextureClient(nullptr)
{}
BasicTiledLayerTile(DeprecatedTextureClientTile* aTextureClient) TileClient(const TileClient& o);
: mDeprecatedTextureClient(aTextureClient)
{}
BasicTiledLayerTile(const BasicTiledLayerTile& o) { TileClient& operator=(const TileClient& o);
mDeprecatedTextureClient = o.mDeprecatedTextureClient;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY bool operator== (const TileClient& o) const
mLastUpdate = o.mLastUpdate; {
#endif return mFrontBuffer == o.mFrontBuffer;
}
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;
} }
bool IsPlaceholderTile() { return mDeprecatedTextureClient == nullptr; } bool operator!= (const TileClient& o) const
{
void ReadUnlock() { return mFrontBuffer != o.mFrontBuffer;
GetSurface()->ReadUnlock();
} }
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(); 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; bool mPaintFinished : 1;
}; };
class ClientTiledThebesLayer;
class ClientLayerManager;
class SharedFrameMetricsHelper class SharedFrameMetricsHelper
{ {
public: public:
@ -210,72 +333,45 @@ private:
}; };
/** /**
* Provide an instance of TiledLayerBuffer backed by image surfaces. * Provide an instance of TiledLayerBuffer backed by drawable TextureClients.
* This buffer provides an implementation to ValidateTile using a * This buffer provides an implementation of ValidateTile using a
* thebes callback and can support painting using a single paint buffer * thebes callback and can support painting using a single paint buffer.
* which is much faster then painting directly into the tiles. * Whether a single paint buffer is used is controlled by
* gfxPrefs::PerTileDrawing().
*/ */
class BasicTiledLayerBuffer class ClientTiledLayerBuffer
: public TiledLayerBuffer<BasicTiledLayerBuffer, BasicTiledLayerTile> : public TiledLayerBuffer<ClientTiledLayerBuffer, TileClient>
{ {
friend class TiledLayerBuffer<BasicTiledLayerBuffer, BasicTiledLayerTile>; friend class TiledLayerBuffer<ClientTiledLayerBuffer, TileClient>;
public: public:
BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer, ClientTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
CompositableClient* aCompositableClient,
ClientLayerManager* aManager, ClientLayerManager* aManager,
SharedFrameMetricsHelper* aHelper); SharedFrameMetricsHelper* aHelper);
BasicTiledLayerBuffer() ClientTiledLayerBuffer()
: mThebesLayer(nullptr) : mThebesLayer(nullptr)
, mCompositableClient(nullptr)
, mManager(nullptr) , mManager(nullptr)
, mLastPaintOpaque(false) , mLastPaintOpaque(false)
, mSharedFrameMetricsHelper(nullptr) , 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, void PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion, const nsIntRegion& aPaintRegion,
LayerManager::DrawThebesLayerCallback aCallback, LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData); void* aCallbackData);
void ReadUnlock() { void ReadUnlock();
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
mRetainedTiles[i].ReadUnlock();
}
}
void ReadLock() { void ReadLock();
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
if (mRetainedTiles[i].IsPlaceholderTile()) continue; void Release();
mRetainedTiles[i].ReadLock();
} void DiscardBackBuffers();
}
const CSSToScreenScale& GetFrameResolution() { return mFrameResolution; } const CSSToScreenScale& GetFrameResolution() { return mFrameResolution; }
void SetFrameResolution(const CSSToScreenScale& aResolution) { mFrameResolution = aResolution; } void SetFrameResolution(const CSSToScreenScale& aResolution) { mFrameResolution = aResolution; }
bool HasFormatChanged() const; bool HasFormatChanged() const;
@ -293,12 +389,8 @@ public:
SurfaceDescriptorTiles GetSurfaceDescriptorTiles(); SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
static BasicTiledLayerBuffer OpenDescriptor(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aDescriptor,
SharedFrameMetricsHelper* aHelper);
protected: protected:
BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile, TileClient ValidateTile(TileClient aTile,
const nsIntPoint& aTileRect, const nsIntPoint& aTileRect,
const nsIntRegion& dirtyRect); const nsIntRegion& dirtyRect);
@ -306,35 +398,29 @@ protected:
// buffer and copy it out to the tiles instead of calling PaintThebes() on // buffer and copy it out to the tiles instead of calling PaintThebes() on
// each tile individually. Somewhat surprisingly, this turns out to be faster // each tile individually. Somewhat surprisingly, this turns out to be faster
// on Android. // 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) { void SwapTiles(TileClient& aTileA, TileClient& aTileB) { std::swap(aTileA, aTileB); }
std::swap(aTileA, aTileB);
}
BasicTiledLayerTile GetPlaceholderTile() const { return BasicTiledLayerTile(); } TileClient GetPlaceholderTile() const { return TileClient(); }
private: private:
gfxContentType GetContentType() const; gfxContentType GetContentType() const;
ClientTiledThebesLayer* mThebesLayer; ClientTiledThebesLayer* mThebesLayer;
CompositableClient* mCompositableClient;
ClientLayerManager* mManager; ClientLayerManager* mManager;
LayerManager::DrawThebesLayerCallback mCallback; LayerManager::DrawThebesLayerCallback mCallback;
void* mCallbackData; void* mCallbackData;
CSSToScreenScale mFrameResolution; CSSToScreenScale mFrameResolution;
bool mLastPaintOpaque; bool mLastPaintOpaque;
// The buffer we use when UseSinglePaintBuffer() above is true. // The DrawTarget we use when UseSinglePaintBuffer() above is true.
nsRefPtr<gfxImageSurface> mSinglePaintBuffer;
RefPtr<gfx::DrawTarget> mSinglePaintDrawTarget; RefPtr<gfx::DrawTarget> mSinglePaintDrawTarget;
nsIntPoint mSinglePaintBufferOffset; nsIntPoint mSinglePaintBufferOffset;
SharedFrameMetricsHelper* mSharedFrameMetricsHelper; SharedFrameMetricsHelper* mSharedFrameMetricsHelper;
BasicTiledLayerTile ValidateTileInternal(BasicTiledLayerTile aTile,
const nsIntPoint& aTileOrigin,
const nsIntRect& aDirtyRect);
/** /**
* Calculates the region to update in a single progressive update transaction. * Calculates the region to update in a single progressive update transaction.
* This employs some heuristics to update the most 'sensible' region to * This employs some heuristics to update the most 'sensible' region to
@ -374,6 +460,9 @@ public:
~TiledContentClient() ~TiledContentClient()
{ {
MOZ_COUNT_DTOR(TiledContentClient); MOZ_COUNT_DTOR(TiledContentClient);
mTiledBuffer.Release();
mLowPrecisionTiledBuffer.Release();
} }
virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
@ -381,16 +470,18 @@ public:
return TextureInfo(BUFFER_TILED); return TextureInfo(BUFFER_TILED);
} }
virtual void ClearCachedResources() MOZ_OVERRIDE;
enum TiledBufferType { enum TiledBufferType {
TILED_BUFFER, TILED_BUFFER,
LOW_PRECISION_TILED_BUFFER LOW_PRECISION_TILED_BUFFER
}; };
void LockCopyAndWrite(TiledBufferType aType); void UseTiledLayerBuffer(TiledBufferType aType);
private: private:
SharedFrameMetricsHelper mSharedFrameMetricsHelper; SharedFrameMetricsHelper mSharedFrameMetricsHelper;
BasicTiledLayerBuffer mTiledBuffer; ClientTiledLayerBuffer mTiledBuffer;
BasicTiledLayerBuffer mLowPrecisionTiledBuffer; ClientTiledLayerBuffer mLowPrecisionTiledBuffer;
}; };
} }

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

@ -174,7 +174,9 @@ CompositableHost::Create(const TextureInfo& aTextureInfo)
default: default:
MOZ_CRASH("Unknown CompositableType"); 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(); RefPtr<CompositableBackendSpecificData> data = CreateCompositableBackendSpecificDataOGL();
result->SetCompositableBackendSpecificData(data); result->SetCompositableBackendSpecificData(data);
} }

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

@ -22,6 +22,7 @@
#include "nsDebug.h" // for NS_RUNTIMEABORT #include "nsDebug.h" // for NS_RUNTIMEABORT
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsRegion.h" // for nsIntRegion #include "nsRegion.h" // for nsIntRegion
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
#include "nscore.h" // for nsACString #include "nscore.h" // for nsACString
#include "mozilla/layers/AtomicRefCountedWithFinalize.h" #include "mozilla/layers/AtomicRefCountedWithFinalize.h"
@ -274,6 +275,7 @@ class TextureHost
void Finalize(); void Finalize();
friend class AtomicRefCountedWithFinalize<TextureHost>; friend class AtomicRefCountedWithFinalize<TextureHost>;
public: public:
TextureHost(TextureFlags aFlags); TextureHost(TextureFlags aFlags);
@ -426,6 +428,13 @@ public:
virtual const char *Name() { return "TextureHost"; } virtual const char *Name() { return "TextureHost"; }
virtual void PrintInfo(nsACString& aTo, const char* aPrefix); 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. * Cast to a TextureHost for each backend.
*/ */
@ -461,6 +470,7 @@ public:
~BufferTextureHost(); ~BufferTextureHost();
virtual uint8_t* GetBuffer() = 0; virtual uint8_t* GetBuffer() = 0;
virtual size_t GetBufferSize() = 0; virtual size_t GetBufferSize() = 0;
virtual void Updated(const nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE; virtual void Updated(const nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE;
@ -488,6 +498,8 @@ public:
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE; virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE;
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
protected: protected:
bool Upload(nsIntRegion *aRegion = nullptr); bool Upload(nsIntRegion *aRegion = nullptr);
bool MaybeUpload(nsIntRegion *aRegion = nullptr); bool MaybeUpload(nsIntRegion *aRegion = nullptr);

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

@ -15,6 +15,7 @@
#include "nsPrintfCString.h" // for nsPrintfCString #include "nsPrintfCString.h" // for nsPrintfCString
#include "nsRect.h" // for nsIntRect #include "nsRect.h" // for nsIntRect
#include "nsSize.h" // for nsIntSize #include "nsSize.h" // for nsIntSize
#include "mozilla/layers/TiledContentClient.h"
class gfxReusableSurfaceWrapper; class gfxReusableSurfaceWrapper;
@ -24,39 +25,119 @@ namespace layers {
class Layer; class Layer;
void TiledLayerBufferComposite::TiledLayerBufferComposite()
TiledLayerBufferComposite::Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer, : mFrameResolution(1.0)
const nsIntRegion& aNewValidRegion, , mHasDoubleBufferedTiles(false)
const nsIntRegion& aInvalidateRegion, , mUninitialized(true)
const CSSToScreenScale& aResolution) {}
TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aDescriptor,
const nsIntRegion& aOldPaintedRegion)
{ {
#ifdef GFX_TILEDLAYER_PREF_WARNINGS mUninitialized = false;
printf_stderr("Upload %i, %i, %i, %i\n", aInvalidateRegion.GetBounds().x, aInvalidateRegion.GetBounds().y, aInvalidateRegion.GetBounds().width, aInvalidateRegion.GetBounds().height); mHasDoubleBufferedTiles = false;
long start = PR_IntervalNow(); mValidRegion = aDescriptor.validRegion();
#endif mPaintedRegion = aDescriptor.paintedRegion();
mRetainedWidth = aDescriptor.retainedWidth();
mRetainedHeight = aDescriptor.retainedHeight();
mResolution = aDescriptor.resolution();
mFrameResolution = aResolution; // Combine any valid content that wasn't already uploaded
mMainMemoryTiledBuffer = aMainMemoryTiledBuffer; nsIntRegion oldPaintedRegion(aOldPaintedRegion);
Update(aNewValidRegion, aInvalidateRegion); oldPaintedRegion.And(oldPaintedRegion, mValidRegion);
mMainMemoryTiledBuffer = nullptr; mPaintedRegion.Or(mPaintedRegion, oldPaintedRegion);
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (PR_IntervalNow() - start > 10) { const InfallibleTArray<TileDescriptor>& tiles = aDescriptor.tiles();
printf_stderr("Time to upload %i\n", PR_IntervalNow() - start); 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 void
TiledLayerBufferComposite::ValidateTile(TiledTexture aTile, 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 nsIntPoint& aTileOrigin,
const nsIntRegion& aDirtyRect) const nsIntRegion& aDirtyRect)
{ {
if (aTile.IsPlaceholderTile()) {
NS_WARNING("Placeholder tile encountered in painted region");
return aTile;
}
#ifdef GFX_TILEDLAYER_PREF_WARNINGS #ifdef GFX_TILEDLAYER_PREF_WARNINGS
printf_stderr("Upload tile %i, %i\n", aTileOrigin.x, aTileOrigin.y); printf_stderr("Upload tile %i, %i\n", aTileOrigin.x, aTileOrigin.y);
long start = PR_IntervalNow(); long start = PR_IntervalNow();
#endif #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 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (PR_IntervalNow() - start > 1) { if (PR_IntervalNow() - start > 1) {
@ -66,6 +147,57 @@ TiledLayerBufferComposite::ValidateTile(TiledTexture aTile,
return 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 void
TiledContentHost::Attach(Layer* aLayer, TiledContentHost::Attach(Layer* aLayer,
Compositor* aCompositor, Compositor* aCompositor,
@ -76,70 +208,41 @@ TiledContentHost::Attach(Layer* aLayer,
} }
void void
TiledContentHost::PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator, TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aTiledDescriptor) const SurfaceDescriptorTiles& aTiledDescriptor)
{ {
if (aTiledDescriptor.resolution() < 1) { if (aTiledDescriptor.resolution() < 1) {
mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor, nullptr); if (mPendingLowPrecisionUpload) {
mLowPrecisionRegionToUpload.Or(mLowPrecisionRegionToUpload, mLowPrecisionTiledBuffer.ReadUnlock();
mLowPrecisionMainMemoryTiledBuffer.GetPaintedRegion()); } else {
mLowPrecisionMainMemoryTiledBuffer.ClearPaintedRegion(); mPendingLowPrecisionUpload = true;
mPendingLowPrecisionUpload = true; // If the old buffer has double-buffered tiles, hang onto it so we can
// unlock it after we've composited the new buffer.
// We only need to hang onto the locks, but not the textures.
// Releasing the textures here can help prevent a memory spike in the
// situation that the client starts rendering new content before we get
// to composite the new buffer.
if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
mOldLowPrecisionTiledBuffer = mLowPrecisionTiledBuffer;
mOldLowPrecisionTiledBuffer.ReleaseTextureHosts();
}
}
mLowPrecisionTiledBuffer =
TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
mLowPrecisionTiledBuffer.GetPaintedRegion());
} else {
if (mPendingUpload) {
mTiledBuffer.ReadUnlock();
} else { } else {
mMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor, nullptr);
mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetPaintedRegion());
mMainMemoryTiledBuffer.ClearPaintedRegion();
mPendingUpload = true; mPendingUpload = true;
if (mTiledBuffer.HasDoubleBufferedTiles()) {
mOldTiledBuffer = mTiledBuffer;
mOldTiledBuffer.ReleaseTextureHosts();
} }
} }
mTiledBuffer = TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
void mTiledBuffer.GetPaintedRegion());
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 void
@ -153,24 +256,51 @@ TiledContentHost::Composite(EffectChain& aEffectChain,
{ {
MOZ_ASSERT(aLayerProperties, "aLayerProperties required for TiledContentHost"); 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. // Render valid tiles.
nsIntRect visibleRect = aVisibleRegion->GetBounds(); nsIntRect visibleRect = aVisibleRegion->GetBounds();
RenderLayerBuffer(mLowPrecisionVideoMemoryTiledBuffer, if (mPendingUpload) {
mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion(), aEffectChain, aOpacity, 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); aFilter, aClipRect, aLayerProperties->mValidRegion, visibleRect, aTransform);
RenderLayerBuffer(mVideoMemoryTiledBuffer, aLayerProperties->mValidRegion, aEffectChain, aOpacity, RenderLayerBuffer(mTiledBuffer, aLayerProperties->mValidRegion, aEffectChain, aOpacity,
aFilter, aClipRect, nsIntRegion(), visibleRect, aTransform); 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 void
TiledContentHost::RenderTile(const TiledTexture& aTile, TiledContentHost::RenderTile(const TileHost& aTile,
EffectChain& aEffectChain, EffectChain& aEffectChain,
float aOpacity, float aOpacity,
const gfx::Matrix4x4& aTransform, const gfx::Matrix4x4& aTransform,
@ -180,19 +310,38 @@ TiledContentHost::RenderTile(const TiledTexture& aTile,
const nsIntPoint& aTextureOffset, const nsIntPoint& aTextureOffset,
const nsIntSize& aTextureBounds) 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 = RefPtr<TexturedEffect> effect =
CreateTexturedEffect(aTile.mDeprecatedTextureHost, aFilter); CreateTexturedEffect(aTile.mTextureHost->GetFormat(), source, aFilter);
if (!effect) { if (!effect) {
return; return;
} }
if (aTile.mDeprecatedTextureHost->Lock()) {
aEffectChain.mPrimaryEffect = effect; aEffectChain.mPrimaryEffect = effect;
} else {
return;
}
nsIntRegionRectIterator it(aScreenRegion); nsIntRegionRectIterator it(aScreenRegion);
for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) { 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, mCompositor->DrawDiagnostics(DIAGNOSTIC_CONTENT|DIAGNOSTIC_TILE,
aScreenRegion, aClipRect, aTransform); aScreenRegion, aClipRect, aTransform);
aTile.mDeprecatedTextureHost->Unlock();
} }
void void
@ -231,9 +378,9 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
gfx::Size layerScale(1, 1); gfx::Size layerScale(1, 1);
// We assume that the current frame resolution is the one used in our primary // We assume that the current frame resolution is the one used in our primary
// layer buffer. Compensate for a changing frame resolution. // 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& layerResolution = aLayerBuffer.GetFrameResolution();
const CSSToScreenScale& localResolution = mVideoMemoryTiledBuffer.GetFrameResolution(); const CSSToScreenScale& localResolution = mTiledBuffer.GetFrameResolution();
layerScale.width = layerScale.height = layerResolution.scale / localResolution.scale; layerScale.width = layerScale.height = layerResolution.scale / localResolution.scale;
aVisibleRect.ScaleRoundOut(layerScale.width, layerScale.height); aVisibleRect.ScaleRoundOut(layerScale.width, layerScale.height);
} }
@ -257,7 +404,7 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
h = aVisibleRect.y + aVisibleRect.height - y; h = aVisibleRect.y + aVisibleRect.height - y;
} }
TiledTexture tileTexture = aLayerBuffer. TileHost tileTexture = aLayerBuffer.
GetTile(nsIntPoint(aLayerBuffer.RoundDownToTileEdge(x), GetTile(nsIntPoint(aLayerBuffer.RoundDownToTileEdge(x),
aLayerBuffer.RoundDownToTileEdge(y))); aLayerBuffer.RoundDownToTileEdge(y)));
if (tileTexture != aLayerBuffer.GetPlaceholderTile()) { if (tileTexture != aLayerBuffer.GetPlaceholderTile()) {
@ -292,23 +439,6 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
rect, aClipRect, aTransform); 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 void
TiledContentHost::PrintInfo(nsACString& aTo, const char* aPrefix) TiledContentHost::PrintInfo(nsACString& aTo, const char* aPrefix)
{ {
@ -327,15 +457,19 @@ TiledContentHost::Dump(FILE* aFile,
aFile = stderr; aFile = stderr;
} }
TiledLayerBufferComposite::Iterator it = mVideoMemoryTiledBuffer.TilesBegin(); TiledLayerBufferComposite::Iterator it = mTiledBuffer.TilesBegin();
TiledLayerBufferComposite::Iterator stop = mVideoMemoryTiledBuffer.TilesEnd(); TiledLayerBufferComposite::Iterator stop = mTiledBuffer.TilesEnd();
if (aDumpHtml) { if (aDumpHtml) {
fprintf_stderr(aFile, "<ul>"); fprintf_stderr(aFile, "<ul>");
} }
for (;it != stop; ++it) { for (;it != stop; ++it) {
fprintf_stderr(aFile, "%s", aPrefix); fprintf_stderr(aFile, "%s", aPrefix);
fprintf_stderr(aFile, aDumpHtml ? "<li> <a href=" : "Tile "); 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>" : " "); fprintf_stderr(aFile, aDumpHtml ? " >Tile</a></li>" : " ");
} }
if (aDumpHtml) { if (aDumpHtml) {

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

@ -47,132 +47,138 @@ class TiledThebesLayerComposite;
struct EffectChain; struct EffectChain;
class TiledTexture { class TileHost {
public: 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; // TiledLayerBuffer for more information on what this is used for;
// essentially, this is a sentinel used to represent an invalid or blank // essentially, this is a sentinel used to represent an invalid or blank
// tile. // tile.
TiledTexture() TileHost()
: mDeprecatedTextureHost(nullptr) : mSharedLock(nullptr)
, mTextureHost(nullptr)
{} {}
// Constructs a TiledTexture from a DeprecatedTextureHost. // Constructs a TileHost from a gfxSharedReadLock and TextureHost.
TiledTexture(DeprecatedTextureHost* aDeprecatedTextureHost) TileHost(gfxSharedReadLock* aSharedLock,
: mDeprecatedTextureHost(aDeprecatedTextureHost) TextureHost* aTextureHost)
: mSharedLock(aSharedLock)
, mTextureHost(aTextureHost)
{} {}
TiledTexture(const TiledTexture& o) { TileHost(const TileHost& o) {
mDeprecatedTextureHost = o.mDeprecatedTextureHost; mTextureHost = o.mTextureHost;
mSharedLock = o.mSharedLock;
} }
TiledTexture& operator=(const TiledTexture& o) { TileHost& operator=(const TileHost& o) {
if (this == &o) { if (this == &o) {
return *this; return *this;
} }
mDeprecatedTextureHost = o.mDeprecatedTextureHost; mTextureHost = o.mTextureHost;
mSharedLock = o.mSharedLock;
return *this; return *this;
} }
void Validate(gfxReusableSurfaceWrapper* aReusableSurface, Compositor* aCompositor, uint16_t aSize); 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;
bool operator!= (const TiledTexture& o) const {
if (!mDeprecatedTextureHost || !o.mDeprecatedTextureHost) {
return mDeprecatedTextureHost != o.mDeprecatedTextureHost;
}
return *mDeprecatedTextureHost != *o.mDeprecatedTextureHost;
} }
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 class TiledLayerBufferComposite
: public TiledLayerBuffer<TiledLayerBufferComposite, TiledTexture> : public TiledLayerBuffer<TiledLayerBufferComposite, TileHost>
{ {
friend class TiledLayerBuffer<TiledLayerBufferComposite, TiledTexture>; friend class TiledLayerBuffer<TiledLayerBufferComposite, TileHost>;
public: public:
typedef TiledLayerBuffer<TiledLayerBufferComposite, TiledTexture>::Iterator Iterator; typedef TiledLayerBuffer<TiledLayerBufferComposite, TileHost>::Iterator Iterator;
TiledLayerBufferComposite()
: mCompositor(nullptr)
{}
void Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer, TiledLayerBufferComposite();
const nsIntRegion& aNewValidRegion, TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
const nsIntRegion& aInvalidateRegion, const SurfaceDescriptorTiles& aDescriptor,
const CSSToScreenScale& aResolution); const nsIntRegion& aOldPaintedRegion);
TiledTexture GetPlaceholderTile() const { return TiledTexture(); } TileHost GetPlaceholderTile() const { return TileHost(); }
// Stores the absolute resolution of the containing frame, calculated // Stores the absolute resolution of the containing frame, calculated
// by the sum of the resolutions of all parent layers' FrameMetrics. // by the sum of the resolutions of all parent layers' FrameMetrics.
const CSSToScreenScale& GetFrameResolution() { return mFrameResolution; } const CSSToScreenScale& GetFrameResolution() { return mFrameResolution; }
void SetCompositor(Compositor* aCompositor) void ReadUnlock();
{
mCompositor = aCompositor; 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: protected:
TiledTexture ValidateTile(TiledTexture aTile, TileHost ValidateTile(TileHost aTile,
const nsIntPoint& aTileRect, const nsIntPoint& aTileRect,
const nsIntRegion& dirtyRect); const nsIntRegion& dirtyRect);
// do nothing, the desctructor in the texture host takes care of releasing resources // 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) { void SwapTiles(TileHost& aTileA, TileHost& aTileB) { std::swap(aTileA, aTileB); }
std::swap(aTileA, aTileB);
}
private: private:
Compositor* mCompositor;
const BasicTiledLayerBuffer* mMainMemoryTiledBuffer;
CSSToScreenScale mFrameResolution; CSSToScreenScale mFrameResolution;
bool mHasDoubleBufferedTiles;
bool mUninitialized;
}; };
/** /**
* ContentHost for tiled Thebes layers. Since tiled layers are special snow * ContentHost for tiled Thebes layers. Since tiled layers are special snow
* flakes, we don't call UpdateThebes or AddTextureHost, etc. We do call Composite * flakes, we have a unique update process. All the textures that back the
* in the usual way though. * 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.
* There is no corresponding content client - on the client side we use a * Composition happens in the normal way.
* BasicTiledLayerBuffer owned by a BasicTiledThebesLayer. On the host side, we
* just use a regular ThebesLayerComposite, but with a tiled content host.
* *
* TiledContentHost has a TiledLayerBufferComposite which keeps hold of the tiles. * TiledContentHost has a TiledLayerBufferComposite which keeps hold of the tiles.
* Each tile has a reference to a texture host. During the layers transaction, we * 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 * receive a list of descriptors for the client-side tile buffer tiles
* copied into the main memory tile buffer and then deleted. Copying copies tiles, * (UseTiledLayerBuffer). If we receive two transactions before a composition,
* but we only copy references to the underlying texture clients. * we immediately unlock and discard the unused buffer.
* *
* When the content host is composited, we first upload any pending tiles * When the content host is composited, we first validate the TiledLayerBuffer
* (Process*UploadQueue), then render (RenderLayerBuffer). The former calls Validate * (Upload), which calls Updated on each tile's texture host to make sure the
* on the tile (via ValidateTile and Update), that calls Update on the texture host, * texture data has been uploaded. For single-buffered tiles, we unlock at this
* which works as for regular texture hosts. Rendering takes us to RenderTile which * 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. * is similar to Composite for non-tiled ContentHosts.
*/ */
class TiledContentHost : public ContentHost, class TiledContentHost : public ContentHost,
public TiledLayerComposer public TiledLayerComposer
{ {
public: public:
TiledContentHost(const TextureInfo& aTextureInfo) TiledContentHost(const TextureInfo& aTextureInfo);
: ContentHost(aTextureInfo)
, mPendingUpload(false)
, mPendingLowPrecisionUpload(false)
{
MOZ_COUNT_CTOR(TiledContentHost);
}
~TiledContentHost() ~TiledContentHost();
{
MOZ_COUNT_DTOR(TiledContentHost);
}
virtual LayerRenderState GetRenderState() MOZ_OVERRIDE virtual LayerRenderState GetRenderState() MOZ_OVERRIDE
{ {
@ -191,14 +197,14 @@ public:
const nsIntRegion& GetValidLowPrecisionRegion() const const nsIntRegion& GetValidLowPrecisionRegion() const
{ {
return mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion(); return mLowPrecisionTiledBuffer.GetValidRegion();
} }
void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator, void UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aTiledDescriptor); const SurfaceDescriptorTiles& aTiledDescriptor);
// Renders a single given tile. // Renders a single given tile.
void RenderTile(const TiledTexture& aTile, void RenderTile(const TileHost& aTile,
EffectChain& aEffectChain, EffectChain& aEffectChain,
float aOpacity, float aOpacity,
const gfx::Matrix4x4& aTransform, const gfx::Matrix4x4& aTransform,
@ -228,13 +234,6 @@ public:
MOZ_CRASH("Does nothing"); 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, virtual void Attach(Layer* aLayer,
Compositor* aCompositor, Compositor* aCompositor,
AttachFlags aFlags = NO_FLAGS) MOZ_OVERRIDE; AttachFlags aFlags = NO_FLAGS) MOZ_OVERRIDE;
@ -248,10 +247,6 @@ public:
virtual void PrintInfo(nsACString& aTo, const char* aPrefix); virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
private: private:
void ProcessUploadQueue(nsIntRegion* aNewValidRegion,
TiledLayerProperties* aLayerProperties);
void ProcessLowPrecisionUploadQueue();
void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer, void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
const nsIntRegion& aValidRegion, const nsIntRegion& aValidRegion,
EffectChain& aEffectChain, EffectChain& aEffectChain,
@ -264,12 +259,10 @@ private:
void EnsureTileStore() {} void EnsureTileStore() {}
nsIntRegion mRegionToUpload; TiledLayerBufferComposite mTiledBuffer;
nsIntRegion mLowPrecisionRegionToUpload; TiledLayerBufferComposite mLowPrecisionTiledBuffer;
BasicTiledLayerBuffer mMainMemoryTiledBuffer; TiledLayerBufferComposite mOldTiledBuffer;
BasicTiledLayerBuffer mLowPrecisionMainMemoryTiledBuffer; TiledLayerBufferComposite mOldLowPrecisionTiledBuffer;
TiledLayerBufferComposite mVideoMemoryTiledBuffer;
TiledLayerBufferComposite mLowPrecisionVideoMemoryTiledBuffer;
bool mPendingUpload : 1; bool mPendingUpload : 1;
bool mPendingLowPrecisionUpload : 1; bool mPendingLowPrecisionUpload : 1;
}; };

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

@ -709,30 +709,6 @@ LayerManagerD3D10::Render(EndTransactionFlags aFlags)
static_cast<LayerD3D10*>(mRoot->ImplData())->RenderLayer(); 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 // See bug 630197 - we have some reasons to believe if an earlier call
// returned an error, the upcoming present call may raise an exception. // 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 // 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 technique10 PrepareAlphaExtractionTextures
{ {
pass P0 pass P0

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -45,6 +45,8 @@ public:
virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; } virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; }
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE; virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; } virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }

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

@ -261,25 +261,6 @@ LayerManagerD3D9::Render()
static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer(); 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(); device()->EndScene();
if (!mTarget) { if (!mTarget) {

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

@ -219,6 +219,8 @@ public:
virtual bool AllocateForSurface(gfx::IntSize aSize, virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE; TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE;
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
private: private:
RefPtr<IDirect3DTexture9> mTexture; RefPtr<IDirect3DTexture9> mTexture;
nsRefPtr<IDirect3DSurface9> mD3D9Surface; nsRefPtr<IDirect3DSurface9> mD3D9Surface;
@ -271,6 +273,8 @@ public:
virtual bool AllocateForSurface(gfx::IntSize aSize, virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE; TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE;
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
protected: protected:
nsRefPtr<gfxWindowsSurface> mSurface; nsRefPtr<gfxWindowsSurface> mSurface;
RefPtr<gfx::DrawTarget> mDrawTarget; RefPtr<gfx::DrawTarget> mDrawTarget;
@ -353,6 +357,8 @@ public:
return nullptr; return nullptr;
} }
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; }
protected: protected:
TextureHostD3D9(TextureFlags aFlags); TextureHostD3D9(TextureFlags aFlags);
IDirect3DDevice9* GetDevice(); IDirect3DDevice9* GetDevice();

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

@ -28,7 +28,7 @@ class SurfaceDescriptor;
class SurfaceDescriptorTiles; class SurfaceDescriptorTiles;
class ThebesBufferData; class ThebesBufferData;
class DeprecatedTextureClient; class DeprecatedTextureClient;
class BasicTiledLayerBuffer; class ClientTiledLayerBuffer;
class PTextureChild; class PTextureChild;
/** /**
@ -49,7 +49,6 @@ public:
CompositableForwarder() CompositableForwarder()
: mSerial(++sSerialCounter) : mSerial(++sSerialCounter)
, mMultiProcess(false)
{} {}
/** /**
@ -92,7 +91,11 @@ public:
*/ */
virtual void DestroyThebesBuffer(CompositableClient* aCompositable) = 0; virtual void DestroyThebesBuffer(CompositableClient* aCompositable) = 0;
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable, /**
* Tell the CompositableHost on the compositor side what TiledLayerBuffer to
* use for the next composition.
*/
virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTiledDescriptor) = 0; const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
/** /**
@ -222,7 +225,7 @@ public:
* We only don't allow changing the backend type at runtime so this value can * 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. * be queried once and will not change until Gecko is restarted.
*/ */
LayersBackend GetCompositorBackendType() const virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE
{ {
return mTextureFactoryIdentifier.mParentBackend; return mTextureFactoryIdentifier.mParentBackend;
} }
@ -237,11 +240,6 @@ public:
return mTextureFactoryIdentifier.mSupportsPartialUploads; return mTextureFactoryIdentifier.mSupportsPartialUploads;
} }
bool ForwardsToDifferentProcess() const
{
return mMultiProcess;
}
const TextureFactoryIdentifier& GetTextureFactoryIdentifier() const const TextureFactoryIdentifier& GetTextureFactoryIdentifier() const
{ {
return mTextureFactoryIdentifier; return mTextureFactoryIdentifier;
@ -254,7 +252,6 @@ protected:
nsTArray<RefPtr<TextureClient> > mTexturesToRemove; nsTArray<RefPtr<TextureClient> > mTexturesToRemove;
const int32_t mSerial; const int32_t mSerial;
static mozilla::Atomic<int32_t> sSerialCounter; static mozilla::Atomic<int32_t> sSerialCounter;
bool mMultiProcess;
}; };
} // namespace } // namespace

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

@ -29,7 +29,7 @@
namespace mozilla { namespace mozilla {
namespace layers { namespace layers {
class BasicTiledLayerBuffer; class ClientTiledLayerBuffer;
class Compositor; class Compositor;
template<typename T> template<typename T>
@ -224,9 +224,9 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
compositable->SetPictureRect(op.picture()); compositable->SetPictureRect(op.picture());
break; break;
} }
case CompositableOperation::TOpPaintTiledLayerBuffer: { case CompositableOperation::TOpUseTiledLayerBuffer: {
MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer")); 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()); CompositableParent* compositableParent = static_cast<CompositableParent*>(op.compositableParent());
CompositableHost* compositable = CompositableHost* compositable =
compositableParent->GetCompositableHost(); compositableParent->GetCompositableHost();
@ -235,7 +235,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
NS_ASSERTION(tileComposer, "compositable is not a tile composer"); NS_ASSERTION(tileComposer, "compositable is not a tile composer");
const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor(); const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor();
tileComposer->PaintedTiledLayerBuffer(this, tileDesc); tileComposer->UseTiledLayerBuffer(this, tileDesc);
break; break;
} }
case CompositableOperation::TOpRemoveTexture: { case CompositableOperation::TOpRemoveTexture: {

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

@ -14,6 +14,7 @@
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "nsIMemoryReporter.h" // for nsIMemoryReporter #include "nsIMemoryReporter.h" // for nsIMemoryReporter
#include "mozilla/Atomics.h" // for Atomic #include "mozilla/Atomics.h" // for Atomic
#include "LayersTypes.h"
/* /*
* FIXME [bjacob] *** PURE CRAZYNESS WARNING *** * FIXME [bjacob] *** PURE CRAZYNESS WARNING ***
@ -79,6 +80,16 @@ public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator) MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator)
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. * 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 * Ownership of this memory is passed when the memory is sent in an IPDL

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

@ -32,7 +32,7 @@ class Shmem;
namespace layers { namespace layers {
class BasicTiledLayerBuffer; class ClientTiledLayerBuffer;
class ImageClient; class ImageClient;
class ImageContainer; class ImageContainer;
class ImageBridgeParent; class ImageBridgeParent;
@ -280,7 +280,7 @@ public:
virtual void RemoveTexture(TextureClient* aTexture) MOZ_OVERRIDE; virtual void RemoveTexture(TextureClient* aTexture) MOZ_OVERRIDE;
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable, virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE
{ {
NS_RUNTIMEABORT("should not be called"); NS_RUNTIMEABORT("should not be called");

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

@ -58,6 +58,12 @@ ImageBridgeParent::~ImageBridgeParent()
} }
} }
LayersBackend
ImageBridgeParent::GetCompositorBackendType() const
{
return Compositor::GetBackend();
}
void void
ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy) ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
{ {

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

@ -42,6 +42,8 @@ public:
ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport); ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport);
~ImageBridgeParent(); ~ImageBridgeParent();
virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE; virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
static PImageBridgeParent* static PImageBridgeParent*

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

@ -174,6 +174,12 @@ LayerTransactionParent::Destroy()
} }
} }
LayersBackend
LayerTransactionParent::GetCompositorBackendType() const
{
return mLayerManager->GetBackendType();
}
/* virtual */ /* virtual */
bool bool
LayerTransactionParent::RecvUpdateNoSwap(const InfallibleTArray<Edit>& cset, LayerTransactionParent::RecvUpdateNoSwap(const InfallibleTArray<Edit>& cset,

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

@ -75,6 +75,8 @@ public:
PLayerTransactionParent::DeallocShmem(aShmem); PLayerTransactionParent::DeallocShmem(aShmem);
} }
virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
virtual bool IsSameProcess() const MOZ_OVERRIDE; virtual bool IsSameProcess() const MOZ_OVERRIDE;
protected: protected:

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

@ -255,8 +255,34 @@ struct OpRaiseToTopChild { PLayer container; PLayer childLayer; };
struct OpSetDiagnosticTypes { DiagnosticTypes diagnostics; }; struct OpSetDiagnosticTypes { DiagnosticTypes diagnostics; };
// Paint (buffer update) union TileLock {
struct OpPaintTiledLayerBuffer { 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; PCompositable compositable;
SurfaceDescriptorTiles tileLayerDescriptor; SurfaceDescriptorTiles tileLayerDescriptor;
}; };
@ -349,7 +375,7 @@ union CompositableOperation {
OpPaintTextureRegion; OpPaintTextureRegion;
OpPaintTextureIncremental; OpPaintTextureIncremental;
OpPaintTiledLayerBuffer; OpUseTiledLayerBuffer;
OpRemoveTexture; OpRemoveTexture;

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

@ -56,32 +56,6 @@ struct SharedTextureDescriptor {
bool inverted; 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 { struct NewSurfaceDescriptorGralloc {
PGrallocBuffer buffer; PGrallocBuffer buffer;
/** /**

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

@ -49,7 +49,7 @@ class Shmem;
namespace layers { namespace layers {
class BasicTiledLayerBuffer; class ClientTiledLayerBuffer;
typedef nsTArray<SurfaceDescriptor> BufferArray; typedef nsTArray<SurfaceDescriptor> BufferArray;
typedef std::vector<Edit> EditVector; typedef std::vector<Edit> EditVector;
@ -177,7 +177,6 @@ void
CompositableForwarder::IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier) CompositableForwarder::IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier)
{ {
mTextureFactoryIdentifier = aIdentifier; mTextureFactoryIdentifier = aIdentifier;
mMultiProcess = aIdentifier.mParentProcessId != XRE_GetProcessType();
} }
ShadowLayerForwarder::ShadowLayerForwarder() ShadowLayerForwarder::ShadowLayerForwarder()
@ -327,10 +326,10 @@ ShadowLayerForwarder::CheckSurfaceDescriptor(const SurfaceDescriptor* aDescripto
#endif #endif
void void
ShadowLayerForwarder::PaintedTiledLayerBuffer(CompositableClient* aCompositable, ShadowLayerForwarder::UseTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTileLayerDescriptor) const SurfaceDescriptorTiles& aTileLayerDescriptor)
{ {
mTxn->AddNoSwapPaint(OpPaintTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(), mTxn->AddNoSwapPaint(OpUseTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(),
aTileLayerDescriptor)); aTileLayerDescriptor));
} }

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

@ -28,7 +28,7 @@ class gfxASurface;
namespace mozilla { namespace mozilla {
namespace layers { namespace layers {
class BasicTiledLayerBuffer; class ClientTiledLayerBuffer;
class CanvasClient; class CanvasClient;
class CanvasLayerComposite; class CanvasLayerComposite;
class CanvasSurface; class CanvasSurface;
@ -255,13 +255,9 @@ public:
ShadowableLayer* aMaskLayer); ShadowableLayer* aMaskLayer);
/** /**
* Notify the compositor that a tiled layer buffer has changed * See CompositableForwarder::UseTiledLayerBuffer
* 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).
*/ */
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable, virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE; const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE;
/** /**

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

@ -106,6 +106,7 @@ EXPORTS.mozilla.layers += [
'client/ContentClient.h', 'client/ContentClient.h',
'client/ImageClient.h', 'client/ImageClient.h',
'client/TextureClient.h', 'client/TextureClient.h',
'client/TextureClientPool.h',
'client/TiledContentClient.h', 'client/TiledContentClient.h',
'composite/APZCTreeManager.h', 'composite/APZCTreeManager.h',
'composite/AsyncCompositionManager.h', 'composite/AsyncCompositionManager.h',
@ -234,6 +235,7 @@ UNIFIED_SOURCES += [
'client/ContentClient.cpp', 'client/ContentClient.cpp',
'client/ImageClient.cpp', 'client/ImageClient.cpp',
'client/TextureClient.cpp', 'client/TextureClient.cpp',
'client/TextureClientPool.cpp',
'client/TiledContentClient.cpp', 'client/TiledContentClient.cpp',
'composite/APZCTreeManager.cpp', 'composite/APZCTreeManager.cpp',
'composite/AsyncCompositionManager.cpp', 'composite/AsyncCompositionManager.cpp',

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

@ -47,6 +47,7 @@
#if MOZ_ANDROID_OMTC #if MOZ_ANDROID_OMTC
#include "TexturePoolOGL.h" #include "TexturePoolOGL.h"
#endif #endif
#include "GeckoProfiler.h" #include "GeckoProfiler.h"
#define BUFFER_OFFSET(i) ((char *)nullptr + (i)) #define BUFFER_OFFSET(i) ((char *)nullptr + (i))
@ -136,6 +137,72 @@ DrawQuads(GLContext *aGLContext,
aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 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, CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
int aSurfaceHeight, bool aUseExternalSurfaceSize) int aSurfaceHeight, bool aUseExternalSurfaceSize)
: mWidget(aWidget) : mWidget(aWidget)
@ -1299,6 +1366,12 @@ CompositorOGL::EndFrame()
mCurrentRenderTarget = nullptr; mCurrentRenderTarget = nullptr;
#ifdef MOZ_WIDGET_GONK
if (mCompositorBackendSpecificData) {
static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositorBackendSpecificData.get())->EndFrame();
}
#endif
mGLContext->SwapBuffers(); mGLContext->SwapBuffers();
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
} }
@ -1407,6 +1480,17 @@ CompositorOGL::Resume()
return true; return true;
} }
#ifdef MOZ_WIDGET_GONK
CompositorBackendSpecificData*
CompositorOGL::GetCompositorBackendSpecificData()
{
if (!mCompositorBackendSpecificData) {
mCompositorBackendSpecificData = new CompositorOGLGonkBackendSpecificData(this);
}
return mCompositorBackendSpecificData;
}
#endif
TemporaryRef<DataTextureSource> TemporaryRef<DataTextureSource>
CompositorOGL::CreateDataTextureSource(TextureFlags aFlags) CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
{ {

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

@ -31,6 +31,9 @@
#include "nsXULAppAPI.h" // for XRE_GetProcessType #include "nsXULAppAPI.h" // for XRE_GetProcessType
#include "nscore.h" // for NS_IMETHOD #include "nscore.h" // for NS_IMETHOD
#include "VBOArena.h" // for gl::VBOArena #include "VBOArena.h" // for gl::VBOArena
#ifdef MOZ_WIDGET_GONK
#include <ui/GraphicBuffer.h>
#endif
class gfx3DMatrix; class gfx3DMatrix;
class nsIWidget; class nsIWidget;
@ -159,6 +162,10 @@ public:
virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; } virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
#ifdef MOZ_WIDGET_GONK
virtual CompositorBackendSpecificData* GetCompositorBackendSpecificData() MOZ_OVERRIDE;
#endif
GLContext* gl() const { return mGLContext; } GLContext* gl() const { return mGLContext; }
gfx::SurfaceFormat GetFBOFormat() const { gfx::SurfaceFormat GetFBOFormat() const {
return gfx::SurfaceFormat::R8G8B8A8; return gfx::SurfaceFormat::R8G8B8A8;
@ -313,8 +320,32 @@ private:
* FlipY for the y-flipping calculation. * FlipY for the y-flipping calculation.
*/ */
GLint mHeight; 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/gfx/2D.h"
#include "mozilla/layers/GrallocTextureClient.h" #include "mozilla/layers/GrallocTextureClient.h"
#include "mozilla/layers/CompositableClient.h"
#include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/ISurfaceAllocator.h" #include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/layers/ShadowLayerUtilsGralloc.h" #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
@ -95,28 +94,16 @@ GrallocTextureClientOGL::GrallocTextureClientOGL(GrallocBufferActor* aActor,
gfx::IntSize aSize, gfx::IntSize aSize,
TextureFlags aFlags) TextureFlags aFlags)
: BufferTextureClient(nullptr, gfx::SurfaceFormat::UNKNOWN, aFlags) : BufferTextureClient(nullptr, gfx::SurfaceFormat::UNKNOWN, aFlags)
, mAllocator(nullptr)
, mMappedBuffer(nullptr) , mMappedBuffer(nullptr)
{ {
InitWith(aActor, aSize); InitWith(aActor, aSize);
MOZ_COUNT_CTOR(GrallocTextureClientOGL); 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, GrallocTextureClientOGL::GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat, gfx::SurfaceFormat aFormat,
TextureFlags aFlags) TextureFlags aFlags)
: BufferTextureClient(nullptr, aFormat, aFlags) : BufferTextureClient(aAllocator, aFormat, aFlags)
, mAllocator(aAllocator)
, mMappedBuffer(nullptr) , mMappedBuffer(nullptr)
{ {
MOZ_COUNT_CTOR(GrallocTextureClientOGL); MOZ_COUNT_CTOR(GrallocTextureClientOGL);
@ -457,15 +444,6 @@ GrallocTextureClientOGL::GetBufferSize() const
return 0; return 0;
} }
ISurfaceAllocator*
GrallocTextureClientOGL::GetAllocator()
{
MOZ_ASSERT(mCompositable || mAllocator);
return mCompositable ?
mCompositable->GetForwarder() :
mAllocator;
}
} // namesapace layers } // namesapace layers
} // namesapace mozilla } // namesapace mozilla

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

@ -37,9 +37,6 @@ public:
GrallocTextureClientOGL(GrallocBufferActor* aActor, GrallocTextureClientOGL(GrallocBufferActor* aActor,
gfx::IntSize aSize, gfx::IntSize aSize,
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT); TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
GrallocTextureClientOGL(CompositableClient* aCompositable,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
GrallocTextureClientOGL(ISurfaceAllocator* aAllocator, GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat, gfx::SurfaceFormat aFormat,
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT); TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
@ -52,6 +49,8 @@ public:
virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; } virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; }
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
virtual bool IsAllocated() const MOZ_OVERRIDE; virtual bool IsAllocated() const MOZ_OVERRIDE;
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE; virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
@ -107,8 +106,6 @@ public:
void SetGraphicBufferLocked(GraphicBufferLocked* aBufferLocked); void SetGraphicBufferLocked(GraphicBufferLocked* aBufferLocked);
protected: protected:
ISurfaceAllocator* GetAllocator();
/** /**
* Unfortunately, until bug 879681 is fixed we need to use a GrallocBufferActor. * Unfortunately, until bug 879681 is fixed we need to use a GrallocBufferActor.
*/ */
@ -118,8 +115,6 @@ protected:
android::sp<android::GraphicBuffer> mGraphicBuffer; android::sp<android::GraphicBuffer> mGraphicBuffer;
RefPtr<ISurfaceAllocator> mAllocator;
/** /**
* Points to a mapped gralloc buffer between calls to lock and unlock. * Points to a mapped gralloc buffer between calls to lock and unlock.
* Should be null outside of the lock-unlock pair. * Should be null outside of the lock-unlock pair.

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

@ -104,7 +104,8 @@ GrallocTextureSourceOGL::~GrallocTextureSourceOGL()
mCompositor = nullptr; 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 * 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()->fActiveTexture(aTextureUnit);
gl()->fBindTexture(textureTarget, tex); 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) { if (!mEGLImage) {
mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer()); mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
} }
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage); gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
}
gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
} }
void GrallocTextureSourceOGL::Lock()
{
if (mCompositableBackendData) return;
MOZ_ASSERT(IsValid());
CompositorOGLGonkBackendSpecificData* backendData =
static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositor->GetCompositorBackendSpecificData());
mTexture = backendData->GetTexture();
GLuint textureTarget = GetTextureTarget();
gl()->MakeCurrent();
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(textureTarget, mTexture);
if (!mEGLImage) {
mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
}
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
}
bool bool
GrallocTextureSourceOGL::IsValid() const GrallocTextureSourceOGL::IsValid() const
{ {
return !!gl() && !!mGraphicBuffer.get(); return !!gl() && !!mGraphicBuffer.get() && (!!mCompositor || !!mCompositableBackendData);
} }
gl::GLContext* gl::GLContext*
@ -178,7 +208,7 @@ GrallocTextureSourceOGL::GetFormat() const {
void void
GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
{ {
if (!aBackendData || !mGraphicBuffer.get()) { if (!aBackendData) {
mCompositableBackendData = nullptr; mCompositableBackendData = nullptr;
DeallocateDeviceData(); DeallocateDeviceData();
return; return;
@ -285,7 +315,11 @@ GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor)
bool bool
GrallocTextureHostOGL::Lock() GrallocTextureHostOGL::Lock()
{ {
return IsValid(); if (IsValid()) {
mTextureSource->Lock();
return true;
}
return false;
} }
void void
@ -384,10 +418,14 @@ GrallocTextureSourceOGL::GetAsSurface() {
GLuint GLuint
GrallocTextureSourceOGL::GetGLTexture() GrallocTextureSourceOGL::GetGLTexture()
{ {
if (mCompositableBackendData) {
mCompositableBackendData->SetCompositor(mCompositor); mCompositableBackendData->SetCompositor(mCompositor);
return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture(); return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture();
} }
return mTexture;
}
void void
GrallocTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) GrallocTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
{ {

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

@ -62,10 +62,13 @@ public:
GLuint GetGLTexture(); GLuint GetGLTexture();
void Lock();
protected: protected:
CompositorOGL* mCompositor; CompositorOGL* mCompositor;
android::sp<android::GraphicBuffer> mGraphicBuffer; android::sp<android::GraphicBuffer> mGraphicBuffer;
EGLImage mEGLImage; EGLImage mEGLImage;
GLuint mTexture;
gfx::SurfaceFormat mFormat; gfx::SurfaceFormat mFormat;
bool mNeedsReset; bool mNeedsReset;
}; };

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

@ -36,6 +36,8 @@ public:
virtual TextureClientData* DropTextureData() MOZ_OVERRIDE; virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
protected: protected:
RefPtr<MacIOSurface> mSurface; RefPtr<MacIOSurface> mSurface;
bool mIsLocked; bool mIsLocked;

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