mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1173364 - support ARIA table and cell roles, r=marcoz (c6f9fc891e) - Bug 1205318 - make aria-owns loop alg more sophisticated, r=yzen (d287b1e41c) - Bug 1205476 - crash in mozilla::a11y::DocAccessible::ProcessInvalidationList(), r=smaug (bf920abdd3) - Bug 1205476 - crash in mozilla::a11y::DocAccessible::ProcessInvalidationList(), part3, r=davidb (675c3a0ee2) - Bug 1205476 - crash in mozilla::a11y::DocAccessible::ProcessInvalidationList, part2, r=davidb (a7cd835169) - Bug 1186786 - Replace nsBaseHashtable::EnumerateRead() calls in accessible/ with iterators. r=tbsaunde. (172fcbe18f) - Bug 1219299 - rework aria-owns implementation, r=yzen (c297a84b41) - Bug 1219744 - no child_of/parent_of relations for aria-owns, r=yzen (38ea8be268) - Bug 1205341 - get rid of aria-owns provided relations, part1: remove ARIA combobox special support (bug 819273 backout), r=yzen (0ca03a27bd) - Bug 1219743 - remove special ARIA owns support for ARIA menus, r=yzen (64468fdfd1) - Bug 1200595 - Introduce TextureData and implement it for X11. r=mattwoodrow, Bas, sotaro (2e6bc3f02c) - Bug 1200595 - Buffer TextureData implementation. r=mattwoodrow (1cb3ffd937) - Bug 1227415 - Fix copy buffer size r=jolin (344130daec) - Bug 1200595 - Gralloc TextureData implementation. r=sotaro (a0726233ca) - Bug 1205725 - Add basic SidebandStream handling to HwcComposer2D r=mwu,nical (42bea59a5f) - namespace (ab69730d53) - Bug 1194775 - Paper over a crash in ContentClient. r=Bas (998051cee4) - minor (c24c0b069d) - Bug 1197315 - remove PR_snprintf calls in gfx/; r=froydnj (f153fed9c8) - Bug 1157664 - Initialize mozilla::layers::FPSCOUNTER::mIteratorIndex. r=nical (cf5d2203ee) - Bug 1157663 - Init mMap in the constructor to avoid half initialized structures. r=nical (d972306493) - Bug 1167370: Check for Map() call failing. r=bas (707eda52ff) - Bug 1221276 - Don't crash if we don't have a surface. r=nical (c53141ea3d) - Bug 1219230 - Use the valid region for determining buffer size instead of the visible region. r=mstange (f2d4783eef) - Pass the correct moz2d backend in CanvasClients. (bug 1212499, r=mattwoodrow) (c16688afbb) - Bug 1179987 - Simplify unlocking of tiled texture hosts. r=nical (781200f702) - Bug 1170189 - Fix tiling crash on Linux. r=jrmuizel (879bbfb506) - Bug 1170189 - fix a comment in the tiling code. r=BenWa (62b47f1bbd) - Bug 1179987 - Make tiled TextureSource recycling based on pointer comparisons rather than trying to do it geometrically. r=nical (7bde534929) - Bug 1189710 - Use correct offset for LayerRenderState in TiledContentHost. r=jrmuizel (cb93c2f98a) - Bug 1215050 - Make layerscope support TiledPaintedLayer when using HWC. r=mattwoodrow, r=cjku (6bffac30f8) - Bug 1186208 - Fix crash when tiling is enabled on linux. r=mattwoodrow (b2f2c85734) - Bug 1197713 - Add missing gfxPrefs.h include to TiledContentHost.cpp. r=nical (22bce4e071) - Bug 1143575. Async image invalidation does not necessarily need to invalidate the layer; LayerTreeInvalidation will do that for us. r=mattwoodrow (a6144b7127) - Bug 1219529 - Don't attempt to deallocate shmems after the ipdl protocol is shut down. r=sotaro (3bb89ef36e) - Bug 1143575. Add assertion for diagnostic purposes. r=nical (e4944dd72f) - Bug 1202175 - Guard GLX-specific call in SurfaceDescriptorX11. r=jgilbert (167a4aa49b) - Bug 1132528 - Handle non existent key r=nical (6c12df1446) - Bug 1137151: Marked destructor of |GrallocReporter| as protected, r=jmuizelaar (57605c4472) - Bug 1145389 - Add gralloc allocation requet size check r=nical (47c6065148) - Bug 1181197 - Fix null dereference in SharedPlanarYCbCrImage destructor. r=jgilbert (3f8c390a6f) - Bug 1195110 - Check if GLContext is destroyed before freeing resources in CompositingRenderTargetOGL. r=jrmuizel (8eac603d84) - bug 1178956 - Specify precision in OGLShaderProgram.cpp to fix compositor on iOS. r=kip (daa6d9db20) - Bug 1186725 - InitTextures should check if LockRect() returns an error, r=mattwoodrow (bc87f908a7) - Bug 1170143 - Add some error checks around the creation of dxgi ycbcrvideo frames. r=Bas (c96e4d9e79) - Bug 1170143 - Build fix. r=me (a9d0064bc3) - Bug 1202700 - Use d3d9 device to upload YCbCr surfaces on the client side if possible. r=Bas (3ccd0c68f5) - Bug 1199361 - Add texture memory reporters for YCbCr TextureClients. r=jrmuizel (723e9d4b10) - bug 1183967 - fixup correct case of mfidl.h (e9abd04709) - Bug 1133007 - followup - make CreateServerSocketRunnable's constructor explicit; r=bustage (5de0ec7900) - Bug 1195653 - Part1.1: Dump SecondaryEffects (EffectTypes::MASK) on Layerscope viewer. r=dglastonbury (v2, carry r+) (a6736ad381) - Bug 1195653 - Part1.2: Use sSentTextureIds instead of sTextureIdList and move HasTextureIdBeenSent into SendTextureSource. r=dglastonbury (v3, carry r+) (7e0b14bca6) - Bug 1195653 - Part1.3: Add isMask attribute field to LayerScopePacket.proto. r=dglastonbury (v2, carry r+) (510e50e09a) - Bug 1195653 - Part1.4: Generated file diffs from patched LayerScopePacket.proto. r=dglastonbury (v1, carry r+) (f1824afcb3) - Bug 1195653 - Part1.5: Send isMask info to LayerScope viewer by TexturePacket. r=dglastonbury (v3) (1722e5e6fe) - Bug 1205521 - Part1: (v3) Add texture/mask attribute fields in LayerScopePacket.proto. r=dglastonbury (0cca15f8f5) - Bug 1205521 - Part2: (v3) Generated file diffs from patched LayerScopePacket.proto. r=dglastonbury (6253724bcf) - Bug 1205521 - Part3: (v3) Dump texture/mask attributes on layerscope viewer. r=dglastonbury (31d346bad1) - Bug 1205521 - Part4: (v2) Align LayerScopePacket to fit changes in Bug 1211324. r=dglastonbury (712da0fe9c) - Bug 1177023 - Log the IsRootContent flag when dumping framemetrics. r=botond (9bea51f318) - Bug 1153724 - Only assert if the size was reasonable to start. r=mchang (c3d61bbee1) - namespace (edcce0a0b3) - Bug 1195857: Make nsPresContext::HasAuthorSpecifiedRules()'s arg 'const', to remove need for const_cast in callers. r=jwatt (274fe66dca) - Bug 1182414, part 1 - Fix printing crash with range input controls. r=dholbert (352a408a83) - Bug 1182414, part 2 - Add printing crash test. r=dholbert (0fc9bd4529) - Bug 1099103 - Prevent numbers input using a grouping separator from being mis-processed as if the separator was a decimal separator. r=dholbert (90276c2f6b) - Bug 1157142 - Support logical (inline/block) in addition to physical orientation for the <input type=range> element; make inline the default behavior so that range sliders respect writing mode. r=jwatt (2ec37cbba8)
This commit is contained in:
@@ -98,6 +98,16 @@ static nsRoleMapEntry sWAIRoleMaps[] =
|
||||
kNoReqStates
|
||||
// eARIAPressed is auto applied on any button
|
||||
},
|
||||
{ // cell
|
||||
&nsGkAtoms::cell,
|
||||
roles::CELL,
|
||||
kUseMapRole,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
eTableCell,
|
||||
kNoReqStates
|
||||
},
|
||||
{ // checkbox
|
||||
&nsGkAtoms::checkbox,
|
||||
roles::CHECKBUTTON,
|
||||
@@ -631,6 +641,17 @@ static nsRoleMapEntry sWAIRoleMaps[] =
|
||||
kNoReqStates,
|
||||
eARIASelectable
|
||||
},
|
||||
{ // table
|
||||
&nsGkAtoms::table,
|
||||
roles::TABLE,
|
||||
kUseMapRole,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
eTable,
|
||||
kNoReqStates,
|
||||
eARIASelectable
|
||||
},
|
||||
{ // tablist
|
||||
&nsGkAtoms::tablist,
|
||||
roles::PAGETABLIST,
|
||||
|
||||
@@ -324,66 +324,14 @@ IDRefsIterator::GetElem(const nsDependentSubstring& aID)
|
||||
Accessible*
|
||||
IDRefsIterator::Next()
|
||||
{
|
||||
nsIContent* nextElm = NextElem();
|
||||
return nextElm ? mDoc->GetAccessible(nextElm) : nullptr;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ARIAOwnedByIterator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ARIAOwnedByIterator::ARIAOwnedByIterator(const Accessible* aDependent) :
|
||||
RelatedAccIterator(aDependent->Document(), aDependent->GetContent(),
|
||||
nsGkAtoms::aria_owns), mDependent(aDependent)
|
||||
{
|
||||
}
|
||||
|
||||
Accessible*
|
||||
ARIAOwnedByIterator::Next()
|
||||
{
|
||||
Accessible* owner = RelatedAccIterator::Next();
|
||||
Accessible* cur = owner;
|
||||
while (cur) {
|
||||
if (cur == mDependent)
|
||||
return Next(); // owner cannot be a child of dependent.
|
||||
|
||||
if (cur->IsDoc())
|
||||
break; // don't cross document boundaries
|
||||
|
||||
cur = cur->Parent();
|
||||
nsIContent* nextEl = nullptr;
|
||||
while ((nextEl = NextElem())) {
|
||||
Accessible* acc = mDoc->GetAccessible(nextEl);
|
||||
if (acc) {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
|
||||
return owner;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ARIAOwnsIterator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ARIAOwnsIterator::ARIAOwnsIterator(const Accessible* aOwner) :
|
||||
mIter(aOwner->Document(), aOwner->GetContent(), nsGkAtoms::aria_owns),
|
||||
mOwner(aOwner)
|
||||
{
|
||||
}
|
||||
|
||||
Accessible*
|
||||
ARIAOwnsIterator::Next()
|
||||
{
|
||||
Accessible* child = mIter.Next();
|
||||
const Accessible* cur = mOwner;
|
||||
while (cur) {
|
||||
if (cur == child)
|
||||
return Next(); // cannot own its own parent
|
||||
|
||||
if (cur->IsDoc())
|
||||
break; // don't cross document boundaries
|
||||
|
||||
cur = cur->Parent();
|
||||
}
|
||||
|
||||
return child;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -248,47 +248,6 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Iterates over related accessible referred by aria-owns.
|
||||
*/
|
||||
class ARIAOwnedByIterator final : public RelatedAccIterator
|
||||
{
|
||||
public:
|
||||
explicit ARIAOwnedByIterator(const Accessible* aDependent);
|
||||
virtual ~ARIAOwnedByIterator() { }
|
||||
|
||||
virtual Accessible* Next() override;
|
||||
|
||||
private:
|
||||
ARIAOwnedByIterator() = delete;
|
||||
ARIAOwnedByIterator(const ARIAOwnedByIterator&) = delete;
|
||||
ARIAOwnedByIterator& operator = (const ARIAOwnedByIterator&) = delete;
|
||||
|
||||
const Accessible* mDependent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Iterates over related accessible referred by aria-owns.
|
||||
*/
|
||||
class ARIAOwnsIterator final : public AccIterable
|
||||
{
|
||||
public:
|
||||
explicit ARIAOwnsIterator(const Accessible* aOwner);
|
||||
virtual ~ARIAOwnsIterator() { }
|
||||
|
||||
virtual Accessible* Next() override;
|
||||
|
||||
private:
|
||||
ARIAOwnsIterator() = delete;
|
||||
ARIAOwnsIterator(const ARIAOwnsIterator&) = delete;
|
||||
ARIAOwnsIterator& operator = (const ARIAOwnsIterator&) = delete;
|
||||
|
||||
IDRefsIterator mIter;
|
||||
const Accessible* mOwner;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Iterator that points to a single accessible returning it on the first call
|
||||
* to Next().
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
||||
@@ -71,13 +72,19 @@ DocManager::GetDocAccessible(nsIDocument* aDocument)
|
||||
Accessible*
|
||||
DocManager::FindAccessibleInCache(nsINode* aNode) const
|
||||
{
|
||||
nsSearchAccessibleInCacheArg arg;
|
||||
arg.mNode = aNode;
|
||||
for (auto iter = mDocAccessibleCache.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
DocAccessible* docAccessible = iter.UserData();
|
||||
NS_ASSERTION(docAccessible,
|
||||
"No doc accessible for the object in doc accessible cache!");
|
||||
|
||||
mDocAccessibleCache.EnumerateRead(SearchAccessibleInDocCache,
|
||||
static_cast<void*>(&arg));
|
||||
|
||||
return arg.mAccessible;
|
||||
if (docAccessible) {
|
||||
Accessible* accessible = docAccessible->GetAccessible(aNode);
|
||||
if (accessible) {
|
||||
return accessible;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -112,11 +119,17 @@ DocManager::GetXPCDocument(DocAccessible* aDocument)
|
||||
bool
|
||||
DocManager::IsProcessingRefreshDriverNotification() const
|
||||
{
|
||||
bool isDocRefreshing = false;
|
||||
mDocAccessibleCache.EnumerateRead(SearchIfDocIsRefreshing,
|
||||
static_cast<void*>(&isDocRefreshing));
|
||||
for (auto iter = mDocAccessibleCache.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
DocAccessible* docAccessible = iter.UserData();
|
||||
NS_ASSERTION(docAccessible,
|
||||
"No doc accessible for the object in doc accessible cache!");
|
||||
|
||||
return isDocRefreshing;
|
||||
if (docAccessible && docAccessible->mNotificationController &&
|
||||
docAccessible->mNotificationController->IsUpdating()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -488,66 +501,24 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DocManager static
|
||||
|
||||
PLDHashOperator
|
||||
DocManager::GetFirstEntryInDocCache(const nsIDocument* aKey,
|
||||
DocAccessible* aDocAccessible,
|
||||
void* aUserArg)
|
||||
{
|
||||
NS_ASSERTION(aDocAccessible,
|
||||
"No doc accessible for the object in doc accessible cache!");
|
||||
*reinterpret_cast<DocAccessible**>(aUserArg) = aDocAccessible;
|
||||
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
void
|
||||
DocManager::ClearDocCache()
|
||||
{
|
||||
DocAccessible* docAcc = nullptr;
|
||||
while (mDocAccessibleCache.EnumerateRead(GetFirstEntryInDocCache, static_cast<void*>(&docAcc))) {
|
||||
if (docAcc)
|
||||
// This unusual do-one-element-per-iterator approach is required because each
|
||||
// DocAccessible is removed elsewhere upon its Shutdown() method being
|
||||
// called, which invalidates the existing iterator.
|
||||
while (mDocAccessibleCache.Count() > 0) {
|
||||
auto iter = mDocAccessibleCache.Iter();
|
||||
MOZ_ASSERT(!iter.Done());
|
||||
DocAccessible* docAcc = iter.UserData();
|
||||
NS_ASSERTION(docAcc,
|
||||
"No doc accessible for the object in doc accessible cache!");
|
||||
if (docAcc) {
|
||||
docAcc->Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
DocManager::SearchAccessibleInDocCache(const nsIDocument* aKey,
|
||||
DocAccessible* aDocAccessible,
|
||||
void* aUserArg)
|
||||
{
|
||||
NS_ASSERTION(aDocAccessible,
|
||||
"No doc accessible for the object in doc accessible cache!");
|
||||
|
||||
if (aDocAccessible) {
|
||||
nsSearchAccessibleInCacheArg* arg =
|
||||
static_cast<nsSearchAccessibleInCacheArg*>(aUserArg);
|
||||
arg->mAccessible = aDocAccessible->GetAccessible(arg->mNode);
|
||||
if (arg->mAccessible)
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PLDHashOperator
|
||||
DocManager::SearchIfDocIsRefreshing(const nsIDocument* aKey,
|
||||
DocAccessible* aDocAccessible,
|
||||
void* aUserArg)
|
||||
{
|
||||
NS_ASSERTION(aDocAccessible,
|
||||
"No doc accessible for the object in doc accessible cache!");
|
||||
|
||||
if (aDocAccessible && aDocAccessible->mNotificationController &&
|
||||
aDocAccessible->mNotificationController->IsUpdating()) {
|
||||
*(static_cast<bool*>(aUserArg)) = true;
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
DocManager::RemoteDocAdded(DocAccessibleParent* aDoc)
|
||||
{
|
||||
|
||||
@@ -135,36 +135,11 @@ private:
|
||||
*/
|
||||
DocAccessible* CreateDocOrRootAccessible(nsIDocument* aDocument);
|
||||
|
||||
/**
|
||||
* Get first entry of the document accessible from cache.
|
||||
*/
|
||||
static PLDHashOperator
|
||||
GetFirstEntryInDocCache(const nsIDocument* aKey,
|
||||
DocAccessible* aDocAccessible,
|
||||
void* aUserArg);
|
||||
|
||||
/**
|
||||
* Clear the cache and shutdown the document accessibles.
|
||||
*/
|
||||
void ClearDocCache();
|
||||
|
||||
struct nsSearchAccessibleInCacheArg
|
||||
{
|
||||
Accessible* mAccessible;
|
||||
nsINode* mNode;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
SearchAccessibleInDocCache(const nsIDocument* aKey,
|
||||
DocAccessible* aDocAccessible,
|
||||
void* aUserArg);
|
||||
|
||||
#ifdef DEBUG
|
||||
static PLDHashOperator
|
||||
SearchIfDocIsRefreshing(const nsIDocument* aKey,
|
||||
DocAccessible* aDocAccessible, void* aUserArg);
|
||||
#endif
|
||||
|
||||
typedef nsRefPtrHashtable<nsPtrHashKey<const nsIDocument>, DocAccessible>
|
||||
DocAccessibleHashtable;
|
||||
DocAccessibleHashtable mDocAccessibleCache;
|
||||
|
||||
@@ -295,12 +295,16 @@ EventQueue::CoalesceReorderEvents(AccEvent* aTailEvent)
|
||||
AccReorderEvent* thisReorder = downcast_accEvent(thisEvent);
|
||||
AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
|
||||
uint32_t eventType = thisReorder->IsShowHideEventTarget(tailParent);
|
||||
if (eventType == nsIAccessibleEvent::EVENT_SHOW)
|
||||
if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
|
||||
tailReorder->DoNotEmitAll();
|
||||
else if (eventType == nsIAccessibleEvent::EVENT_HIDE)
|
||||
}
|
||||
else if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
|
||||
NS_ERROR("Accessible tree was modified after it was removed! Huh?");
|
||||
else
|
||||
}
|
||||
else {
|
||||
aTailEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
mEvents[index].swap(mEvents[count - 1]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -48,8 +48,9 @@ uint32_t
|
||||
filters::GetCell(Accessible* aAccessible)
|
||||
{
|
||||
a11y::role role = aAccessible->Role();
|
||||
return role == roles::GRID_CELL || role == roles::ROWHEADER ||
|
||||
role == roles::COLUMNHEADER ? eMatch : eSkipSubtree;
|
||||
return role == roles::CELL || role == roles::GRID_CELL ||
|
||||
role == roles::ROWHEADER || role == roles::COLUMNHEADER ?
|
||||
eMatch : eSkipSubtree;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
||||
@@ -299,33 +299,18 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
|
||||
// Fire menu start/end events for ARIA menus.
|
||||
if (target->IsARIARole(nsGkAtoms::menuitem)) {
|
||||
// The focus was moved into menu.
|
||||
bool tryOwnsParent = true;
|
||||
Accessible* ARIAMenubar = nullptr;
|
||||
Accessible* child = target;
|
||||
Accessible* parent = child->Parent();
|
||||
while (parent) {
|
||||
nsRoleMapEntry* roleMap = parent->ARIARoleMap();
|
||||
if (roleMap) {
|
||||
if (roleMap->Is(nsGkAtoms::menubar)) {
|
||||
ARIAMenubar = parent;
|
||||
break;
|
||||
}
|
||||
|
||||
// Go up in the parent chain of the menu hierarchy.
|
||||
if (roleMap->Is(nsGkAtoms::menuitem) || roleMap->Is(nsGkAtoms::menu)) {
|
||||
child = parent;
|
||||
parent = child->Parent();
|
||||
tryOwnsParent = true;
|
||||
continue;
|
||||
}
|
||||
for (Accessible* parent = target->Parent(); parent; parent = parent->Parent()) {
|
||||
if (parent->IsARIARole(nsGkAtoms::menubar)) {
|
||||
ARIAMenubar = parent;
|
||||
break;
|
||||
}
|
||||
|
||||
// If no required context role then check aria-owns relation.
|
||||
if (!tryOwnsParent)
|
||||
// Go up in the parent chain of the menu hierarchy.
|
||||
if (!parent->IsARIARole(nsGkAtoms::menuitem) &&
|
||||
!parent->IsARIARole(nsGkAtoms::menu)) {
|
||||
break;
|
||||
|
||||
parent = ARIAOwnedByIterator(child).Next();
|
||||
tryOwnsParent = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ARIAMenubar != mActiveARIAMenubar) {
|
||||
|
||||
@@ -54,6 +54,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NotificationController)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHangingChildDocuments)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContentInsertions)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvents)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelocations)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController, AddRef)
|
||||
@@ -86,6 +87,7 @@ NotificationController::Shutdown()
|
||||
mContentInsertions.Clear();
|
||||
mNotifications.Clear();
|
||||
mEvents.Clear();
|
||||
mRelocations.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -350,6 +352,16 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
|
||||
// modification are done.
|
||||
mDocument->ProcessInvalidationList();
|
||||
|
||||
// We cannot rely on DOM tree to keep aria-owns relations updated. Make
|
||||
// a validation to remove dead links.
|
||||
mDocument->ValidateARIAOwned();
|
||||
|
||||
// Process relocation list.
|
||||
for (uint32_t idx = 0; idx < mRelocations.Length(); idx++) {
|
||||
mDocument->DoARIAOwnsRelocation(mRelocations[idx]);
|
||||
}
|
||||
mRelocations.Clear();
|
||||
|
||||
// If a generic notification occurs after this point then we may be allowed to
|
||||
// process it synchronously. However we do not want to reenter if fireing
|
||||
// events causes script to run.
|
||||
|
||||
@@ -133,6 +133,16 @@ public:
|
||||
nsIContent* aStartChildNode,
|
||||
nsIContent* aEndChildNode);
|
||||
|
||||
/**
|
||||
* Pend an accessible subtree relocation.
|
||||
*/
|
||||
void ScheduleRelocation(Accessible* aOwner)
|
||||
{
|
||||
if (!mRelocations.Contains(aOwner) && mRelocations.AppendElement(aOwner)) {
|
||||
ScheduleProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start to observe refresh to make notifications and events processing after
|
||||
* layout.
|
||||
@@ -303,6 +313,11 @@ private:
|
||||
* use SwapElements() on it.
|
||||
*/
|
||||
nsTArray<RefPtr<Notification> > mNotifications;
|
||||
|
||||
/**
|
||||
* Holds all scheduled relocations.
|
||||
*/
|
||||
nsTArray<RefPtr<Accessible> > mRelocations;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
|
||||
@@ -116,7 +116,7 @@ TreeWalker::Next(ChildrenIterator* aIter, Accessible** aAccesible,
|
||||
// Ignore the accessible and its subtree if it was repositioned by means of
|
||||
// aria-owns.
|
||||
if (accessible) {
|
||||
if (accessible->IsRepositioned()) {
|
||||
if (accessible->IsRelocated()) {
|
||||
*aSkipSubtree = true;
|
||||
} else {
|
||||
*aAccesible = accessible;
|
||||
|
||||
@@ -68,7 +68,7 @@ ARIAGridAccessible::RowCount()
|
||||
|
||||
Accessible*
|
||||
ARIAGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
|
||||
{
|
||||
{
|
||||
Accessible* row = GetRowAt(aRowIndex);
|
||||
if (!row)
|
||||
return nullptr;
|
||||
@@ -79,6 +79,9 @@ ARIAGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
|
||||
bool
|
||||
ARIAGridAccessible::IsColSelected(uint32_t aColIdx)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return false;
|
||||
|
||||
AccIterator rowIter(this, filters::GetRow);
|
||||
Accessible* row = rowIter.Next();
|
||||
if (!row)
|
||||
@@ -98,6 +101,9 @@ ARIAGridAccessible::IsColSelected(uint32_t aColIdx)
|
||||
bool
|
||||
ARIAGridAccessible::IsRowSelected(uint32_t aRowIdx)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return false;
|
||||
|
||||
Accessible* row = GetRowAt(aRowIdx);
|
||||
if(!row)
|
||||
return false;
|
||||
@@ -117,6 +123,9 @@ ARIAGridAccessible::IsRowSelected(uint32_t aRowIdx)
|
||||
bool
|
||||
ARIAGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return false;
|
||||
|
||||
Accessible* row = GetRowAt(aRowIdx);
|
||||
if(!row)
|
||||
return false;
|
||||
@@ -133,6 +142,9 @@ ARIAGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
|
||||
uint32_t
|
||||
ARIAGridAccessible::SelectedCellCount()
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return 0;
|
||||
|
||||
uint32_t count = 0, colCount = ColCount();
|
||||
|
||||
AccIterator rowIter(this, filters::GetRow);
|
||||
@@ -159,6 +171,9 @@ ARIAGridAccessible::SelectedCellCount()
|
||||
uint32_t
|
||||
ARIAGridAccessible::SelectedColCount()
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return 0;
|
||||
|
||||
uint32_t colCount = ColCount();
|
||||
if (!colCount)
|
||||
return 0;
|
||||
@@ -193,6 +208,9 @@ ARIAGridAccessible::SelectedColCount()
|
||||
uint32_t
|
||||
ARIAGridAccessible::SelectedRowCount()
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return 0;
|
||||
|
||||
uint32_t count = 0;
|
||||
|
||||
AccIterator rowIter(this, filters::GetRow);
|
||||
@@ -227,6 +245,9 @@ ARIAGridAccessible::SelectedRowCount()
|
||||
void
|
||||
ARIAGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return;
|
||||
|
||||
AccIterator rowIter(this, filters::GetRow);
|
||||
|
||||
Accessible* row = nullptr;
|
||||
@@ -251,6 +272,9 @@ ARIAGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
|
||||
void
|
||||
ARIAGridAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return;
|
||||
|
||||
uint32_t colCount = ColCount();
|
||||
|
||||
AccIterator rowIter(this, filters::GetRow);
|
||||
@@ -275,6 +299,9 @@ ARIAGridAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
|
||||
void
|
||||
ARIAGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return;
|
||||
|
||||
uint32_t colCount = ColCount();
|
||||
if (!colCount)
|
||||
return;
|
||||
@@ -309,6 +336,9 @@ ARIAGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
|
||||
void
|
||||
ARIAGridAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return;
|
||||
|
||||
AccIterator rowIter(this, filters::GetRow);
|
||||
Accessible* row = nullptr;
|
||||
for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
|
||||
@@ -338,6 +368,9 @@ ARIAGridAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
|
||||
void
|
||||
ARIAGridAccessible::SelectRow(uint32_t aRowIdx)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return;
|
||||
|
||||
AccIterator rowIter(this, filters::GetRow);
|
||||
|
||||
Accessible* row = nullptr;
|
||||
@@ -350,6 +383,9 @@ ARIAGridAccessible::SelectRow(uint32_t aRowIdx)
|
||||
void
|
||||
ARIAGridAccessible::SelectCol(uint32_t aColIdx)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return;
|
||||
|
||||
AccIterator rowIter(this, filters::GetRow);
|
||||
|
||||
Accessible* row = nullptr;
|
||||
@@ -368,8 +404,10 @@ ARIAGridAccessible::SelectCol(uint32_t aColIdx)
|
||||
void
|
||||
ARIAGridAccessible::UnselectRow(uint32_t aRowIdx)
|
||||
{
|
||||
Accessible* row = GetRowAt(aRowIdx);
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return;
|
||||
|
||||
Accessible* row = GetRowAt(aRowIdx);
|
||||
if (row)
|
||||
SetARIASelected(row, false);
|
||||
}
|
||||
@@ -377,6 +415,9 @@ ARIAGridAccessible::UnselectRow(uint32_t aRowIdx)
|
||||
void
|
||||
ARIAGridAccessible::UnselectCol(uint32_t aColIdx)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return;
|
||||
|
||||
AccIterator rowIter(this, filters::GetRow);
|
||||
|
||||
Accessible* row = nullptr;
|
||||
@@ -421,6 +462,9 @@ nsresult
|
||||
ARIAGridAccessible::SetARIASelected(Accessible* aAccessible,
|
||||
bool aIsSelected, bool aNotify)
|
||||
{
|
||||
if (IsARIARole(nsGkAtoms::table))
|
||||
return NS_OK;
|
||||
|
||||
nsIContent *content = aAccessible->GetContent();
|
||||
NS_ENSURE_STATE(content);
|
||||
|
||||
@@ -552,8 +596,8 @@ ARIAGridCellAccessible::ColIdx() const
|
||||
for (int32_t idx = 0; idx < indexInRow; idx++) {
|
||||
Accessible* cell = row->GetChildAt(idx);
|
||||
roles::Role role = cell->Role();
|
||||
if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
|
||||
role == roles::COLUMNHEADER)
|
||||
if (role == roles::CELL || role == roles::GRID_CELL ||
|
||||
role == roles::ROWHEADER || role == roles::COLUMNHEADER)
|
||||
colIdx++;
|
||||
}
|
||||
|
||||
@@ -621,8 +665,8 @@ ARIAGridCellAccessible::NativeAttributes()
|
||||
colIdx = colCount;
|
||||
|
||||
roles::Role role = child->Role();
|
||||
if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
|
||||
role == roles::COLUMNHEADER)
|
||||
if (role == roles::CELL || role == roles::GRID_CELL ||
|
||||
role == roles::ROWHEADER || role == roles::COLUMNHEADER)
|
||||
colCount++;
|
||||
}
|
||||
|
||||
|
||||
@@ -1325,21 +1325,14 @@ Accessible::Value(nsString& aValue)
|
||||
if (mRoleMapEntry->Is(nsGkAtoms::combobox)) {
|
||||
Accessible* option = CurrentItem();
|
||||
if (!option) {
|
||||
Accessible* listbox = nullptr;
|
||||
ARIAOwnsIterator iter(this);
|
||||
while ((listbox = iter.Next()) && !listbox->IsListControl());
|
||||
|
||||
if (!listbox) {
|
||||
uint32_t childCount = ChildCount();
|
||||
for (uint32_t idx = 0; idx < childCount; idx++) {
|
||||
Accessible* child = mChildren.ElementAt(idx);
|
||||
if (child->IsListControl())
|
||||
listbox = child;
|
||||
uint32_t childCount = ChildCount();
|
||||
for (uint32_t idx = 0; idx < childCount; idx++) {
|
||||
Accessible* child = mChildren.ElementAt(idx);
|
||||
if (child->IsListControl()) {
|
||||
option = child->GetSelectedItem(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (listbox)
|
||||
option = listbox->GetSelectedItem(0);
|
||||
}
|
||||
|
||||
if (option)
|
||||
@@ -1610,8 +1603,7 @@ Accessible::RelationByType(RelationType aType)
|
||||
}
|
||||
|
||||
case RelationType::NODE_CHILD_OF: {
|
||||
Relation rel(new ARIAOwnedByIterator(this));
|
||||
|
||||
Relation rel;
|
||||
// This is an ARIA tree or treegrid that doesn't use owns, so we need to
|
||||
// get the parent the hard way.
|
||||
if (mRoleMapEntry && (mRoleMapEntry->role == roles::OUTLINEITEM ||
|
||||
@@ -1640,8 +1632,6 @@ Accessible::RelationByType(RelationType aType)
|
||||
}
|
||||
|
||||
case RelationType::NODE_PARENT_OF: {
|
||||
Relation rel(new ARIAOwnsIterator(this));
|
||||
|
||||
// ARIA tree or treegrid can do the hierarchy by @aria-level, ARIA trees
|
||||
// also can be organized by groups.
|
||||
if (mRoleMapEntry &&
|
||||
@@ -1651,10 +1641,10 @@ Accessible::RelationByType(RelationType aType)
|
||||
mRoleMapEntry->role == roles::OUTLINE ||
|
||||
mRoleMapEntry->role == roles::LIST ||
|
||||
mRoleMapEntry->role == roles::TREE_TABLE)) {
|
||||
rel.AppendIter(new ItemIterator(this));
|
||||
return Relation(new ItemIterator(this));
|
||||
}
|
||||
|
||||
return rel;
|
||||
return Relation();
|
||||
}
|
||||
|
||||
case RelationType::CONTROLLED_BY:
|
||||
|
||||
@@ -910,13 +910,13 @@ public:
|
||||
* Get/set repositioned bit indicating that the accessible was moved in
|
||||
* the accessible tree, i.e. the accessible tree structure differs from DOM.
|
||||
*/
|
||||
bool IsRepositioned() const { return mStateFlags & eRepositioned; }
|
||||
void SetRepositioned(bool aRepositioned)
|
||||
bool IsRelocated() const { return mStateFlags & eRelocated; }
|
||||
void SetRelocated(bool aRelocated)
|
||||
{
|
||||
if (aRepositioned)
|
||||
mStateFlags |= eRepositioned;
|
||||
if (aRelocated)
|
||||
mStateFlags |= eRelocated;
|
||||
else
|
||||
mStateFlags &= ~eRepositioned;
|
||||
mStateFlags &= ~eRelocated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1009,9 +1009,9 @@ protected:
|
||||
eSubtreeMutating = 1 << 6, // subtree is being mutated
|
||||
eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
|
||||
eSurvivingInUpdate = 1 << 8, // parent drops children to recollect them
|
||||
eRepositioned = 1 << 9, // accessible was moved in tree
|
||||
eRelocated = 1 << 9, // accessible was moved in tree
|
||||
|
||||
eLastStateFlag = eRepositioned
|
||||
eLastStateFlag = eRelocated
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
||||
@@ -113,10 +114,31 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DocAccessible, Accessible)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationController)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVirtualCursor)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildDocuments)
|
||||
tmp->mDependentIDsHash.EnumerateRead(CycleCollectorTraverseDepIDsEntry, &cb);
|
||||
for (auto iter = tmp->mDependentIDsHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
AttrRelProviderArray* providers = iter.UserData();
|
||||
|
||||
for (int32_t jdx = providers->Length() - 1; jdx >= 0; jdx--) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
|
||||
cb, "content of dependent ids hash entry of document accessible");
|
||||
|
||||
AttrRelProvider* provider = (*providers)[jdx];
|
||||
cb.NoteXPCOMChild(provider->mContent);
|
||||
|
||||
NS_ASSERTION(provider->mContent->IsInDoc(),
|
||||
"Referred content is not in document!");
|
||||
}
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessibleCache)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchorJumpElm)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInvalidationList)
|
||||
for (auto it = tmp->mARIAOwnsHash.ConstIter(); !it.Done(); it.Next()) {
|
||||
nsTArray<RefPtr<Accessible> >* ar = it.UserData();
|
||||
for (uint32_t i = 0; i < ar->Length(); i++) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||
"mARIAOwnsHash entry item");
|
||||
cb.NoteXPCOMChild(ar->ElementAt(i));
|
||||
}
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DocAccessible, Accessible)
|
||||
@@ -128,6 +150,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DocAccessible, Accessible)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessibleCache)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchorJumpElm)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInvalidationList)
|
||||
tmp->mARIAOwnsHash.Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocAccessible)
|
||||
@@ -710,6 +733,10 @@ DocAccessible::AttributeWillChange(nsIDocument* aDocument,
|
||||
if (aModType != nsIDOMMutationEvent::ADDITION)
|
||||
RemoveDependentIDsFor(accessible, aAttribute);
|
||||
|
||||
if (aAttribute == nsGkAtoms::id) {
|
||||
RelocateARIAOwnedIfNeeded(aElement);
|
||||
}
|
||||
|
||||
// Store the ARIA attribute old value so that it can be used after
|
||||
// attribute change. Note, we assume there's no nested ARIA attribute
|
||||
// changes. If this happens then we should end up with keeping a stack of
|
||||
@@ -885,6 +912,10 @@ DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
|
||||
return;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::id) {
|
||||
RelocateARIAOwnedIfNeeded(elm);
|
||||
}
|
||||
|
||||
// ARIA or XUL selection
|
||||
if ((aAccessible->GetContent()->IsXULElement() &&
|
||||
aAttribute == nsGkAtoms::selected) ||
|
||||
@@ -1024,6 +1055,10 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
|
||||
FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::aria_owns) {
|
||||
mNotificationController->ScheduleRelocation(aAccessible);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1255,6 +1290,15 @@ DocAccessible::BindToDocument(Accessible* aAccessible,
|
||||
aAccessible->SetRoleMapEntry(aRoleMapEntry);
|
||||
|
||||
AddDependentIDsFor(aAccessible);
|
||||
|
||||
if (aAccessible->HasOwnContent()) {
|
||||
nsIContent* el = aAccessible->GetContent();
|
||||
if (el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_owns)) {
|
||||
mNotificationController->ScheduleRelocation(aAccessible);
|
||||
}
|
||||
|
||||
RelocateARIAOwnedIfNeeded(el);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1349,49 +1393,6 @@ DocAccessible::ProcessInvalidationList()
|
||||
}
|
||||
|
||||
mInvalidationList.Clear();
|
||||
|
||||
// Alter the tree according to aria-owns (seize the trees).
|
||||
for (uint32_t idx = 0; idx < mARIAOwnsInvalidationList.Length(); idx++) {
|
||||
Accessible* owner = mARIAOwnsInvalidationList[idx].mOwner;
|
||||
Accessible* child = GetAccessible(mARIAOwnsInvalidationList[idx].mChild);
|
||||
if (!child) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// XXX: update context flags
|
||||
{
|
||||
Accessible* oldParent = child->Parent();
|
||||
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent);
|
||||
RefPtr<AccMutationEvent> hideEvent =
|
||||
new AccHideEvent(child, child->GetContent(), false);
|
||||
FireDelayedEvent(hideEvent);
|
||||
reorderEvent->AddSubMutationEvent(hideEvent);
|
||||
|
||||
AutoTreeMutation mut(oldParent);
|
||||
oldParent->RemoveChild(child);
|
||||
|
||||
MaybeNotifyOfValueChange(oldParent);
|
||||
FireDelayedEvent(reorderEvent);
|
||||
}
|
||||
|
||||
{
|
||||
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(owner);
|
||||
RefPtr<AccMutationEvent> showEvent =
|
||||
new AccShowEvent(child, child->GetContent());
|
||||
FireDelayedEvent(showEvent);
|
||||
reorderEvent->AddSubMutationEvent(showEvent);
|
||||
|
||||
AutoTreeMutation mut(owner);
|
||||
owner->AppendChild(child);
|
||||
|
||||
MaybeNotifyOfValueChange(owner);
|
||||
FireDelayedEvent(reorderEvent);
|
||||
}
|
||||
|
||||
child->SetRepositioned(true);
|
||||
}
|
||||
|
||||
mARIAOwnsInvalidationList.Clear();
|
||||
}
|
||||
|
||||
Accessible*
|
||||
@@ -1601,44 +1602,6 @@ DocAccessible::AddDependentIDsFor(Accessible* aRelProvider, nsIAtom* aRelAttr)
|
||||
if (!HasAccessible(dependentContent)) {
|
||||
mInvalidationList.AppendElement(dependentContent);
|
||||
}
|
||||
|
||||
if (relAttr == nsGkAtoms::aria_owns) {
|
||||
// Dependent content cannot point to other aria-owns content or
|
||||
// their parents. Ignore it if so.
|
||||
// XXX: note, this alg may make invalid the scenario when X owns Y
|
||||
// and Y owns Z, we should have something smarter to handle that.
|
||||
bool isvalid = true;
|
||||
for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
|
||||
Accessible* owner = it.Key();
|
||||
nsIContent* parentEl = owner->GetContent();
|
||||
while (parentEl && parentEl != dependentContent) {
|
||||
parentEl = parentEl->GetParent();
|
||||
}
|
||||
if (parentEl) {
|
||||
isvalid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isvalid) {
|
||||
// ARIA owns also cannot refer to itself or a parent.
|
||||
nsIContent* parentEl = relProviderEl;
|
||||
while (parentEl && parentEl != dependentContent) {
|
||||
parentEl = parentEl->GetParent();
|
||||
}
|
||||
if (parentEl) {
|
||||
isvalid = false;
|
||||
}
|
||||
|
||||
if (isvalid) {
|
||||
nsTArray<nsIContent*>* list =
|
||||
mARIAOwnsHash.LookupOrAdd(aRelProvider);
|
||||
list->AppendElement(dependentContent);
|
||||
|
||||
mARIAOwnsInvalidationList.AppendElement(
|
||||
ARIAOwnsPair(aRelProvider, dependentContent));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1688,59 +1651,6 @@ DocAccessible::RemoveDependentIDsFor(Accessible* aRelProvider,
|
||||
}
|
||||
}
|
||||
|
||||
// aria-owns has gone, put the children back.
|
||||
if (relAttr == nsGkAtoms::aria_owns) {
|
||||
nsTArray<nsIContent*>* children = mARIAOwnsHash.Get(aRelProvider);
|
||||
if (children) {
|
||||
nsTArray<Accessible*> containers;
|
||||
|
||||
// Remove ARIA owned elements from where they belonged.
|
||||
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aRelProvider);
|
||||
{
|
||||
AutoTreeMutation mut(aRelProvider);
|
||||
for (uint32_t idx = 0; idx < children->Length(); idx++) {
|
||||
nsIContent* childEl = children->ElementAt(idx);
|
||||
Accessible* child = GetAccessible(childEl);
|
||||
if (child && child->IsRepositioned()) {
|
||||
{
|
||||
RefPtr<AccMutationEvent> hideEvent =
|
||||
new AccHideEvent(child, childEl, false);
|
||||
FireDelayedEvent(hideEvent);
|
||||
reorderEvent->AddSubMutationEvent(hideEvent);
|
||||
|
||||
aRelProvider->RemoveChild(child);
|
||||
}
|
||||
|
||||
// Collect DOM-order containers to update their trees.
|
||||
child->SetRepositioned(false);
|
||||
Accessible* container = GetContainerAccessible(childEl);
|
||||
if (!containers.Contains(container)) {
|
||||
containers.AppendElement(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mARIAOwnsHash.Remove(aRelProvider);
|
||||
for (uint32_t idx = 0; idx < mARIAOwnsInvalidationList.Length();) {
|
||||
if (mARIAOwnsInvalidationList[idx].mOwner == aRelProvider) {
|
||||
mARIAOwnsInvalidationList.RemoveElementAt(idx);
|
||||
continue;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
MaybeNotifyOfValueChange(aRelProvider);
|
||||
FireDelayedEvent(reorderEvent);
|
||||
|
||||
// Reinserted previously ARIA owned elements into the tree
|
||||
// (restore a DOM-like order).
|
||||
for (uint32_t idx = 0; idx < containers.Length(); idx++) {
|
||||
UpdateTreeOnInsertion(containers[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the relation attribute is given then we don't have anything else to
|
||||
// check.
|
||||
if (aRelAttr)
|
||||
@@ -1963,11 +1873,6 @@ DocAccessible::UpdateTreeOnRemoval(Accessible* aContainer, nsIContent* aChildNod
|
||||
}
|
||||
}
|
||||
|
||||
// We may not have an integral DOM tree to remove all aria-owns relations
|
||||
// from the tree. Validate all relations after timeout to workaround that.
|
||||
mNotificationController->ScheduleNotification<DocAccessible>
|
||||
(this, &DocAccessible::ValidateARIAOwned);
|
||||
|
||||
// Content insertion/removal is not cause of accessible tree change.
|
||||
if (updateFlags == eNoAccessible)
|
||||
return;
|
||||
@@ -2051,18 +1956,243 @@ DocAccessible::UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
|
||||
return updateFlags;
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessible::RelocateARIAOwnedIfNeeded(nsIContent* aElement)
|
||||
{
|
||||
if (!aElement->HasID())
|
||||
return;
|
||||
|
||||
AttrRelProviderArray* list =
|
||||
mDependentIDsHash.Get(nsDependentAtomString(aElement->GetID()));
|
||||
if (list) {
|
||||
for (uint32_t idx = 0; idx < list->Length(); idx++) {
|
||||
if (list->ElementAt(idx)->mRelAttr == nsGkAtoms::aria_owns) {
|
||||
Accessible* owner = GetAccessible(list->ElementAt(idx)->mContent);
|
||||
if (owner) {
|
||||
mNotificationController->ScheduleRelocation(owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessible::ValidateARIAOwned()
|
||||
{
|
||||
for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
|
||||
nsTArray<nsIContent*>* childEls = it.UserData();
|
||||
for (uint32_t idx = 0; idx < childEls->Length(); idx++) {
|
||||
nsIContent* childEl = childEls->ElementAt(idx);
|
||||
Accessible* child = GetAccessible(childEl);
|
||||
if (child && !child->GetFrame()) {
|
||||
UpdateTreeOnRemoval(child->Parent(), childEl);
|
||||
Accessible* owner = it.Key();
|
||||
nsTArray<RefPtr<Accessible> >* children = it.UserData();
|
||||
|
||||
// Owner is about to die, put children back if applicable.
|
||||
if (!owner->IsInDocument()) {
|
||||
PutChildrenBack(children, 0);
|
||||
it.Remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t idx = 0; idx < children->Length(); idx++) {
|
||||
Accessible* child = children->ElementAt(idx);
|
||||
if (!child->IsInDocument()) {
|
||||
children->RemoveElementAt(idx);
|
||||
idx--;
|
||||
continue;
|
||||
}
|
||||
|
||||
NS_ASSERTION(child->Parent(), "No parent for ARIA owned?");
|
||||
|
||||
// If DOM node doesn't have a frame anymore then shutdown its accessible.
|
||||
if (child->Parent() && !child->GetFrame()) {
|
||||
UpdateTreeOnRemoval(child->Parent(), child->GetContent());
|
||||
children->RemoveElementAt(idx);
|
||||
idx--;
|
||||
continue;
|
||||
}
|
||||
|
||||
NS_ASSERTION(child->Parent() == owner,
|
||||
"Illigally stolen ARIA owned child!");
|
||||
}
|
||||
|
||||
if (children->Length() == 0) {
|
||||
it.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
|
||||
{
|
||||
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.LookupOrAdd(aOwner);
|
||||
|
||||
IDRefsIterator iter(this, aOwner->Elm(), nsGkAtoms::aria_owns);
|
||||
Accessible* child = nullptr;
|
||||
|
||||
uint32_t arrayIdx = 0, insertIdx = aOwner->ChildCount() - children->Length();
|
||||
while ((child = iter.Next())) {
|
||||
// Same child on same position, no change.
|
||||
if (child->Parent() == aOwner &&
|
||||
child->IndexInParent() == static_cast<int32_t>(insertIdx)) {
|
||||
NS_ASSERTION(child == children->ElementAt(arrayIdx), "Not in sync!");
|
||||
insertIdx++; arrayIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
NS_ASSERTION(children->SafeElementAt(arrayIdx) != child, "Already in place!");
|
||||
|
||||
nsTArray<RefPtr<Accessible> >::index_type idx = children->IndexOf(child);
|
||||
if (idx < arrayIdx) {
|
||||
continue; // ignore second entry of same ID
|
||||
}
|
||||
|
||||
// A new child is found, check for loops.
|
||||
if (child->Parent() != aOwner) {
|
||||
Accessible* parent = aOwner;
|
||||
while (parent && parent != child && !parent->IsDoc()) {
|
||||
parent = parent->Parent();
|
||||
}
|
||||
// A referred child cannot be a parent of the owner.
|
||||
if (parent == child) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (child->Parent() == aOwner) {
|
||||
MoveChild(child, insertIdx - 1);
|
||||
children->InsertElementAt(arrayIdx, child);
|
||||
arrayIdx++;
|
||||
|
||||
} else if (SeizeChild(aOwner, child, insertIdx)) {
|
||||
children->InsertElementAt(arrayIdx, child);
|
||||
insertIdx++; arrayIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
// Put back children that are not seized anymore.
|
||||
PutChildrenBack(children, arrayIdx);
|
||||
if (children->Length() == 0) {
|
||||
mARIAOwnsHash.Remove(aOwner);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessible::SeizeChild(Accessible* aNewParent, Accessible* aChild,
|
||||
int32_t aIdxInParent)
|
||||
{
|
||||
Accessible* oldParent = aChild->Parent();
|
||||
NS_PRECONDITION(oldParent, "No parent?");
|
||||
|
||||
int32_t oldIdxInParent = aChild->IndexInParent();
|
||||
|
||||
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent);
|
||||
RefPtr<AccMutationEvent> hideEvent =
|
||||
new AccHideEvent(aChild, aChild->GetContent(), false);
|
||||
reorderEvent->AddSubMutationEvent(hideEvent);
|
||||
|
||||
{
|
||||
AutoTreeMutation mut(oldParent);
|
||||
oldParent->RemoveChild(aChild);
|
||||
}
|
||||
|
||||
bool isReinserted = false;
|
||||
{
|
||||
AutoTreeMutation mut(aNewParent);
|
||||
isReinserted = aNewParent->InsertChildAt(aIdxInParent, aChild);
|
||||
}
|
||||
|
||||
if (!isReinserted) {
|
||||
AutoTreeMutation mut(oldParent);
|
||||
oldParent->InsertChildAt(oldIdxInParent, aChild);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The child may be stolen from other ARIA owns element.
|
||||
if (aChild->IsRelocated()) {
|
||||
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(oldParent);
|
||||
children->RemoveElement(aChild);
|
||||
}
|
||||
|
||||
FireDelayedEvent(hideEvent);
|
||||
MaybeNotifyOfValueChange(oldParent);
|
||||
FireDelayedEvent(reorderEvent);
|
||||
|
||||
reorderEvent = new AccReorderEvent(aNewParent);
|
||||
RefPtr<AccMutationEvent> showEvent =
|
||||
new AccShowEvent(aChild, aChild->GetContent());
|
||||
reorderEvent->AddSubMutationEvent(showEvent);
|
||||
|
||||
FireDelayedEvent(showEvent);
|
||||
MaybeNotifyOfValueChange(aNewParent);
|
||||
FireDelayedEvent(reorderEvent);
|
||||
|
||||
aChild->SetRelocated(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessible::MoveChild(Accessible* aChild, int32_t aIdxInParent)
|
||||
{
|
||||
NS_PRECONDITION(aChild->Parent(), "No parent?");
|
||||
|
||||
Accessible* parent = aChild->Parent();
|
||||
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(parent);
|
||||
RefPtr<AccMutationEvent> hideEvent =
|
||||
new AccHideEvent(aChild, aChild->GetContent(), false);
|
||||
reorderEvent->AddSubMutationEvent(hideEvent);
|
||||
|
||||
AutoTreeMutation mut(parent);
|
||||
parent->RemoveChild(aChild);
|
||||
|
||||
parent->InsertChildAt(aIdxInParent, aChild);
|
||||
aChild->SetRelocated(true);
|
||||
|
||||
FireDelayedEvent(hideEvent);
|
||||
|
||||
RefPtr<AccMutationEvent> showEvent =
|
||||
new AccShowEvent(aChild, aChild->GetContent());
|
||||
reorderEvent->AddSubMutationEvent(showEvent);
|
||||
FireDelayedEvent(showEvent);
|
||||
|
||||
MaybeNotifyOfValueChange(parent);
|
||||
FireDelayedEvent(reorderEvent);
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessible::PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
|
||||
uint32_t aStartIdx)
|
||||
{
|
||||
nsTArray<Accessible*> containers;
|
||||
for (auto idx = aStartIdx; idx < aChildren->Length(); idx++) {
|
||||
Accessible* child = aChildren->ElementAt(idx);
|
||||
|
||||
// If the child is in the tree then remove it from the owner.
|
||||
if (child->IsInDocument()) {
|
||||
Accessible* owner = child->Parent();
|
||||
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(owner);
|
||||
RefPtr<AccMutationEvent> hideEvent =
|
||||
new AccHideEvent(child, child->GetContent(), false);
|
||||
reorderEvent->AddSubMutationEvent(hideEvent);
|
||||
|
||||
{
|
||||
AutoTreeMutation mut(owner);
|
||||
owner->RemoveChild(child);
|
||||
child->SetRelocated(false);
|
||||
}
|
||||
|
||||
FireDelayedEvent(hideEvent);
|
||||
MaybeNotifyOfValueChange(owner);
|
||||
FireDelayedEvent(reorderEvent);
|
||||
}
|
||||
|
||||
Accessible* container = GetContainerAccessible(child->GetContent());
|
||||
if (container &&
|
||||
containers.IndexOf(container) == nsTArray<Accessible*>::NoIndex) {
|
||||
containers.AppendElement(container);
|
||||
}
|
||||
}
|
||||
|
||||
// And put it back where it belongs to.
|
||||
aChildren->RemoveElementsAt(aStartIdx, aChildren->Length() - aStartIdx);
|
||||
for (uint32_t idx = 0; idx < containers.Length(); idx++) {
|
||||
UpdateTreeOnInsertion(containers[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2167,25 +2297,3 @@ DocAccessible::IsLoadEventTarget() const
|
||||
return (treeItem->ItemType() == nsIDocShellTreeItem::typeContent);
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
DocAccessible::CycleCollectorTraverseDepIDsEntry(const nsAString& aKey,
|
||||
AttrRelProviderArray* aProviders,
|
||||
void* aUserArg)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback* cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aUserArg);
|
||||
|
||||
for (int32_t jdx = aProviders->Length() - 1; jdx >= 0; jdx--) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"content of dependent ids hash entry of document accessible");
|
||||
|
||||
AttrRelProvider* provider = (*aProviders)[jdx];
|
||||
cb->NoteXPCOMChild(provider->mContent);
|
||||
|
||||
NS_ASSERTION(provider->mContent->IsInDoc(),
|
||||
"Referred content is not in document!");
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
|
||||
@@ -286,13 +286,9 @@ public:
|
||||
*/
|
||||
Accessible* ARIAOwnedAt(Accessible* aParent, uint32_t aIndex) const
|
||||
{
|
||||
nsTArray<nsIContent*>* childrenEl = mARIAOwnsHash.Get(aParent);
|
||||
if (childrenEl) {
|
||||
nsIContent* childEl = childrenEl->SafeElementAt(aIndex);
|
||||
Accessible* child = GetAccessible(childEl);
|
||||
if (child && child->IsRepositioned()) {
|
||||
return child;
|
||||
}
|
||||
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(aParent);
|
||||
if (children) {
|
||||
return children->SafeElementAt(aIndex);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -507,11 +503,38 @@ protected:
|
||||
uint32_t UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
|
||||
AccReorderEvent* aReorderEvent);
|
||||
|
||||
/**
|
||||
* Schedule ARIA owned element relocation if needed.
|
||||
*/
|
||||
void RelocateARIAOwnedIfNeeded(nsIContent* aEl);
|
||||
|
||||
/**
|
||||
* Validates all aria-owns connections and updates the tree accordingly.
|
||||
*/
|
||||
void ValidateARIAOwned();
|
||||
|
||||
/**
|
||||
* Steals or puts back accessible subtrees.
|
||||
*/
|
||||
void DoARIAOwnsRelocation(Accessible* aOwner);
|
||||
|
||||
/**
|
||||
* Moves the child from old parent under new one.
|
||||
*/
|
||||
bool SeizeChild(Accessible* aNewParent, Accessible* aChild,
|
||||
int32_t aIdxInParent);
|
||||
|
||||
/**
|
||||
* Move the child under same parent.
|
||||
*/
|
||||
void MoveChild(Accessible* aChild, int32_t aIdxInParent);
|
||||
|
||||
/**
|
||||
* Moves children back under their original parents.
|
||||
*/
|
||||
void PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
|
||||
uint32_t aStartIdx);
|
||||
|
||||
/**
|
||||
* Create accessible tree.
|
||||
*
|
||||
@@ -643,19 +666,12 @@ protected:
|
||||
AttrRelProvider& operator =(const AttrRelProvider&);
|
||||
};
|
||||
|
||||
typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
|
||||
typedef nsClassHashtable<nsStringHashKey, AttrRelProviderArray>
|
||||
DependentIDsHashtable;
|
||||
|
||||
/**
|
||||
* The cache of IDs pointed by relation attributes.
|
||||
*/
|
||||
DependentIDsHashtable mDependentIDsHash;
|
||||
|
||||
static PLDHashOperator
|
||||
CycleCollectorTraverseDepIDsEntry(const nsAString& aKey,
|
||||
AttrRelProviderArray* aProviders,
|
||||
void* aUserArg);
|
||||
typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
|
||||
nsClassHashtable<nsStringHashKey, AttrRelProviderArray>
|
||||
mDependentIDsHash;
|
||||
|
||||
friend class RelatedAccIterator;
|
||||
|
||||
@@ -668,24 +684,11 @@ protected:
|
||||
nsTArray<RefPtr<nsIContent>> mInvalidationList;
|
||||
|
||||
/**
|
||||
* Holds a list of aria-owns relations.
|
||||
* Holds a list of aria-owns relocations.
|
||||
*/
|
||||
nsClassHashtable<nsPtrHashKey<Accessible>, nsTArray<nsIContent*> >
|
||||
nsClassHashtable<nsPtrHashKey<Accessible>, nsTArray<RefPtr<Accessible> > >
|
||||
mARIAOwnsHash;
|
||||
|
||||
struct ARIAOwnsPair {
|
||||
ARIAOwnsPair(Accessible* aOwner, nsIContent* aChild) :
|
||||
mOwner(aOwner), mChild(aChild) { }
|
||||
ARIAOwnsPair(const ARIAOwnsPair& aPair) :
|
||||
mOwner(aPair.mOwner), mChild(aPair.mChild) { }
|
||||
ARIAOwnsPair& operator =(const ARIAOwnsPair& aPair)
|
||||
{ mOwner = aPair.mOwner; mChild = aPair.mChild; return *this; }
|
||||
|
||||
Accessible* mOwner;
|
||||
nsIContent* mChild;
|
||||
};
|
||||
nsTArray<ARIAOwnsPair> mARIAOwnsInvalidationList;
|
||||
|
||||
/**
|
||||
* Used to process notification from core and accessible events.
|
||||
*/
|
||||
|
||||
@@ -454,11 +454,11 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
|
||||
|
||||
if (accTree.children.length != childCount) {
|
||||
for (var i = 0; i < Math.max(accTree.children.length, childCount); i++) {
|
||||
var accChild;
|
||||
var accChild = null, testChild = null;
|
||||
try {
|
||||
testChild = accTree.children[i];
|
||||
accChild = children.queryElementAt(i, nsIAccessible);
|
||||
|
||||
testChild = accTree.children[i];
|
||||
if (!testChild) {
|
||||
ok(false, prettyName(acc) + " has an extra child at index " + i +
|
||||
" : " + prettyName(accChild));
|
||||
@@ -481,10 +481,10 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
|
||||
}
|
||||
info("Matching " + prettyName(accTree) + " and " + prettyName(acc) +
|
||||
" child at index " + i + " : " + prettyName(accChild));
|
||||
|
||||
} catch (e) {
|
||||
ok(false, prettyName(accTree) + " has an extra child at index " + i +
|
||||
ok(false, prettyName(accTree) + " is expected to have a child at index " + i +
|
||||
" : " + prettyName(testChild) + ", " + e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -51,9 +51,11 @@
|
||||
{
|
||||
this.menuNode = getNode(aMenuID);
|
||||
|
||||
// Because of aria-owns processing we may have menupopup start fired before
|
||||
// related show event.
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_SHOW, this.menuNode),
|
||||
new invokerChecker(EVENT_MENUPOPUP_START, this.menuNode),
|
||||
new asyncInvokerChecker(EVENT_MENUPOPUP_START, this.menuNode),
|
||||
new invokerChecker(EVENT_REORDER, getNode(aParentMenuID))
|
||||
];
|
||||
|
||||
|
||||
@@ -74,15 +74,6 @@
|
||||
testRelation("treeitem1", RELATION_NODE_CHILD_OF, "tree");
|
||||
testRelation("treeitem2", RELATION_NODE_CHILD_OF, "tree");
|
||||
|
||||
// aria-owns, bad relations
|
||||
testRelation("ariaowns_container", RELATION_NODE_CHILD_OF, null);
|
||||
testRelation("ariaowns_self", RELATION_NODE_CHILD_OF, null);
|
||||
testRelation("ariaowns_uncle", RELATION_NODE_CHILD_OF, "ariaowns_self");
|
||||
|
||||
testRelation("ariaowns_container", RELATION_NODE_PARENT_OF, null);
|
||||
testRelation("ariaowns_self", RELATION_NODE_PARENT_OF, "ariaowns_uncle");
|
||||
testRelation("ariaowns_uncle", RELATION_NODE_PARENT_OF, null);
|
||||
|
||||
// 'node child of' relation for outlineitem role
|
||||
testRelation("treeitem3", RELATION_NODE_CHILD_OF, "tree");
|
||||
testRelation("treeitem4", RELATION_NODE_CHILD_OF, "tree");
|
||||
@@ -94,8 +85,6 @@
|
||||
testRelation("tree2_ti1b", RELATION_NODE_CHILD_OF, "tree2_ti1");
|
||||
|
||||
// 'node child of' relation for row role in grid.
|
||||
// Relation for row associated using aria-owns should exist.
|
||||
testRelation("simplegrid-ownrow", RELATION_NODE_CHILD_OF, "simplegrid");
|
||||
// Relation for row associated using aria-level should exist.
|
||||
testRelation("simplegrid-row3", RELATION_NODE_CHILD_OF,
|
||||
"simplegrid-row2");
|
||||
@@ -140,8 +129,6 @@
|
||||
["treegridrow1", "treegridrow2"]);
|
||||
|
||||
// 'node parent of' relation on ARIA grid.
|
||||
// Should only have relation to child added through aria-owns.
|
||||
testRelation("simplegrid", RELATION_NODE_PARENT_OF, "simplegrid-ownrow");
|
||||
// 'node parent of' relation on ARIA grid's row.
|
||||
// Should only have relation to child through aria-level.
|
||||
testRelation("simplegrid-row2", RELATION_NODE_PARENT_OF,
|
||||
@@ -319,13 +306,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="ariaowns_container">
|
||||
<div id="ariaowns_self"
|
||||
aria-owns="aria_ownscontainer ariaowns_self ariaowns_uncle"></div>
|
||||
</div>
|
||||
<div id="ariaowns_uncle"></div>
|
||||
|
||||
<div aria-owns="simplegrid-ownrow" role="grid" id="simplegrid">
|
||||
<div role="grid" id="simplegrid">
|
||||
<div role="row" id="simplegrid-row1" aria-level="1">
|
||||
<div role="gridcell">cell 1,1</div>
|
||||
<div role="gridcell">cell 1,2</div>
|
||||
@@ -339,7 +320,6 @@
|
||||
<div role="gridcell">cell 3,2</div>
|
||||
</div>
|
||||
</div>
|
||||
<div role="row" id="simplegrid-ownrow"></div>
|
||||
|
||||
<ul role="tree" id="tree2">
|
||||
<li role="treeitem" id="tree2_ti1">Item 1
|
||||
|
||||
@@ -138,10 +138,6 @@
|
||||
RELATION_DESCRIBED_BY, RELATION_DESCRIPTION_FOR,
|
||||
"host", "host", "dependent1", "dependent2");
|
||||
|
||||
testRelated("aria-owns",
|
||||
null, RELATION_NODE_CHILD_OF,
|
||||
"host", "host", "dependent1", "dependent2");
|
||||
|
||||
testRelated("aria-controls",
|
||||
RELATION_CONTROLLER_FOR, RELATION_CONTROLLED_BY,
|
||||
"host", "host", "dependent1", "dependent2");
|
||||
@@ -169,11 +165,6 @@
|
||||
RELATION_DESCRIBED_BY,
|
||||
RELATION_DESCRIPTION_FOR));
|
||||
|
||||
gQueue.push(new insertRelated("aria-owns", "dependent7", true,
|
||||
null, RELATION_NODE_CHILD_OF));
|
||||
gQueue.push(new insertRelated("aria-owns", "dependent8", false,
|
||||
null, RELATION_NODE_CHILD_OF));
|
||||
|
||||
gQueue.push(new insertRelated("aria-controls", "dependent9", true,
|
||||
RELATION_CONTROLLER_FOR,
|
||||
RELATION_CONTROLLED_BY));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[DEFAULT]
|
||||
|
||||
[test_headers_ariagrid.html]
|
||||
[test_headers_ariatable.html]
|
||||
[test_headers_listbox.xul]
|
||||
[test_headers_table.html]
|
||||
[test_headers_tree.xul]
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<title>Table header information cells for ARIA table</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../table.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
function doTest()
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// column and row headers from markup
|
||||
|
||||
headerInfoMap = [
|
||||
{
|
||||
cell: "table_dc_1",
|
||||
rowHeaderCells: [ "table_rh_1" ],
|
||||
columnHeaderCells: [ "table_ch_2" ]
|
||||
},
|
||||
{
|
||||
cell: "table_dc_2",
|
||||
rowHeaderCells: [ "table_rh_1" ],
|
||||
columnHeaderCells: [ "table_ch_3" ]
|
||||
},
|
||||
{
|
||||
cell: "table_dc_3",
|
||||
rowHeaderCells: [ "table_rh_2" ],
|
||||
columnHeaderCells: [ "table_ch_2" ]
|
||||
},
|
||||
{
|
||||
cell: "table_dc_4",
|
||||
rowHeaderCells: [ "table_rh_2" ],
|
||||
columnHeaderCells: [ "table_ch_3" ]
|
||||
},
|
||||
{
|
||||
cell: "table_rh_1",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: [ "table_ch_1" ]
|
||||
},
|
||||
{
|
||||
cell: "table_rh_2",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: [ "table_ch_1" ]
|
||||
}
|
||||
];
|
||||
|
||||
testHeaderCells(headerInfoMap);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a target="_blank"
|
||||
title="support ARIA table and cell roles"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1173364">Bug 1173364</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<div role="table">
|
||||
<div role="row">
|
||||
<span id="table_ch_1" role="columnheader">col_1</span>
|
||||
<span id="table_ch_2" role="columnheader">col_2</span>
|
||||
<span id="table_ch_3" role="columnheader">col_3</span>
|
||||
</div>
|
||||
<div role="row">
|
||||
<span id="table_rh_1" role="rowheader">row_1</span>
|
||||
<span id="table_dc_1" role="cell">cell1</span>
|
||||
<span id="table_dc_2" role="cell">cell2</span>
|
||||
</div>
|
||||
<div role="row">
|
||||
<span id="table_rh_2" role="rowheader">row_2</span>
|
||||
<span id="table_dc_3" role="cell">cell3</span>
|
||||
<span id="table_dc_4" role="cell">cell4</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -10,7 +10,9 @@ skip-if = true # Bug 561508
|
||||
[test_aria_imgmap.html]
|
||||
[test_aria_list.html]
|
||||
[test_aria_menu.html]
|
||||
[test_aria_owns.html]
|
||||
[test_aria_presentation.html]
|
||||
[test_aria_table.html]
|
||||
[test_brokencontext.html]
|
||||
[test_button.xul]
|
||||
[test_canvas.html]
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>@aria-owns attribute testing</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../role.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//enableLogging("tree"); // debug stuff
|
||||
|
||||
var gQueue = null;
|
||||
|
||||
function doTest()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [ // t1_1
|
||||
{ HEADING: [ // t1_2
|
||||
// no kids, no loop
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t1_1", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [ // t2_1
|
||||
{ GROUPING: [ // t2_2
|
||||
{ HEADING: [ // t2_3
|
||||
// no kids, no loop
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t2_1", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [ // t3_3
|
||||
{ GROUPING: [ // t3_1
|
||||
{ NOTE: [ // t3_2
|
||||
{ HEADING: [ // DOM child of t3_2
|
||||
// no kids, no loop
|
||||
] }
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t3_3", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [ // t4_1
|
||||
{ GROUPING: [ // DOM child of t4_1, aria-owns ignored
|
||||
// no kids, no loop
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t4_1", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [ // t5_1
|
||||
{ GROUPING: [ // DOM child of t5_1
|
||||
{ NOTE: [ // t5_2
|
||||
{ HEADING: [ // DOM child of t5_2
|
||||
{ FORM: [ // t5_3
|
||||
{ TOOLTIP: [ // DOM child of t5_3
|
||||
// no kids, no loop
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t5_1", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [ // t6_1
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ CHECKBUTTON: [ ] }, // t6_3, rearranged by aria-owns
|
||||
{ PUSHBUTTON: [ ] }, // t6_2, rearranged by aria-owns
|
||||
] };
|
||||
testAccessibleTree("t6_1", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [ // ariaowns_container
|
||||
{ SECTION: [ // ariaowns_self
|
||||
{ SECTION: [ // ariaowns_uncle
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("ariaowns_container", tree);
|
||||
|
||||
tree =
|
||||
{ TABLE: [
|
||||
{ ROW: [
|
||||
{ GRID_CELL: [
|
||||
{ TEXT_LEAF: [] }
|
||||
] },
|
||||
{ GRID_CELL: [
|
||||
{ TEXT_LEAF: [] }
|
||||
] }
|
||||
] },
|
||||
{ ROW: [
|
||||
{ GRID_CELL: [
|
||||
{ TEXT_LEAF: [] }
|
||||
] },
|
||||
{ GRID_CELL: [
|
||||
{ TEXT_LEAF: [] }
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("grid", tree);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<!-- simple loop -->
|
||||
<div id="t1_1" aria-owns="t1_2"></div>
|
||||
<div id="t1_2" aria-owns="t1_1" role="heading"></div>
|
||||
|
||||
<!-- loop -->
|
||||
<div id="t2_2" aria-owns="t2_3" role="group"></div>
|
||||
<div id="t2_1" aria-owns="t2_2"></div>
|
||||
<div id="t2_3" aria-owns="t2_1" role="heading"></div>
|
||||
|
||||
<!-- loop #2 -->
|
||||
<div id="t3_1" aria-owns="t3_2" role="group"></div>
|
||||
<div id="t3_2" role="note">
|
||||
<div aria-owns="t3_3" role="heading"></div>
|
||||
</div>
|
||||
<div id="t3_3" aria-owns="t3_1"></div>
|
||||
|
||||
<!-- self loop -->
|
||||
<div id="t4_1"><div aria-owns="t4_1" role="group"></div></div>
|
||||
|
||||
<!-- natural and aria-owns hierarchy -->
|
||||
<div id="t5_1"><div aria-owns="t5_2" role="group"></div></div>
|
||||
<div id="t5_2" role="note"><div aria-owns="t5_3" role="heading"></div></div>
|
||||
<div id="t5_3" role="form"><div aria-owns="t5_1" role="tooltip"></div></div>
|
||||
|
||||
<!-- rearrange children -->
|
||||
<div id="t6_1" aria-owns="t6_3 t6_2">
|
||||
<div id="t6_2" role="button"></div>
|
||||
<div id="t6_3" role="checkbox"></div>
|
||||
<div role="radio"></div>
|
||||
</div>
|
||||
|
||||
<div id="ariaowns_container">
|
||||
<div id="ariaowns_self"
|
||||
aria-owns="aria_ownscontainer ariaowns_self ariaowns_uncle"></div>
|
||||
</div>
|
||||
<div id="ariaowns_uncle"></div>
|
||||
|
||||
<!-- grid -->
|
||||
<div aria-owns="grid-row2" role="grid" id="grid">
|
||||
<div role="row">
|
||||
<div role="gridcell">cell 1,1</div>
|
||||
<div role="gridcell">cell 1,2</div>
|
||||
</div>
|
||||
</div>
|
||||
<div role="row" id="grid-row2">
|
||||
<div role="gridcell">cell 2,1</div>
|
||||
<div role="gridcell">cell 2,2</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>ARIA table tests</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../role.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
function doTest()
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// table having rowgroups
|
||||
|
||||
var accTree =
|
||||
{ TABLE: [
|
||||
{ GROUPING: [
|
||||
{ ROW: [
|
||||
{ CELL: [
|
||||
{ TEXT_LEAF: [ ] }
|
||||
] }
|
||||
] }
|
||||
] },
|
||||
] };
|
||||
|
||||
testAccessibleTree("table", accTree);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
title="support ARIA table and cell roles"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1173364">
|
||||
Bug 1173364
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<div id="table" role="table">
|
||||
<div role="rowgroup">
|
||||
<div role="row">
|
||||
<div role="cell">cell</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -26,11 +26,11 @@
|
||||
function removeARIAOwns()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_HIDE, getNode("t2_checkbox")),
|
||||
new invokerChecker(EVENT_HIDE, getNode("t2_button")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t2_button")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t2_checkbox")),
|
||||
new invokerChecker(EVENT_REORDER, getNode("container2"))
|
||||
new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")),
|
||||
new invokerChecker(EVENT_HIDE, getNode("t1_button")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t1_button")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t1_checkbox")),
|
||||
new invokerChecker(EVENT_REORDER, getNode("t1_container"))
|
||||
];
|
||||
|
||||
this.invoke = function removeARIAOwns_invoke()
|
||||
@@ -43,9 +43,9 @@
|
||||
] },
|
||||
{ PUSHBUTTON: [ ] }
|
||||
] };
|
||||
testAccessibleTree("container2", tree);
|
||||
testAccessibleTree("t1_container", tree);
|
||||
|
||||
getNode("container2").removeAttribute("aria-owns");
|
||||
getNode("t1_container").removeAttribute("aria-owns");
|
||||
}
|
||||
|
||||
this.finalCheck = function removeARIAOwns_finalCheck()
|
||||
@@ -58,7 +58,7 @@
|
||||
{ SECTION: [] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("container2", tree);
|
||||
testAccessibleTree("t1_container", tree);
|
||||
}
|
||||
|
||||
this.getID = function removeARIAOwns_getID()
|
||||
@@ -70,16 +70,17 @@
|
||||
function setARIAOwns()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_HIDE, getNode("t2_button")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t2_button")),
|
||||
new invokerChecker(EVENT_HIDE, getNode("t2_subdiv")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t2_subdiv")),
|
||||
new invokerChecker(EVENT_REORDER, getNode("container2"))
|
||||
new invokerChecker(EVENT_HIDE, getNode("t1_button")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t1_button")),
|
||||
new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
|
||||
new invokerChecker(EVENT_REORDER, getNode("t1_container"))
|
||||
];
|
||||
|
||||
this.invoke = function setARIAOwns_invoke()
|
||||
{
|
||||
getNode("container2").setAttribute("aria-owns", "t2_button t2_subdiv");
|
||||
getNode("t1_container").
|
||||
setAttribute("aria-owns", "t1_button t1_subdiv");
|
||||
}
|
||||
|
||||
this.finalCheck = function setARIAOwns_finalCheck()
|
||||
@@ -88,11 +89,11 @@
|
||||
// the children.
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // div
|
||||
{ PUSHBUTTON: [ ] }, // button
|
||||
{ SECTION: [ ] } // subdiv
|
||||
{ CHECKBUTTON: [ ] }, // checkbox
|
||||
{ PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
|
||||
{ SECTION: [ ] } // subdiv from the subtree, ARIA owned
|
||||
] };
|
||||
testAccessibleTree("container2", tree);
|
||||
testAccessibleTree("t1_container", tree);
|
||||
}
|
||||
|
||||
this.getID = function setARIAOwns_getID()
|
||||
@@ -101,19 +102,53 @@
|
||||
}
|
||||
}
|
||||
|
||||
function addIdToARIAOwns()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_HIDE, getNode("t1_group")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t1_group")),
|
||||
new invokerChecker(EVENT_REORDER, document)
|
||||
];
|
||||
|
||||
this.invoke = function addIdToARIAOwns_invoke()
|
||||
{
|
||||
getNode("t1_container").
|
||||
setAttribute("aria-owns", "t1_button t1_subdiv t1_group");
|
||||
}
|
||||
|
||||
this.finalCheck = function addIdToARIAOwns_finalCheck()
|
||||
{
|
||||
// children are swapped again, button and subdiv are appended to
|
||||
// the children.
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // t1_checkbox
|
||||
{ PUSHBUTTON: [ ] }, // button, t1_button
|
||||
{ SECTION: [ ] }, // subdiv from the subtree, t1_subdiv
|
||||
{ GROUPING: [ ] } // group from outside, t1_group
|
||||
] };
|
||||
testAccessibleTree("t1_container", tree);
|
||||
}
|
||||
|
||||
this.getID = function addIdToARIAOwns_getID()
|
||||
{
|
||||
return "Add id to @aria-owns attribute value";
|
||||
}
|
||||
}
|
||||
|
||||
function appendEl()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_SHOW, getNode, "child3"),
|
||||
new invokerChecker(EVENT_REORDER, getNode("container2"))
|
||||
new invokerChecker(EVENT_SHOW, getNode, "t1_child3"),
|
||||
new invokerChecker(EVENT_REORDER, getNode("t1_container"))
|
||||
];
|
||||
|
||||
this.invoke = function appendEl_invoke()
|
||||
{
|
||||
var div = document.createElement("div");
|
||||
div.setAttribute("id", "child3");
|
||||
div.setAttribute("id", "t1_child3");
|
||||
div.setAttribute("role", "radio")
|
||||
getNode("container2").appendChild(div);
|
||||
getNode("t1_container").appendChild(div);
|
||||
}
|
||||
|
||||
this.finalCheck = function appendEl_finalCheck()
|
||||
@@ -124,10 +159,11 @@
|
||||
{ SECTION: [
|
||||
{ CHECKBUTTON: [ ] },
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ PUSHBUTTON: [ ] }, // ARIA owned
|
||||
{ SECTION: [ ] } // ARIA owned
|
||||
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
|
||||
{ SECTION: [ ] }, // ARIA owned, t1_subdiv
|
||||
{ GROUPING: [ ] } // ARIA owned, t1_group
|
||||
] };
|
||||
testAccessibleTree("container2", tree);
|
||||
testAccessibleTree("t1_container", tree);
|
||||
}
|
||||
|
||||
this.getID = function appendEl_getID()
|
||||
@@ -139,15 +175,15 @@
|
||||
function removeEl()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_HIDE, getNode, "t2_checkbox"),
|
||||
new invokerChecker(EVENT_SHOW, getNode, "t2_checkbox"),
|
||||
new invokerChecker(EVENT_REORDER, getNode("container2"))
|
||||
new invokerChecker(EVENT_HIDE, getNode, "t1_checkbox"),
|
||||
new invokerChecker(EVENT_SHOW, getNode, "t1_checkbox"),
|
||||
new invokerChecker(EVENT_REORDER, getNode("t1_container"))
|
||||
];
|
||||
|
||||
this.invoke = function removeEl_invoke()
|
||||
{
|
||||
// remove a container of t2_subdiv
|
||||
getNode("t2_span").parentNode.removeChild(getNode("t2_span"));
|
||||
// remove a container of t1_subdiv
|
||||
getNode("t1_span").parentNode.removeChild(getNode("t1_span"));
|
||||
}
|
||||
|
||||
this.finalCheck = function removeEl_finalCheck()
|
||||
@@ -157,14 +193,214 @@
|
||||
{ SECTION: [
|
||||
{ CHECKBUTTON: [ ] },
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ PUSHBUTTON: [ ] } // ARIA owned
|
||||
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
|
||||
{ GROUPING: [ ] } // ARIA owned, t1_group
|
||||
] };
|
||||
testAccessibleTree("container2", tree);
|
||||
testAccessibleTree("t1_container", tree);
|
||||
}
|
||||
|
||||
this.getID = function removeEl_getID()
|
||||
{
|
||||
return "Remove a container of ARIA ownded element";
|
||||
return "Remove a container of ARIA owned element";
|
||||
}
|
||||
}
|
||||
|
||||
function removeId()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_HIDE, getNode("t1_group")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t1_group")),
|
||||
new invokerChecker(EVENT_REORDER, document)
|
||||
];
|
||||
|
||||
this.invoke = function removeId_invoke()
|
||||
{
|
||||
getNode("t1_group").removeAttribute("id");
|
||||
}
|
||||
|
||||
this.finalCheck = function removeId_finalCheck()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ CHECKBUTTON: [ ] },
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ PUSHBUTTON: [ ] } // ARIA owned, t1_button
|
||||
] };
|
||||
testAccessibleTree("t1_container", tree);
|
||||
}
|
||||
|
||||
this.getID = function removeId_getID()
|
||||
{
|
||||
return "Remove ID from ARIA owned element";
|
||||
}
|
||||
}
|
||||
|
||||
function setId()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_HIDE, getNode("t1_grouptmp")),
|
||||
new invokerChecker(EVENT_SHOW, getNode("t1_grouptmp")),
|
||||
new invokerChecker(EVENT_REORDER, document)
|
||||
];
|
||||
|
||||
this.invoke = function setId_invoke()
|
||||
{
|
||||
getNode("t1_grouptmp").setAttribute("id", "t1_group");
|
||||
}
|
||||
|
||||
this.finalCheck = function setId_finalCheck()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ CHECKBUTTON: [ ] },
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
|
||||
{ GROUPING: [ ] } // ARIA owned, t1_group, previously t1_grouptmp
|
||||
] };
|
||||
testAccessibleTree("t1_container", tree);
|
||||
}
|
||||
|
||||
this.getID = function setId_getID()
|
||||
{
|
||||
return "Set ID that is referred by ARIA owns";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an accessible DOM element containing an element referred by
|
||||
* ARIA owns.
|
||||
*/
|
||||
function removeA11eteiner()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_REORDER, getNode("t2_container1"))
|
||||
];
|
||||
|
||||
this.invoke = function removeA11eteiner_invoke()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ CHECKBUTTON: [ ] } // ARIA owned, 't2_owned'
|
||||
] };
|
||||
testAccessibleTree("t2_container1", tree);
|
||||
|
||||
getNode("t2_container2").removeChild(getNode("t2_container3"));
|
||||
}
|
||||
|
||||
this.finalCheck = function removeA11eteiner_finalCheck()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
] };
|
||||
testAccessibleTree("t2_container1", tree);
|
||||
}
|
||||
|
||||
this.getID = function removeA11eteiner_getID()
|
||||
{
|
||||
return "Remove an accessible DOM element containing an element referred by ARIA owns";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Steal an element from other ARIA owns element. This use case guarantees
|
||||
* that result of setAttribute/removeAttribute doesn't depend on their order.
|
||||
*/
|
||||
function stealFromOtherARIAOwns()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_REORDER, getNode("t3_container2"))
|
||||
];
|
||||
|
||||
this.invoke = function stealFromOtherARIAOwns_invoke()
|
||||
{
|
||||
getNode("t3_container2").setAttribute("aria-owns", "t3_child");
|
||||
}
|
||||
|
||||
this.finalCheck = function stealFromOtherARIAOwns_finalCheck()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
] };
|
||||
testAccessibleTree("t3_container1", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [
|
||||
{ CHECKBUTTON: [
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("t3_container2", tree);
|
||||
}
|
||||
|
||||
this.getID = function stealFromOtherARIAOwns_getID()
|
||||
{
|
||||
return "Steal an element from other ARIA owns element";
|
||||
}
|
||||
}
|
||||
|
||||
function appendElToRecacheChildren()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_REORDER, getNode("t3_container2"))
|
||||
];
|
||||
|
||||
this.invoke = function appendElToRecacheChildren_invoke()
|
||||
{
|
||||
var div = document.createElement("div");
|
||||
div.setAttribute("role", "radio")
|
||||
getNode("t3_container2").appendChild(div);
|
||||
}
|
||||
|
||||
this.finalCheck = function appendElToRecacheChildren_finalCheck()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
] };
|
||||
testAccessibleTree("t3_container1", tree);
|
||||
|
||||
tree =
|
||||
{ SECTION: [
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ CHECKBUTTON: [ ] } // ARIA owned
|
||||
] };
|
||||
testAccessibleTree("t3_container2", tree);
|
||||
}
|
||||
|
||||
this.getID = function appendElToRecacheChildren_getID()
|
||||
{
|
||||
return "Append a child under @aria-owns element to trigger children recache";
|
||||
}
|
||||
}
|
||||
|
||||
function showHiddenElement()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_REORDER, getNode("t4_container1"))
|
||||
];
|
||||
|
||||
this.invoke = function showHiddenElement_invoke()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ RADIOBUTTON: [] }
|
||||
] };
|
||||
testAccessibleTree("t4_container1", tree);
|
||||
|
||||
getNode("t4_child1").style.display = "block";
|
||||
}
|
||||
|
||||
this.finalCheck = function showHiddenElement_finalCheck()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ CHECKBUTTON: [] },
|
||||
{ RADIOBUTTON: [] }
|
||||
] };
|
||||
testAccessibleTree("t4_container1", tree);
|
||||
}
|
||||
|
||||
this.getID = function showHiddenElement_getID()
|
||||
{
|
||||
return "Show hidden ARIA owns referred element";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,31 +408,33 @@
|
||||
// Test
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
gA11yEventDumpToConsole = true;
|
||||
enableLogging("tree"); // debug stuff
|
||||
//gA11yEventDumpToConsole = true;
|
||||
//enableLogging("tree"); // debug stuff
|
||||
|
||||
var gQueue = null;
|
||||
|
||||
function doTest()
|
||||
{
|
||||
// nested and recursive aria-owns
|
||||
var tree =
|
||||
{ SECTION: [ // container
|
||||
{ SECTION: [ // child
|
||||
{ SECTION: [ // mid div
|
||||
{ SECTION: [] } // grandchild
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("container", tree);
|
||||
|
||||
// dynamic tests
|
||||
gQueue = new eventQueue();
|
||||
|
||||
// test1
|
||||
gQueue.push(new removeARIAOwns());
|
||||
gQueue.push(new setARIAOwns());
|
||||
gQueue.push(new addIdToARIAOwns());
|
||||
gQueue.push(new appendEl());
|
||||
gQueue.push(new removeEl());
|
||||
gQueue.push(new removeId());
|
||||
gQueue.push(new setId());
|
||||
|
||||
// test2
|
||||
gQueue.push(new removeA11eteiner());
|
||||
|
||||
// test3
|
||||
gQueue.push(new stealFromOtherARIAOwns());
|
||||
gQueue.push(new appendElToRecacheChildren());
|
||||
|
||||
// test4
|
||||
gQueue.push(new showHiddenElement());
|
||||
|
||||
gQueue.invoke(); // SimpleTest.finish() will be called in the end
|
||||
}
|
||||
@@ -214,21 +452,31 @@
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<div id="container" aria-owns="child" aria-label="container"></div>
|
||||
<div id="child" aria-label="child">
|
||||
<div aria-owns="grandchild" aria-label="midchild"></div>
|
||||
</div>
|
||||
<div id="grandchild" aria-owns="container" aria-label="grandchild"></div>
|
||||
|
||||
<div id="container2" aria-owns="t2_checkbox t2_button">
|
||||
<div role="button" id="t2_button"></div>
|
||||
<div role="checkbox" id="t2_checkbox">
|
||||
<span id="t2_span">
|
||||
<div id="t2_subdiv"></div>
|
||||
<div id="t1_container" aria-owns="t1_checkbox t1_button">
|
||||
<div role="button" id="t1_button"></div>
|
||||
<div role="checkbox" id="t1_checkbox">
|
||||
<span id="t1_span">
|
||||
<div id="t1_subdiv"></div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="t1_group" role="group"></div>
|
||||
<div id="t1_grouptmp" role="group"></div>
|
||||
|
||||
<div id="t2_container1" aria-owns="t2_owned"></div>
|
||||
<div id="t2_container2">
|
||||
<div id="t2_container3"><div id="t2_owned" role="checkbox"></div></div>
|
||||
</div>
|
||||
|
||||
<div id="t3_container1" aria-owns="t3_child"></div>
|
||||
<div id="t3_child" role="checkbox"></div>
|
||||
<div id="t3_container2"></div>
|
||||
|
||||
<div id="t4_container1" aria-owns="t4_child1 t4_child2"></div>
|
||||
<div id="t4_container2">
|
||||
<div id="t4_child1" style="display:none" role="checkbox"></div>
|
||||
<div id="t4_child2" role="radio"></div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_HIDE, getNode("child")),
|
||||
new invokerChecker(EVENT_REORDER, this.containerNode),
|
||||
new invokerChecker(EVENT_HIDE, getNode("childDoc")),
|
||||
new invokerChecker(EVENT_SHOW, "newChildDoc")
|
||||
new invokerChecker(EVENT_SHOW, "newChildDoc"),
|
||||
new invokerChecker(EVENT_REORDER, this.containerNode)
|
||||
];
|
||||
|
||||
this.invoke = function runTest_invoke()
|
||||
|
||||
@@ -30,3 +30,9 @@ var tests = [
|
||||
inputWithoutGrouping: "123456.78", value: 123456.78
|
||||
},
|
||||
];
|
||||
|
||||
var invalidTests = [
|
||||
// Right now this will pass in a 'de' build, but not in the 'en' build that
|
||||
// are used for testing. See bug .
|
||||
// { desc: "Invalid German", langTag: "de", input: "12.34" }
|
||||
];
|
||||
|
||||
@@ -49,11 +49,24 @@ function runTest(test) {
|
||||
"') localization without grouping separator");
|
||||
}
|
||||
|
||||
function runInvalidInputTest(test) {
|
||||
elem.lang = test.langTag;
|
||||
elem.value = 0;
|
||||
elem.focus();
|
||||
elem.select();
|
||||
sendString(test.input);
|
||||
is(elem.value, "", "Test " + test.desc + " ('" + test.langTag +
|
||||
"') with invalid input: " + test.input);
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
elem = document.getElementById("input");
|
||||
for (var test of tests) {
|
||||
runTest(test, elem);
|
||||
}
|
||||
for (var test of invalidTests) {
|
||||
runInvalidInputTest(test, elem);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -57,11 +57,26 @@ function runTest(test) {
|
||||
checkIsInvalid(elem, `${desc} without grouping separator`);
|
||||
}
|
||||
|
||||
function runInvalidInputTest(test) {
|
||||
elem.lang = test.langTag;
|
||||
|
||||
gInvalid = false; // reset
|
||||
var desc = `${test.desc} (lang='${test.langTag}', id='${elem.id}')`;
|
||||
elem.value = 0;
|
||||
elem.focus();
|
||||
elem.select();
|
||||
sendString(test.input);
|
||||
checkIsInvalid(elem, `${desc} with invalid input ${test.input}`);
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
elem = document.getElementById("input");
|
||||
for (var test of tests) {
|
||||
runTest(test);
|
||||
}
|
||||
for (var test of invalidTests) {
|
||||
runInvalidInputTest(test);
|
||||
}
|
||||
elem = document.getElementById("requiredinput");
|
||||
for (var test of tests) {
|
||||
runTest(test);
|
||||
|
||||
@@ -354,10 +354,10 @@ OmxDecoder::ReleaseMediaResources() {
|
||||
for (std::set<TextureClient*>::iterator it=mPendingRecycleTexutreClients.begin();
|
||||
it!=mPendingRecycleTexutreClients.end(); it++)
|
||||
{
|
||||
GrallocTextureClientOGL* client = static_cast<GrallocTextureClientOGL*>(*it);
|
||||
client->ClearRecycleCallback();
|
||||
GrallocTextureData* client = static_cast<GrallocTextureData*>((*it)->GetInternalData());
|
||||
(*it)->ClearRecycleCallback();
|
||||
if (client->GetMediaBuffer()) {
|
||||
mPendingVideoBuffers.push(BufferItem(client->GetMediaBuffer(), client->GetAndResetReleaseFenceHandle()));
|
||||
mPendingVideoBuffers.push(BufferItem(client->GetMediaBuffer(), (*it)->GetAndResetReleaseFenceHandle()));
|
||||
}
|
||||
}
|
||||
mPendingRecycleTexutreClients.clear();
|
||||
@@ -653,8 +653,7 @@ OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs,
|
||||
// Manually increment reference count to keep MediaBuffer alive
|
||||
// during TextureClient is in use.
|
||||
mVideoBuffer->add_ref();
|
||||
GrallocTextureClientOGL* grallocClient = static_cast<GrallocTextureClientOGL*>(textureClient.get());
|
||||
grallocClient->SetMediaBuffer(mVideoBuffer);
|
||||
static_cast<GrallocTextureData*>(textureClient->GetInternalData())->SetMediaBuffer(mVideoBuffer);
|
||||
// Set recycle callback for TextureClient
|
||||
textureClient->SetRecycleCallback(OmxDecoder::RecycleCallback, this);
|
||||
{
|
||||
@@ -917,9 +916,9 @@ OmxDecoder::RecycleCallbackImp(TextureClient* aClient)
|
||||
return;
|
||||
}
|
||||
mPendingRecycleTexutreClients.erase(aClient);
|
||||
GrallocTextureClientOGL* client = static_cast<GrallocTextureClientOGL*>(aClient);
|
||||
if (client->GetMediaBuffer()) {
|
||||
mPendingVideoBuffers.push(BufferItem(client->GetMediaBuffer(), client->GetAndResetReleaseFenceHandle()));
|
||||
GrallocTextureData* grallocData = static_cast<GrallocTextureData*>(aClient->GetInternalData());
|
||||
if (grallocData->GetMediaBuffer()) {
|
||||
mPendingVideoBuffers.push(BufferItem(grallocData->GetMediaBuffer(), aClient->GetAndResetReleaseFenceHandle()));
|
||||
}
|
||||
}
|
||||
sp<AMessage> notify =
|
||||
|
||||
@@ -251,7 +251,7 @@ Align(int aX, int aAlign)
|
||||
}
|
||||
|
||||
static void
|
||||
CopyGraphicBuffer(sp<GraphicBuffer>& aSource, sp<GraphicBuffer>& aDestination, gfx::IntRect& aPicture)
|
||||
CopyGraphicBuffer(sp<GraphicBuffer>& aSource, sp<GraphicBuffer>& aDestination)
|
||||
{
|
||||
void* srcPtr = nullptr;
|
||||
aSource->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &srcPtr);
|
||||
@@ -340,7 +340,7 @@ GonkVideoDecoderManager::CreateVideoDataFromGraphicBuffer(MediaBuffer* aSource,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::IntSize size(Align(srcBuffer->getWidth(), 2) , Align(srcBuffer->getHeight(), 2));
|
||||
gfx::IntSize size(Align(aPicture.width, 2) , Align(aPicture.height, 2));
|
||||
textureClient =
|
||||
mCopyAllocator->CreateOrRecycle(gfx::SurfaceFormat::YUV, size,
|
||||
BackendSelector::Content,
|
||||
@@ -355,14 +355,13 @@ GonkVideoDecoderManager::CreateVideoDataFromGraphicBuffer(MediaBuffer* aSource,
|
||||
aPicture.height = size.height;
|
||||
|
||||
sp<GraphicBuffer> destBuffer =
|
||||
static_cast<GrallocTextureClientOGL*>(textureClient.get())->GetGraphicBuffer();
|
||||
static_cast<GrallocTextureData*>(textureClient->GetInternalData())->GetGraphicBuffer();
|
||||
|
||||
CopyGraphicBuffer(srcBuffer, destBuffer, aPicture);
|
||||
CopyGraphicBuffer(srcBuffer, destBuffer);
|
||||
} else {
|
||||
textureClient = mNativeWindow->getTextureClientFromBuffer(srcBuffer.get());
|
||||
textureClient->SetRecycleCallback(GonkVideoDecoderManager::RecycleCallback, this);
|
||||
GrallocTextureClientOGL* grallocClient = static_cast<GrallocTextureClientOGL*>(textureClient.get());
|
||||
grallocClient->SetMediaBuffer(aSource);
|
||||
static_cast<GrallocTextureData*>(textureClient->GetInternalData())->SetMediaBuffer(aSource);
|
||||
}
|
||||
|
||||
RefPtr<VideoData> data = VideoData::Create(mInfo.mVideo,
|
||||
@@ -657,7 +656,7 @@ GonkVideoDecoderManager::RecycleCallback(TextureClient* aClient, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aClient && !aClient->IsDead());
|
||||
GonkVideoDecoderManager* videoManager = static_cast<GonkVideoDecoderManager*>(aClosure);
|
||||
GrallocTextureClientOGL* client = static_cast<GrallocTextureClientOGL*>(aClient);
|
||||
GrallocTextureData* client = static_cast<GrallocTextureData*>(aClient->GetInternalData());
|
||||
aClient->ClearRecycleCallback();
|
||||
FenceHandle handle = aClient->GetAndResetReleaseFenceHandle();
|
||||
videoManager->PostReleaseVideoBuffer(client->GetMediaBuffer(), handle);
|
||||
|
||||
@@ -759,9 +759,8 @@ MediaEngineGonkVideoSource::RotateImage(layers::Image* aImage, uint32_t aWidth,
|
||||
layers::TextureFlags::DEFAULT,
|
||||
layers::ALLOC_DISALLOW_BUFFERTEXTURECLIENT);
|
||||
if (textureClient) {
|
||||
RefPtr<layers::GrallocTextureClientOGL> grallocTextureClient = textureClient->AsGrallocTextureClientOGL();
|
||||
|
||||
android::sp<android::GraphicBuffer> destBuffer = grallocTextureClient->GetGraphicBuffer();
|
||||
android::sp<android::GraphicBuffer> destBuffer =
|
||||
static_cast<layers::GrallocTextureData*>(textureClient->GetInternalData())->GetGraphicBuffer();
|
||||
|
||||
void* destMem = nullptr;
|
||||
destBuffer->lock(android::GraphicBuffer::USAGE_SW_WRITE_OFTEN, &destMem);
|
||||
|
||||
@@ -63,17 +63,17 @@ SharedSurface_Gralloc::Create(GLContext* prodGL,
|
||||
gfxContentType type = hasAlpha ? gfxContentType::COLOR_ALPHA
|
||||
: gfxContentType::COLOR;
|
||||
|
||||
typedef GrallocTextureClientOGL ptrT;
|
||||
RefPtr<ptrT> grallocTC = new ptrT(allocator,
|
||||
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(type),
|
||||
gfx::BackendType::NONE, // we don't need to use it with a DrawTarget
|
||||
flags);
|
||||
GrallocTextureData* texData = GrallocTextureData::CreateForGLRendering(
|
||||
size, gfxPlatform::GetPlatform()->Optimal2DFormatForContent(type), allocator
|
||||
);
|
||||
|
||||
if (!grallocTC->AllocateForGLRendering(size)) {
|
||||
if (!texData) {
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
sp<GraphicBuffer> buffer = grallocTC->GetGraphicBuffer();
|
||||
RefPtr<TextureClient> grallocTC = new ClientTexture(texData, flags, allocator);
|
||||
|
||||
sp<GraphicBuffer> buffer = texData->GetGraphicBuffer();
|
||||
|
||||
EGLDisplay display = egl->Display();
|
||||
EGLClientBuffer clientBuffer = buffer->getNativeBuffer();
|
||||
@@ -119,7 +119,7 @@ SharedSurface_Gralloc::SharedSurface_Gralloc(GLContext* prodGL,
|
||||
bool hasAlpha,
|
||||
GLLibraryEGL* egl,
|
||||
layers::ISurfaceAllocator* allocator,
|
||||
layers::GrallocTextureClientOGL* textureClient,
|
||||
layers::TextureClient* textureClient,
|
||||
GLuint prodTex)
|
||||
: SharedSurface(SharedSurfaceType::Gralloc,
|
||||
AttachmentType::GLTexture,
|
||||
@@ -287,7 +287,9 @@ bool
|
||||
SharedSurface_Gralloc::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
|
||||
{
|
||||
MOZ_ASSERT(out_surface);
|
||||
sp<GraphicBuffer> buffer = mTextureClient->GetGraphicBuffer();
|
||||
sp<GraphicBuffer> buffer = static_cast<GrallocTextureData*>(
|
||||
mTextureClient->GetInternalData()
|
||||
)->GetGraphicBuffer();
|
||||
|
||||
const uint8_t* grallocData = nullptr;
|
||||
auto result = buffer->lock(
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class ISurfaceAllocator;
|
||||
class GrallocTextureClientOGL;
|
||||
class TextureClient;
|
||||
}
|
||||
|
||||
namespace gl {
|
||||
@@ -41,7 +41,7 @@ protected:
|
||||
GLLibraryEGL* const mEGL;
|
||||
EGLSync mSync;
|
||||
RefPtr<layers::ISurfaceAllocator> mAllocator;
|
||||
RefPtr<layers::GrallocTextureClientOGL> mTextureClient;
|
||||
RefPtr<layers::TextureClient> mTextureClient;
|
||||
const GLuint mProdTex;
|
||||
|
||||
SharedSurface_Gralloc(GLContext* prodGL,
|
||||
@@ -49,7 +49,7 @@ protected:
|
||||
bool hasAlpha,
|
||||
GLLibraryEGL* egl,
|
||||
layers::ISurfaceAllocator* allocator,
|
||||
layers::GrallocTextureClientOGL* textureClient,
|
||||
layers::TextureClient* textureClient,
|
||||
GLuint prodTex);
|
||||
|
||||
static bool HasExtensions(GLLibraryEGL* egl, GLContext* gl);
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
return mProdTex;
|
||||
}
|
||||
|
||||
layers::GrallocTextureClientOGL* GetTextureClient() {
|
||||
layers::TextureClient* GetTextureClient() {
|
||||
return mTextureClient;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "GLScreenBuffer.h"
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/layers/BufferTexture.h"
|
||||
#include "mozilla/layers/CanvasClient.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
@@ -147,8 +148,8 @@ void
|
||||
AsyncCanvasRenderer::CopyFromTextureClient(TextureClient* aTextureClient)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
RefPtr<BufferTextureClient> buffer = static_cast<BufferTextureClient*>(aTextureClient);
|
||||
if (!buffer->Lock(layers::OpenMode::OPEN_READ)) {
|
||||
TextureClientAutoLock texLock(aTextureClient, layers::OpenMode::OPEN_READ);
|
||||
if (texLock.Succeeded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -165,16 +166,20 @@ AsyncCanvasRenderer::CopyFromTextureClient(TextureClient* aTextureClient)
|
||||
mSurfaceForBasic = gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
|
||||
}
|
||||
|
||||
const uint8_t* lockedBytes = buffer->GetLockedData();
|
||||
gfx::DataSourceSurface::ScopedMap map(mSurfaceForBasic,
|
||||
gfx::DataSourceSurface::MapType::WRITE);
|
||||
if (!map.IsMapped()) {
|
||||
buffer->Unlock();
|
||||
MappedTextureData mapped;
|
||||
if (!aTextureClient->BorrowMappedData(mapped)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t* lockedBytes = mapped.data;
|
||||
gfx::DataSourceSurface::ScopedMap map(mSurfaceForBasic,
|
||||
gfx::DataSourceSurface::MapType::WRITE);
|
||||
if (!map.IsMapped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(map.GetStride() == mapped.stride);
|
||||
memcpy(map.GetData(), lockedBytes, map.GetStride() * mSurfaceForBasic->GetSize().height);
|
||||
buffer->Unlock();
|
||||
|
||||
if (mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
|
||||
mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8X8) {
|
||||
|
||||
@@ -0,0 +1,449 @@
|
||||
/* -*- 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 "BufferTexture.h"
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/fallible.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class MemoryTextureData : public BufferTextureData
|
||||
{
|
||||
public:
|
||||
static MemoryTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend,TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags,
|
||||
ISurfaceAllocator* aAllocator);
|
||||
|
||||
virtual TextureData*
|
||||
CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
virtual void Deallocate(ISurfaceAllocator*) override;
|
||||
|
||||
MemoryTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
uint8_t* aBuffer, size_t aBufferSize)
|
||||
: BufferTextureData(aSize, aFormat, aMoz2DBackend)
|
||||
, mBuffer(aBuffer)
|
||||
, mBufferSize(aBufferSize)
|
||||
{
|
||||
MOZ_ASSERT(aBuffer);
|
||||
MOZ_ASSERT(aBufferSize);
|
||||
}
|
||||
|
||||
virtual uint8_t* GetBuffer() override { return mBuffer; }
|
||||
|
||||
virtual size_t GetBufferSize() override { return mBufferSize; }
|
||||
|
||||
protected:
|
||||
uint8_t* mBuffer;
|
||||
size_t mBufferSize;
|
||||
};
|
||||
|
||||
class ShmemTextureData : public BufferTextureData
|
||||
{
|
||||
public:
|
||||
static ShmemTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend, TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags,
|
||||
ISurfaceAllocator* aAllocator);
|
||||
|
||||
virtual TextureData*
|
||||
CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
virtual void Deallocate(ISurfaceAllocator* aAllocator) override;
|
||||
|
||||
ShmemTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend, mozilla::ipc::Shmem aShmem)
|
||||
: BufferTextureData(aSize, aFormat, aMoz2DBackend)
|
||||
, mShmem(aShmem)
|
||||
{
|
||||
MOZ_ASSERT(mShmem.Size<uint8_t>());
|
||||
}
|
||||
|
||||
virtual uint8_t* GetBuffer() override { return mShmem.get<uint8_t>(); }
|
||||
|
||||
virtual size_t GetBufferSize() override { return mShmem.Size<uint8_t>(); }
|
||||
|
||||
protected:
|
||||
mozilla::ipc::Shmem mShmem;
|
||||
};
|
||||
|
||||
BufferTextureData*
|
||||
BufferTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend, TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags,
|
||||
ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
if (!aAllocator || aAllocator->IsSameProcess()) {
|
||||
return MemoryTextureData::Create(aSize, aFormat, aMoz2DBackend, aFlags, aAllocFlags, aAllocator);
|
||||
} else {
|
||||
return ShmemTextureData::Create(aSize, aFormat, aMoz2DBackend, aFlags, aAllocFlags, aAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
BufferTextureData*
|
||||
BufferTextureData::CreateWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
if (aSize == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BufferTextureData* data;
|
||||
if (!aAllocator || aAllocator->IsSameProcess()) {
|
||||
uint8_t* buffer = new (fallible) uint8_t[aSize];
|
||||
if (!buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
data = new MemoryTextureData(gfx::IntSize(), aFormat, gfx::BackendType::NONE, buffer, aSize);
|
||||
} else {
|
||||
ipc::Shmem shm;
|
||||
if (!aAllocator->AllocUnsafeShmem(aSize, OptimalShmemType(), &shm)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
data = new ShmemTextureData(gfx::IntSize(), aFormat, gfx::BackendType::NONE, shm);
|
||||
}
|
||||
|
||||
// Initialize the metadata with something, even if it will have to be rewritten
|
||||
// afterwards since we don't know the dimensions of the texture at this point.
|
||||
if (aFormat == gfx::SurfaceFormat::YUV) {
|
||||
YCbCrImageDataSerializer serializer(data->GetBuffer(), data->GetBufferSize());
|
||||
serializer.InitializeBufferInfo(gfx::IntSize(0,0), gfx::IntSize(0,0), StereoMode::MONO);
|
||||
} else {
|
||||
ImageDataSerializer serializer(data->GetBuffer(), data->GetBufferSize());
|
||||
serializer.InitializeBufferInfo(gfx::IntSize(0, 0), aFormat);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
BufferTextureData*
|
||||
BufferTextureData::CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
||||
gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize, aCbCrSize);
|
||||
BufferTextureData* texture = CreateWithBufferSize(aAllocator, gfx::SurfaceFormat::YUV,
|
||||
bufSize, aTextureFlags);
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
YCbCrImageDataSerializer serializer(texture->GetBuffer(), texture->GetBufferSize());
|
||||
serializer.InitializeBufferInfo(aYSize, aCbCrSize, aStereoMode);
|
||||
texture->mSize = aYSize;
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureData::SupportsMoz2D() const
|
||||
{
|
||||
switch (mFormat) {
|
||||
case gfx::SurfaceFormat::YUV:
|
||||
case gfx::SurfaceFormat::NV12:
|
||||
case gfx::SurfaceFormat::UNKNOWN:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
BufferTextureData::BorrowDrawTarget()
|
||||
{
|
||||
if (mDrawTarget) {
|
||||
mDrawTarget->SetTransform(gfx::Matrix());
|
||||
RefPtr<gfx::DrawTarget> dt = mDrawTarget;
|
||||
return dt.forget();
|
||||
}
|
||||
|
||||
ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
|
||||
if (!serializer.IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mDrawTarget = serializer.GetAsDrawTarget(mMoz2DBackend);
|
||||
if (mDrawTarget) {
|
||||
RefPtr<gfx::DrawTarget> dt = mDrawTarget;
|
||||
return dt.forget();
|
||||
}
|
||||
|
||||
// TODO - should we warn? should we really fallback to cairo? perhaps
|
||||
// at least update mMoz2DBackend...
|
||||
mDrawTarget = serializer.GetAsDrawTarget(gfx::BackendType::CAIRO);
|
||||
if (!mDrawTarget) {
|
||||
gfxCriticalNote << "BorrowDrawTarget failure, original backend " << (int)mMoz2DBackend;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DrawTarget> dt = mDrawTarget;
|
||||
return dt.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureData::BorrowMappedData(MappedTextureData& aData)
|
||||
{
|
||||
if (mFormat == gfx::SurfaceFormat::YUV) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageDataDeserializer view(GetBuffer(), GetBufferSize());
|
||||
if (!view.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aData.data = view.GetData();
|
||||
aData.size = view.GetSize();
|
||||
aData.stride = view.GetStride();
|
||||
aData.format = mFormat;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureData::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap)
|
||||
{
|
||||
if (mFormat != gfx::SurfaceFormat::YUV) {
|
||||
return false;
|
||||
}
|
||||
|
||||
YCbCrImageDataDeserializer view(GetBuffer(), GetBufferSize());
|
||||
if (!view.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aMap.stereoMode = view.GetStereoMode();
|
||||
aMap.metadata = GetBuffer();
|
||||
|
||||
aMap.y.data = view.GetYData();
|
||||
aMap.y.size = view.GetYSize();
|
||||
aMap.y.stride = view.GetYStride();
|
||||
aMap.y.skip = 0;
|
||||
|
||||
aMap.cb.data = view.GetCbData();
|
||||
aMap.cb.size = view.GetCbCrSize();
|
||||
aMap.cb.stride = view.GetCbCrStride();
|
||||
aMap.cb.skip = 0;
|
||||
|
||||
aMap.cr.data = view.GetCrData();
|
||||
aMap.cr.size = view.GetCbCrSize();
|
||||
aMap.cr.stride = view.GetCbCrStride();
|
||||
aMap.cr.skip = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
{
|
||||
ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> surface = serializer.GetAsSurface();
|
||||
|
||||
if (!surface) {
|
||||
gfxCriticalError() << "Failed to get serializer as surface!";
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> srcSurf = aSurface->GetDataSurface();
|
||||
|
||||
if (!srcSurf) {
|
||||
gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (surface->GetSize() != srcSurf->GetSize() || surface->GetFormat() != srcSurf->GetFormat()) {
|
||||
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << surface->GetSize() << " " << surface->GetFormat() << " Other: " << aSurface->GetSize() << " " << aSurface->GetFormat();
|
||||
return false;
|
||||
}
|
||||
|
||||
gfx::DataSourceSurface::MappedSurface sourceMap;
|
||||
gfx::DataSourceSurface::MappedSurface destMap;
|
||||
if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) {
|
||||
gfxCriticalError() << "Failed to map source surface for UpdateFromSurface.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!surface->Map(gfx::DataSourceSurface::WRITE, &destMap)) {
|
||||
srcSurf->Unmap();
|
||||
gfxCriticalError() << "Failed to map destination surface for UpdateFromSurface.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (int y = 0; y < srcSurf->GetSize().height; y++) {
|
||||
memcpy(destMap.mData + destMap.mStride * y,
|
||||
sourceMap.mData + sourceMap.mStride * y,
|
||||
srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
|
||||
}
|
||||
|
||||
srcSurf->Unmap();
|
||||
surface->Unmap();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MemoryTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN);
|
||||
if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aOutDescriptor = SurfaceDescriptorMemory(reinterpret_cast<uintptr_t>(mBuffer),
|
||||
GetFormat());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool InitBuffer(uint8_t* buf, size_t bufSize,
|
||||
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
if (!buf) {
|
||||
gfxDebug() << "BufferTextureData: Failed to allocate " << bufSize << " bytes";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aAllocFlags & ALLOC_CLEAR_BUFFER) {
|
||||
memset(buf, 0, bufSize);
|
||||
}
|
||||
if (aAllocFlags & ALLOC_CLEAR_BUFFER_WHITE) {
|
||||
memset(buf, 0xFF, bufSize);
|
||||
}
|
||||
|
||||
ImageDataSerializer serializer(buf, bufSize);
|
||||
serializer.InitializeBufferInfo(aSize, aFormat);
|
||||
return true;
|
||||
}
|
||||
|
||||
MemoryTextureData*
|
||||
MemoryTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend, TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags,
|
||||
ISurfaceAllocator*)
|
||||
{
|
||||
if (aSize.width <= 0 || aSize.height <= 0) {
|
||||
gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, aFormat);
|
||||
if (!bufSize) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t* buf = new (fallible) uint8_t[bufSize];
|
||||
|
||||
if (InitBuffer(buf, bufSize, aSize, aFormat, aAllocFlags)) {
|
||||
GfxMemoryImageReporter::DidAlloc(buf);
|
||||
return new MemoryTextureData(aSize, aFormat, aMoz2DBackend, buf, bufSize);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MemoryTextureData::Deallocate(ISurfaceAllocator*)
|
||||
{
|
||||
MOZ_ASSERT(mBuffer);
|
||||
GfxMemoryImageReporter::WillFree(mBuffer);
|
||||
delete [] mBuffer;
|
||||
mBuffer = nullptr;
|
||||
}
|
||||
|
||||
TextureData*
|
||||
MemoryTextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
return MemoryTextureData::Create(mSize, mFormat, mMoz2DBackend,
|
||||
aFlags, aAllocFlags, aAllocator);
|
||||
}
|
||||
|
||||
bool
|
||||
ShmemTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(GetFormat() != gfx::SurfaceFormat::UNKNOWN);
|
||||
if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aOutDescriptor = SurfaceDescriptorShmem(mShmem, GetFormat());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ShmemTextureData*
|
||||
ShmemTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend, TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags,
|
||||
ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
MOZ_ASSERT(aAllocator);
|
||||
if (!aAllocator) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aSize.width <= 0 || aSize.height <= 0) {
|
||||
gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, aFormat);
|
||||
if (!bufSize) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mozilla::ipc::Shmem shm;
|
||||
if (!aAllocator->AllocUnsafeShmem(bufSize, OptimalShmemType(), &shm)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t* buf = shm.get<uint8_t>();
|
||||
|
||||
if (InitBuffer(buf, bufSize, aSize, aFormat, aAllocFlags)) {
|
||||
return new ShmemTextureData(aSize, aFormat, aMoz2DBackend, shm);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TextureData*
|
||||
ShmemTextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
return ShmemTextureData::Create(mSize, mFormat, mMoz2DBackend,
|
||||
aFlags, aAllocFlags, aAllocator);
|
||||
}
|
||||
|
||||
void
|
||||
ShmemTextureData::Deallocate(ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
aAllocator->DeallocShmem(mShmem);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
@@ -0,0 +1,81 @@
|
||||
/* -*- 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_LAYERS_BUFFERETEXTURE
|
||||
#define MOZILLA_LAYERS_BUFFERETEXTURE
|
||||
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class BufferTextureData : public TextureData
|
||||
{
|
||||
public:
|
||||
static BufferTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend,TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags,
|
||||
ISurfaceAllocator* aAllocator);
|
||||
|
||||
static BufferTextureData* CreateWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
static BufferTextureData* CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
||||
gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
virtual bool Lock(OpenMode aMode, FenceHandle*) override { return true; }
|
||||
|
||||
virtual void Unlock() override {}
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
virtual bool CanExposeMappedData() const override { return true; }
|
||||
|
||||
virtual bool BorrowMappedData(MappedTextureData& aMap) override;
|
||||
|
||||
virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap) override;
|
||||
|
||||
virtual bool SupportsMoz2D() const override;
|
||||
|
||||
virtual bool HasInternalBuffer() const override { return true; }
|
||||
|
||||
// use ClientTexture's default implementation
|
||||
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
protected:
|
||||
virtual uint8_t* GetBuffer() = 0;
|
||||
virtual size_t GetBufferSize() = 0;
|
||||
|
||||
BufferTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, gfx::BackendType aMoz2DBackend)
|
||||
: mSize(aSize)
|
||||
, mFormat(aFormat)
|
||||
, mMoz2DBackend(aMoz2DBackend)
|
||||
{}
|
||||
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
gfx::IntSize mSize;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
gfx::BackendType mMoz2DBackend;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
@@ -73,25 +73,21 @@ GrallocImage::SetData(const Data& aData)
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<GrallocTextureClientOGL> textureClient =
|
||||
new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(),
|
||||
gfx::SurfaceFormat::UNKNOWN,
|
||||
gfx::BackendType::NONE);
|
||||
// GrallocImages are all YUV and don't support alpha.
|
||||
textureClient->SetIsOpaque(true);
|
||||
bool result =
|
||||
textureClient->AllocateGralloc(mData.mYSize,
|
||||
HAL_PIXEL_FORMAT_YV12,
|
||||
GraphicBuffer::USAGE_SW_READ_OFTEN |
|
||||
GraphicBuffer::USAGE_SW_WRITE_OFTEN |
|
||||
GraphicBuffer::USAGE_HW_TEXTURE);
|
||||
sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer();
|
||||
if (!result || !graphicBuffer.get()) {
|
||||
mTextureClient = nullptr;
|
||||
ISurfaceAllocator* allocator = ImageBridgeChild::GetSingleton();
|
||||
GrallocTextureData* texData = GrallocTextureData::Create(mData.mYSize, HAL_PIXEL_FORMAT_YV12,
|
||||
gfx::BackendType::NONE,
|
||||
GraphicBuffer::USAGE_SW_READ_OFTEN |
|
||||
GraphicBuffer::USAGE_SW_WRITE_OFTEN |
|
||||
GraphicBuffer::USAGE_HW_TEXTURE,
|
||||
allocator
|
||||
);
|
||||
|
||||
if (!texData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mTextureClient = textureClient;
|
||||
mTextureClient = new ClientTexture(texData, TextureFlags::DEFAULT, allocator);
|
||||
sp<GraphicBuffer> graphicBuffer = texData->GetGraphicBuffer();
|
||||
|
||||
void* vaddr;
|
||||
if (graphicBuffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
|
||||
@@ -150,8 +146,7 @@ GrallocImage::SetData(const Data& aData)
|
||||
void
|
||||
GrallocImage::SetData(TextureClient* aGraphicBuffer, const gfx::IntSize& aSize)
|
||||
{
|
||||
MOZ_ASSERT(aGraphicBuffer->AsGrallocTextureClientOGL());
|
||||
mTextureClient = aGraphicBuffer->AsGrallocTextureClientOGL();
|
||||
mTextureClient = aGraphicBuffer;
|
||||
mSize = aSize;
|
||||
}
|
||||
|
||||
@@ -443,8 +438,7 @@ GrallocImage::GetAsSourceSurface()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
android::sp<GraphicBuffer> graphicBuffer =
|
||||
mTextureClient->GetGraphicBuffer();
|
||||
android::sp<GraphicBuffer> graphicBuffer = GetGraphicBuffer();
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> surface =
|
||||
GetDataSourceSurfaceFrom(graphicBuffer, mSize, mData);
|
||||
@@ -458,7 +452,7 @@ GrallocImage::GetGraphicBuffer() const
|
||||
if (!mTextureClient) {
|
||||
return nullptr;
|
||||
}
|
||||
return mTextureClient->GetGraphicBuffer();
|
||||
return static_cast<GrallocTextureData*>(mTextureClient->GetInternalData())->GetGraphicBuffer();
|
||||
}
|
||||
|
||||
void*
|
||||
@@ -467,8 +461,7 @@ GrallocImage::GetNativeBuffer()
|
||||
if (!mTextureClient) {
|
||||
return nullptr;
|
||||
}
|
||||
android::sp<android::GraphicBuffer> graphicBuffer =
|
||||
mTextureClient->GetGraphicBuffer();
|
||||
android::sp<android::GraphicBuffer> graphicBuffer = GetGraphicBuffer();
|
||||
if (!graphicBuffer.get()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class GrallocTextureClientOGL;
|
||||
class TextureClient;
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
GetDataSourceSurfaceFrom(android::sp<android::GraphicBuffer>& aGraphicBuffer,
|
||||
@@ -124,7 +124,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<GrallocTextureClientOGL> mTextureClient;
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
||||
@@ -89,8 +89,8 @@ InitTextures(IDirect3DDevice9* aDevice,
|
||||
}
|
||||
|
||||
tmpTexture->GetSurfaceLevel(0, getter_AddRefs(aSurface));
|
||||
aSurface->LockRect(&aLockedRect, nullptr, 0);
|
||||
if (!aLockedRect.pBits) {
|
||||
if (FAILED(aSurface->LockRect(&aLockedRect, nullptr, 0)) ||
|
||||
!aLockedRect.pBits) {
|
||||
NS_WARNING("Could not lock surface");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -98,19 +98,31 @@ InitTextures(IDirect3DDevice9* aDevice,
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
static void
|
||||
static bool
|
||||
FinishTextures(IDirect3DDevice9* aDevice,
|
||||
IDirect3DTexture9* aTexture,
|
||||
IDirect3DSurface9* aSurface)
|
||||
{
|
||||
if (!aDevice) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr = aSurface->UnlockRect();
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aSurface->UnlockRect();
|
||||
RefPtr<IDirect3DSurface9> dstSurface;
|
||||
aTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||
aDevice->UpdateSurface(aSurface, nullptr, dstSurface, nullptr);
|
||||
hr = aTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = aDevice->UpdateSurface(aSurface, nullptr, dstSurface, nullptr);
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool UploadData(IDirect3DDevice9* aDevice,
|
||||
@@ -137,14 +149,16 @@ static bool UploadData(IDirect3DDevice9* aDevice,
|
||||
}
|
||||
}
|
||||
|
||||
FinishTextures(aDevice, aTexture, surf);
|
||||
return true;
|
||||
return FinishTextures(aDevice, aTexture, surf);
|
||||
}
|
||||
|
||||
TextureClient*
|
||||
IMFYCbCrImage::GetD3D9TextureClient(CompositableClient* aClient)
|
||||
{
|
||||
IDirect3DDevice9* device = gfxWindowsPlatform::GetPlatform()->GetD3D9Device();
|
||||
if (!device) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<IDirect3DTexture9> textureY;
|
||||
HANDLE shareHandleY = 0;
|
||||
@@ -208,12 +222,12 @@ IMFYCbCrImage::GetD3D9TextureClient(CompositableClient* aClient)
|
||||
TextureClient*
|
||||
IMFYCbCrImage::GetTextureClient(CompositableClient* aClient)
|
||||
{
|
||||
LayersBackend backend = aClient->GetForwarder()->GetCompositorBackendType();
|
||||
ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11ImageBridgeDevice();
|
||||
if (!device ||
|
||||
aClient->GetForwarder()->GetCompositorBackendType() != LayersBackend::LAYERS_D3D11) {
|
||||
|
||||
IDirect3DDevice9* d3d9device = gfxWindowsPlatform::GetPlatform()->GetD3D9Device();
|
||||
if (d3d9device && aClient->GetForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D9) {
|
||||
if (!device || backend != LayersBackend::LAYERS_D3D11) {
|
||||
if (backend == LayersBackend::LAYERS_D3D9 ||
|
||||
backend == LayersBackend::LAYERS_D3D11) {
|
||||
return GetD3D9TextureClient(aClient);
|
||||
}
|
||||
return nullptr;
|
||||
@@ -259,28 +273,11 @@ IMFYCbCrImage::GetTextureClient(CompositableClient* aClient)
|
||||
mData.mCbCrStride, mData.mCbCrStride * mData.mCbCrSize.height);
|
||||
}
|
||||
|
||||
RefPtr<IDXGIResource> resource;
|
||||
|
||||
HANDLE shareHandleY;
|
||||
textureY->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
|
||||
hr = resource->GetSharedHandle(&shareHandleY);
|
||||
|
||||
HANDLE shareHandleCb;
|
||||
textureCb->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
|
||||
hr = resource->GetSharedHandle(&shareHandleCb);
|
||||
|
||||
HANDLE shareHandleCr;
|
||||
textureCr->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
|
||||
hr = resource->GetSharedHandle(&shareHandleCr);
|
||||
|
||||
mTextureClient = DXGIYCbCrTextureClient::Create(aClient->GetForwarder(),
|
||||
TextureFlags::DEFAULT,
|
||||
textureY,
|
||||
textureCb,
|
||||
textureCr,
|
||||
shareHandleY,
|
||||
shareHandleCb,
|
||||
shareHandleCr,
|
||||
GetSize(),
|
||||
mData.mYSize,
|
||||
mData.mCbCrSize);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "Mfidl.h"
|
||||
#include "mfidl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
@@ -39,6 +39,8 @@ public:
|
||||
static uint32_t ComputeMinBufferSize(gfx::IntSize aSize,
|
||||
gfx::SurfaceFormat aFormat);
|
||||
|
||||
size_t GetBufferSize() const { return mDataSize; }
|
||||
|
||||
protected:
|
||||
|
||||
ImageDataSerializerBase(uint8_t* aData, size_t aDataSize)
|
||||
|
||||
+180
-90
@@ -345,7 +345,7 @@ private:
|
||||
class CreateServerSocketRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CreateServerSocketRunnable(LayerScopeManager *aLayerScopeManager)
|
||||
explicit CreateServerSocketRunnable(LayerScopeManager *aLayerScopeManager)
|
||||
: mLayerScopeManager(aLayerScopeManager)
|
||||
{
|
||||
}
|
||||
@@ -366,6 +366,38 @@ private:
|
||||
|
||||
LayerScopeManager gLayerScopeManager;
|
||||
|
||||
/*
|
||||
* The static helper functions that set data into the packet
|
||||
* 1. DumpRect
|
||||
* 2. DumpFilter
|
||||
*/
|
||||
template<typename T>
|
||||
static void DumpRect(T* aPacketRect, const Rect& aRect)
|
||||
{
|
||||
aPacketRect->set_x(aRect.x);
|
||||
aPacketRect->set_y(aRect.y);
|
||||
aPacketRect->set_w(aRect.width);
|
||||
aPacketRect->set_h(aRect.height);
|
||||
}
|
||||
|
||||
static void DumpFilter(TexturePacket* aTexturePacket, const Filter& aFilter)
|
||||
{
|
||||
switch (aFilter) {
|
||||
case Filter::GOOD:
|
||||
aTexturePacket->set_mfilter(TexturePacket::GOOD);
|
||||
break;
|
||||
case Filter::LINEAR:
|
||||
aTexturePacket->set_mfilter(TexturePacket::LINEAR);
|
||||
break;
|
||||
case Filter::POINT:
|
||||
aTexturePacket->set_mfilter(TexturePacket::POINT);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Can't dump unexpected mFilter to texture packet!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* DebugGLData is the base class of
|
||||
* 1. DebugGLFrameStatusData (Frame start/end packet)
|
||||
@@ -435,28 +467,33 @@ public:
|
||||
DebugGLGraphicBuffer(void *layerRef,
|
||||
GLenum target,
|
||||
GLuint name,
|
||||
const LayerRenderState &aState)
|
||||
const LayerRenderState &aState,
|
||||
bool aIsMask,
|
||||
UniquePtr<Packet> aPacket)
|
||||
: DebugGLData(Packet::TEXTURE),
|
||||
mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
|
||||
mTarget(target),
|
||||
mName(name),
|
||||
mState(aState)
|
||||
mState(aState),
|
||||
mIsMask(aIsMask),
|
||||
mPacket(Move(aPacket))
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Write() override {
|
||||
return WriteToStream(mPacket);
|
||||
return WriteToStream(*mPacket);
|
||||
}
|
||||
|
||||
bool TryPack(bool packData) {
|
||||
android::sp<android::GraphicBuffer> buffer = mState.mSurface;
|
||||
MOZ_ASSERT(buffer.get());
|
||||
|
||||
mPacket.set_type(mDataType);
|
||||
TexturePacket* tp = mPacket.mutable_texture();
|
||||
mPacket->set_type(mDataType);
|
||||
TexturePacket* tp = mPacket->mutable_texture();
|
||||
tp->set_layerref(mLayerRef);
|
||||
tp->set_name(mName);
|
||||
tp->set_target(mTarget);
|
||||
tp->set_ismask(mIsMask);
|
||||
|
||||
int pFormat = buffer->getPixelFormat();
|
||||
if (HAL_PIXEL_FORMAT_RGBA_8888 != pFormat &&
|
||||
@@ -513,7 +550,8 @@ private:
|
||||
GLenum mTarget;
|
||||
GLuint mName;
|
||||
const LayerRenderState &mState;
|
||||
Packet mPacket;
|
||||
bool mIsMask;
|
||||
UniquePtr<Packet> mPacket;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -523,13 +561,17 @@ public:
|
||||
void* layerRef,
|
||||
GLenum target,
|
||||
GLuint name,
|
||||
DataSourceSurface* img)
|
||||
DataSourceSurface* img,
|
||||
bool aIsMask,
|
||||
UniquePtr<Packet> aPacket)
|
||||
: DebugGLData(Packet::TEXTURE),
|
||||
mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
|
||||
mTarget(target),
|
||||
mName(name),
|
||||
mContextAddress(reinterpret_cast<intptr_t>(cx)),
|
||||
mDatasize(0)
|
||||
mDatasize(0),
|
||||
mIsMask(aIsMask),
|
||||
mPacket(Move(aPacket))
|
||||
{
|
||||
// pre-packing
|
||||
// DataSourceSurface may have locked buffer,
|
||||
@@ -539,19 +581,20 @@ public:
|
||||
}
|
||||
|
||||
virtual bool Write() override {
|
||||
return WriteToStream(mPacket);
|
||||
return WriteToStream(*mPacket);
|
||||
}
|
||||
|
||||
private:
|
||||
void pack(DataSourceSurface* aImage) {
|
||||
mPacket.set_type(mDataType);
|
||||
mPacket->set_type(mDataType);
|
||||
|
||||
TexturePacket* tp = mPacket.mutable_texture();
|
||||
TexturePacket* tp = mPacket->mutable_texture();
|
||||
tp->set_layerref(mLayerRef);
|
||||
tp->set_name(mName);
|
||||
tp->set_target(mTarget);
|
||||
tp->set_dataformat(LOCAL_GL_RGBA);
|
||||
tp->set_glcontext(static_cast<uint64_t>(mContextAddress));
|
||||
tp->set_ismask(mIsMask);
|
||||
|
||||
if (aImage) {
|
||||
tp->set_width(aImage->GetSize().width);
|
||||
@@ -590,9 +633,10 @@ protected:
|
||||
GLuint mName;
|
||||
intptr_t mContextAddress;
|
||||
uint32_t mDatasize;
|
||||
bool mIsMask;
|
||||
|
||||
// Packet data
|
||||
Packet mPacket;
|
||||
UniquePtr<Packet> mPacket;
|
||||
};
|
||||
|
||||
class DebugGLColorData final: public DebugGLData {
|
||||
@@ -713,18 +757,9 @@ public:
|
||||
MOZ_ASSERT(mRects > 0 && mRects < 4);
|
||||
for (size_t i = 0; i < mRects; i++) {
|
||||
// Vertex
|
||||
layerscope::DrawPacket::Rect* pRect = dp->add_layerrect();
|
||||
pRect->set_x(mLayerRects[i].x);
|
||||
pRect->set_y(mLayerRects[i].y);
|
||||
pRect->set_w(mLayerRects[i].width);
|
||||
pRect->set_h(mLayerRects[i].height);
|
||||
|
||||
DumpRect(dp->add_layerrect(), mLayerRects[i]);
|
||||
// UV
|
||||
pRect = dp->add_texturerect();
|
||||
pRect->set_x(mTextureRects[i].x);
|
||||
pRect->set_y(mTextureRects[i].y);
|
||||
pRect->set_w(mTextureRects[i].width);
|
||||
pRect->set_h(mTextureRects[i].height);
|
||||
DumpRect(dp->add_texturerect(), mTextureRects[i]);
|
||||
}
|
||||
|
||||
for (GLuint texId: mTexIDs) {
|
||||
@@ -872,9 +907,11 @@ NS_IMPL_ISUPPORTS(DebugDataSender::SendTask, nsIRunnable);
|
||||
* 2. SendEffectChain
|
||||
* 1. SendTexturedEffect
|
||||
* -> SendTextureSource
|
||||
* 2. SendYCbCrEffect
|
||||
* 2. SendMaskEffect
|
||||
* -> SendTextureSource
|
||||
* 3. SendColor
|
||||
* 3. SendYCbCrEffect
|
||||
* -> SendTextureSource
|
||||
* 4. SendColor
|
||||
*/
|
||||
class SenderHelper
|
||||
{
|
||||
@@ -895,8 +932,7 @@ public:
|
||||
|
||||
static bool GetLayersTreeSendable() {return sLayersTreeSendable;}
|
||||
|
||||
static void ClearTextureIdList();
|
||||
|
||||
static void ClearSentTextureIds();
|
||||
|
||||
// Sender private functions
|
||||
private:
|
||||
@@ -907,58 +943,57 @@ private:
|
||||
static void SendTextureSource(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
GLuint aTexID,
|
||||
bool aFlipY);
|
||||
bool aFlipY,
|
||||
bool aIsMask,
|
||||
UniquePtr<Packet> aPacket);
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
static bool SendGraphicBuffer(void* aLayerRef,
|
||||
static bool SendGraphicBuffer(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
GLuint aTexID,
|
||||
const TexturedEffect* aEffect);
|
||||
const TexturedEffect* aEffect,
|
||||
bool aIsMask);
|
||||
#endif
|
||||
static void SetAndSendTexture(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
const TexturedEffect* aEffect);
|
||||
static void SendTexturedEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const TexturedEffect* aEffect);
|
||||
static void SendMaskEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const EffectMask* aEffect);
|
||||
static void SendYCbCrEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const EffectYCbCr* aEffect);
|
||||
static GLuint GetTextureID(GLContext* aGLContext,
|
||||
TextureSourceOGL* aSource);
|
||||
static bool IsTextureIdContainsInList(GLuint aTextureId);
|
||||
static bool HasTextureIdBeenSent(GLuint aTextureId);
|
||||
// Data fields
|
||||
private:
|
||||
static bool sLayersTreeSendable;
|
||||
static bool sLayersBufferSendable;
|
||||
static std::list<GLuint> sTextureIdList;
|
||||
static std::vector<GLuint> sSentTextureIds;
|
||||
};
|
||||
|
||||
bool SenderHelper::sLayersTreeSendable = true;
|
||||
bool SenderHelper::sLayersBufferSendable = true;
|
||||
std::list<GLuint> SenderHelper::sTextureIdList;
|
||||
std::vector<GLuint> SenderHelper::sSentTextureIds;
|
||||
|
||||
|
||||
// ----------------------------------------------
|
||||
// SenderHelper implementation
|
||||
// ----------------------------------------------
|
||||
void
|
||||
SenderHelper::ClearTextureIdList()
|
||||
SenderHelper::ClearSentTextureIds()
|
||||
{
|
||||
std::list<GLuint>::iterator it;
|
||||
while (!sTextureIdList.empty()) {
|
||||
it = sTextureIdList.begin();
|
||||
sTextureIdList.erase(it);
|
||||
}
|
||||
sSentTextureIds.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
SenderHelper::IsTextureIdContainsInList(GLuint aTextureId)
|
||||
SenderHelper::HasTextureIdBeenSent(GLuint aTextureId)
|
||||
{
|
||||
for (std::list<GLuint>::iterator it = sTextureIdList.begin();
|
||||
it != sTextureIdList.end(); ++it) {
|
||||
if (*it == aTextureId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return std::find(sSentTextureIds.begin(), sSentTextureIds.end(), aTextureId) != sSentTextureIds.end();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -975,7 +1010,9 @@ SenderHelper::SendLayer(LayerComposite* aLayer,
|
||||
case Layer::TYPE_COLOR: {
|
||||
EffectChain effect;
|
||||
aLayer->GenEffectChain(effect);
|
||||
SenderHelper::SendEffectChain(nullptr, effect, aWidth, aHeight);
|
||||
|
||||
LayerScope::DrawBegin();
|
||||
LayerScope::DrawEnd(nullptr, effect, aWidth, aHeight);
|
||||
break;
|
||||
}
|
||||
case Layer::TYPE_IMAGE:
|
||||
@@ -991,7 +1028,9 @@ SenderHelper::SendLayer(LayerComposite* aLayer,
|
||||
// Generate primary effect (lock and gen)
|
||||
AutoLockCompositableHost lock(compHost);
|
||||
aLayer->GenEffectChain(effect);
|
||||
SenderHelper::SendEffectChain(compOGL->gl(), effect);
|
||||
|
||||
LayerScope::DrawBegin();
|
||||
LayerScope::DrawEnd(compOGL->gl(), effect, aWidth, aHeight);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1035,13 +1074,18 @@ void
|
||||
SenderHelper::SendTextureSource(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
GLuint aTexID,
|
||||
bool aFlipY)
|
||||
bool aFlipY,
|
||||
bool aIsMask,
|
||||
UniquePtr<Packet> aPacket)
|
||||
{
|
||||
MOZ_ASSERT(aGLContext);
|
||||
if (!aGLContext) {
|
||||
return;
|
||||
}
|
||||
GLuint texID = GetTextureID(aGLContext, aSource);
|
||||
if (HasTextureIdBeenSent(texID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLenum textureTarget = aSource->GetTextureTarget();
|
||||
ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(textureTarget,
|
||||
@@ -1058,26 +1102,38 @@ SenderHelper::SendTextureSource(GLContext* aGLContext,
|
||||
shaderConfig, aFlipY);
|
||||
gLayerScopeManager.GetSocketManager()->AppendDebugData(
|
||||
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
|
||||
aTexID, img));
|
||||
texID, img, aIsMask, Move(aPacket)));
|
||||
|
||||
sTextureIdList.push_back(aTexID);
|
||||
gLayerScopeManager.CurrentSession().mTexIDs.push_back(aTexID);
|
||||
sSentTextureIds.push_back(texID);
|
||||
gLayerScopeManager.CurrentSession().mTexIDs.push_back(texID);
|
||||
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
bool
|
||||
SenderHelper::SendGraphicBuffer(void* aLayerRef,
|
||||
SenderHelper::SendGraphicBuffer(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
GLuint aTexID,
|
||||
const TexturedEffect* aEffect) {
|
||||
const TexturedEffect* aEffect,
|
||||
bool aIsMask) {
|
||||
GLuint texID = GetTextureID(aGLContext, aSource);
|
||||
if (HasTextureIdBeenSent(texID)) {
|
||||
return false;
|
||||
}
|
||||
if (!aEffect->mState.mSurface.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Expose packet creation here, so we could dump primary texture effect attributes.
|
||||
auto packet = MakeUnique<layerscope::Packet>();
|
||||
layerscope::TexturePacket* texturePacket = packet->mutable_texture();
|
||||
texturePacket->set_mpremultiplied(aEffect->mPremultiplied);
|
||||
DumpFilter(texturePacket, aEffect->mFilter);
|
||||
DumpRect(texturePacket->mutable_mtexturecoords(), aEffect->mTextureCoords);
|
||||
|
||||
GLenum target = aSource->GetTextureTarget();
|
||||
mozilla::UniquePtr<DebugGLGraphicBuffer> package =
|
||||
MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, aTexID, aEffect->mState);
|
||||
MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, texID, aEffect->mState, aIsMask, Move(packet));
|
||||
|
||||
// The texure content in this TexureHost is not altered,
|
||||
// we don't need to send it again.
|
||||
@@ -1089,15 +1145,30 @@ SenderHelper::SendGraphicBuffer(void* aLayerRef,
|
||||
|
||||
// Transfer ownership to SocketManager.
|
||||
gLayerScopeManager.GetSocketManager()->AppendDebugData(package.release());
|
||||
sTextureIdList.push_back(aTexID);
|
||||
sSentTextureIds.push_back(texID);
|
||||
|
||||
gLayerScopeManager.CurrentSession().mTexIDs.push_back(aTexID);
|
||||
gLayerScopeManager.CurrentSession().mTexIDs.push_back(texID);
|
||||
|
||||
gLayerScopeManager.GetContentMonitor()->ClearChangedHost(aEffect->mState.mTexture);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
SenderHelper::SetAndSendTexture(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
const TexturedEffect* aEffect)
|
||||
{
|
||||
// Expose packet creation here, so we could dump primary texture effect attributes.
|
||||
auto packet = MakeUnique<layerscope::Packet>();
|
||||
layerscope::TexturePacket* texturePacket = packet->mutable_texture();
|
||||
texturePacket->set_mpremultiplied(aEffect->mPremultiplied);
|
||||
DumpFilter(texturePacket, aEffect->mFilter);
|
||||
DumpRect(texturePacket->mutable_mtexturecoords(), aEffect->mTextureCoords);
|
||||
SendTextureSource(aGLContext, aLayerRef, aSource, false, false, Move(packet));
|
||||
}
|
||||
|
||||
void
|
||||
SenderHelper::SendTexturedEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
@@ -1108,19 +1179,38 @@ SenderHelper::SendTexturedEffect(GLContext* aGLContext,
|
||||
return;
|
||||
}
|
||||
|
||||
GLuint texID = GetTextureID(aGLContext, source);
|
||||
if (IsTextureIdContainsInList(texID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (SendGraphicBuffer(aLayerRef, source, texID, aEffect)) {
|
||||
if (SendGraphicBuffer(aGLContext, aLayerRef, source, aEffect, false)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fallback texture sending path.
|
||||
// Render to texture and read pixels back.
|
||||
SendTextureSource(aGLContext, aLayerRef, source, texID, false);
|
||||
SetAndSendTexture(aGLContext, aLayerRef, source, aEffect);
|
||||
}
|
||||
|
||||
void
|
||||
SenderHelper::SendMaskEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const EffectMask* aEffect)
|
||||
{
|
||||
TextureSourceOGL* source = aEffect->mMaskTexture->AsSourceOGL();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Expose packet creation here, so we could dump secondary mask effect attributes.
|
||||
auto packet = MakeUnique<layerscope::Packet>();
|
||||
TexturePacket::EffectMask* mask = packet->mutable_texture()->mutable_mask();
|
||||
mask->set_mis3d(aEffect->mIs3D);
|
||||
mask->mutable_msize()->set_w(aEffect->mSize.width);
|
||||
mask->mutable_msize()->set_h(aEffect->mSize.height);
|
||||
auto element = reinterpret_cast<const Float *>(&(aEffect->mMaskTransform));
|
||||
for (int i = 0; i < 16; i++) {
|
||||
mask->mutable_mmasktransform()->add_m(*element++);
|
||||
}
|
||||
|
||||
SendTextureSource(aGLContext, aLayerRef, source, false, true, Move(packet));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1133,23 +1223,14 @@ SenderHelper::SendYCbCrEffect(GLContext* aGLContext,
|
||||
return;
|
||||
|
||||
const int Y = 0, Cb = 1, Cr = 2;
|
||||
TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
|
||||
TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
|
||||
TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
|
||||
TextureSourceOGL *sources[] = {
|
||||
sourceYCbCr->GetSubSource(Y)->AsSourceOGL(),
|
||||
sourceYCbCr->GetSubSource(Cb)->AsSourceOGL(),
|
||||
sourceYCbCr->GetSubSource(Cr)->AsSourceOGL()
|
||||
};
|
||||
|
||||
GLuint texID = GetTextureID(aGLContext, sourceY);
|
||||
if (!IsTextureIdContainsInList(texID)) {
|
||||
SendTextureSource(aGLContext, aLayerRef, sourceY, texID, false);
|
||||
}
|
||||
|
||||
texID = GetTextureID(aGLContext, sourceCb);
|
||||
if (!IsTextureIdContainsInList(texID)) {
|
||||
SendTextureSource(aGLContext, aLayerRef, sourceCb, texID, false);
|
||||
}
|
||||
|
||||
texID = GetTextureID(aGLContext, sourceCr);
|
||||
if (!IsTextureIdContainsInList(texID)) {
|
||||
SendTextureSource(aGLContext, aLayerRef, sourceCr, texID, false);
|
||||
for (auto source: sources) {
|
||||
SetAndSendTexture(aGLContext, aLayerRef, source, aEffect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1162,6 +1243,12 @@ SenderHelper::SendEffectChain(GLContext* aGLContext,
|
||||
if (!sLayersBufferSendable) return;
|
||||
|
||||
const Effect* primaryEffect = aEffectChain.mPrimaryEffect;
|
||||
MOZ_ASSERT(primaryEffect);
|
||||
|
||||
if (!primaryEffect) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (primaryEffect->mType) {
|
||||
case EffectTypes::RGB: {
|
||||
const TexturedEffect* texturedEffect =
|
||||
@@ -1188,8 +1275,11 @@ SenderHelper::SendEffectChain(GLContext* aGLContext,
|
||||
break;
|
||||
}
|
||||
|
||||
//const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EffectTypes::MASK];
|
||||
// TODO:
|
||||
if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
|
||||
const EffectMask* effectMask =
|
||||
static_cast<const EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
|
||||
SendMaskEffect(aGLContext, aEffectChain.mLayerRef, effectMask);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1872,7 +1962,7 @@ LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp)
|
||||
if (!LayerScope::CheckSendable()) {
|
||||
return;
|
||||
}
|
||||
SenderHelper::ClearTextureIdList();
|
||||
SenderHelper::ClearSentTextureIds();
|
||||
|
||||
gLayerScopeManager.GetSocketManager()->AppendDebugData(
|
||||
new DebugGLFrameStatusData(Packet::FRAMESTART, aFrameStamp));
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "nsDebug.h" // for NS_ERROR
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
#include "base/basictypes.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
@@ -164,6 +165,9 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
|
||||
if (m.GetScrollParentId() != FrameMetrics::NULL_SCROLL_ID) {
|
||||
AppendToString(aStream, m.GetScrollParentId(), "] [scrollParent=");
|
||||
}
|
||||
if (m.IsRootContent()) {
|
||||
aStream << "] [rcd";
|
||||
}
|
||||
if (m.HasClipRect()) {
|
||||
AppendToString(aStream, m.ClipRect(), "] [clip=");
|
||||
}
|
||||
@@ -183,8 +187,8 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
|
||||
m.GetScrollOffsetUpdated(), m.GetDoSmoothScroll(),
|
||||
m.GetScrollGeneration()).get();
|
||||
AppendToString(aStream, m.GetScrollParentId(), "] [p=");
|
||||
aStream << nsPrintfCString("] [i=(%ld %lld)] }",
|
||||
m.GetPresShellId(), m.GetScrollId()).get();
|
||||
aStream << nsPrintfCString("] [i=(%ld %lld %d)] }",
|
||||
m.GetPresShellId(), m.GetScrollId(), m.IsRootContent()).get();
|
||||
}
|
||||
aStream << sfx;
|
||||
}
|
||||
|
||||
@@ -54,5 +54,5 @@ LayerRenderState::LayerRenderState(android::GraphicBuffer* aSurface,
|
||||
{}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -7,16 +7,21 @@
|
||||
#define GFX_LAYERSTYPES_H
|
||||
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include "mozilla/gfx/Point.h" // for IntPoint
|
||||
#include "nsRegion.h"
|
||||
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include <utils/RefBase.h>
|
||||
#if ANDROID_VERSION >= 21
|
||||
#include <utils/NativeHandle.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "mozilla/gfx/Point.h" // for IntPoint
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
#include "nsRegion.h"
|
||||
|
||||
#include <stdio.h> // FILE
|
||||
#include "mozilla/Logging.h" // for PR_LOG
|
||||
|
||||
#ifndef MOZ_LAYERS_HAVE_LOG
|
||||
# define MOZ_LAYERS_HAVE_LOG
|
||||
#endif
|
||||
@@ -29,7 +34,7 @@
|
||||
|
||||
namespace android {
|
||||
class MOZ_EXPORT GraphicBuffer;
|
||||
}
|
||||
} // namespace android
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@@ -110,6 +115,14 @@ struct LayerRenderState {
|
||||
|
||||
void SetOverlayId(const int32_t& aId)
|
||||
{ mOverlayId = aId; }
|
||||
|
||||
android::GraphicBuffer* GetGrallocBuffer() const
|
||||
{ return mSurface.get(); }
|
||||
|
||||
#if ANDROID_VERSION >= 21
|
||||
android::NativeHandle* GetSidebandStream() const
|
||||
{ return mSidebandStream.get(); }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void SetOffset(const nsIntPoint& aOffset)
|
||||
@@ -133,6 +146,9 @@ struct LayerRenderState {
|
||||
// size of mSurface
|
||||
gfx::IntSize mSize;
|
||||
TextureHost* mTexture;
|
||||
#if ANDROID_VERSION >= 21
|
||||
android::sp<android::NativeHandle> mSidebandStream;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -22,5 +22,5 @@ PersistentBufferProviderBasic::PersistentBufferProviderBasic(gfx::IntSize aSize,
|
||||
mDrawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(aBackend, aSize, aFormat);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -306,9 +306,12 @@ RotatedContentBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
|
||||
void
|
||||
BorrowDrawTarget::ReturnDrawTarget(gfx::DrawTarget*& aReturned)
|
||||
{
|
||||
MOZ_ASSERT(mLoanedDrawTarget);
|
||||
MOZ_ASSERT(aReturned == mLoanedDrawTarget);
|
||||
mLoanedDrawTarget->SetTransform(mLoanedTransform);
|
||||
mLoanedDrawTarget = nullptr;
|
||||
if (mLoanedDrawTarget) {
|
||||
mLoanedDrawTarget->SetTransform(mLoanedTransform);
|
||||
mLoanedDrawTarget = nullptr;
|
||||
}
|
||||
aReturned = nullptr;
|
||||
}
|
||||
|
||||
@@ -646,7 +649,7 @@ RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
|
||||
&destDTBuffer, &destDTBufferOnWhite);
|
||||
if (!destDTBuffer ||
|
||||
(!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
|
||||
gfxCriticalError() << "Failed 1 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.width << ", " << destBufferRect.height;
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(IntSize(destBufferRect.width, destBufferRect.height)))) << "Failed 1 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.width << ", " << destBufferRect.height;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -668,7 +671,7 @@ RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
|
||||
&destDTBuffer, &destDTBufferOnWhite);
|
||||
if (!destDTBuffer ||
|
||||
(!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
|
||||
gfxCriticalError() << "Failed 2 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.width << ", " << destBufferRect.height;
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(IntSize(destBufferRect.width, destBufferRect.height)))) << "Failed 2 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.width << ", " << destBufferRect.height;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -752,9 +755,8 @@ RotatedContentBuffer::BorrowDrawTargetForPainting(PaintState& aPaintState,
|
||||
if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
|
||||
if (!mDTBuffer || !mDTBufferOnWhite) {
|
||||
// This can happen in release builds if allocating one of the two buffers
|
||||
// failed. This is pretty bad and the reason for the failure is already
|
||||
// reported through gfxCriticalError.
|
||||
MOZ_ASSERT(false);
|
||||
// failed. This in turn can happen if unreasonably large textures are
|
||||
// requested.
|
||||
return nullptr;
|
||||
}
|
||||
nsIntRegionRectIterator iter(*drawPtr);
|
||||
|
||||
@@ -75,7 +75,7 @@ void YCbCrImageDataDeserializerBase::Validate()
|
||||
info->mYStride,
|
||||
IntSize(info->mCbCrWidth, info->mCbCrHeight),
|
||||
info->mCbCrStride);
|
||||
mIsValid = requiredSize && requiredSize <= mDataSize;
|
||||
mIsValid = requiredSize <= mDataSize;
|
||||
|
||||
}
|
||||
|
||||
@@ -147,14 +147,15 @@ YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize,
|
||||
uint32_t aCbCrStride)
|
||||
{
|
||||
MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
|
||||
if (aYSize.height <= 0 || aYSize.width <= 0 || aCbCrSize.height <= 0 || aCbCrSize.width <= 0) {
|
||||
if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 || aCbCrSize.width < 0) {
|
||||
gfxDebug() << "Non-positive YCbCr buffer size request " << aYSize.height << "x" << aYSize.width << ", " << aCbCrSize.height << "x" << aCbCrSize.width;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!gfx::Factory::AllowedSurfaceSize(aYSize) ||
|
||||
aCbCrSize.width > aYSize.width ||
|
||||
aCbCrSize.height > aYSize.height) {
|
||||
if (aYSize != IntSize() &&
|
||||
(!gfx::Factory::AllowedSurfaceSize(aYSize) ||
|
||||
aCbCrSize.width > aYSize.width ||
|
||||
aCbCrSize.height > aYSize.height)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
static SurfaceFormat
|
||||
static gfx::SurfaceFormat
|
||||
HalFormatToSurfaceFormat(int aHalFormat, TextureFlags aFlags)
|
||||
{
|
||||
bool swapRB = bool(aFlags & TextureFlags::RB_SWAPPED);
|
||||
@@ -45,7 +45,7 @@ HalFormatToSurfaceFormat(int aHalFormat, TextureFlags aFlags)
|
||||
return gfx::SurfaceFormat::R5G6B5_UINT16;
|
||||
} else {
|
||||
MOZ_CRASH("Unhandled HAL pixel format");
|
||||
return SurfaceFormat::UNKNOWN; // not reached
|
||||
return gfx::SurfaceFormat::UNKNOWN; // not reached
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ GrallocTextureHostBasic::Lock()
|
||||
NS_WARNING("Couldn't lock graphic buffer");
|
||||
return false;
|
||||
}
|
||||
surf = Factory::CreateWrappingDataSourceSurface(
|
||||
surf = gfx::Factory::CreateWrappingDataSourceSurface(
|
||||
mMappedBuffer,
|
||||
graphicBuffer->getStride() * gfx::BytesPerPixel(mFormat),
|
||||
mCropSize,
|
||||
@@ -217,7 +217,7 @@ GrallocTextureHostBasic::WaitAcquireFenceHandleSyncComplete()
|
||||
void
|
||||
GrallocTextureHostBasic::SetCropRect(nsIntRect aCropRect)
|
||||
{
|
||||
MOZ_ASSERT(aCropRect.TopLeft() == IntPoint(0, 0));
|
||||
MOZ_ASSERT(aCropRect.TopLeft() == gfx::IntPoint(0, 0));
|
||||
MOZ_ASSERT(!aCropRect.IsEmpty());
|
||||
MOZ_ASSERT(aCropRect.width <= mSize.width);
|
||||
MOZ_ASSERT(aCropRect.height <= mSize.height);
|
||||
|
||||
@@ -17,83 +17,57 @@
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
TextureClientX11::TextureClientX11(ISurfaceAllocator* aAllocator,
|
||||
SurfaceFormat aFormat,
|
||||
TextureFlags aFlags)
|
||||
: TextureClient(aAllocator, aFlags),
|
||||
mFormat(aFormat),
|
||||
mLocked(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(TextureClientX11);
|
||||
}
|
||||
|
||||
TextureClientX11::~TextureClientX11()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TextureClientX11);
|
||||
}
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
TextureClientX11::CreateSimilar(TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const
|
||||
CreateX11TextureClient(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags, ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
RefPtr<TextureClient> tex = new TextureClientX11(mAllocator, mFormat, mFlags);
|
||||
|
||||
// mSize is guaranteed to be non-negative
|
||||
MOZ_ASSERT(mSize.width >= 0 && mSize.height >= 0);
|
||||
if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
|
||||
TextureData* data = X11TextureData::Create(aSize, aFormat, aFlags, aAllocator);
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeAndAddRef<ClientTexture>(data, aFlags, aAllocator);
|
||||
}
|
||||
|
||||
return tex.forget();
|
||||
X11TextureData::X11TextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
bool aClientDeallocation, bool aIsCrossProcess,
|
||||
gfxXlibSurface* aSurface)
|
||||
: mSize(aSize)
|
||||
, mFormat(aFormat)
|
||||
, mSurface(aSurface)
|
||||
, mClientDeallocation(aClientDeallocation)
|
||||
, mIsCrossProcess(aIsCrossProcess)
|
||||
{
|
||||
MOZ_ASSERT(mSurface);
|
||||
}
|
||||
|
||||
bool
|
||||
TextureClientX11::IsAllocated() const
|
||||
X11TextureData::Lock(OpenMode aMode, FenceHandle*)
|
||||
{
|
||||
return !!mSurface;
|
||||
}
|
||||
|
||||
bool
|
||||
TextureClientX11::Lock(OpenMode aMode)
|
||||
{
|
||||
MOZ_ASSERT(!mLocked, "The TextureClient is already Locked!");
|
||||
mLocked = IsValid() && IsAllocated();
|
||||
return mLocked;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientX11::Unlock()
|
||||
X11TextureData::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mLocked, "The TextureClient is already Unlocked!");
|
||||
mLocked = false;
|
||||
|
||||
if (mDrawTarget) {
|
||||
// see the comment on TextureClient::BorrowDrawTarget.
|
||||
// This DrawTarget is internal to the TextureClient and is only exposed to the
|
||||
// outside world between Lock() and Unlock(). This assertion checks that no outside
|
||||
// reference remains by the time Unlock() is called.
|
||||
MOZ_ASSERT(mDrawTarget->refCount() == 1);
|
||||
|
||||
mDrawTarget->Flush();
|
||||
mDrawTarget = nullptr;
|
||||
}
|
||||
|
||||
if (mSurface && !mAllocator->IsSameProcess()) {
|
||||
if (mSurface && mIsCrossProcess) {
|
||||
FinishX(DefaultXDisplay());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TextureClientX11::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
||||
X11TextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
MOZ_ASSERT(mSurface);
|
||||
if (!mSurface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(mFlags & TextureFlags::DEALLOCATE_CLIENT)) {
|
||||
if (!mClientDeallocation) {
|
||||
// Pass to the host the responsibility of freeing the pixmap. ReleasePixmap means
|
||||
// the underlying pixmap will not be deallocated in mSurface's destructor.
|
||||
// ToSurfaceDescriptor is at most called once per TextureClient.
|
||||
@@ -104,66 +78,79 @@ TextureClientX11::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TextureClientX11::AllocateForSurface(IntSize aSize, TextureAllocationFlags aTextureFlags)
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
X11TextureData::BorrowDrawTarget()
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
MOZ_ASSERT(!IsAllocated());
|
||||
//MOZ_ASSERT(mFormat != gfx::FORMAT_YUV, "This TextureClient cannot use YCbCr data");
|
||||
MOZ_ASSERT(mSurface);
|
||||
if (!mSurface) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IntSize size = mSurface->GetSize();
|
||||
RefPtr<gfx::DrawTarget> dt = Factory::CreateDrawTargetForCairoSurface(mSurface->CairoSurface(), size);
|
||||
|
||||
return dt.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
X11TextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
{
|
||||
RefPtr<DrawTarget> dt = BorrowDrawTarget();
|
||||
|
||||
if (!dt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dt->CopySurface(aSurface, IntRect(IntPoint(), aSurface->GetSize()), IntPoint());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
X11TextureData::Deallocate(ISurfaceAllocator*)
|
||||
{
|
||||
mSurface = nullptr;
|
||||
}
|
||||
|
||||
TextureData*
|
||||
X11TextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
return X11TextureData::Create(mSize, mFormat, aFlags, aAllocator);
|
||||
}
|
||||
|
||||
X11TextureData*
|
||||
X11TextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags, ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
MOZ_ASSERT(aSize.width >= 0 && aSize.height >= 0);
|
||||
if (aSize.width <= 0 || aSize.height <= 0 ||
|
||||
aSize.width > XLIB_IMAGE_SIDE_SIZE_LIMIT ||
|
||||
aSize.height > XLIB_IMAGE_SIDE_SIZE_LIMIT) {
|
||||
gfxDebug() << "Asking for X11 surface of invalid size " << aSize.width << "x" << aSize.height;
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
gfxImageFormat imageFormat = SurfaceFormatToImageFormat(mFormat);
|
||||
gfxImageFormat imageFormat = SurfaceFormatToImageFormat(aFormat);
|
||||
RefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, imageFormat);
|
||||
if (!surface || surface->GetType() != gfxSurfaceType::Xlib) {
|
||||
NS_ERROR("creating Xlib surface failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
mSize = aSize;
|
||||
mSurface = static_cast<gfxXlibSurface*>(surface.get());
|
||||
|
||||
if (!mAllocator->IsSameProcess()) {
|
||||
FinishX(DefaultXDisplay());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DrawTarget*
|
||||
TextureClientX11::BorrowDrawTarget()
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
MOZ_ASSERT(mLocked);
|
||||
|
||||
if (!mSurface) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mDrawTarget) {
|
||||
IntSize size = mSurface->GetSize();
|
||||
mDrawTarget = Factory::CreateDrawTargetForCairoSurface(mSurface->CairoSurface(), size);
|
||||
gfxXlibSurface* xlibSurface = static_cast<gfxXlibSurface*>(surface.get());
|
||||
|
||||
bool crossProcess = !aAllocator->IsSameProcess();
|
||||
X11TextureData* texture = new X11TextureData(aSize, aFormat,
|
||||
!!(aFlags & TextureFlags::DEALLOCATE_CLIENT),
|
||||
crossProcess,
|
||||
xlibSurface);
|
||||
if (crossProcess) {
|
||||
FinishX(DefaultXDisplay());
|
||||
}
|
||||
|
||||
return mDrawTarget;
|
||||
return texture;
|
||||
}
|
||||
|
||||
void
|
||||
TextureClientX11::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
{
|
||||
MOZ_ASSERT(CanExposeDrawTarget());
|
||||
|
||||
DrawTarget* dt = BorrowDrawTarget();
|
||||
|
||||
if (!dt) {
|
||||
gfxCriticalError() << "Failed to borrow drawtarget for TextureClientX11::UpdateFromSurface";
|
||||
return;
|
||||
}
|
||||
|
||||
dt->CopySurface(aSurface, IntRect(IntPoint(), aSurface->GetSize()), IntPoint());
|
||||
}
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
@@ -13,54 +13,53 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* A TextureClient implementation based on Xlib.
|
||||
*/
|
||||
class TextureClientX11 : public TextureClient
|
||||
class X11TextureData : public TextureData
|
||||
{
|
||||
public:
|
||||
TextureClientX11(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat format, TextureFlags aFlags = TextureFlags::DEFAULT);
|
||||
public:
|
||||
static X11TextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags, ISurfaceAllocator* aAllocator);
|
||||
|
||||
~TextureClientX11();
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
// TextureClient
|
||||
|
||||
virtual bool IsAllocated() const override;
|
||||
|
||||
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual bool Lock(OpenMode aMode) override;
|
||||
virtual bool Lock(OpenMode aMode, FenceHandle*) override;
|
||||
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual bool IsLocked() const override { return mLocked; }
|
||||
|
||||
virtual bool AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags flags) override;
|
||||
|
||||
virtual bool CanExposeDrawTarget() const override { return true; }
|
||||
|
||||
virtual gfx::DrawTarget* BorrowDrawTarget() override;
|
||||
|
||||
virtual void UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
virtual bool SupportsMoz2D() const override { return true; }
|
||||
|
||||
virtual bool HasInternalBuffer() const override { return false; }
|
||||
|
||||
virtual already_AddRefed<TextureClient>
|
||||
CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
virtual void Deallocate(ISurfaceAllocator*) override;
|
||||
|
||||
virtual TextureData*
|
||||
CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
|
||||
|
||||
private:
|
||||
gfx::SurfaceFormat mFormat;
|
||||
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
protected:
|
||||
X11TextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
bool aClientDeallocation, bool aIsCrossProcess,
|
||||
gfxXlibSurface* aSurface);
|
||||
|
||||
gfx::IntSize mSize;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
RefPtr<gfxXlibSurface> mSurface;
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
bool mLocked;
|
||||
bool mClientDeallocation;
|
||||
bool mIsCrossProcess;
|
||||
};
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
CreateX11TextureClient(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags, ISurfaceAllocator* aAllocator);
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/layers/BufferTexture.h"
|
||||
#include "mozilla/layers/AsyncCanvasRenderer.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/CompositorChild.h" // for CompositorChild
|
||||
@@ -149,8 +150,9 @@ CanvasClient2D::CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
|
||||
#else
|
||||
// XXX - We should use CreateTextureClientForDrawing, but we first need
|
||||
// to use double buffering.
|
||||
gfx::BackendType backend = gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
|
||||
return TextureClient::CreateForRawBufferAccess(GetForwarder(),
|
||||
aFormat, aSize, gfx::BackendType::NONE,
|
||||
aFormat, aSize, backend,
|
||||
mTextureFlags | aFlags);
|
||||
#endif
|
||||
}
|
||||
@@ -199,21 +201,21 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
already_AddRefed<BufferTextureClient> Create(gfx::SurfaceFormat format) {
|
||||
already_AddRefed<TextureClient> Create(gfx::SurfaceFormat format) {
|
||||
return TextureClient::CreateForRawBufferAccess(mAllocator, format,
|
||||
mSize, mBackendType,
|
||||
mBaseTexFlags);
|
||||
}
|
||||
|
||||
public:
|
||||
already_AddRefed<BufferTextureClient> CreateB8G8R8AX8() {
|
||||
already_AddRefed<TextureClient> CreateB8G8R8AX8() {
|
||||
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8
|
||||
: gfx::SurfaceFormat::B8G8R8X8;
|
||||
return Create(format);
|
||||
}
|
||||
|
||||
already_AddRefed<BufferTextureClient> CreateR8G8B8AX8() {
|
||||
RefPtr<BufferTextureClient> ret;
|
||||
already_AddRefed<TextureClient> CreateR8G8B8AX8() {
|
||||
RefPtr<TextureClient> ret;
|
||||
|
||||
bool areRGBAFormatsBroken = mLayersBackend == LayersBackend::LAYERS_BASIC;
|
||||
if (!areRGBAFormatsBroken) {
|
||||
@@ -241,7 +243,7 @@ TexClientFromReadback(SharedSurface* src, ISurfaceAllocator* allocator,
|
||||
TexClientFactory factory(allocator, src->mHasAlpha, src->mSize, backendType,
|
||||
baseFlags, layersBackend);
|
||||
|
||||
RefPtr<BufferTextureClient> texClient;
|
||||
RefPtr<TextureClient> texClient;
|
||||
|
||||
{
|
||||
gl::ScopedReadbackFB autoReadback(src);
|
||||
@@ -287,16 +289,18 @@ TexClientFromReadback(SharedSurface* src, ISurfaceAllocator* allocator,
|
||||
DebugOnly<bool> succeeded = autoLock.Succeeded();
|
||||
MOZ_ASSERT(succeeded, "texture should have locked");
|
||||
|
||||
uint8_t* lockedBytes = texClient->GetLockedData();
|
||||
MappedTextureData mapped;
|
||||
texClient->BorrowMappedData(mapped);
|
||||
|
||||
// ReadPixels from the current FB into lockedBits.
|
||||
// ReadPixels from the current FB into mapped.data.
|
||||
auto width = src->mSize.width;
|
||||
auto height = src->mSize.height;
|
||||
|
||||
{
|
||||
ScopedPackAlignment autoAlign(gl, 4);
|
||||
|
||||
gl->raw_fReadPixels(0, 0, width, height, readFormat, readType, lockedBytes);
|
||||
MOZ_ASSERT(mapped.stride/4 == mapped.size.width);
|
||||
gl->raw_fReadPixels(0, 0, width, height, readFormat, readType, mapped.data);
|
||||
}
|
||||
|
||||
// RB_SWAPPED doesn't work with D3D11. (bug 1051010)
|
||||
@@ -309,7 +313,7 @@ TexClientFromReadback(SharedSurface* src, ISurfaceAllocator* allocator,
|
||||
layersNeedsManualSwap)
|
||||
{
|
||||
size_t pixels = width * height;
|
||||
uint8_t* itr = lockedBytes;
|
||||
uint8_t* itr = mapped.data;
|
||||
for (size_t i = 0; i < pixels; i++) {
|
||||
SwapRB_R8G8B8A8(itr);
|
||||
itr += 4;
|
||||
@@ -436,6 +440,10 @@ CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRendere
|
||||
void
|
||||
CanvasClientSharedSurface::Updated()
|
||||
{
|
||||
if (!mNewFront) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto forwarder = GetForwarder();
|
||||
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
|
||||
@@ -198,7 +198,7 @@ CompositableClient::GetAsyncID() const
|
||||
return 0; // zero is always an invalid async ID
|
||||
}
|
||||
|
||||
already_AddRefed<BufferTextureClient>
|
||||
already_AddRefed<TextureClient>
|
||||
CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class CompositableClient;
|
||||
class BufferTextureClient;
|
||||
class ImageBridgeChild;
|
||||
class ImageContainer;
|
||||
class CompositableForwarder;
|
||||
@@ -136,7 +135,7 @@ public:
|
||||
|
||||
LayersBackend GetCompositorBackendType() const;
|
||||
|
||||
already_AddRefed<BufferTextureClient>
|
||||
already_AddRefed<TextureClient>
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
gfx::BackendType aMoz2dBackend = gfx::BackendType::NONE,
|
||||
|
||||
@@ -192,7 +192,7 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag
|
||||
return false;
|
||||
}
|
||||
|
||||
bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data);
|
||||
bool status = UpdateYCbCrTextureClient(texture, *data);
|
||||
MOZ_ASSERT(status);
|
||||
if (!status) {
|
||||
return false;
|
||||
|
||||
@@ -120,9 +120,9 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{
|
||||
// Compare layer visible region size to current backbuffer size, discard if not matching.
|
||||
IntSize size = mPaintedLayer->GetVisibleRegion().GetBounds().Size();
|
||||
IntPoint origin = mPaintedLayer->GetVisibleRegion().GetBounds().TopLeft();
|
||||
// Compare layer valid region size to current backbuffer size, discard if not matching.
|
||||
IntSize size = aNewValidRegion.GetBounds().Size();
|
||||
IntPoint origin = aNewValidRegion.GetBounds().TopLeft();
|
||||
nsIntRegion paintRegion = aPaintRegion;
|
||||
if (mSize != size ||
|
||||
mTilingOrigin != origin) {
|
||||
|
||||
+306
-425
@@ -26,6 +26,7 @@
|
||||
#include "LayersLogging.h" // for AppendToString
|
||||
#include "gfxUtils.h" // for gfxUtils::GetAsLZ4Base64Str
|
||||
#include "IPDLActor.h"
|
||||
#include "BufferTexture.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/layers/TextureD3D9.h"
|
||||
@@ -192,6 +193,202 @@ TextureChild::ActorDestroy(ActorDestroyReason why)
|
||||
mKeep = nullptr;
|
||||
}
|
||||
|
||||
ClientTexture::ClientTexture(TextureData* aData, TextureFlags aFlags, ISurfaceAllocator* aAllocator)
|
||||
: TextureClient(aAllocator, aFlags)
|
||||
, mData(aData)
|
||||
, mOpenMode(OpenMode::OPEN_NONE)
|
||||
#ifdef DEBUG
|
||||
, mExpectedDtRefs(0)
|
||||
#endif
|
||||
, mIsLocked(false)
|
||||
{}
|
||||
|
||||
bool
|
||||
ClientTexture::Lock(OpenMode aMode)
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
MOZ_ASSERT(!mIsLocked);
|
||||
if (mIsLocked) {
|
||||
return mOpenMode == aMode;
|
||||
}
|
||||
|
||||
mIsLocked = mData->Lock(aMode, mReleaseFenceHandle.IsValid() ? &mReleaseFenceHandle : nullptr);
|
||||
mOpenMode = aMode;
|
||||
|
||||
return mIsLocked;
|
||||
}
|
||||
|
||||
void
|
||||
ClientTexture::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
MOZ_ASSERT(mIsLocked);
|
||||
if (!mIsLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBorrowedDrawTarget) {
|
||||
MOZ_ASSERT(mBorrowedDrawTarget->refCount() <= mExpectedDtRefs);
|
||||
if (mOpenMode & OpenMode::OPEN_WRITE) {
|
||||
mBorrowedDrawTarget->Flush();
|
||||
if (mReadbackSink) {
|
||||
RefPtr<SourceSurface> snapshot = mBorrowedDrawTarget->Snapshot();
|
||||
RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface();
|
||||
mReadbackSink->ProcessReadback(dataSurf);
|
||||
}
|
||||
}
|
||||
mBorrowedDrawTarget = nullptr;
|
||||
}
|
||||
|
||||
mData->Unlock();
|
||||
mIsLocked = false;
|
||||
mOpenMode = OpenMode::OPEN_NONE;
|
||||
}
|
||||
|
||||
bool
|
||||
ClientTexture::HasInternalBuffer() const
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
return mData->HasInternalBuffer();
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
ClientTexture::GetSize() const
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
return mData->GetSize();
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat
|
||||
ClientTexture::GetFormat() const
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
return mData->GetFormat();
|
||||
}
|
||||
|
||||
ClientTexture::~ClientTexture()
|
||||
{
|
||||
// All the destruction code that may lead to virtual method calls must
|
||||
// be in Finalize() which is called just before the destructor.
|
||||
|
||||
// TODO[nical] temporarily integrate this with FinalizeOnIPDLThred
|
||||
if (ShouldDeallocateInDestructor()) {
|
||||
mData->Deallocate(mAllocator);
|
||||
} else {
|
||||
mData->Forget(mAllocator);
|
||||
}
|
||||
delete mData;
|
||||
}
|
||||
|
||||
void
|
||||
ClientTexture::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
MOZ_ASSERT(mIsLocked);
|
||||
MOZ_ASSERT(aSurface);
|
||||
|
||||
// XXX - It would be better to first try the DrawTarget approach and fallback
|
||||
// to the backend-specific implementation because the latter will usually do
|
||||
// an expensive read-back + cpu-side copy if the texture is on the gpu.
|
||||
// There is a bug with the DrawTarget approach, though specific to reading back
|
||||
// from WebGL (where R and B channel end up inverted) to figure out first.
|
||||
if (mData->UpdateFromSurface(aSurface)) {
|
||||
return;
|
||||
}
|
||||
if (CanExposeDrawTarget() && NS_IsMainThread()) {
|
||||
RefPtr<DrawTarget> dt = BorrowDrawTarget();
|
||||
|
||||
MOZ_ASSERT(dt);
|
||||
if (dt) {
|
||||
dt->CopySurface(aSurface,
|
||||
gfx::IntRect(gfx::IntPoint(0, 0), aSurface->GetSize()),
|
||||
gfx::IntPoint(0, 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
NS_WARNING("ClientTexture::UpdateFromSurface failed");
|
||||
}
|
||||
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
ClientTexture::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
TextureData* data = mData->CreateSimilar(mAllocator, aFlags, aAllocFlags);
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return MakeAndAddRef<ClientTexture>(data, aFlags, mAllocator);
|
||||
}
|
||||
|
||||
gfx::DrawTarget*
|
||||
ClientTexture::BorrowDrawTarget()
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
MOZ_ASSERT(mIsLocked);
|
||||
// TODO- We can't really assert that at the moment because there is code that Borrows
|
||||
// the DrawTarget, just to get a snapshot, which is legit in term of OpenMode
|
||||
// but we should have a way to get a SourceSurface directly instead.
|
||||
//MOZ_ASSERT(mOpenMode & OpenMode::OPEN_WRITE);
|
||||
|
||||
if (!mIsLocked) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mBorrowedDrawTarget) {
|
||||
mBorrowedDrawTarget = mData->BorrowDrawTarget();
|
||||
#ifdef DEBUG
|
||||
mExpectedDtRefs = mBorrowedDrawTarget ? mBorrowedDrawTarget->refCount() : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return mBorrowedDrawTarget;
|
||||
}
|
||||
|
||||
bool
|
||||
ClientTexture::BorrowMappedData(MappedTextureData& aMap)
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
|
||||
// TODO - SharedRGBImage just accesses the buffer without properly locking
|
||||
// the texture. It's bad.
|
||||
//MOZ_ASSERT(mIsLocked);
|
||||
//if (!mIsLocked) {
|
||||
// return nullptr;
|
||||
//}
|
||||
|
||||
return mData->BorrowMappedData(aMap);
|
||||
}
|
||||
|
||||
bool
|
||||
ClientTexture::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap)
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
return mData->BorrowMappedYCbCrData(aMap);
|
||||
}
|
||||
|
||||
bool
|
||||
ClientTexture::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
return mData->Serialize(aOutDescriptor);
|
||||
}
|
||||
|
||||
void
|
||||
ClientTexture::WaitForBufferOwnership(bool aWaitReleaseFence)
|
||||
{
|
||||
if (mRemoveFromCompositableWaiter) {
|
||||
mRemoveFromCompositableWaiter->WaitComplete();
|
||||
mRemoveFromCompositableWaiter = nullptr;
|
||||
}
|
||||
|
||||
if (aWaitReleaseFence && mReleaseFenceHandle.IsValid()) {
|
||||
mData->WaitForFence(&mReleaseFenceHandle);
|
||||
mReleaseFenceHandle = FenceHandle();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
PTextureChild*
|
||||
TextureClient::CreateIPDLActor()
|
||||
@@ -317,49 +514,6 @@ TextureClient::GetIPDLActor()
|
||||
return mActor;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
static bool
|
||||
DisableGralloc(SurfaceFormat aFormat, const gfx::IntSize& aSizeHint)
|
||||
{
|
||||
if (gfxPrefs::DisableGralloc()) {
|
||||
return true;
|
||||
}
|
||||
if (aFormat == gfx::SurfaceFormat::A8) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if ANDROID_VERSION <= 15
|
||||
// Adreno 200 has a problem of drawing gralloc buffer width less than 64 and
|
||||
// drawing gralloc buffer with a height 9px-16px.
|
||||
// See Bug 983971.
|
||||
if (aSizeHint.width < 64 || aSizeHint.height < 32) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
already_AddRefed<BufferTextureClient>
|
||||
CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
|
||||
SurfaceFormat aFormat,
|
||||
TextureFlags aTextureFlags,
|
||||
gfx::BackendType aMoz2DBackend)
|
||||
{
|
||||
if (aAllocator->IsSameProcess()) {
|
||||
RefPtr<BufferTextureClient> result = new MemoryTextureClient(aAllocator, aFormat,
|
||||
aMoz2DBackend,
|
||||
aTextureFlags);
|
||||
return result.forget();
|
||||
}
|
||||
RefPtr<BufferTextureClient> result = new ShmemTextureClient(aAllocator, aFormat,
|
||||
aMoz2DBackend,
|
||||
aTextureFlags);
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
static inline gfx::BackendType
|
||||
BackendTypeForBackendSelector(LayersBackend aLayersBackend, BackendSelector aSelector)
|
||||
{
|
||||
@@ -397,7 +551,7 @@ TextureClient::CreateForDrawing(CompositableForwarder* aAllocator,
|
||||
|
||||
RefPtr<TextureClient> texture;
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK) || defined(XP_WIN)
|
||||
#if defined(XP_WIN)
|
||||
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
|
||||
#endif
|
||||
|
||||
@@ -441,7 +595,10 @@ TextureClient::CreateForDrawing(CompositableForwarder* aAllocator,
|
||||
moz2DBackend == gfx::BackendType::CAIRO &&
|
||||
type == gfxSurfaceType::Xlib)
|
||||
{
|
||||
texture = new TextureClientX11(aAllocator, aFormat, aTextureFlags);
|
||||
texture = CreateX11TextureClient(aSize, aFormat, aTextureFlags, aAllocator);
|
||||
if (texture) {
|
||||
return texture.forget();
|
||||
}
|
||||
}
|
||||
#ifdef GL_PROVIDER_GLX
|
||||
if (parentBackend == LayersBackend::LAYERS_OPENGL &&
|
||||
@@ -449,19 +606,19 @@ TextureClient::CreateForDrawing(CompositableForwarder* aAllocator,
|
||||
aFormat != SurfaceFormat::A8 &&
|
||||
gl::sGLXLibrary.UseTextureFromPixmap())
|
||||
{
|
||||
texture = new TextureClientX11(aAllocator, aFormat, aTextureFlags);
|
||||
texture = CreateX11TextureClient(aSize, aFormat, aTextureFlags, aAllocator);
|
||||
if (texture) {
|
||||
return texture.forget();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (!DisableGralloc(aFormat, aSize)) {
|
||||
// Don't allow Gralloc texture clients to exceed the maximum texture size.
|
||||
// BufferTextureClients have code to handle tiling the surface client-side.
|
||||
if (aSize.width <= maxTextureSize && aSize.height <= maxTextureSize) {
|
||||
texture = new GrallocTextureClientOGL(aAllocator, aFormat, moz2DBackend,
|
||||
aTextureFlags);
|
||||
}
|
||||
texture = CreateGrallocTextureClientForDrawing(aSize, aFormat, moz2DBackend,
|
||||
aTextureFlags, aAllocator);
|
||||
if (texture) {
|
||||
return texture.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -480,17 +637,12 @@ TextureClient::CreateForDrawing(CompositableForwarder* aAllocator,
|
||||
}
|
||||
|
||||
// Can't do any better than a buffer texture client.
|
||||
texture = CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags, moz2DBackend);
|
||||
|
||||
if (!texture->AllocateForSurface(aSize, aAllocFlags)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return texture.forget();
|
||||
return TextureClient::CreateForRawBufferAccess(aAllocator, aFormat, aSize,
|
||||
moz2DBackend, aTextureFlags, aAllocFlags);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<BufferTextureClient>
|
||||
already_AddRefed<TextureClient>
|
||||
TextureClient::CreateForRawBufferAccess(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
@@ -507,27 +659,27 @@ TextureClient::CreateForRawBufferAccess(ISurfaceAllocator* aAllocator,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BufferTextureClient> texture =
|
||||
CreateBufferTextureClient(aAllocator, aFormat,
|
||||
aTextureFlags, aMoz2DBackend);
|
||||
if (texture) {
|
||||
if (!texture->AllocateForSurface(aSize, aAllocFlags)) {
|
||||
return nullptr;
|
||||
}
|
||||
TextureData* texData = BufferTextureData::Create(aSize, aFormat, aMoz2DBackend,
|
||||
aTextureFlags, aAllocFlags,
|
||||
aAllocator);
|
||||
if (!texData) {
|
||||
return nullptr;
|
||||
}
|
||||
return texture.forget();
|
||||
|
||||
return MakeAndAddRef<ClientTexture>(texData, aTextureFlags, aAllocator);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<BufferTextureClient>
|
||||
already_AddRefed<TextureClient>
|
||||
TextureClient::CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
||||
gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
MOZ_ASSERT(aAllocator->IPCOpen());
|
||||
if (!aAllocator || !aAllocator->IPCOpen()) {
|
||||
// The only reason we allow aAllocator to be null is for gtests
|
||||
MOZ_ASSERT(!aAllocator || aAllocator->IPCOpen());
|
||||
if (aAllocator && !aAllocator->IPCOpen()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -535,52 +687,34 @@ TextureClient::CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BufferTextureClient> texture;
|
||||
if (aAllocator->IsSameProcess()) {
|
||||
texture = new MemoryTextureClient(aAllocator, gfx::SurfaceFormat::YUV,
|
||||
gfx::BackendType::NONE,
|
||||
aTextureFlags);
|
||||
} else {
|
||||
texture = new ShmemTextureClient(aAllocator, gfx::SurfaceFormat::YUV,
|
||||
gfx::BackendType::NONE,
|
||||
aTextureFlags);
|
||||
}
|
||||
|
||||
if (!texture->AllocateForYCbCr(aYSize, aCbCrSize, aStereoMode)) {
|
||||
TextureData* data = BufferTextureData::CreateForYCbCr(aAllocator, aYSize, aCbCrSize,
|
||||
aStereoMode, aTextureFlags);
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return texture.forget();
|
||||
return MakeAndAddRef<ClientTexture>(data, aTextureFlags, aAllocator);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<BufferTextureClient>
|
||||
already_AddRefed<TextureClient>
|
||||
TextureClient::CreateWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags)
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
MOZ_ASSERT(aAllocator->IPCOpen());
|
||||
if (!aAllocator || !aAllocator->IPCOpen()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BufferTextureClient> texture;
|
||||
if (aAllocator->IsSameProcess()) {
|
||||
texture = new MemoryTextureClient(aAllocator, gfx::SurfaceFormat::YUV,
|
||||
gfx::BackendType::NONE,
|
||||
aTextureFlags);
|
||||
} else {
|
||||
texture = new ShmemTextureClient(aAllocator, gfx::SurfaceFormat::YUV,
|
||||
gfx::BackendType::NONE,
|
||||
aTextureFlags);
|
||||
}
|
||||
|
||||
if (!texture->Allocate(aSize)) {
|
||||
TextureData* data = BufferTextureData::CreateWithBufferSize(aAllocator, aFormat, aSize,
|
||||
aTextureFlags);
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return texture.forget();
|
||||
return MakeAndAddRef<ClientTexture>(data, aTextureFlags, aAllocator);
|
||||
}
|
||||
|
||||
TextureClient::TextureClient(ISurfaceAllocator* aAllocator, TextureFlags aFlags)
|
||||
@@ -700,6 +834,11 @@ TextureClient::ShouldDeallocateInDestructor() const
|
||||
return !mShared || (GetFlags() & TextureFlags::DEALLOCATE_CLIENT);
|
||||
}
|
||||
|
||||
void
|
||||
TextureClient::SetRemoveFromCompositableWaiter(AsyncTransactionWaiter* aWaiter) {
|
||||
mRemoveFromCompositableWaiter = aWaiter;
|
||||
}
|
||||
|
||||
void
|
||||
TextureClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
{
|
||||
@@ -722,344 +861,51 @@ TextureClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
bool
|
||||
ShmemTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aDescriptor = SurfaceDescriptorShmem(mShmem, GetFormat());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ShmemTextureClient::Allocate(uint32_t aSize)
|
||||
UpdateYCbCrTextureClient(TextureClient* aTexture, const PlanarYCbCrData& aData)
|
||||
{
|
||||
MOZ_ASSERT(mValid);
|
||||
if (aSize > 0) {
|
||||
SharedMemory::SharedMemoryType memType = OptimalShmemType();
|
||||
mAllocated = GetAllocator()->AllocUnsafeShmem(aSize, memType, &mShmem);
|
||||
}
|
||||
return mAllocated;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
ShmemTextureClient::GetBuffer() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
if (mAllocated) {
|
||||
return mShmem.get<uint8_t>();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t
|
||||
ShmemTextureClient::GetBufferSize() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return mShmem.Size<uint8_t>();
|
||||
}
|
||||
|
||||
ShmemTextureClient::ShmemTextureClient(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureClient(aAllocator, aFormat, aMoz2DBackend, aFlags)
|
||||
, mAllocated(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ShmemTextureClient);
|
||||
}
|
||||
|
||||
ShmemTextureClient::~ShmemTextureClient()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ShmemTextureClient);
|
||||
if (ShouldDeallocateInDestructor()) {
|
||||
// if the buffer has never been shared we must deallocate it or ir would
|
||||
// leak.
|
||||
GetAllocator()->DeallocShmem(mShmem);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MemoryTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
aDescriptor = SurfaceDescriptorMemory(reinterpret_cast<uintptr_t>(mBuffer),
|
||||
GetFormat());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MemoryTextureClient::Allocate(uint32_t aSize)
|
||||
{
|
||||
MOZ_ASSERT(!mBuffer);
|
||||
mBuffer = new (fallible) uint8_t[aSize];
|
||||
if (!mBuffer) {
|
||||
NS_WARNING("Failed to allocate buffer");
|
||||
return false;
|
||||
}
|
||||
GfxMemoryImageReporter::DidAlloc(mBuffer);
|
||||
mBufSize = aSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
MemoryTextureClient::MemoryTextureClient(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureClient(aAllocator, aFormat, aMoz2DBackend, aFlags)
|
||||
, mBuffer(nullptr)
|
||||
, mBufSize(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MemoryTextureClient);
|
||||
}
|
||||
|
||||
MemoryTextureClient::~MemoryTextureClient()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MemoryTextureClient);
|
||||
if (mBuffer && ShouldDeallocateInDestructor()) {
|
||||
// if the buffer has never been shared we must deallocate it or it would
|
||||
// leak.
|
||||
GfxMemoryImageReporter::WillFree(mBuffer);
|
||||
delete [] mBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
BufferTextureClient::BufferTextureClient(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
TextureFlags aFlags)
|
||||
: TextureClient(aAllocator, aFlags)
|
||||
, mFormat(aFormat)
|
||||
, mBackend(aMoz2DBackend)
|
||||
, mOpenMode(OpenMode::OPEN_NONE)
|
||||
, mLocked(false)
|
||||
{}
|
||||
|
||||
BufferTextureClient::~BufferTextureClient()
|
||||
{}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
BufferTextureClient::CreateSimilar(TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
// This may return null
|
||||
RefPtr<BufferTextureClient> newBufferTex = TextureClient::CreateForRawBufferAccess(
|
||||
mAllocator, mFormat, mSize, mBackend, mFlags | aFlags, aAllocFlags
|
||||
);
|
||||
|
||||
return newBufferTex.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
MOZ_ASSERT(mFormat != gfx::SurfaceFormat::YUV, "This textureClient cannot use YCbCr data");
|
||||
MOZ_ASSERT(aSize.width > 0 && aSize.height > 0);
|
||||
|
||||
if (aSize.width <= 0 || aSize.height <= 0) {
|
||||
gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat);
|
||||
if (!bufSize || !Allocate(bufSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aFlags & ALLOC_CLEAR_BUFFER) {
|
||||
memset(GetBuffer(), 0, bufSize);
|
||||
}
|
||||
if (aFlags & ALLOC_CLEAR_BUFFER_WHITE) {
|
||||
memset(GetBuffer(), 0xFF, bufSize);
|
||||
}
|
||||
|
||||
ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
|
||||
serializer.InitializeBufferInfo(aSize, mFormat);
|
||||
mSize = aSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
gfx::DrawTarget*
|
||||
BufferTextureClient::BorrowDrawTarget()
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mLocked, "BorrowDrawTarget should be called on locked textures only");
|
||||
if (!mLocked) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mDrawTarget) {
|
||||
mDrawTarget->SetTransform(Matrix());
|
||||
return mDrawTarget;
|
||||
}
|
||||
|
||||
ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
|
||||
if (!serializer.IsValid()) {
|
||||
gfxCriticalNote << "Invalid serializer " << IsValid() << ", " << IsLocked() << ", " << GetBufferSize();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mDrawTarget = serializer.GetAsDrawTarget(mBackend);
|
||||
if (mDrawTarget) {
|
||||
return mDrawTarget;
|
||||
}
|
||||
|
||||
mDrawTarget = serializer.GetAsDrawTarget(BackendType::CAIRO);
|
||||
if (!mDrawTarget) {
|
||||
gfxCriticalNote << "BorrowDrawTarget failure, original backend " << (int)mBackend;
|
||||
}
|
||||
|
||||
return mDrawTarget;
|
||||
}
|
||||
|
||||
void
|
||||
BufferTextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
{
|
||||
ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
|
||||
|
||||
RefPtr<DataSourceSurface> surface = serializer.GetAsSurface();
|
||||
|
||||
if (!surface) {
|
||||
gfxCriticalError() << "Failed to get serializer as surface!";
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
|
||||
|
||||
if (!srcSurf) {
|
||||
gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface->GetSize() != srcSurf->GetSize() || surface->GetFormat() != srcSurf->GetFormat()) {
|
||||
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << surface->GetSize() << " " << surface->GetFormat() << " Other: " << aSurface->GetSize() << " " << aSurface->GetFormat();
|
||||
return;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface sourceMap;
|
||||
DataSourceSurface::MappedSurface destMap;
|
||||
if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) {
|
||||
gfxCriticalError() << "Failed to map source surface for UpdateFromSurface.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!surface->Map(DataSourceSurface::WRITE, &destMap)) {
|
||||
srcSurf->Unmap();
|
||||
gfxCriticalError() << "Failed to map destination surface for UpdateFromSurface.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int y = 0; y < srcSurf->GetSize().height; y++) {
|
||||
memcpy(destMap.mData + destMap.mStride * y,
|
||||
sourceMap.mData + sourceMap.mStride * y,
|
||||
srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
|
||||
}
|
||||
|
||||
srcSurf->Unmap();
|
||||
surface->Unmap();
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureClient::Lock(OpenMode aMode)
|
||||
{
|
||||
MOZ_ASSERT(!mLocked, "The TextureClient is already Locked!");
|
||||
mOpenMode = aMode;
|
||||
mLocked = IsValid() && IsAllocated();;
|
||||
return mLocked;
|
||||
}
|
||||
|
||||
void
|
||||
BufferTextureClient::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mLocked, "The TextureClient is already Unlocked!");
|
||||
mLocked = false;
|
||||
if (!mDrawTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
// see the comment on TextureClient::BorrowDrawTarget.
|
||||
// This DrawTarget is internal to the TextureClient and is only exposed to the
|
||||
// outside world between Lock() and Unlock(). This assertion checks that no outside
|
||||
// reference remains by the time Unlock() is called.
|
||||
MOZ_ASSERT(mDrawTarget->refCount() == 1);
|
||||
|
||||
if (mReadbackSink) {
|
||||
RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot();
|
||||
RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface();
|
||||
mReadbackSink->ProcessReadback(dataSurf);
|
||||
}
|
||||
|
||||
mDrawTarget->Flush();
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureClient::UpdateYCbCr(const PlanarYCbCrData& aData)
|
||||
{
|
||||
MOZ_ASSERT(mLocked);
|
||||
MOZ_ASSERT(mFormat == gfx::SurfaceFormat::YUV, "This textureClient can only use YCbCr data");
|
||||
MOZ_ASSERT(!IsImmutable());
|
||||
MOZ_ASSERT(IsValid());
|
||||
MOZ_ASSERT(aTexture);
|
||||
MOZ_ASSERT(aTexture->IsLocked());
|
||||
MOZ_ASSERT(aTexture->GetFormat() == gfx::SurfaceFormat::YUV, "This textureClient can only use YCbCr data");
|
||||
MOZ_ASSERT(!aTexture->IsImmutable());
|
||||
MOZ_ASSERT(aTexture->IsValid());
|
||||
MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip);
|
||||
|
||||
YCbCrImageDataSerializer serializer(GetBuffer(), GetBufferSize());
|
||||
MOZ_ASSERT(serializer.IsValid());
|
||||
if (!serializer.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel,
|
||||
aData.mYSize, aData.mYStride,
|
||||
aData.mCbCrSize, aData.mCbCrStride,
|
||||
aData.mYSkip, aData.mCbSkip)) {
|
||||
MappedYCbCrTextureData mapped;
|
||||
if (!aTexture->BorrowMappedYCbCrData(mapped)) {
|
||||
NS_WARNING("Failed to extract YCbCr info!");
|
||||
return false;
|
||||
}
|
||||
|
||||
MappedYCbCrTextureData srcData;
|
||||
srcData.y.data = aData.mYChannel;
|
||||
srcData.y.size = aData.mYSize;
|
||||
srcData.y.stride = aData.mYStride;
|
||||
srcData.y.skip = aData.mYSkip;
|
||||
srcData.cb.data = aData.mCbChannel;
|
||||
srcData.cb.size = aData.mCbCrSize;
|
||||
srcData.cb.stride = aData.mCbCrStride;
|
||||
srcData.cb.skip = aData.mCbSkip;
|
||||
srcData.cr.data = aData.mCrChannel;
|
||||
srcData.cr.size = aData.mCbCrSize;
|
||||
srcData.cr.stride = aData.mCbCrStride;
|
||||
srcData.cr.skip = aData.mCrSkip;
|
||||
srcData.metadata = nullptr;
|
||||
|
||||
if (!srcData.CopyInto(mapped)) {
|
||||
NS_WARNING("Failed to copy image data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextureRequiresLocking(mFlags)) {
|
||||
if (TextureRequiresLocking(aTexture->GetFlags())) {
|
||||
// We don't have support for proper locking yet, so we'll
|
||||
// have to be immutable instead.
|
||||
MarkImmutable();
|
||||
aTexture->MarkImmutable();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureClient::AllocateForYCbCr(gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize,
|
||||
aCbCrSize);
|
||||
if (!bufSize || !Allocate(bufSize)) {
|
||||
return false;
|
||||
}
|
||||
YCbCrImageDataSerializer serializer(GetBuffer(), GetBufferSize());
|
||||
serializer.InitializeBufferInfo(aYSize,
|
||||
aCbCrSize,
|
||||
aStereoMode);
|
||||
mSize = aYSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
BufferTextureClient::GetLockedData() const
|
||||
{
|
||||
MOZ_ASSERT(IsLocked());
|
||||
|
||||
ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
|
||||
MOZ_ASSERT(serializer.IsValid());
|
||||
|
||||
return serializer.GetData();
|
||||
}
|
||||
|
||||
already_AddRefed<SyncObject>
|
||||
SyncObject::CreateSyncObject(SyncHandle aHandle)
|
||||
{
|
||||
@@ -1075,5 +921,40 @@ SyncObject::CreateSyncObject(SyncHandle aHandle)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
MappedYCbCrChannelData::CopyInto(MappedYCbCrChannelData& aDst)
|
||||
{
|
||||
if (!data || !aDst.data || size != aDst.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stride == aDst.stride) {
|
||||
// fast path!
|
||||
// We assume that the padding in the destination is there for alignment
|
||||
// purposes and doesn't contain useful data.
|
||||
memcpy(aDst.data, data, stride * size.height);
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < size.height; ++i) {
|
||||
if (aDst.skip == 0 && skip == 0) {
|
||||
// fast-ish path
|
||||
memcpy(aDst.data + i * aDst.stride,
|
||||
data + i * stride,
|
||||
size.width);
|
||||
} else {
|
||||
// slow path
|
||||
uint8_t* src = data + i * stride;
|
||||
uint8_t* dst = aDst.data + i * aDst.stride;
|
||||
for (int32_t j = 0; j < size.width; ++j) {
|
||||
*dst = *src;
|
||||
src += 1 + skip;
|
||||
dst += 1 + aDst.skip;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
+192
-191
@@ -39,6 +39,10 @@ namespace mozilla {
|
||||
#define GFX_DEBUG_TRACK_CLIENTS_IN_POOL 1
|
||||
#endif
|
||||
|
||||
namespace gl {
|
||||
class SharedSurface_Gralloc;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
class AsyncTransactionWaiter;
|
||||
@@ -49,14 +53,15 @@ struct PlanarYCbCrData;
|
||||
class Image;
|
||||
class PTextureChild;
|
||||
class TextureChild;
|
||||
class BufferTextureClient;
|
||||
class TextureData;
|
||||
struct RawTextureBuffer;
|
||||
class RawYCbCrTextureBuffer;
|
||||
class TextureClient;
|
||||
class TextureClientRecycleAllocator;
|
||||
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
|
||||
class TextureClientPool;
|
||||
#endif
|
||||
class KeepAlive;
|
||||
class GrallocTextureClientOGL;
|
||||
|
||||
/**
|
||||
* TextureClient is the abstraction that allows us to share data between the
|
||||
@@ -95,31 +100,6 @@ protected:
|
||||
SyncObject() { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface for TextureClients that can be updated using YCbCr data.
|
||||
*/
|
||||
class TextureClientYCbCr
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Copy aData into this texture client.
|
||||
*
|
||||
* This must never be called on a TextureClient that is not sucessfully locked.
|
||||
*/
|
||||
virtual bool UpdateYCbCr(const PlanarYCbCrData& aData) = 0;
|
||||
|
||||
/**
|
||||
* Allocates for a given surface size, taking into account the pixel format
|
||||
* which is part of the state of the TextureClient.
|
||||
*
|
||||
* Does not clear the surface, since we consider that the surface
|
||||
* be painted entirely with opaque content.
|
||||
*/
|
||||
virtual bool AllocateForYCbCr(gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class may be used to asynchronously receive an update when the content
|
||||
* drawn to this texture client is available for reading in CPU memory. This
|
||||
@@ -147,6 +127,43 @@ enum class BackendSelector
|
||||
Canvas
|
||||
};
|
||||
|
||||
/// Temporary object providing direct access to a Texture's memory.
|
||||
///
|
||||
/// see TextureClient::CanExposeMappedData() and TextureClient::BorrowMappedData().
|
||||
struct MappedTextureData
|
||||
{
|
||||
uint8_t* data;
|
||||
gfx::IntSize size;
|
||||
int32_t stride;
|
||||
gfx::SurfaceFormat format;
|
||||
};
|
||||
|
||||
struct MappedYCbCrChannelData
|
||||
{
|
||||
uint8_t* data;
|
||||
gfx::IntSize size;
|
||||
int32_t stride;
|
||||
int32_t skip;
|
||||
|
||||
bool CopyInto(MappedYCbCrChannelData& aDst);
|
||||
};
|
||||
|
||||
struct MappedYCbCrTextureData {
|
||||
MappedYCbCrChannelData y;
|
||||
MappedYCbCrChannelData cb;
|
||||
MappedYCbCrChannelData cr;
|
||||
// Sad but because of how SharedPlanarYCbCrData is used we have to expose this for now.
|
||||
uint8_t* metadata;
|
||||
StereoMode stereoMode;
|
||||
|
||||
bool CopyInto(MappedYCbCrTextureData& aDst)
|
||||
{
|
||||
return y.CopyInto(aDst.y)
|
||||
&& cb.CopyInto(aDst.cb)
|
||||
&& cr.CopyInto(aDst.cr);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* TextureClient is a thin abstraction over texture data that need to be shared
|
||||
* between the content process and the compositor process. It is the
|
||||
@@ -187,17 +204,17 @@ public:
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags flags = ALLOC_DEFAULT);
|
||||
|
||||
// Creates and allocates a BufferTextureClient supporting the YCbCr format.
|
||||
static already_AddRefed<BufferTextureClient>
|
||||
// Creates and allocates a TextureClient supporting the YCbCr format.
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
||||
gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
// Creates and allocates a BufferTextureClient (can beaccessed through raw
|
||||
// Creates and allocates a TextureClient (can be accessed through raw
|
||||
// pointers).
|
||||
static already_AddRefed<BufferTextureClient>
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateForRawBufferAccess(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::IntSize aSize,
|
||||
@@ -205,10 +222,10 @@ public:
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags flags = ALLOC_DEFAULT);
|
||||
|
||||
// Creates and allocates a BufferTextureClient (can beaccessed through raw
|
||||
// Creates and allocates a TextureClient (can beaccessed through raw
|
||||
// pointers) with a certain buffer size. It's unfortunate that we need this.
|
||||
// providing format and sizes could let us do more optimization.
|
||||
static already_AddRefed<BufferTextureClient>
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
@@ -234,9 +251,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual TextureClientYCbCr* AsTextureClientYCbCr() { return nullptr; }
|
||||
virtual GrallocTextureClientOGL* AsGrallocTextureClientOGL() { return nullptr; }
|
||||
|
||||
/**
|
||||
* Locks the shared data, allowing the caller to get access to it.
|
||||
*
|
||||
@@ -251,6 +265,8 @@ public:
|
||||
|
||||
virtual bool CanExposeDrawTarget() const { return false; }
|
||||
|
||||
virtual bool CanExposeMappedData() const { return false; }
|
||||
|
||||
/**
|
||||
* Returns a DrawTarget to draw into the TextureClient.
|
||||
* This function should never be called when not on the main thread!
|
||||
@@ -279,6 +295,13 @@ public:
|
||||
*/
|
||||
virtual gfx::DrawTarget* BorrowDrawTarget() { return nullptr; }
|
||||
|
||||
/**
|
||||
* Similar to BorrowDrawTarget but provides direct access to the texture's bits
|
||||
* instead of a DrawTarget.
|
||||
*/
|
||||
virtual bool BorrowMappedData(MappedTextureData&) { return false; }
|
||||
virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) { return false; }
|
||||
|
||||
/**
|
||||
* This function can be used to update the contents of the TextureClient
|
||||
* off the main thread.
|
||||
@@ -315,12 +338,14 @@ public:
|
||||
const gfx::IntPoint* aPoint);
|
||||
|
||||
/**
|
||||
* Returns true if this texture has a lock/unlock mechanism.
|
||||
* Textures that do not implement locking should be immutable or should
|
||||
* Returns true if this texture has a synchronization mechanism (mutex, fence, etc.).
|
||||
* Textures that do not implement synchronization should be immutable or should
|
||||
* use immediate uploads (see TextureFlags in CompositorTypes.h)
|
||||
* Even if a texture does not implement synchronization, Lock and Unlock need
|
||||
* to be used appropriately since the latter are also there to map/numap data.
|
||||
*/
|
||||
virtual bool ImplementsLocking() const { return false; }
|
||||
|
||||
virtual bool HasSynchronization() const { return false; }
|
||||
|
||||
/**
|
||||
* Indicates whether the TextureClient implementation is backed by an
|
||||
* in-memory buffer. The consequence of this is that locking the
|
||||
@@ -467,7 +492,7 @@ public:
|
||||
/**
|
||||
* Set AsyncTransactionTracker of RemoveTextureFromCompositableAsync() transaction.
|
||||
*/
|
||||
virtual void SetRemoveFromCompositableWaiter(AsyncTransactionWaiter* aWaiter) {}
|
||||
virtual void SetRemoveFromCompositableWaiter(AsyncTransactionWaiter* aWaiter);
|
||||
|
||||
/**
|
||||
* This function waits until the buffer is no longer being used.
|
||||
@@ -482,20 +507,20 @@ public:
|
||||
mWasteTracker.Update(aWasteArea, BytesPerPixel(GetFormat()));
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the readback sink that this texture is to use. This will
|
||||
* receive the data for this texture as soon as it becomes available after
|
||||
* texture unlock.
|
||||
*/
|
||||
virtual void SetReadbackSink(TextureReadbackSink* aReadbackSink) {
|
||||
mReadbackSink = aReadbackSink;
|
||||
}
|
||||
/**
|
||||
* This sets the readback sink that this texture is to use. This will
|
||||
* receive the data for this texture as soon as it becomes available after
|
||||
* texture unlock.
|
||||
*/
|
||||
virtual void SetReadbackSink(TextureReadbackSink* aReadbackSink) {
|
||||
mReadbackSink = aReadbackSink;
|
||||
}
|
||||
|
||||
virtual void SyncWithObject(SyncObject* aSyncObject) { }
|
||||
virtual void SyncWithObject(SyncObject* aSyncObject) { }
|
||||
|
||||
void MarkShared() {
|
||||
mShared = true;
|
||||
}
|
||||
void MarkShared() {
|
||||
mShared = true;
|
||||
}
|
||||
|
||||
ISurfaceAllocator* GetAllocator()
|
||||
{
|
||||
@@ -505,6 +530,9 @@ public:
|
||||
TextureClientRecycleAllocator* GetRecycleAllocator() { return mRecycleAllocator; }
|
||||
void SetRecycleAllocator(TextureClientRecycleAllocator* aAllocator);
|
||||
|
||||
/// If you add new code that uses this funtion, you are probably doing something wrong.
|
||||
virtual TextureData* GetInternalData() { return nullptr; }
|
||||
|
||||
private:
|
||||
static void TextureClientRecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
|
||||
@@ -524,7 +552,7 @@ private:
|
||||
virtual void FinalizeOnIPDLThread() {}
|
||||
|
||||
friend class AtomicRefCountedWithFinalize<TextureClient>;
|
||||
|
||||
friend class gl::SharedSurface_Gralloc;
|
||||
protected:
|
||||
/**
|
||||
* An invalid TextureClient cannot provide access to its shared data
|
||||
@@ -545,6 +573,8 @@ protected:
|
||||
RefPtr<TextureChild> mActor;
|
||||
RefPtr<ISurfaceAllocator> mAllocator;
|
||||
RefPtr<TextureClientRecycleAllocator> mRecycleAllocator;
|
||||
RefPtr<AsyncTransactionWaiter> mRemoveFromCompositableWaiter;
|
||||
|
||||
TextureFlags mFlags;
|
||||
FenceHandle mReleaseFenceHandle;
|
||||
FenceHandle mAcquireFenceHandle;
|
||||
@@ -567,6 +597,111 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
class TextureData {
|
||||
public:
|
||||
TextureData() { MOZ_COUNT_CTOR(TextureData); }
|
||||
|
||||
virtual ~TextureData() { MOZ_COUNT_DTOR(TextureData); }
|
||||
|
||||
virtual gfx::IntSize GetSize() const = 0;
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const = 0;
|
||||
|
||||
virtual bool Lock(OpenMode aMode, FenceHandle* aFence) = 0;
|
||||
|
||||
virtual void Unlock() = 0;
|
||||
|
||||
virtual bool SupportsMoz2D() const { return false; }
|
||||
|
||||
virtual bool CanExposeMappedData() const { return false; }
|
||||
|
||||
virtual bool HasInternalBuffer() const = 0;
|
||||
|
||||
virtual bool HasSynchronization() const { return false; }
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() { return nullptr; }
|
||||
|
||||
virtual bool BorrowMappedData(MappedTextureData&) { return false; }
|
||||
|
||||
virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) { return false; }
|
||||
|
||||
virtual void Deallocate(ISurfaceAllocator* aAllocator) = 0;
|
||||
|
||||
/// Depending on the texture's flags either Deallocate or Forget is called.
|
||||
virtual void Forget(ISurfaceAllocator* aAllocator) {}
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aDescriptor) = 0;
|
||||
|
||||
virtual TextureData*
|
||||
CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const { return nullptr; }
|
||||
|
||||
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) { return false; };
|
||||
|
||||
/// Ideally this should not be exposed and users of TextureClient would use Lock/Unlock
|
||||
/// preoperly but that requires a few changes to SharedSurface and maybe gonk video.
|
||||
virtual void WaitForFence(FenceHandle* aFence) {};
|
||||
};
|
||||
|
||||
/// temporary class that will be merged back into TextureClient when all texture implementations
|
||||
/// are based on TextureData.
|
||||
class ClientTexture : public TextureClient {
|
||||
public:
|
||||
ClientTexture(TextureData* aData, TextureFlags aFlags, ISurfaceAllocator* aAllocator);
|
||||
|
||||
~ClientTexture();
|
||||
|
||||
virtual bool CanExposeDrawTarget() const override { return mData->SupportsMoz2D(); }
|
||||
|
||||
virtual bool CanExposeMappedData() const override { return mData->CanExposeMappedData(); }
|
||||
|
||||
virtual bool HasInternalBuffer() const override;
|
||||
|
||||
virtual bool HasSynchronization() const { return mData->HasSynchronization(); }
|
||||
|
||||
virtual gfx::IntSize GetSize() const override;
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override;
|
||||
|
||||
virtual bool Lock(OpenMode aMode) override;
|
||||
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual bool IsLocked() const override { return mIsLocked; }
|
||||
|
||||
virtual gfx::DrawTarget* BorrowDrawTarget() override;
|
||||
|
||||
virtual bool BorrowMappedData(MappedTextureData&) override;
|
||||
|
||||
virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) override;
|
||||
|
||||
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
virtual already_AddRefed<TextureClient>
|
||||
CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
|
||||
|
||||
virtual void UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
// TODO - we should be able to make this implicit and not expose the method.
|
||||
virtual void WaitForBufferOwnership(bool aWaitReleaseFence = true) override;
|
||||
|
||||
// by construction, ClientTexture cannot be created without successful allocation.
|
||||
virtual bool IsAllocated() const override { return true; }
|
||||
|
||||
/// If you add new code that uses this method, you are probably doing something wrong.
|
||||
virtual TextureData* GetInternalData() override { return mData; }
|
||||
protected:
|
||||
TextureData* mData;
|
||||
RefPtr<gfx::DrawTarget> mBorrowedDrawTarget;
|
||||
RefPtr<TextureReadbackSink> mReadbackSink;
|
||||
|
||||
OpenMode mOpenMode;
|
||||
DebugOnly<uint32_t> mExpectedDtRefs;
|
||||
bool mIsLocked;
|
||||
};
|
||||
|
||||
/**
|
||||
* Task that releases TextureClient pointer on a specified thread.
|
||||
*/
|
||||
@@ -586,143 +721,6 @@ private:
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* TextureClient that wraps a random access buffer such as a Shmem or raw memory.
|
||||
* This class must be inherited to implement the memory allocation and access bits.
|
||||
* (see ShmemTextureClient and MemoryTextureClient)
|
||||
*/
|
||||
class BufferTextureClient : public TextureClient
|
||||
, public TextureClientYCbCr
|
||||
{
|
||||
public:
|
||||
BufferTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aBackend, TextureFlags aFlags);
|
||||
|
||||
virtual ~BufferTextureClient();
|
||||
|
||||
virtual bool IsAllocated() const override = 0;
|
||||
|
||||
virtual uint8_t* GetBuffer() const = 0;
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual bool Lock(OpenMode aMode) override;
|
||||
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual bool IsLocked() const override { return mLocked; }
|
||||
|
||||
uint8_t* GetLockedData() const;
|
||||
|
||||
virtual bool CanExposeDrawTarget() const override { return true; }
|
||||
|
||||
virtual gfx::DrawTarget* BorrowDrawTarget() override;
|
||||
|
||||
virtual void UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
virtual bool AllocateForSurface(gfx::IntSize aSize,
|
||||
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
|
||||
|
||||
// TextureClientYCbCr
|
||||
|
||||
virtual TextureClientYCbCr* AsTextureClientYCbCr() override { return this; }
|
||||
|
||||
virtual bool UpdateYCbCr(const PlanarYCbCrData& aData) override;
|
||||
|
||||
virtual bool AllocateForYCbCr(gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode) override;
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
|
||||
// XXX - Bug 908196 - Make Allocate(uint32_t) and GetBufferSize() protected.
|
||||
// these two methods should only be called by methods of BufferTextureClient
|
||||
// that are overridden in GrallocTextureClient (which does not implement the
|
||||
// two methods below)
|
||||
virtual bool Allocate(uint32_t aSize) = 0;
|
||||
|
||||
virtual size_t GetBufferSize() const = 0;
|
||||
|
||||
virtual bool HasInternalBuffer() const override { return true; }
|
||||
|
||||
virtual already_AddRefed<TextureClient>
|
||||
CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
|
||||
|
||||
protected:
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
gfx::IntSize mSize;
|
||||
gfx::BackendType mBackend;
|
||||
OpenMode mOpenMode;
|
||||
bool mLocked;
|
||||
};
|
||||
|
||||
/**
|
||||
* TextureClient that wraps shared memory.
|
||||
* the corresponding texture on the host side is ShmemTextureHost.
|
||||
*/
|
||||
class ShmemTextureClient : public BufferTextureClient
|
||||
{
|
||||
public:
|
||||
ShmemTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aBackend, TextureFlags aFlags);
|
||||
|
||||
protected:
|
||||
~ShmemTextureClient();
|
||||
|
||||
public:
|
||||
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) override;
|
||||
|
||||
virtual bool Allocate(uint32_t aSize) override;
|
||||
|
||||
virtual uint8_t* GetBuffer() const override;
|
||||
|
||||
virtual size_t GetBufferSize() const override;
|
||||
|
||||
virtual bool IsAllocated() const override { return mAllocated; }
|
||||
|
||||
virtual bool HasInternalBuffer() const override { return true; }
|
||||
|
||||
mozilla::ipc::Shmem& GetShmem() { return mShmem; }
|
||||
|
||||
protected:
|
||||
mozilla::ipc::Shmem mShmem;
|
||||
bool mAllocated;
|
||||
};
|
||||
|
||||
/**
|
||||
* TextureClient that wraps raw memory.
|
||||
* The corresponding texture on the host side is MemoryTextureHost.
|
||||
* Can obviously not be used in a cross process setup.
|
||||
*/
|
||||
class MemoryTextureClient : public BufferTextureClient
|
||||
{
|
||||
public:
|
||||
MemoryTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aBackend, TextureFlags aFlags);
|
||||
|
||||
protected:
|
||||
~MemoryTextureClient();
|
||||
|
||||
public:
|
||||
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) override;
|
||||
|
||||
virtual bool Allocate(uint32_t aSize) override;
|
||||
|
||||
virtual uint8_t* GetBuffer() const override { return mBuffer; }
|
||||
|
||||
virtual size_t GetBufferSize() const override { return mBufSize; }
|
||||
|
||||
virtual bool IsAllocated() const override { return mBuffer != nullptr; }
|
||||
|
||||
virtual bool HasInternalBuffer() const override { return true; }
|
||||
|
||||
protected:
|
||||
uint8_t* mBuffer;
|
||||
size_t mBufSize;
|
||||
};
|
||||
|
||||
// Automatically lock and unlock a texture. Since texture locking is fallible,
|
||||
// Succeeded() must be checked on the guard object before proceeding.
|
||||
class MOZ_RAII TextureClientAutoLock
|
||||
@@ -773,6 +771,9 @@ protected:
|
||||
RefPtr<T> mData;
|
||||
};
|
||||
|
||||
/// Convenience function to set the content of ycbcr texture.
|
||||
bool UpdateYCbCrTextureClient(TextureClient* aTexture, const PlanarYCbCrData& aData);
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "TextureClientPool.h"
|
||||
#include "CompositableClient.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
|
||||
@@ -52,9 +52,9 @@ void
|
||||
SharedSurfaceTextureClient::SetReleaseFenceHandle(const FenceHandle& aReleaseFenceHandle)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
SharedSurface_Gralloc* surf = nullptr;
|
||||
if (mSurf->mType == SharedSurfaceType::Gralloc) {
|
||||
surf = SharedSurface_Gralloc::Cast(mSurf.get());
|
||||
gl::SharedSurface_Gralloc* surf = nullptr;
|
||||
if (mSurf->mType == gl::SharedSurfaceType::Gralloc) {
|
||||
surf = gl::SharedSurface_Gralloc::Cast(mSurf.get());
|
||||
}
|
||||
if (surf && surf->GetTextureClient()) {
|
||||
surf->GetTextureClient()->SetReleaseFenceHandle(aReleaseFenceHandle);
|
||||
@@ -68,9 +68,9 @@ FenceHandle
|
||||
SharedSurfaceTextureClient::GetAndResetReleaseFenceHandle()
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
SharedSurface_Gralloc* surf = nullptr;
|
||||
if (mSurf->mType == SharedSurfaceType::Gralloc) {
|
||||
surf = SharedSurface_Gralloc::Cast(mSurf.get());
|
||||
gl::SharedSurface_Gralloc* surf = nullptr;
|
||||
if (mSurf->mType == gl::SharedSurfaceType::Gralloc) {
|
||||
surf = gl::SharedSurface_Gralloc::Cast(mSurf.get());
|
||||
}
|
||||
if (surf && surf->GetTextureClient()) {
|
||||
return surf->GetTextureClient()->GetAndResetReleaseFenceHandle();
|
||||
@@ -83,9 +83,9 @@ void
|
||||
SharedSurfaceTextureClient::SetAcquireFenceHandle(const FenceHandle& aAcquireFenceHandle)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
SharedSurface_Gralloc* surf = nullptr;
|
||||
if (mSurf->mType == SharedSurfaceType::Gralloc) {
|
||||
surf = SharedSurface_Gralloc::Cast(mSurf.get());
|
||||
gl::SharedSurface_Gralloc* surf = nullptr;
|
||||
if (mSurf->mType == gl::SharedSurfaceType::Gralloc) {
|
||||
surf = gl::SharedSurface_Gralloc::Cast(mSurf.get());
|
||||
}
|
||||
if (surf && surf->GetTextureClient()) {
|
||||
return surf->GetTextureClient()->SetAcquireFenceHandle(aAcquireFenceHandle);
|
||||
@@ -98,9 +98,9 @@ const FenceHandle&
|
||||
SharedSurfaceTextureClient::GetAcquireFenceHandle() const
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
SharedSurface_Gralloc* surf = nullptr;
|
||||
if (mSurf->mType == SharedSurfaceType::Gralloc) {
|
||||
surf = SharedSurface_Gralloc::Cast(mSurf.get());
|
||||
gl::SharedSurface_Gralloc* surf = nullptr;
|
||||
if (mSurf->mType == gl::SharedSurfaceType::Gralloc) {
|
||||
surf = gl::SharedSurface_Gralloc::Cast(mSurf.get());
|
||||
}
|
||||
if (surf && surf->GetTextureClient()) {
|
||||
return surf->GetTextureClient()->GetAcquireFenceHandle();
|
||||
|
||||
@@ -703,7 +703,7 @@ TileClient::DiscardBackBuffer()
|
||||
{
|
||||
if (mBackBuffer) {
|
||||
MOZ_ASSERT(mBackLock);
|
||||
if (!mBackBuffer->ImplementsLocking() && mBackLock->GetReadCount() > 1) {
|
||||
if (!mBackBuffer->HasSynchronization() && mBackLock->GetReadCount() > 1) {
|
||||
// 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.
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
#include "nsIFile.h" // for nsIFile
|
||||
#include "nsDirectoryServiceDefs.h" // for NS_OS_TMP_DIR
|
||||
#include "prprf.h" // for PR_snprintf
|
||||
#include "mozilla/Snprintf.h"
|
||||
#include "FPSCounter.h"
|
||||
|
||||
namespace mozilla {
|
||||
@@ -28,6 +28,7 @@ using namespace mozilla::gfx;
|
||||
|
||||
FPSCounter::FPSCounter(const char* aName)
|
||||
: mWriteIndex(0)
|
||||
, mIteratorIndex(-1)
|
||||
, mFPSName(aName)
|
||||
{
|
||||
Init();
|
||||
@@ -208,7 +209,7 @@ FPSCounter::WriteFrameTimeStamps(PRFileDesc* fd)
|
||||
{
|
||||
const int bufferSize = 256;
|
||||
char buffer[bufferSize];
|
||||
int writtenCount = PR_snprintf(buffer, bufferSize, "FPS Data for: %s\n", mFPSName);
|
||||
int writtenCount = snprintf_literal(buffer, "FPS Data for: %s\n", mFPSName);
|
||||
MOZ_ASSERT(writtenCount >= 0);
|
||||
PR_Write(fd, buffer, writtenCount);
|
||||
|
||||
@@ -223,7 +224,7 @@ FPSCounter::WriteFrameTimeStamps(PRFileDesc* fd)
|
||||
|
||||
while (HasNext(startTimeStamp)) {
|
||||
TimeDuration duration = previousSample - nextTimeStamp;
|
||||
writtenCount = PR_snprintf(buffer, bufferSize, "%f,\n", duration.ToMilliseconds());
|
||||
writtenCount = snprintf_literal(buffer, "%f,\n", duration.ToMilliseconds());
|
||||
|
||||
MOZ_ASSERT(writtenCount >= 0);
|
||||
PR_Write(fd, buffer, writtenCount);
|
||||
@@ -308,8 +309,8 @@ FPSCounter::PrintHistogram(std::map<int, int>& aHistogram)
|
||||
int fps = iter->first;
|
||||
int count = iter->second;
|
||||
|
||||
length += PR_snprintf(buffer + length, kBufferLength - length,
|
||||
"FPS: %d = %d. ", fps, count);
|
||||
length += snprintf(buffer + length, kBufferLength - length,
|
||||
"FPS: %d = %d. ", fps, count);
|
||||
NS_ASSERTION(length >= kBufferLength, "Buffer overrun while printing FPS histogram.");
|
||||
}
|
||||
|
||||
|
||||
@@ -148,5 +148,5 @@ FrameUniformityData::ToJS(JS::MutableHandleValue aOutValue, JSContext* aContext)
|
||||
return dom::ToJSValue(aContext, results, aOutValue);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -48,8 +48,8 @@ private:
|
||||
std::map<uintptr_t,LayerTransforms*> mFrameTransforms;
|
||||
};
|
||||
|
||||
} // mozilla
|
||||
} // layers
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
namespace IPC {
|
||||
template<>
|
||||
@@ -68,6 +68,6 @@ struct ParamTraits<mozilla::layers::FrameUniformityData>
|
||||
}
|
||||
};
|
||||
|
||||
}// ipc
|
||||
} // namespace IPC
|
||||
|
||||
#endif // mozilla_layers_FrameUniformityData_h_
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "mozilla/layers/TextureHost.h" // for TextureHost, etc
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsAString.h"
|
||||
#include "mozilla/RefPtr.h" // for nsRefPtr
|
||||
#include "mozilla/RefPtr.h" // for nsRefPtr
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsString.h" // for nsAutoCString
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsAString.h"
|
||||
#include "mozilla/RefPtr.h" // for nsRefPtr
|
||||
#include "mozilla/RefPtr.h" // for nsRefPtr
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
@@ -45,7 +45,6 @@ namespace gfx {
|
||||
class DrawTarget;
|
||||
} // namespace gfx
|
||||
|
||||
|
||||
namespace layers {
|
||||
|
||||
class CanvasLayerComposite;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "mozilla/layers/Effects.h" // for EffectChain
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsAString.h"
|
||||
#include "mozilla/RefPtr.h" // for nsRefPtr
|
||||
#include "mozilla/RefPtr.h" // for nsRefPtr
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsMathUtils.h" // for NS_lround
|
||||
#include "nsString.h" // for nsAutoCString
|
||||
|
||||
@@ -90,7 +90,9 @@ TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin,
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map);
|
||||
if (NS_WARN_IF(!textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize the surface to transparent white.
|
||||
memset(map.mData, uint8_t(sBackgroundOpacity * 255.0f),
|
||||
@@ -151,7 +153,9 @@ TextRenderer::EnsureInitialized()
|
||||
return;
|
||||
}
|
||||
|
||||
mGlyphBitmaps->Map(DataSourceSurface::MapType::READ_WRITE, &mMap);
|
||||
if (NS_WARN_IF(!mGlyphBitmaps->Map(DataSourceSurface::MapType::READ_WRITE, &mMap))) {
|
||||
return;
|
||||
}
|
||||
|
||||
png_structp png_ptr = NULL;
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
NS_INLINE_DECL_REFCOUNTING(TextRenderer)
|
||||
|
||||
explicit TextRenderer(Compositor *aCompositor)
|
||||
: mCompositor(aCompositor)
|
||||
: mCompositor(aCompositor), mMap({nullptr, 0})
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "TiledContentHost.h"
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "PaintedLayerComposite.h" // for PaintedLayerComposite
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
@@ -69,6 +70,27 @@ TiledContentHost::~TiledContentHost()
|
||||
MOZ_COUNT_DTOR(TiledContentHost);
|
||||
}
|
||||
|
||||
already_AddRefed<TexturedEffect>
|
||||
TiledContentHost::GenEffect(const gfx::Filter& aFilter)
|
||||
{
|
||||
// If we can use hwc for this TiledContentHost, it implies that we have exactly
|
||||
// one high precision tile. Please check TiledContentHost::GetRenderState() for
|
||||
// all condition.
|
||||
MOZ_ASSERT(mTiledBuffer.GetTileCount() == 1 && mLowPrecisionTiledBuffer.GetTileCount() == 0);
|
||||
MOZ_ASSERT(mTiledBuffer.GetTile(0).mTextureHost);
|
||||
|
||||
TileHost& tile = mTiledBuffer.GetTile(0);
|
||||
if (!tile.mTextureHost->BindTextureSource(tile.mTextureSource)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CreateTexturedEffect(tile.mTextureSource,
|
||||
nullptr,
|
||||
aFilter,
|
||||
true,
|
||||
tile.mTextureHost->GetRenderState());
|
||||
}
|
||||
|
||||
void
|
||||
TiledContentHost::Attach(Layer* aLayer,
|
||||
Compositor* aCompositor,
|
||||
@@ -110,34 +132,31 @@ void
|
||||
UseTileTexture(CompositableTextureHostRef& aTexture,
|
||||
CompositableTextureSourceRef& aTextureSource,
|
||||
const IntRect& aUpdateRect,
|
||||
TextureHost* aNewTexture,
|
||||
Compositor* aCompositor)
|
||||
{
|
||||
if (aTexture && aTexture->GetFormat() != aNewTexture->GetFormat()) {
|
||||
// Only reuse textures if their format match the new texture's.
|
||||
aTextureSource = nullptr;
|
||||
aTexture = nullptr;
|
||||
MOZ_ASSERT(aTexture);
|
||||
if (!aTexture) {
|
||||
return;
|
||||
}
|
||||
aTexture = aNewTexture;
|
||||
if (aTexture) {
|
||||
if (aCompositor) {
|
||||
aTexture->SetCompositor(aCompositor);
|
||||
}
|
||||
|
||||
if (!aUpdateRect.IsEmpty()) {
|
||||
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
aTexture->Updated(nullptr);
|
||||
#else
|
||||
// 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.
|
||||
nsIntRegion region = aUpdateRect;
|
||||
aTexture->Updated(®ion);
|
||||
#endif
|
||||
}
|
||||
aTexture->PrepareTextureSource(aTextureSource);
|
||||
if (aCompositor) {
|
||||
aTexture->SetCompositor(aCompositor);
|
||||
}
|
||||
|
||||
if (!aUpdateRect.IsEmpty()) {
|
||||
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
aTexture->Updated(nullptr);
|
||||
#else
|
||||
// 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.
|
||||
nsIntRegion region = aUpdateRect;
|
||||
aTexture->Updated(®ion);
|
||||
#endif
|
||||
}
|
||||
|
||||
aTexture->PrepareTextureSource(aTextureSource);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -164,6 +183,83 @@ GetCopyOnWriteLock(const TileLock& ipcLock, TileHost& aTile, ISurfaceAllocator*
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::MarkTilesForUnlock()
|
||||
{
|
||||
// Tiles without an internal buffer will have internal locks
|
||||
// held by the gpu driver until the previous draw operation has finished.
|
||||
// We don't know when that will be exactly, so wait until we start the
|
||||
// next composite before unlocking.
|
||||
for (TileHost& tile : mRetainedTiles) {
|
||||
// Tile with an internal buffer get unlocked as soon as we've uploaded,
|
||||
// so won't have a lock at this point.
|
||||
if (tile.mTextureHost && tile.mSharedLock) {
|
||||
mDelayedUnlocks.AppendElement(tile.mSharedLock);
|
||||
tile.mSharedLock = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TextureSourceRecycler
|
||||
{
|
||||
public:
|
||||
explicit TextureSourceRecycler(nsTArray<TileHost>&& aTileSet)
|
||||
: mTiles(Move(aTileSet))
|
||||
, mFirstPossibility(0)
|
||||
{}
|
||||
|
||||
// Attempts to recycle a texture source that is already bound to the
|
||||
// texture host for aTile.
|
||||
void RecycleTextureSourceForTile(TileHost& aTile) {
|
||||
for (size_t i = mFirstPossibility; i < mTiles.Length(); i++) {
|
||||
// Skip over existing tiles without a retained texture source
|
||||
// and make sure we don't iterate them in the future.
|
||||
if (!mTiles[i].mTextureSource) {
|
||||
if (i == mFirstPossibility) {
|
||||
mFirstPossibility++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this tile matches, then copy across the retained texture source (if
|
||||
// any).
|
||||
if (aTile.mTextureHost == mTiles[i].mTextureHost) {
|
||||
aTile.mTextureSource = Move(mTiles[i].mTextureSource);
|
||||
if (aTile.mTextureHostOnWhite) {
|
||||
aTile.mTextureSourceOnWhite = Move(mTiles[i].mTextureSourceOnWhite);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to recycle any texture source to avoid needing to allocate
|
||||
// a new one.
|
||||
void RecycleTextureSource(TileHost& aTile) {
|
||||
for (size_t i = mFirstPossibility; i < mTiles.Length(); i++) {
|
||||
if (!mTiles[i].mTextureSource) {
|
||||
if (i == mFirstPossibility) {
|
||||
mFirstPossibility++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mTiles[i].mTextureSource &&
|
||||
mTiles[i].mTextureHost->GetFormat() == aTile.mTextureHost->GetFormat()) {
|
||||
aTile.mTextureSource = Move(mTiles[i].mTextureSource);
|
||||
if (aTile.mTextureHostOnWhite) {
|
||||
aTile.mTextureSourceOnWhite = Move(mTiles[i].mTextureSourceOnWhite);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
nsTArray<TileHost> mTiles;
|
||||
size_t mFirstPossibility;
|
||||
};
|
||||
|
||||
bool
|
||||
TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
Compositor* aCompositor,
|
||||
@@ -185,146 +281,98 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
return false;
|
||||
}
|
||||
|
||||
TilesPlacement oldTiles = mTiles;
|
||||
TilesPlacement newTiles(aTiles.firstTileX(), aTiles.firstTileY(),
|
||||
aTiles.retainedWidth(), aTiles.retainedHeight());
|
||||
|
||||
const InfallibleTArray<TileDescriptor>& tileDescriptors = aTiles.tiles();
|
||||
|
||||
nsTArray<TileHost> oldRetainedTiles;
|
||||
mRetainedTiles.SwapElements(oldRetainedTiles);
|
||||
// Step 1, unlock all the old tiles that haven't been unlocked yet. Any tiles that
|
||||
// exist in both the old and new sets will have been locked again by content, so this
|
||||
// doesn't result in the surface being writeable again.
|
||||
MarkTilesForUnlock();
|
||||
|
||||
TextureSourceRecycler oldRetainedTiles(Move(mRetainedTiles));
|
||||
mRetainedTiles.SetLength(tileDescriptors.Length());
|
||||
|
||||
// Step 1, we need to unlock tiles that don't have an internal buffer after the
|
||||
// next frame where they are replaced.
|
||||
// Since we are about to replace the tiles' textures, we need to keep their locks
|
||||
// somewhere (in mPreviousSharedLock) until we composite the layer.
|
||||
for (size_t i = 0; i < oldRetainedTiles.Length(); ++i) {
|
||||
TileHost& tile = oldRetainedTiles[i];
|
||||
// It can happen that we still have a previous lock at this point,
|
||||
// if we changed a tile's front buffer (causing mSharedLock to
|
||||
// go into mPreviousSharedLock, and then did not composite that tile until
|
||||
// the next transaction, either because the tile is offscreen or because the
|
||||
// two transactions happened with no composition in between (over-production).
|
||||
tile.ReadUnlockPrevious();
|
||||
|
||||
if (tile.mTextureHost && !tile.mTextureHost->HasInternalBuffer()) {
|
||||
MOZ_ASSERT(tile.mSharedLock);
|
||||
const TileIntPoint tilePosition = oldTiles.TilePosition(i);
|
||||
if (newTiles.HasTile(tilePosition)) {
|
||||
// This tile still exist in the new buffer
|
||||
tile.mPreviousSharedLock = tile.mSharedLock;
|
||||
tile.mSharedLock = nullptr;
|
||||
} else {
|
||||
// This tile does not exist anymore in the new buffer because the size
|
||||
// changed.
|
||||
tile.ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
// By now we should not have anything in mSharedLock.
|
||||
MOZ_ASSERT(!tile.mSharedLock);
|
||||
}
|
||||
|
||||
// Step 2, move the tiles in mRetainedTiles at places that correspond to where
|
||||
// they should be with the new retained with and height rather than the
|
||||
// old one.
|
||||
// Step 2, deserialize the incoming set of tiles into mRetainedTiles, and attempt
|
||||
// to recycle the TextureSource for any repeated tiles.
|
||||
//
|
||||
// Since we don't have any retained 'tile' object, we have to search for instances
|
||||
// of the same TextureHost in the old tile set. The cost of binding a TextureHost
|
||||
// to a TextureSource for gralloc (binding EGLImage to GL texture) can be really
|
||||
// high, so we avoid this whenever possible.
|
||||
for (size_t i = 0; i < tileDescriptors.Length(); i++) {
|
||||
const TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
// First, get the already existing tiles to the right place in the array,
|
||||
// and use placeholders where there was no tiles.
|
||||
if (!oldTiles.HasTile(tilePosition)) {
|
||||
mRetainedTiles[i] = GetPlaceholderTile();
|
||||
} else {
|
||||
mRetainedTiles[i] = oldRetainedTiles[oldTiles.TileIndex(tilePosition)];
|
||||
// If we hit this assertion it means we probably mixed something up in the
|
||||
// logic that tries to reuse tiles on the compositor side. It is most likely
|
||||
// benign, but we are missing some fast paths so let's try to make it not happen.
|
||||
MOZ_ASSERT(tilePosition.x == mRetainedTiles[i].x &&
|
||||
tilePosition.y == mRetainedTiles[i].y);
|
||||
}
|
||||
}
|
||||
|
||||
// It is important to remove the duplicated reference to tiles before calling
|
||||
// TextureHost::PrepareTextureSource, etc. because depending on the textures
|
||||
// ref counts we may or may not get some of the fast paths.
|
||||
oldRetainedTiles.Clear();
|
||||
|
||||
// Step 3, handle the texture updates and release the copy-on-write locks.
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
const TileDescriptor& tileDesc = tileDescriptors[i];
|
||||
|
||||
TileHost& tile = mRetainedTiles[i];
|
||||
|
||||
switch (tileDesc.type()) {
|
||||
case TileDescriptor::TTexturedTileDescriptor: {
|
||||
const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
|
||||
|
||||
const TileLock& ipcLock = texturedDesc.sharedLock();
|
||||
if (!GetCopyOnWriteLock(ipcLock, tile, aAllocator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<TextureHost> textureHost = TextureHost::AsTextureHost(
|
||||
texturedDesc.textureParent()
|
||||
);
|
||||
|
||||
RefPtr<TextureHost> textureOnWhite = nullptr;
|
||||
if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
|
||||
textureOnWhite = TextureHost::AsTextureHost(
|
||||
texturedDesc.textureOnWhite().get_PTextureParent()
|
||||
);
|
||||
}
|
||||
|
||||
UseTileTexture(tile.mTextureHost,
|
||||
tile.mTextureSource,
|
||||
texturedDesc.updateRect(),
|
||||
textureHost,
|
||||
aCompositor);
|
||||
|
||||
if (textureOnWhite) {
|
||||
UseTileTexture(tile.mTextureHostOnWhite,
|
||||
tile.mTextureSourceOnWhite,
|
||||
texturedDesc.updateRect(),
|
||||
textureOnWhite,
|
||||
aCompositor);
|
||||
} else {
|
||||
// We could still have component alpha textures from a previous frame.
|
||||
tile.mTextureSourceOnWhite = nullptr;
|
||||
tile.mTextureHostOnWhite = nullptr;
|
||||
}
|
||||
|
||||
if (textureHost->HasInternalBuffer()) {
|
||||
// Now that we did the texture upload (in UseTileTexture), we can release
|
||||
// the lock.
|
||||
tile.ReadUnlock();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_WARNING("Unrecognised tile descriptor type");
|
||||
case TileDescriptor::TPlaceholderTileDescriptor: {
|
||||
|
||||
if (tile.mTextureHost) {
|
||||
tile.mTextureHost->UnbindTextureSource();
|
||||
tile.mTextureSource = nullptr;
|
||||
}
|
||||
if (tile.mTextureHostOnWhite) {
|
||||
tile.mTextureHostOnWhite->UnbindTextureSource();
|
||||
tile.mTextureSourceOnWhite = nullptr;
|
||||
}
|
||||
// we may have a previous lock, and are about to loose our reference to it.
|
||||
// It is okay to unlock it because we just destroyed the texture source.
|
||||
tile.ReadUnlockPrevious();
|
||||
tile = GetPlaceholderTile();
|
||||
|
||||
break;
|
||||
}
|
||||
if (tileDesc.type() != TileDescriptor::TTexturedTileDescriptor) {
|
||||
NS_WARN_IF_FALSE(tileDesc.type() == TileDescriptor::TPlaceholderTileDescriptor,
|
||||
"Unrecognised tile descriptor type");
|
||||
continue;
|
||||
}
|
||||
|
||||
const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
|
||||
|
||||
const TileLock& ipcLock = texturedDesc.sharedLock();
|
||||
if (!GetCopyOnWriteLock(ipcLock, tile, aAllocator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tile.mTextureHost = TextureHost::AsTextureHost(texturedDesc.textureParent());
|
||||
tile.mTextureHost->SetCompositor(aCompositor);
|
||||
|
||||
if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
|
||||
tile.mTextureHostOnWhite =
|
||||
TextureHost::AsTextureHost(texturedDesc.textureOnWhite().get_PTextureParent());
|
||||
}
|
||||
|
||||
tile.mTilePosition = newTiles.TilePosition(i);
|
||||
|
||||
// If this same tile texture existed in the old tile set then this will move the texture
|
||||
// source into our new tile.
|
||||
oldRetainedTiles.RecycleTextureSourceForTile(tile);
|
||||
}
|
||||
|
||||
// Step 3, attempt to recycle unused texture sources from the old tile set into new tiles.
|
||||
//
|
||||
// For gralloc, binding a new TextureHost to the existing TextureSource is the fastest way
|
||||
// to ensure that any implicit locking on the old gralloc image is released.
|
||||
for (TileHost& tile : mRetainedTiles) {
|
||||
if (!tile.mTextureHost || tile.mTextureSource) {
|
||||
continue;
|
||||
}
|
||||
oldRetainedTiles.RecycleTextureSource(tile);
|
||||
}
|
||||
|
||||
// Step 4, handle the texture uploads, texture source binding and release the
|
||||
// copy-on-write locks for textures with an internal buffer.
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
TileHost& tile = mRetainedTiles[i];
|
||||
if (!tile.mTextureHost) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const TileDescriptor& tileDesc = tileDescriptors[i];
|
||||
const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
|
||||
|
||||
UseTileTexture(tile.mTextureHost,
|
||||
tile.mTextureSource,
|
||||
texturedDesc.updateRect(),
|
||||
aCompositor);
|
||||
|
||||
if (tile.mTextureHostOnWhite) {
|
||||
UseTileTexture(tile.mTextureHostOnWhite,
|
||||
tile.mTextureSourceOnWhite,
|
||||
texturedDesc.updateRect(),
|
||||
aCompositor);
|
||||
}
|
||||
|
||||
if (tile.mTextureHost->HasInternalBuffer()) {
|
||||
// Now that we did the texture upload (in UseTileTexture), we can release
|
||||
// the lock.
|
||||
tile.ReadUnlock();
|
||||
}
|
||||
TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
tile.x = tilePosition.x;
|
||||
tile.y = tilePosition.y;
|
||||
}
|
||||
|
||||
mTiles = newTiles;
|
||||
@@ -338,14 +386,23 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::ProcessDelayedUnlocks()
|
||||
{
|
||||
for (gfxSharedReadLock* lock : mDelayedUnlocks) {
|
||||
lock->ReadUnlock();
|
||||
}
|
||||
mDelayedUnlocks.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::Clear()
|
||||
{
|
||||
for (TileHost& tile : mRetainedTiles) {
|
||||
tile.ReadUnlock();
|
||||
tile.ReadUnlockPrevious();
|
||||
}
|
||||
mRetainedTiles.Clear();
|
||||
ProcessDelayedUnlocks();
|
||||
mTiles.mFirst = TileIntPoint();
|
||||
mTiles.mSize = TileIntSize();
|
||||
mValidRegion = nsIntRegion();
|
||||
@@ -407,6 +464,8 @@ TiledContentHost::Composite(LayerComposite* aLayer,
|
||||
aFilter, aClipRect, *renderRegion, aTransform);
|
||||
RenderLayerBuffer(mTiledBuffer, nullptr, aEffectChain, aOpacity, aFilter,
|
||||
aClipRect, *renderRegion, aTransform);
|
||||
mLowPrecisionTiledBuffer.ProcessDelayedUnlocks();
|
||||
mTiledBuffer.ProcessDelayedUnlocks();
|
||||
}
|
||||
|
||||
|
||||
@@ -470,7 +529,6 @@ TiledContentHost::RenderTile(TileHost& aTile,
|
||||
}
|
||||
mCompositor->DrawDiagnostics(flags,
|
||||
aScreenRegion, aClipRect, aTransform, mFlashCounter);
|
||||
aTile.ReadUnlockPrevious();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -490,9 +548,9 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
||||
float resolution = aLayerBuffer.GetResolution();
|
||||
gfx::Size layerScale(1, 1);
|
||||
|
||||
// Make sure we don't render at low resolution where we have valid high
|
||||
// resolution content, to avoid overdraw and artifacts with semi-transparent
|
||||
// layers.
|
||||
// We assume that the current frame resolution is the one used in our high
|
||||
// precision layer buffer. Compensate for a changing frame resolution when
|
||||
// rendering the low precision buffer.
|
||||
if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) {
|
||||
const CSSToParentLayerScale2D& layerResolution = aLayerBuffer.GetFrameResolution();
|
||||
const CSSToParentLayerScale2D& localResolution = mTiledBuffer.GetFrameResolution();
|
||||
@@ -501,9 +559,9 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
||||
aVisibleRegion.ScaleRoundOut(layerScale.width, layerScale.height);
|
||||
}
|
||||
|
||||
// If we're drawing the low precision buffer, make sure the high precision
|
||||
// buffer is masked out to avoid overdraw and rendering artifacts with
|
||||
// non-opaque layers.
|
||||
// Make sure we don't render at low resolution where we have valid high
|
||||
// resolution content, to avoid overdraw and artifacts with semi-transparent
|
||||
// layers.
|
||||
nsIntRegion maskRegion;
|
||||
if (resolution != mTiledBuffer.GetResolution()) {
|
||||
maskRegion = mTiledBuffer.GetValidRegion();
|
||||
@@ -549,7 +607,7 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
||||
|
||||
TileIntPoint tilePosition = aLayerBuffer.GetPlacement().TilePosition(i);
|
||||
// A sanity check that catches a lot of mistakes.
|
||||
MOZ_ASSERT(tilePosition.x == tile.x && tilePosition.y == tile.y);
|
||||
MOZ_ASSERT(tilePosition.x == tile.mTilePosition.x && tilePosition.y == tile.mTilePosition.y);
|
||||
|
||||
IntPoint tileOffset = aLayerBuffer.GetTileOffset(tilePosition);
|
||||
nsIntRegion tileDrawRegion = IntRect(tileOffset, aLayerBuffer.GetScaledTileSize());
|
||||
|
||||
@@ -52,8 +52,6 @@ public:
|
||||
// essentially, this is a sentinel used to represent an invalid or blank
|
||||
// tile.
|
||||
TileHost()
|
||||
: x(-1)
|
||||
, y(-1)
|
||||
{}
|
||||
|
||||
// Constructs a TileHost from a gfxSharedReadLock and TextureHost.
|
||||
@@ -67,8 +65,6 @@ public:
|
||||
, mTextureHostOnWhite(aTextureHostOnWhite)
|
||||
, mTextureSource(aSource)
|
||||
, mTextureSourceOnWhite(aSourceOnWhite)
|
||||
, x(-1)
|
||||
, y(-1)
|
||||
{}
|
||||
|
||||
TileHost(const TileHost& o) {
|
||||
@@ -77,9 +73,7 @@ public:
|
||||
mTextureSource = o.mTextureSource;
|
||||
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
|
||||
mSharedLock = o.mSharedLock;
|
||||
mPreviousSharedLock = o.mPreviousSharedLock;
|
||||
x = o.x;
|
||||
y = o.y;
|
||||
mTilePosition = o.mTilePosition;
|
||||
}
|
||||
TileHost& operator=(const TileHost& o) {
|
||||
if (this == &o) {
|
||||
@@ -90,9 +84,7 @@ public:
|
||||
mTextureSource = o.mTextureSource;
|
||||
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
|
||||
mSharedLock = o.mSharedLock;
|
||||
mPreviousSharedLock = o.mPreviousSharedLock;
|
||||
x = o.x;
|
||||
y = o.y;
|
||||
mTilePosition = o.mTilePosition;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -112,13 +104,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void ReadUnlockPrevious() {
|
||||
if (mPreviousSharedLock) {
|
||||
mPreviousSharedLock->ReadUnlock();
|
||||
mPreviousSharedLock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Dump(std::stringstream& aStream) {
|
||||
aStream << "TileHost(...)"; // fill in as needed
|
||||
}
|
||||
@@ -129,14 +114,12 @@ public:
|
||||
}
|
||||
|
||||
RefPtr<gfxSharedReadLock> mSharedLock;
|
||||
RefPtr<gfxSharedReadLock> mPreviousSharedLock;
|
||||
CompositableTextureHostRef mTextureHost;
|
||||
CompositableTextureHostRef mTextureHostOnWhite;
|
||||
mutable CompositableTextureSourceRef mTextureSource;
|
||||
mutable CompositableTextureSourceRef mTextureSourceOnWhite;
|
||||
// This is not strictly necessary but makes debugging whole lot easier.
|
||||
int x;
|
||||
int y;
|
||||
TileIntPoint mTilePosition;
|
||||
};
|
||||
|
||||
class TiledLayerBufferComposite
|
||||
@@ -154,6 +137,9 @@ public:
|
||||
|
||||
void Clear();
|
||||
|
||||
void MarkTilesForUnlock();
|
||||
void ProcessDelayedUnlocks();
|
||||
|
||||
TileHost GetPlaceholderTile() const { return TileHost(); }
|
||||
|
||||
// Stores the absolute resolution of the containing frame, calculated
|
||||
@@ -167,7 +153,9 @@ public:
|
||||
static void RecycleCallback(TextureHost* textureHost, void* aClosure);
|
||||
|
||||
protected:
|
||||
|
||||
CSSToParentLayerScale2D mFrameResolution;
|
||||
nsTArray<RefPtr<gfxSharedReadLock>> mDelayedUnlocks;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -207,19 +195,24 @@ public:
|
||||
TextureHost* host = mTiledBuffer.GetTile(0).mTextureHost;
|
||||
if (host) {
|
||||
MOZ_ASSERT(!mTiledBuffer.GetTile(0).mTextureHostOnWhite, "Component alpha not supported!");
|
||||
LayerRenderState state = host->GetRenderState();
|
||||
|
||||
// Offset by the distance between the start of the valid (visible) region and the top-left
|
||||
// of the tile.
|
||||
gfx::IntPoint offset = mTiledBuffer.GetTileOffset(mTiledBuffer.GetPlacement().TilePosition(0));
|
||||
|
||||
state.SetOffset(offset - GetValidRegion().GetBounds().TopLeft());
|
||||
return host->GetRenderState();
|
||||
// Don't try to use HWC if the content doesn't start at the top-left of the tile.
|
||||
if (offset != GetValidRegion().GetBounds().TopLeft()) {
|
||||
return LayerRenderState();
|
||||
}
|
||||
|
||||
LayerRenderState state = host->GetRenderState();
|
||||
state.SetOffset(offset);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
return LayerRenderState();
|
||||
}
|
||||
|
||||
// Generate effect for layerscope when using hwc.
|
||||
virtual already_AddRefed<TexturedEffect> GenEffect(const gfx::Filter& aFilter) override;
|
||||
|
||||
virtual bool UpdateThebes(const ThebesBufferData& aData,
|
||||
const nsIntRegion& aUpdated,
|
||||
|
||||
@@ -143,6 +143,14 @@ static bool LockD3DTexture(T* aTexture)
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool HasKeyedMutex(T* aTexture)
|
||||
{
|
||||
RefPtr<IDXGIKeyedMutex> mutex;
|
||||
aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
|
||||
return !!mutex;
|
||||
}
|
||||
|
||||
template<typename T> // ID3D10Texture2D or ID3D11Texture2D
|
||||
static void UnlockD3DTexture(T* aTexture)
|
||||
{
|
||||
@@ -678,9 +686,9 @@ DXGIYCbCrTextureClient::FinalizeOnIPDLThread()
|
||||
already_AddRefed<DXGIYCbCrTextureClient>
|
||||
DXGIYCbCrTextureClient::Create(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
IUnknown* aTextureY,
|
||||
IUnknown* aTextureCb,
|
||||
IUnknown* aTextureCr,
|
||||
IDirect3DTexture9* aTextureY,
|
||||
IDirect3DTexture9* aTextureCb,
|
||||
IDirect3DTexture9* aTextureCr,
|
||||
HANDLE aHandleY,
|
||||
HANDLE aHandleCb,
|
||||
HANDLE aHandleCr,
|
||||
@@ -688,6 +696,18 @@ DXGIYCbCrTextureClient::Create(ISurfaceAllocator* aAllocator,
|
||||
const gfx::IntSize& aSizeY,
|
||||
const gfx::IntSize& aSizeCbCr)
|
||||
{
|
||||
if (!aHandleY || !aHandleCb || !aHandleCr ||
|
||||
!aTextureY || !aTextureCb || !aTextureCr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aTextureY->SetPrivateData(sD3D11TextureUsage,
|
||||
new TextureMemoryMeasurer(aSizeY.width * aSizeY.height), sizeof(IUnknown*), D3DSPD_IUNKNOWN);
|
||||
aTextureCb->SetPrivateData(sD3D11TextureUsage,
|
||||
new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height), sizeof(IUnknown*), D3DSPD_IUNKNOWN);
|
||||
aTextureCr->SetPrivateData(sD3D11TextureUsage,
|
||||
new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height), sizeof(IUnknown*), D3DSPD_IUNKNOWN);
|
||||
|
||||
RefPtr<DXGIYCbCrTextureClient> texture =
|
||||
new DXGIYCbCrTextureClient(aAllocator, aFlags);
|
||||
texture->mHandles[0] = aHandleY;
|
||||
@@ -702,6 +722,59 @@ DXGIYCbCrTextureClient::Create(ISurfaceAllocator* aAllocator,
|
||||
return texture.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DXGIYCbCrTextureClient>
|
||||
DXGIYCbCrTextureClient::Create(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
ID3D11Texture2D* aTextureY,
|
||||
ID3D11Texture2D* aTextureCb,
|
||||
ID3D11Texture2D* aTextureCr,
|
||||
const gfx::IntSize& aSize,
|
||||
const gfx::IntSize& aSizeY,
|
||||
const gfx::IntSize& aSizeCbCr)
|
||||
{
|
||||
if (!aTextureY || !aTextureCb || !aTextureCr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aTextureY->SetPrivateDataInterface(sD3D11TextureUsage,
|
||||
new TextureMemoryMeasurer(aSize.width * aSize.height));
|
||||
aTextureCb->SetPrivateDataInterface(sD3D11TextureUsage,
|
||||
new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height));
|
||||
aTextureCr->SetPrivateDataInterface(sD3D11TextureUsage,
|
||||
new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height));
|
||||
|
||||
RefPtr<DXGIYCbCrTextureClient> texture =
|
||||
new DXGIYCbCrTextureClient(aAllocator, aFlags);
|
||||
|
||||
RefPtr<IDXGIResource> resource;
|
||||
|
||||
aTextureY->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
|
||||
HRESULT hr = resource->GetSharedHandle(&texture->mHandles[0]);
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aTextureCb->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
|
||||
hr = resource->GetSharedHandle(&texture->mHandles[1]);
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aTextureCr->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
|
||||
hr = resource->GetSharedHandle(&texture->mHandles[2]);
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
texture->mHoldRefs[0] = aTextureY;
|
||||
texture->mHoldRefs[1] = aTextureCb;
|
||||
texture->mHoldRefs[2] = aTextureCr;
|
||||
texture->mSize = aSize;
|
||||
texture->mSizeY = aSizeY;
|
||||
texture->mSizeCbCr = aSizeCbCr;
|
||||
return texture.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
DXGIYCbCrTextureClient::Lock(OpenMode)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "mozilla/GfxMessageUtils.h"
|
||||
#include <d3d11.h>
|
||||
#include "d3d9.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mozilla {
|
||||
@@ -110,8 +111,6 @@ public:
|
||||
|
||||
virtual bool IsLocked() const override { return mIsLocked; }
|
||||
|
||||
virtual bool ImplementsLocking() const override { return true; }
|
||||
|
||||
virtual bool HasInternalBuffer() const override { return false; }
|
||||
|
||||
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
|
||||
@@ -164,9 +163,9 @@ public:
|
||||
static already_AddRefed<DXGIYCbCrTextureClient>
|
||||
Create(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
IUnknown* aTextureY,
|
||||
IUnknown* aTextureCb,
|
||||
IUnknown* aTextureCr,
|
||||
IDirect3DTexture9* aTextureY,
|
||||
IDirect3DTexture9* aTextureCb,
|
||||
IDirect3DTexture9* aTextureCr,
|
||||
HANDLE aHandleY,
|
||||
HANDLE aHandleCb,
|
||||
HANDLE aHandleCr,
|
||||
@@ -174,6 +173,17 @@ public:
|
||||
const gfx::IntSize& aSizeY,
|
||||
const gfx::IntSize& aSizeCbCr);
|
||||
|
||||
// Creates a TextureClient and init width.
|
||||
static already_AddRefed<DXGIYCbCrTextureClient>
|
||||
Create(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
ID3D11Texture2D* aTextureY,
|
||||
ID3D11Texture2D* aTextureCb,
|
||||
ID3D11Texture2D* aTextureCr,
|
||||
const gfx::IntSize& aSize,
|
||||
const gfx::IntSize& aSizeY,
|
||||
const gfx::IntSize& aSizeCbCr);
|
||||
|
||||
// TextureClient
|
||||
|
||||
virtual bool IsAllocated() const override{ return !!mHoldRefs[0]; }
|
||||
|
||||
@@ -196,9 +196,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
||||
|
||||
if (IsAsync() && compositable->GetLayer()) {
|
||||
ScheduleComposition(op);
|
||||
// Async layer updates don't trigger invalidation, manually tell the layer
|
||||
// that its content have changed.
|
||||
compositable->GetLayer()->SetInvalidRectToVisibleRegion();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
|
||||
: mMessageLoop(aLoop)
|
||||
, mTransport(aTransport)
|
||||
, mSetChildThreadPriority(false)
|
||||
, mStopped(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
sMainLoop = MessageLoop::current();
|
||||
@@ -206,9 +207,12 @@ ReleaseImageBridgeParent(ImageBridgeParent* aImageBridgeParent)
|
||||
|
||||
bool ImageBridgeParent::RecvStop()
|
||||
{
|
||||
// This message just serves as synchronization between the
|
||||
// This message mostly serves as synchronization between the
|
||||
// child and parent threads during shutdown.
|
||||
|
||||
// Can't alloc/dealloc shmems from now on.
|
||||
mStopped = true;
|
||||
|
||||
// There is one thing that we need to do here: temporarily addref, so that
|
||||
// the handling of this sync message can't race with the destruction of
|
||||
// the ImageBridgeParent, which would trigger the dreaded "mismatched CxxStackFrames"
|
||||
@@ -322,6 +326,7 @@ ImageBridgeParent::NotifyImageComposites(nsTArray<ImageCompositeNotification>& a
|
||||
nsAutoTArray<ImageCompositeNotification,1> notifications;
|
||||
notifications.AppendElement(aNotifications[i]);
|
||||
uint32_t end = i + 1;
|
||||
MOZ_ASSERT(aNotifications[i].imageContainerParent());
|
||||
ProcessId pid = aNotifications[i].imageContainerParent()->OtherPid();
|
||||
while (end < aNotifications.Length() &&
|
||||
aNotifications[end].imageContainerParent()->OtherPid() == pid) {
|
||||
@@ -382,6 +387,38 @@ ImageBridgeParent::OnChannelConnected(int32_t aPid)
|
||||
mCompositorThreadHolder = GetCompositorThreadHolder();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ImageBridgeParent::AllocShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aShmem)
|
||||
{
|
||||
if (mStopped) {
|
||||
return false;
|
||||
}
|
||||
return PImageBridgeParent::AllocShmem(aSize, aType, aShmem);
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeParent::AllocUnsafeShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aShmem)
|
||||
{
|
||||
if (mStopped) {
|
||||
return false;
|
||||
}
|
||||
return PImageBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
|
||||
}
|
||||
|
||||
void
|
||||
ImageBridgeParent::DeallocShmem(ipc::Shmem& aShmem)
|
||||
{
|
||||
if (mStopped) {
|
||||
return;
|
||||
}
|
||||
PImageBridgeParent::DeallocShmem(aShmem);
|
||||
}
|
||||
|
||||
bool ImageBridgeParent::IsSameProcess() const
|
||||
{
|
||||
return OtherPid() == base::GetCurrentProcId();
|
||||
|
||||
@@ -100,24 +100,15 @@ public:
|
||||
|
||||
// ISurfaceAllocator
|
||||
|
||||
bool AllocShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aShmem) override
|
||||
{
|
||||
return PImageBridgeParent::AllocShmem(aSize, aType, aShmem);
|
||||
}
|
||||
virtual bool AllocShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aShmem) override;
|
||||
|
||||
bool AllocUnsafeShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aShmem) override
|
||||
{
|
||||
return PImageBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
|
||||
}
|
||||
virtual bool AllocUnsafeShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aShmem) override;
|
||||
|
||||
void DeallocShmem(ipc::Shmem& aShmem) override
|
||||
{
|
||||
PImageBridgeParent::DeallocShmem(aShmem);
|
||||
}
|
||||
virtual void DeallocShmem(ipc::Shmem& aShmem) override;
|
||||
|
||||
virtual bool IsSameProcess() const override;
|
||||
|
||||
@@ -162,6 +153,7 @@ private:
|
||||
RefPtr<ImageBridgeParent> mSelfRef;
|
||||
|
||||
bool mSetChildThreadPriority;
|
||||
bool mStopped;
|
||||
|
||||
/**
|
||||
* Map of all living ImageBridgeParent instances
|
||||
|
||||
@@ -174,13 +174,19 @@ LayerTransactionParent::RecvShutdown()
|
||||
void
|
||||
LayerTransactionParent::Destroy()
|
||||
{
|
||||
mDestroyed = true;
|
||||
const ManagedContainer<PLayerParent>& layers = ManagedPLayerParent();
|
||||
for (auto iter = layers.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
ShadowLayerParent* slp =
|
||||
static_cast<ShadowLayerParent*>(iter.Get()->GetKey());
|
||||
slp->Destroy();
|
||||
}
|
||||
InfallibleTArray<PTextureParent*> textures;
|
||||
ManagedPTextureParent(textures);
|
||||
for (unsigned int i = 0; i < textures.Length(); ++i) {
|
||||
RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
|
||||
tex->DeallocateDeviceData();
|
||||
}
|
||||
mDestroyed = true;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -989,6 +995,38 @@ LayerTransactionParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
LayerTransactionParent::AllocShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aShmem)
|
||||
{
|
||||
if (!mIPCOpen || mDestroyed) {
|
||||
return false;
|
||||
}
|
||||
return PLayerTransactionParent::AllocShmem(aSize, aType, aShmem);
|
||||
}
|
||||
|
||||
bool
|
||||
LayerTransactionParent::AllocUnsafeShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aShmem)
|
||||
{
|
||||
if (!mIPCOpen || mDestroyed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return PLayerTransactionParent::AllocUnsafeShmem(aSize, aType, aShmem);
|
||||
}
|
||||
|
||||
void
|
||||
LayerTransactionParent::DeallocShmem(ipc::Shmem& aShmem)
|
||||
{
|
||||
if (!mIPCOpen || mDestroyed) {
|
||||
return;
|
||||
}
|
||||
PLayerTransactionParent::DeallocShmem(aShmem);
|
||||
}
|
||||
|
||||
bool LayerTransactionParent::IsSameProcess() const
|
||||
{
|
||||
return OtherPid() == base::GetCurrentProcId();
|
||||
|
||||
@@ -63,20 +63,13 @@ public:
|
||||
// ISurfaceAllocator
|
||||
virtual bool AllocShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aShmem) override {
|
||||
return PLayerTransactionParent::AllocShmem(aSize, aType, aShmem);
|
||||
}
|
||||
ipc::Shmem* aShmem) override;
|
||||
|
||||
virtual bool AllocUnsafeShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
ipc::Shmem* aShmem) override {
|
||||
return PLayerTransactionParent::AllocUnsafeShmem(aSize, aType, aShmem);
|
||||
}
|
||||
ipc::Shmem* aShmem) override;
|
||||
|
||||
virtual void DeallocShmem(ipc::Shmem& aShmem) override
|
||||
{
|
||||
PLayerTransactionParent::DeallocShmem(aShmem);
|
||||
}
|
||||
virtual void DeallocShmem(ipc::Shmem& aShmem) override;
|
||||
|
||||
virtual bool IsSameProcess() const override;
|
||||
|
||||
|
||||
@@ -75,9 +75,11 @@ SurfaceDescriptorX11::SurfaceDescriptorX11(gfxXlibSurface* aSurf,
|
||||
mFormat = cairo_xlib_surface_get_visual(aSurf->CairoSurface())->visualid;
|
||||
}
|
||||
|
||||
#ifdef GL_PROVIDER_GLX
|
||||
if (aForwardGLX) {
|
||||
mGLXPixmap = aSurf->GetGLXPixmap();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SurfaceDescriptorX11::SurfaceDescriptorX11(Drawable aDrawable, XID aFormatID,
|
||||
|
||||
@@ -52,6 +52,10 @@ public:
|
||||
for (it = SharedBufferManagerParent::sManagers.begin(); it != SharedBufferManagerParent::sManagers.end(); it++) {
|
||||
base::ProcessId pid = it->first;
|
||||
SharedBufferManagerParent *mgr = it->second;
|
||||
if (!mgr) {
|
||||
printf_stderr("GrallocReporter::CollectReports() mgr is nullptr");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoCString pidName;
|
||||
LinuxUtils::GetThreadName(pid, pidName);
|
||||
@@ -94,6 +98,8 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
~GrallocReporter() {}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(GrallocReporter, nsIMemoryReporter)
|
||||
@@ -203,7 +209,12 @@ bool SharedBufferManagerParent::RecvAllocateGrallocBuffer(const IntSize& aSize,
|
||||
|
||||
if (aFormat == 0 || aUsage == 0) {
|
||||
printf_stderr("SharedBufferManagerParent::RecvAllocateGrallocBuffer -- format and usage must be non-zero");
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aSize.width <= 0 || aSize.height <= 0) {
|
||||
printf_stderr("SharedBufferManagerParent::RecvAllocateGrallocBuffer -- requested gralloc buffer size is invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the requested size is too big (i.e. exceeds the commonly used max GL texture size)
|
||||
@@ -328,7 +339,11 @@ MessageLoop* SharedBufferManagerParent::GetMessageLoop()
|
||||
SharedBufferManagerParent* SharedBufferManagerParent::GetInstance(ProcessId id)
|
||||
{
|
||||
NS_ASSERTION(sManagers.count(id) == 1, "No BufferManager for the process");
|
||||
return sManagers[id];
|
||||
if (sManagers.count(id) == 1) {
|
||||
return sManagers[id];
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
|
||||
#include "mozilla/layers/ImageClient.h" // for ImageClient
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
||||
#include "mozilla/layers/TextureClient.h" // for BufferTextureClient, etc
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/BufferTexture.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
@@ -36,9 +37,11 @@ SharedPlanarYCbCrImage::~SharedPlanarYCbCrImage() {
|
||||
|
||||
if (mCompositable->GetAsyncID() != 0 &&
|
||||
!InImageBridgeChildThread()) {
|
||||
ADDREF_MANUALLY(mTextureClient);
|
||||
ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
|
||||
mTextureClient = nullptr;
|
||||
if (mTextureClient) {
|
||||
ADDREF_MANUALLY(mTextureClient);
|
||||
ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
|
||||
mTextureClient = nullptr;
|
||||
}
|
||||
|
||||
ImageBridgeChild::DispatchReleaseImageClient(mCompositable.forget().take());
|
||||
}
|
||||
@@ -63,7 +66,9 @@ SharedPlanarYCbCrImage::GetTextureClient(CompositableClient* aClient)
|
||||
uint8_t*
|
||||
SharedPlanarYCbCrImage::GetBuffer()
|
||||
{
|
||||
return mTextureClient ? mTextureClient->GetBuffer() : nullptr;
|
||||
// This should never be used
|
||||
MOZ_ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::SourceSurface>
|
||||
@@ -87,15 +92,13 @@ SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData)
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mTextureClient->AsTextureClientYCbCr());
|
||||
|
||||
TextureClientAutoLock autoLock(mTextureClient, OpenMode::OPEN_WRITE_ONLY);
|
||||
if (!autoLock.Succeeded()) {
|
||||
MOZ_ASSERT(false, "Failed to lock the texture.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mTextureClient->AsTextureClientYCbCr()->UpdateYCbCr(aData)) {
|
||||
if (!UpdateYCbCrTextureClient(mTextureClient, aData)) {
|
||||
MOZ_ASSERT(false, "Failed to copy YCbCr data into the TextureClient");
|
||||
return false;
|
||||
}
|
||||
@@ -126,8 +129,18 @@ SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
|
||||
// update buffer size
|
||||
mBufferSize = size;
|
||||
|
||||
YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize());
|
||||
return serializer.GetData();
|
||||
MappedYCbCrTextureData mapped;
|
||||
if (mTextureClient->BorrowMappedYCbCrData(mapped)) {
|
||||
// The caller expects a pointer to the beginning of the writable part of the
|
||||
// buffer (after the metadata) which is where the y channel starts by default.
|
||||
// The caller might choose to write the y channel at a different offset and
|
||||
// if it does so, it will also update the metadata.
|
||||
// Anyway, we return the y channel here but the intent is to obtain the start of
|
||||
// the writable part of the buffer.
|
||||
return mapped.y.data;
|
||||
} else {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -145,7 +158,11 @@ SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
|
||||
* with AllocateAndGetNewBuffer(), that we subtract from the Y, Cb, Cr
|
||||
* channels to compute 0-based offsets to pass to InitializeBufferInfo.
|
||||
*/
|
||||
YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize());
|
||||
MappedYCbCrTextureData mapped;
|
||||
if(!mTextureClient->BorrowMappedYCbCrData(mapped)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
YCbCrImageDataSerializer serializer(mapped.metadata, mBufferSize);
|
||||
uint8_t *base = serializer.GetData();
|
||||
uint32_t yOffset = aData.mYChannel - base;
|
||||
uint32_t cbOffset = aData.mCbChannel - base;
|
||||
@@ -181,15 +198,18 @@ SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData)
|
||||
return false;
|
||||
}
|
||||
|
||||
YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize());
|
||||
serializer.InitializeBufferInfo(aData.mYSize,
|
||||
aData.mCbCrSize,
|
||||
aData.mStereoMode);
|
||||
MOZ_ASSERT(serializer.IsValid());
|
||||
MappedYCbCrTextureData mapped;
|
||||
// The locking here is sort of a lie. The SharedPlanarYCbCrImage just pulls
|
||||
// pointers out of the TextureClient and keeps them around, which works only
|
||||
// because the underlyin BufferTextureData is always mapped in memory even outside
|
||||
// of the lock/unlock interval. That's sad and new code should follow this example.
|
||||
if (!mTextureClient->Lock(OpenMode::OPEN_READ) || !mTextureClient->BorrowMappedYCbCrData(mapped)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
aData.mYChannel = serializer.GetYData();
|
||||
aData.mCbChannel = serializer.GetCbData();
|
||||
aData.mCrChannel = serializer.GetCrData();
|
||||
aData.mYChannel = mapped.y.data;
|
||||
aData.mCbChannel = mapped.cb.data;
|
||||
aData.mCrChannel = mapped.cr.data;
|
||||
|
||||
// copy some of aData's values in mData (most of them)
|
||||
mData.mYChannel = aData.mYChannel;
|
||||
@@ -216,6 +236,8 @@ SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData)
|
||||
mData.mCbCrSize);
|
||||
mSize = mData.mPicSize;
|
||||
|
||||
mTextureClient->Unlock();
|
||||
|
||||
return mBufferSize > 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class BufferTextureClient;
|
||||
class ImageClient;
|
||||
class TextureClient;
|
||||
|
||||
@@ -51,7 +50,7 @@ public:
|
||||
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
|
||||
|
||||
private:
|
||||
RefPtr<BufferTextureClient> mTextureClient;
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
RefPtr<ImageClient> mCompositable;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat, etc
|
||||
#include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
|
||||
#include "mozilla/gfx/Point.h" // for IntSIze
|
||||
#include "mozilla/layers/BufferTexture.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator, etc
|
||||
#include "mozilla/layers/ImageClient.h" // for ImageClient
|
||||
#include "mozilla/layers/ImageDataSerializer.h" // for ImageDataSerializer
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
||||
#include "mozilla/layers/TextureClient.h" // for BufferTextureClient, etc
|
||||
#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
|
||||
@@ -87,12 +87,11 @@ SharedRGBImage::Allocate(gfx::IntSize aSize, gfx::SurfaceFormat aFormat)
|
||||
uint8_t*
|
||||
SharedRGBImage::GetBuffer()
|
||||
{
|
||||
if (!mTextureClient) {
|
||||
return nullptr;
|
||||
MappedTextureData mapped;
|
||||
if (mTextureClient && mTextureClient->BorrowMappedData(mapped)) {
|
||||
return mapped.data;
|
||||
}
|
||||
|
||||
ImageDataSerializer serializer(mTextureClient->GetBuffer(), mTextureClient->GetBufferSize());
|
||||
return serializer.GetData();
|
||||
return 0;
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
@@ -101,13 +100,6 @@ SharedRGBImage::GetSize()
|
||||
return mSize;
|
||||
}
|
||||
|
||||
size_t
|
||||
SharedRGBImage::GetBufferSize()
|
||||
{
|
||||
return mTextureClient ? mTextureClient->GetBufferSize()
|
||||
: 0;
|
||||
}
|
||||
|
||||
TextureClient*
|
||||
SharedRGBImage::GetTextureClient(CompositableClient* aClient)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class BufferTextureClient;
|
||||
class ImageClient;
|
||||
class TextureClient;
|
||||
|
||||
@@ -45,15 +44,13 @@ public:
|
||||
|
||||
gfx::IntSize GetSize() override;
|
||||
|
||||
size_t GetBufferSize();
|
||||
|
||||
already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
|
||||
|
||||
bool Allocate(gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
|
||||
private:
|
||||
gfx::IntSize mSize;
|
||||
RefPtr<ImageClient> mCompositable;
|
||||
RefPtr<BufferTextureClient> mTextureClient;
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
||||
@@ -113,6 +113,7 @@ EXPORTS.mozilla.layers += [
|
||||
'basic/BasicCompositor.h',
|
||||
'basic/MacIOSurfaceTextureHostBasic.h',
|
||||
'basic/TextureHostBasic.h',
|
||||
'BufferTexture.h',
|
||||
'client/CanvasClient.h',
|
||||
'client/CompositableClient.h',
|
||||
'client/ContentClient.h',
|
||||
@@ -266,6 +267,7 @@ UNIFIED_SOURCES += [
|
||||
'basic/BasicLayersImpl.cpp',
|
||||
'basic/BasicPaintedLayer.cpp',
|
||||
'basic/TextureHostBasic.cpp',
|
||||
'BufferTexture.cpp',
|
||||
'BufferUnrotate.cpp',
|
||||
'client/CanvasClient.cpp',
|
||||
'client/ClientCanvasLayer.cpp',
|
||||
|
||||
@@ -16,9 +16,10 @@ using namespace mozilla::gl;
|
||||
|
||||
CompositingRenderTargetOGL::~CompositingRenderTargetOGL()
|
||||
{
|
||||
mGL->MakeCurrent();
|
||||
mGL->fDeleteTextures(1, &mTextureHandle);
|
||||
mGL->fDeleteFramebuffers(1, &mFBO);
|
||||
if (mGL->MakeCurrent()) {
|
||||
mGL->fDeleteTextures(1, &mTextureHandle);
|
||||
mGL->fDeleteFramebuffers(1, &mFBO);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -24,153 +24,28 @@ namespace layers {
|
||||
using namespace mozilla::gfx;
|
||||
using namespace android;
|
||||
|
||||
GrallocTextureClientOGL::GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureClient(aAllocator, aFormat, aMoz2dBackend, aFlags)
|
||||
, mGrallocHandle(null_t())
|
||||
, mMappedBuffer(nullptr)
|
||||
, mMediaBuffer(nullptr)
|
||||
, mIsOpaque(gfx::IsOpaque(aFormat))
|
||||
static bool
|
||||
DisableGralloc(SurfaceFormat aFormat, const gfx::IntSize& aSizeHint)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GrallocTextureClientOGL);
|
||||
}
|
||||
|
||||
GrallocTextureClientOGL::~GrallocTextureClientOGL()
|
||||
{
|
||||
MOZ_COUNT_DTOR(GrallocTextureClientOGL);
|
||||
ISurfaceAllocator* allocator = GetAllocator();
|
||||
if (ShouldDeallocateInDestructor()) {
|
||||
allocator->DeallocGrallocBuffer(&mGrallocHandle);
|
||||
} else {
|
||||
allocator->DropGrallocBuffer(&mGrallocHandle);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
GrallocTextureClientOGL::CreateSimilar(TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
RefPtr<TextureClient> tex = new GrallocTextureClientOGL(
|
||||
mAllocator, mFormat, mBackend, mFlags | aFlags
|
||||
);
|
||||
|
||||
if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return tex.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureClientOGL::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
if (!IsAllocated()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aOutDescriptor = NewSurfaceDescriptorGralloc(mGrallocHandle, mIsOpaque);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureClientOGL::SetRemoveFromCompositableWaiter(AsyncTransactionWaiter* aWaiter)
|
||||
{
|
||||
mRemoveFromCompositableWaiter = aWaiter;
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureClientOGL::WaitForBufferOwnership(bool aWaitReleaseFence)
|
||||
{
|
||||
if (mRemoveFromCompositableWaiter) {
|
||||
mRemoveFromCompositableWaiter->WaitComplete();
|
||||
mRemoveFromCompositableWaiter = nullptr;
|
||||
}
|
||||
|
||||
if (!aWaitReleaseFence) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
|
||||
if (mReleaseFenceHandle.IsValid()) {
|
||||
RefPtr<FenceHandle::FdObj> fdObj = mReleaseFenceHandle.GetAndResetFdObj();
|
||||
android::sp<Fence> fence = new Fence(fdObj->GetAndResetFd());
|
||||
#if ANDROID_VERSION == 17
|
||||
fence->waitForever(1000, "GrallocTextureClientOGL::Lock");
|
||||
// 1000 is what Android uses. It is a warning timeout in ms.
|
||||
// This timeout was removed in ANDROID_VERSION 18.
|
||||
#else
|
||||
fence->waitForever("GrallocTextureClientOGL::Lock");
|
||||
#endif
|
||||
mReleaseFenceHandle = FenceHandle();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureClientOGL::Lock(OpenMode aMode)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
if (!IsValid() || !IsAllocated()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mMappedBuffer) {
|
||||
if (gfxPrefs::DisableGralloc()) {
|
||||
return true;
|
||||
}
|
||||
if (aFormat == gfx::SurfaceFormat::A8) {
|
||||
return true;
|
||||
}
|
||||
#if ANDROID_VERSION <= 15
|
||||
// Adreno 200 has a problem of drawing gralloc buffer width less than 64 and
|
||||
// drawing gralloc buffer with a height 9px-16px.
|
||||
// See Bug 983971.
|
||||
if (aSizeHint.width < 64 || aSizeHint.height < 32) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
|
||||
WaitForBufferOwnership(false /* aWaitReleaseFence */);
|
||||
#else
|
||||
WaitForBufferOwnership();
|
||||
#endif
|
||||
|
||||
uint32_t usage = 0;
|
||||
if (aMode & OpenMode::OPEN_READ) {
|
||||
usage |= GRALLOC_USAGE_SW_READ_OFTEN;
|
||||
}
|
||||
if (aMode & OpenMode::OPEN_WRITE) {
|
||||
usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
|
||||
}
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
|
||||
RefPtr<FenceHandle::FdObj> fdObj = mReleaseFenceHandle.GetAndResetFdObj();
|
||||
int32_t rv = mGraphicBuffer->lockAsync(usage,
|
||||
reinterpret_cast<void**>(&mMappedBuffer),
|
||||
fdObj->GetAndResetFd());
|
||||
#else
|
||||
int32_t rv = mGraphicBuffer->lock(usage,
|
||||
reinterpret_cast<void**>(&mMappedBuffer));
|
||||
#endif
|
||||
if (rv) {
|
||||
mMappedBuffer = nullptr;
|
||||
NS_WARNING("Couldn't lock graphic buffer");
|
||||
return false;
|
||||
}
|
||||
return BufferTextureClient::Lock(aMode);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureClientOGL::Unlock()
|
||||
{
|
||||
BufferTextureClient::Unlock();
|
||||
mDrawTarget = nullptr;
|
||||
if (mMappedBuffer) {
|
||||
mMappedBuffer = nullptr;
|
||||
mGraphicBuffer->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
GrallocTextureClientOGL::GetBuffer() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
NS_WARN_IF_FALSE(mMappedBuffer, "Trying to get a gralloc buffer without getting the lock?");
|
||||
return mMappedBuffer;
|
||||
}
|
||||
|
||||
static gfx::SurfaceFormat
|
||||
gfx::SurfaceFormat
|
||||
SurfaceFormatForPixelFormat(android::PixelFormat aFormat)
|
||||
{
|
||||
switch (aFormat) {
|
||||
@@ -185,56 +60,188 @@ SurfaceFormatForPixelFormat(android::PixelFormat aFormat)
|
||||
case HAL_PIXEL_FORMAT_YV12:
|
||||
return gfx::SurfaceFormat::YUV;
|
||||
default:
|
||||
MOZ_CRASH("Unknown gralloc pixel format");
|
||||
return gfx::SurfaceFormat::UNKNOWN;
|
||||
}
|
||||
return gfx::SurfaceFormat::R8G8B8A8;
|
||||
}
|
||||
|
||||
gfx::DrawTarget*
|
||||
GrallocTextureClientOGL::BorrowDrawTarget()
|
||||
bool
|
||||
IsGrallocRBSwapped(gfx::SurfaceFormat aFormat) {
|
||||
switch (aFormat) {
|
||||
case gfx::SurfaceFormat::B8G8R8A8:
|
||||
case gfx::SurfaceFormat::B8G8R8X8:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GetAndroidFormat(gfx::SurfaceFormat aFormat)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
MOZ_ASSERT(mMappedBuffer, "Calling TextureClient::BorrowDrawTarget without locking :(");
|
||||
|
||||
if (!IsValid() || !IsAllocated() || !mMappedBuffer) {
|
||||
return nullptr;
|
||||
switch (aFormat) {
|
||||
case gfx::SurfaceFormat::R8G8B8A8:
|
||||
case gfx::SurfaceFormat::B8G8R8A8:
|
||||
return android::PIXEL_FORMAT_RGBA_8888;
|
||||
case gfx::SurfaceFormat::R8G8B8X8:
|
||||
case gfx::SurfaceFormat::B8G8R8X8:
|
||||
return android::PIXEL_FORMAT_RGBX_8888;
|
||||
case gfx::SurfaceFormat::R5G6B5_UINT16:
|
||||
return android::PIXEL_FORMAT_RGB_565;
|
||||
case gfx::SurfaceFormat::YUV:
|
||||
return HAL_PIXEL_FORMAT_YV12;
|
||||
case gfx::SurfaceFormat::A8:
|
||||
NS_WARNING("gralloc does not support SurfaceFormat::A8");
|
||||
default:
|
||||
NS_WARNING("Unsupported surface format");
|
||||
return android::PIXEL_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
if (mDrawTarget) {
|
||||
return mDrawTarget;
|
||||
}
|
||||
GrallocTextureData::GrallocTextureData(MaybeMagicGrallocBufferHandle aGrallocHandle,
|
||||
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend)
|
||||
: mSize(aSize)
|
||||
, mFormat(aFormat)
|
||||
, mMoz2DBackend(aMoz2DBackend)
|
||||
, mGrallocHandle(aGrallocHandle)
|
||||
, mMappedBuffer(nullptr)
|
||||
, mMediaBuffer(nullptr)
|
||||
{
|
||||
mGraphicBuffer = GetGraphicBufferFrom(aGrallocHandle);
|
||||
MOZ_COUNT_CTOR(GrallocTextureData);
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat format = SurfaceFormatForPixelFormat(mGraphicBuffer->getPixelFormat());
|
||||
long pixelStride = mGraphicBuffer->getStride();
|
||||
long byteStride = pixelStride * BytesPerPixel(format);
|
||||
mDrawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(GetBuffer(),
|
||||
mSize,
|
||||
byteStride,
|
||||
mFormat);
|
||||
return mDrawTarget;
|
||||
GrallocTextureData::~GrallocTextureData()
|
||||
{
|
||||
MOZ_COUNT_DTOR(GrallocTextureData);
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureClientOGL::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
GrallocTextureData::Deallocate(ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
aAllocator->DeallocGrallocBuffer(&mGrallocHandle);
|
||||
mGrallocHandle = null_t();
|
||||
mGraphicBuffer = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureData::Forget(ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
aAllocator->DropGrallocBuffer(&mGrallocHandle);
|
||||
mGrallocHandle = null_t();
|
||||
mGraphicBuffer = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
aOutDescriptor = NewSurfaceDescriptorGralloc(mGrallocHandle, gfx::IsOpaque(mFormat));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureData::WaitForFence(FenceHandle* aFence)
|
||||
{
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 21 && ANDROID_VERSION >= 17
|
||||
if (aFence->IsValid()) {
|
||||
RefPtr<FenceHandle::FdObj> fdObj = aFence->GetAndResetFdObj();
|
||||
android::sp<Fence> fence = new Fence(fdObj->GetAndResetFd());
|
||||
#if ANDROID_VERSION == 17
|
||||
fence->waitForever(1000, "GrallocTextureData::Lock");
|
||||
// 1000 is what Android uses. It is a warning timeout in ms.
|
||||
// This timeout was removed in ANDROID_VERSION 18.
|
||||
#else
|
||||
fence->waitForever("GrallocTextureData::Lock");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureData::Lock(OpenMode aMode, FenceHandle* aReleaseFence)
|
||||
{
|
||||
MOZ_ASSERT(!mMappedBuffer);
|
||||
|
||||
WaitForFence(aReleaseFence);
|
||||
|
||||
uint32_t usage = 0;
|
||||
if (aMode & OpenMode::OPEN_READ) {
|
||||
usage |= GRALLOC_USAGE_SW_READ_OFTEN;
|
||||
}
|
||||
if (aMode & OpenMode::OPEN_WRITE) {
|
||||
usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
|
||||
}
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
|
||||
RefPtr<FenceHandle::FdObj> fdObj = aReleaseFence->GetAndResetFdObj();
|
||||
int32_t rv = mGraphicBuffer->lockAsync(usage,
|
||||
reinterpret_cast<void**>(&mMappedBuffer),
|
||||
fdObj->GetAndResetFd());
|
||||
#else
|
||||
int32_t rv = mGraphicBuffer->lock(usage,
|
||||
reinterpret_cast<void**>(&mMappedBuffer));
|
||||
#endif
|
||||
if (rv) {
|
||||
mMappedBuffer = nullptr;
|
||||
NS_WARNING("Couldn't lock graphic buffer");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureData::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mMappedBuffer);
|
||||
mMappedBuffer = nullptr;
|
||||
mGraphicBuffer->unlock();
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
GrallocTextureData::BorrowDrawTarget()
|
||||
{
|
||||
MOZ_ASSERT(mMappedBuffer);
|
||||
if (!mMappedBuffer) {
|
||||
return nullptr;
|
||||
}
|
||||
long byteStride = mGraphicBuffer->getStride() * BytesPerPixel(mFormat);
|
||||
return gfxPlatform::GetPlatform()->CreateDrawTargetForData(mMappedBuffer, mSize,
|
||||
byteStride, mFormat);
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureData::BorrowMappedData(MappedTextureData& aMap)
|
||||
{
|
||||
if (mFormat == gfx::SurfaceFormat::YUV || !mMappedBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aMap.data = mMappedBuffer;
|
||||
aMap.size = mSize;
|
||||
aMap.stride = mGraphicBuffer->getStride() * BytesPerPixel(mFormat);
|
||||
aMap.format = mFormat;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
MOZ_ASSERT(mMappedBuffer, "Calling TextureClient::BorrowDrawTarget without locking :(");
|
||||
|
||||
if (!IsValid() || !IsAllocated() || !mMappedBuffer) {
|
||||
return;
|
||||
if (!mMappedBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
|
||||
|
||||
if (!srcSurf) {
|
||||
gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface.";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat format = SurfaceFormatForPixelFormat(mGraphicBuffer->getPixelFormat());
|
||||
if (mSize != srcSurf->GetSize() || mFormat != srcSurf->GetFormat()) {
|
||||
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << mSize << " " << format << " Other: " << srcSurf->GetSize() << " " << srcSurf->GetFormat();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
long pixelStride = mGraphicBuffer->getStride();
|
||||
@@ -244,160 +251,149 @@ GrallocTextureClientOGL::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
|
||||
if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) {
|
||||
gfxCriticalError() << "Failed to map source surface for UpdateFromSurface.";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* buffer = GetBuffer();
|
||||
|
||||
for (int y = 0; y < srcSurf->GetSize().height; y++) {
|
||||
memcpy(buffer + byteStride * y,
|
||||
memcpy(mMappedBuffer + byteStride * y,
|
||||
sourceMap.mData + sourceMap.mStride * y,
|
||||
srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
|
||||
}
|
||||
|
||||
srcSurf->Unmap();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureClientOGL::AllocateForSurface(gfx::IntSize aSize,
|
||||
TextureAllocationFlags)
|
||||
// static
|
||||
GrallocTextureData*
|
||||
GrallocTextureData::Create(gfx::IntSize aSize, AndroidFormat aAndroidFormat,
|
||||
gfx::BackendType aMoz2dBackend, uint32_t aUsage,
|
||||
ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
uint32_t format;
|
||||
uint32_t usage = android::GraphicBuffer::USAGE_SW_READ_OFTEN |
|
||||
android::GraphicBuffer::USAGE_SW_WRITE_OFTEN |
|
||||
android::GraphicBuffer::USAGE_HW_TEXTURE;
|
||||
|
||||
switch (mFormat) {
|
||||
case gfx::SurfaceFormat::R8G8B8A8:
|
||||
format = android::PIXEL_FORMAT_RGBA_8888;
|
||||
break;
|
||||
case gfx::SurfaceFormat::B8G8R8A8:
|
||||
format = android::PIXEL_FORMAT_RGBA_8888;
|
||||
mFlags |= TextureFlags::RB_SWAPPED;
|
||||
break;
|
||||
case gfx::SurfaceFormat::R8G8B8X8:
|
||||
format = android::PIXEL_FORMAT_RGBX_8888;
|
||||
break;
|
||||
case gfx::SurfaceFormat::B8G8R8X8:
|
||||
format = android::PIXEL_FORMAT_RGBX_8888;
|
||||
mFlags |= TextureFlags::RB_SWAPPED;
|
||||
break;
|
||||
case gfx::SurfaceFormat::R5G6B5_UINT16:
|
||||
format = android::PIXEL_FORMAT_RGB_565;
|
||||
break;
|
||||
case gfx::SurfaceFormat::YUV:
|
||||
format = HAL_PIXEL_FORMAT_YV12;
|
||||
break;
|
||||
case gfx::SurfaceFormat::A8:
|
||||
NS_WARNING("gralloc does not support gfx::SurfaceFormat::A8");
|
||||
return false;
|
||||
default:
|
||||
NS_WARNING("Unsupported surface format");
|
||||
return false;
|
||||
int32_t maxSize = aAllocator->GetMaxTextureSize();
|
||||
if (aSize.width > maxSize || aSize.height > maxSize) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return AllocateGralloc(aSize, format, usage);
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureClientOGL::AllocateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize, StereoMode aStereoMode)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return AllocateGralloc(aYSize,
|
||||
HAL_PIXEL_FORMAT_YV12,
|
||||
android::GraphicBuffer::USAGE_SW_READ_OFTEN);
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureClientOGL::AllocateForGLRendering(gfx::IntSize aSize)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
uint32_t format;
|
||||
uint32_t usage = android::GraphicBuffer::USAGE_HW_RENDER |
|
||||
android::GraphicBuffer::USAGE_HW_TEXTURE;
|
||||
|
||||
switch (mFormat) {
|
||||
case gfx::SurfaceFormat::R8G8B8A8:
|
||||
case gfx::SurfaceFormat::B8G8R8A8:
|
||||
format = android::PIXEL_FORMAT_RGBA_8888;
|
||||
gfx::SurfaceFormat format;
|
||||
switch (aAndroidFormat) {
|
||||
case android::PIXEL_FORMAT_RGBA_8888:
|
||||
format = gfx::SurfaceFormat::B8G8R8A8;
|
||||
break;
|
||||
case gfx::SurfaceFormat::R8G8B8X8:
|
||||
case gfx::SurfaceFormat::B8G8R8X8:
|
||||
// there is no android BGRX format?
|
||||
format = android::PIXEL_FORMAT_RGBX_8888;
|
||||
case android::PIXEL_FORMAT_BGRA_8888:
|
||||
format = gfx::SurfaceFormat::B8G8R8A8;
|
||||
break;
|
||||
case gfx::SurfaceFormat::R5G6B5_UINT16:
|
||||
format = android::PIXEL_FORMAT_RGB_565;
|
||||
case android::PIXEL_FORMAT_RGBX_8888:
|
||||
format = gfx::SurfaceFormat::B8G8R8X8;
|
||||
break;
|
||||
case android::PIXEL_FORMAT_RGB_565:
|
||||
format = gfx::SurfaceFormat::R5G6B5_UINT16;
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_YV12:
|
||||
format = gfx::SurfaceFormat::YUV;
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Unsupported surface format");
|
||||
return false;
|
||||
format = gfx::SurfaceFormat::UNKNOWN;
|
||||
}
|
||||
|
||||
return AllocateGralloc(aSize, format, usage);
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureClientOGL::AllocateGralloc(gfx::IntSize aSize,
|
||||
uint32_t aAndroidFormat,
|
||||
uint32_t aUsage)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
ISurfaceAllocator* allocator = GetAllocator();
|
||||
if (DisableGralloc(format, aSize)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MaybeMagicGrallocBufferHandle handle;
|
||||
bool allocateResult =
|
||||
allocator->AllocGrallocBuffer(aSize,
|
||||
aAndroidFormat,
|
||||
aUsage,
|
||||
&handle);
|
||||
if (!allocateResult) {
|
||||
return false;
|
||||
if (!aAllocator->AllocGrallocBuffer(aSize, aAndroidFormat, aUsage, &handle)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sp<GraphicBuffer> graphicBuffer = GetGraphicBufferFrom(handle);
|
||||
if (!graphicBuffer.get()) {
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (graphicBuffer->initCheck() != NO_ERROR) {
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mGrallocHandle = handle;
|
||||
mGraphicBuffer = graphicBuffer;
|
||||
mSize = aSize;
|
||||
return true;
|
||||
return new GrallocTextureData(handle, aSize, format, aMoz2dBackend);
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureClientOGL::IsAllocated() const
|
||||
// static
|
||||
GrallocTextureData*
|
||||
GrallocTextureData::CreateForDrawing(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
return !!mGraphicBuffer.get();
|
||||
if (DisableGralloc(aFormat, aSize)) {
|
||||
return nullptr;
|
||||
}
|
||||
uint32_t usage = android::GraphicBuffer::USAGE_SW_READ_OFTEN |
|
||||
android::GraphicBuffer::USAGE_SW_WRITE_OFTEN |
|
||||
android::GraphicBuffer::USAGE_HW_TEXTURE;
|
||||
auto data = GrallocTextureData::Create(aSize, GetAndroidFormat(aFormat),
|
||||
aMoz2dBackend, usage, aAllocator);
|
||||
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DebugOnly<gfx::SurfaceFormat> grallocFormat =
|
||||
SurfaceFormatForPixelFormat(data->mGraphicBuffer->getPixelFormat());
|
||||
// mFormat may be different from the format the graphic buffer reports if we
|
||||
// swap the R and B channels but we should always have at least the same bytes
|
||||
// per pixel!
|
||||
MOZ_ASSERT(BytesPerPixel(data->mFormat) == BytesPerPixel(grallocFormat));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureClientOGL::Allocate(uint32_t aSize)
|
||||
already_AddRefed<TextureClient>
|
||||
CreateGrallocTextureClientForDrawing(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
TextureFlags aFlags,
|
||||
ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
// see Bug 908196
|
||||
MOZ_CRASH("This method should never be called.");
|
||||
return false;
|
||||
TextureData* data = GrallocTextureData::CreateForDrawing(aSize, aFormat, aMoz2dBackend,
|
||||
aAllocator);
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
if (IsGrallocRBSwapped(aFormat)) {
|
||||
aFlags |= TextureFlags::RB_SWAPPED;
|
||||
}
|
||||
return MakeAndAddRef<ClientTexture>(data, aFlags, aAllocator);
|
||||
}
|
||||
|
||||
size_t
|
||||
GrallocTextureClientOGL::GetBufferSize() const
|
||||
// static
|
||||
GrallocTextureData*
|
||||
GrallocTextureData::CreateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize,
|
||||
ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
// see Bug 908196
|
||||
MOZ_CRASH("This method should never be called.");
|
||||
return 0;
|
||||
MOZ_ASSERT(aYSize.width == aCbCrSize.width * 2);
|
||||
MOZ_ASSERT(aYSize.height == aCbCrSize.height * 2);
|
||||
return GrallocTextureData::Create(aYSize, HAL_PIXEL_FORMAT_YV12,
|
||||
gfx::BackendType::NONE,
|
||||
android::GraphicBuffer::USAGE_SW_READ_OFTEN,
|
||||
aAllocator);
|
||||
}
|
||||
|
||||
/*static*/ already_AddRefed<TextureClient>
|
||||
GrallocTextureClientOGL::FromSharedSurface(gl::SharedSurface* abstractSurf,
|
||||
TextureFlags flags)
|
||||
// static
|
||||
GrallocTextureData*
|
||||
GrallocTextureData::CreateForGLRendering(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
if (aFormat == gfx::SurfaceFormat::YUV) {
|
||||
return nullptr;
|
||||
}
|
||||
uint32_t usage = android::GraphicBuffer::USAGE_HW_RENDER |
|
||||
android::GraphicBuffer::USAGE_HW_TEXTURE;
|
||||
return GrallocTextureData::Create(aSize, GetAndroidFormat(aFormat),
|
||||
gfx::BackendType::NONE, usage, aAllocator);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<TextureClient>
|
||||
GrallocTextureData::TextureClientFromSharedSurface(gl::SharedSurface* abstractSurf,
|
||||
TextureFlags flags)
|
||||
{
|
||||
auto surf = gl::SharedSurface_Gralloc::Cast(abstractSurf);
|
||||
|
||||
@@ -418,6 +414,18 @@ GrallocTextureClientOGL::FromSharedSurface(gl::SharedSurface* abstractSurf,
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
TextureData*
|
||||
GrallocTextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
if (mFormat == gfx::SurfaceFormat::YUV) {
|
||||
return GrallocTextureData::CreateForYCbCr(mSize, mSize*2, aAllocator);
|
||||
} else {
|
||||
return GrallocTextureData::CreateForDrawing(mSize, mFormat, mMoz2DBackend, aAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
} // namesapace layers
|
||||
} // namesapace mozilla
|
||||
|
||||
|
||||
@@ -25,131 +25,113 @@ class SharedSurface;
|
||||
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* A TextureClient implementation based on android::GraphicBuffer (also referred to
|
||||
* as "gralloc").
|
||||
*
|
||||
* Gralloc lets us map texture data in memory (accessible through pointers)
|
||||
* and also use it directly as an OpenGL texture without the cost of texture
|
||||
* uploads.
|
||||
* Gralloc buffers can also be shared accros processes.
|
||||
*
|
||||
* More info about Gralloc here: https://wiki.mozilla.org/Platform/GFX/Gralloc
|
||||
*
|
||||
* This is only used in Firefox OS
|
||||
*/
|
||||
class GrallocTextureClientOGL : public BufferTextureClient
|
||||
{
|
||||
/// A TextureData implementation based on android::GraphicBuffer (also referred to
|
||||
/// as "gralloc").
|
||||
///
|
||||
/// Gralloc lets us map texture data in memory (accessible through pointers)
|
||||
/// and also use it directly as an OpenGL texture without the cost of texture
|
||||
/// uploads.
|
||||
/// Gralloc buffers can also be shared accros processes.
|
||||
///
|
||||
/// More info about Gralloc here: https://wiki.mozilla.org/Platform/GFX/Gralloc
|
||||
///
|
||||
/// This is only used in Firefox OS
|
||||
class GrallocTextureData : public TextureData {
|
||||
public:
|
||||
GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
TextureFlags aFlags = TextureFlags::DEFAULT);
|
||||
typedef uint32_t AndroidFormat;
|
||||
|
||||
~GrallocTextureClientOGL();
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
virtual bool Lock(OpenMode aMode) override;
|
||||
virtual bool Lock(OpenMode aMode, FenceHandle* aFence) override;
|
||||
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual bool ImplementsLocking() const override { return true; }
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
virtual bool CanExposeMappedData() const override { return true; }
|
||||
|
||||
virtual bool BorrowMappedData(MappedTextureData& aMap) override;
|
||||
|
||||
virtual bool SupportsMoz2D() const override { return true; }
|
||||
|
||||
virtual bool HasInternalBuffer() const override { return false; }
|
||||
|
||||
virtual bool IsAllocated() const override;
|
||||
virtual bool HasSynchronization() const override { return true; }
|
||||
|
||||
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
|
||||
virtual void Deallocate(ISurfaceAllocator*) override;
|
||||
|
||||
virtual void SetRemoveFromCompositableWaiter(AsyncTransactionWaiter* aWaiter) override;
|
||||
virtual void Forget(ISurfaceAllocator*) override;
|
||||
|
||||
virtual void WaitForBufferOwnership(bool aWaitReleaseFence = true) override;
|
||||
static GrallocTextureData* CreateForDrawing(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2dBackend,
|
||||
ISurfaceAllocator* aAllocator);
|
||||
|
||||
GrallocTextureClientOGL* AsGrallocTextureClientOGL() override {
|
||||
return this;
|
||||
}
|
||||
static GrallocTextureData* CreateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize,
|
||||
ISurfaceAllocator* aAllocator);
|
||||
|
||||
void SetTextureFlags(TextureFlags aFlags) { AddFlags(aFlags); }
|
||||
static GrallocTextureData* CreateForGLRendering(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
ISurfaceAllocator* aAllocator);
|
||||
|
||||
gfx::IntSize GetSize() const override { return mSize; }
|
||||
static GrallocTextureData* Create(gfx::IntSize aSize, AndroidFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend, uint32_t aUsage,
|
||||
ISurfaceAllocator* aAllocator);
|
||||
|
||||
android::sp<android::GraphicBuffer> GetGraphicBuffer()
|
||||
{
|
||||
return mGraphicBuffer;
|
||||
}
|
||||
|
||||
android::PixelFormat GetPixelFormat()
|
||||
{
|
||||
return mGraphicBuffer->getPixelFormat();
|
||||
}
|
||||
static already_AddRefed<TextureClient>
|
||||
TextureClientFromSharedSurface(gl::SharedSurface* abstractSurf, TextureFlags flags);
|
||||
|
||||
virtual uint8_t* GetBuffer() const override;
|
||||
|
||||
virtual gfx::DrawTarget* BorrowDrawTarget() override;
|
||||
|
||||
virtual void UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
virtual bool AllocateForSurface(gfx::IntSize aSize,
|
||||
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
|
||||
|
||||
virtual bool AllocateForYCbCr(gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode) override;
|
||||
|
||||
bool AllocateForGLRendering(gfx::IntSize aSize);
|
||||
|
||||
bool AllocateGralloc(gfx::IntSize aYSize, uint32_t aAndroidFormat, uint32_t aUsage);
|
||||
|
||||
void SetIsOpaque(bool aIsOpaque) { mIsOpaque = aIsOpaque; }
|
||||
|
||||
virtual bool Allocate(uint32_t aSize) override;
|
||||
|
||||
virtual size_t GetBufferSize() const override;
|
||||
|
||||
/**
|
||||
* Hold android::MediaBuffer.
|
||||
* MediaBuffer needs to be add refed to keep MediaBuffer alive
|
||||
* during TextureClient is in use.
|
||||
*/
|
||||
void SetMediaBuffer(android::MediaBuffer* aMediaBuffer)
|
||||
{
|
||||
mMediaBuffer = aMediaBuffer;
|
||||
}
|
||||
|
||||
android::MediaBuffer* GetMediaBuffer()
|
||||
{
|
||||
return mMediaBuffer;
|
||||
}
|
||||
|
||||
virtual already_AddRefed<TextureClient>
|
||||
CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
virtual TextureData*
|
||||
CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags = TextureFlags::DEFAULT,
|
||||
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
|
||||
|
||||
static already_AddRefed<TextureClient> FromSharedSurface(gl::SharedSurface* surf,
|
||||
TextureFlags flags);
|
||||
// use ClientTexture's default implementation
|
||||
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
/// Hold android::MediaBuffer.
|
||||
/// MediaBuffer needs to be add refed to keep MediaBuffer alive while the texture
|
||||
/// is in use.
|
||||
///
|
||||
/// TODO - ideally we should be able to put the MediaBuffer in the texture's
|
||||
/// constructor and not expose these methods.
|
||||
void SetMediaBuffer(android::MediaBuffer* aMediaBuffer) { mMediaBuffer = aMediaBuffer; }
|
||||
android::MediaBuffer* GetMediaBuffer() { return mMediaBuffer; }
|
||||
|
||||
android::sp<android::GraphicBuffer> GetGraphicBuffer() { return mGraphicBuffer; }
|
||||
|
||||
virtual void WaitForFence(FenceHandle* aFence) override;
|
||||
|
||||
~GrallocTextureData();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Unfortunately, until bug 879681 is fixed we need to use a GrallocBufferActor.
|
||||
*/
|
||||
GrallocTextureData(MaybeMagicGrallocBufferHandle aGrallocHandle,
|
||||
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2DBackend);
|
||||
|
||||
gfx::IntSize mSize;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
gfx::BackendType mMoz2DBackend;
|
||||
|
||||
MaybeMagicGrallocBufferHandle mGrallocHandle;
|
||||
|
||||
RefPtr<AsyncTransactionWaiter> mRemoveFromCompositableWaiter;
|
||||
|
||||
android::sp<android::GraphicBuffer> mGraphicBuffer;
|
||||
|
||||
/**
|
||||
* Points to a mapped gralloc buffer between calls to lock and unlock.
|
||||
* Should be null outside of the lock-unlock pair.
|
||||
*/
|
||||
// Points to a mapped gralloc buffer between calls to lock and unlock.
|
||||
// Should be null outside of the lock-unlock pair.
|
||||
uint8_t* mMappedBuffer;
|
||||
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
|
||||
android::MediaBuffer* mMediaBuffer;
|
||||
|
||||
bool mIsOpaque;
|
||||
};
|
||||
|
||||
gfx::SurfaceFormat SurfaceFormatForPixelFormat(android::PixelFormat aFormat);
|
||||
|
||||
already_AddRefed<TextureClient> CreateGrallocTextureClientForDrawing(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::BackendType aMoz2dBackend, TextureFlags aFlags,
|
||||
ISurfaceAllocator* aAllocator);
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -167,12 +167,17 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
|
||||
AddUniforms(result);
|
||||
|
||||
vs << "#ifdef GL_ES" << endl;
|
||||
vs << "#define EDGE_PRECISION mediump" << endl;
|
||||
vs << "#else" << endl;
|
||||
vs << "#define EDGE_PRECISION" << endl;
|
||||
vs << "#endif" << endl;
|
||||
vs << "uniform mat4 uMatrixProj;" << endl;
|
||||
vs << "uniform vec4 uLayerRects[4];" << endl;
|
||||
vs << "uniform mat4 uLayerTransform;" << endl;
|
||||
if (aConfig.mFeatures & ENABLE_DEAA) {
|
||||
vs << "uniform mat4 uLayerTransformInverse;" << endl;
|
||||
vs << "uniform vec3 uSSEdges[4];" << endl;
|
||||
vs << "uniform EDGE_PRECISION vec3 uSSEdges[4];" << endl;
|
||||
vs << "uniform vec2 uVisibleCenter;" << endl;
|
||||
vs << "uniform vec2 uViewportSize;" << endl;
|
||||
}
|
||||
@@ -280,8 +285,10 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
fs << "#ifdef GL_ES" << endl;
|
||||
fs << "precision mediump float;" << endl;
|
||||
fs << "#define COLOR_PRECISION lowp" << endl;
|
||||
fs << "#define EDGE_PRECISION mediump" << endl;
|
||||
fs << "#else" << endl;
|
||||
fs << "#define COLOR_PRECISION" << endl;
|
||||
fs << "#define EDGE_PRECISION" << endl;
|
||||
fs << "#endif" << endl;
|
||||
if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
|
||||
fs << "uniform COLOR_PRECISION vec4 uRenderColor;" << endl;
|
||||
@@ -342,7 +349,7 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
}
|
||||
|
||||
if (aConfig.mFeatures & ENABLE_DEAA) {
|
||||
fs << "uniform vec3 uSSEdges[4];" << endl;
|
||||
fs << "uniform EDGE_PRECISION vec3 uSSEdges[4];" << endl;
|
||||
}
|
||||
|
||||
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,33 @@ message ColorPacket {
|
||||
}
|
||||
|
||||
message TexturePacket {
|
||||
enum Filter {
|
||||
GOOD = 0;
|
||||
LINEAR = 1;
|
||||
POINT = 2;
|
||||
}
|
||||
message Rect {
|
||||
optional float x = 1;
|
||||
optional float y = 2;
|
||||
optional float w = 3;
|
||||
optional float h = 4;
|
||||
}
|
||||
message Size {
|
||||
optional int32 w = 1;
|
||||
optional int32 h = 2;
|
||||
}
|
||||
message Matrix {
|
||||
optional bool is2D = 1;
|
||||
optional bool isId = 2;
|
||||
repeated float m = 3;
|
||||
}
|
||||
message EffectMask {
|
||||
optional bool mIs3D = 1;
|
||||
optional Size mSize = 2;
|
||||
optional Matrix mMaskTransform = 3;
|
||||
}
|
||||
|
||||
// Basic info
|
||||
required uint64 layerref = 1;
|
||||
optional uint32 width = 2;
|
||||
optional uint32 height = 3;
|
||||
@@ -29,6 +56,15 @@ message TexturePacket {
|
||||
optional uint32 dataformat = 7;
|
||||
optional uint64 glcontext = 8;
|
||||
optional bytes data = 9;
|
||||
|
||||
// TextureEffect attributes
|
||||
optional Rect mTextureCoords = 10;
|
||||
optional bool mPremultiplied = 11;
|
||||
optional Filter mFilter = 12;
|
||||
|
||||
// Mask attributes
|
||||
optional bool isMask = 20;
|
||||
optional EffectMask mask = 21;
|
||||
}
|
||||
|
||||
message LayersPacket {
|
||||
@@ -49,13 +85,15 @@ message LayersPacket {
|
||||
HORIZONTAL = 2;
|
||||
}
|
||||
enum Filter {
|
||||
FILTER_FAST = 0;
|
||||
FILTER_FAST = 0; // deprecated
|
||||
FILTER_GOOD = 1;
|
||||
FILTER_BEST = 2;
|
||||
FILTER_NEAREST = 3;
|
||||
FILTER_BILINEAR = 4;
|
||||
FILTER_GAUSSIAN = 5;
|
||||
FILTER_SENTINEL = 6;
|
||||
FILTER_BEST = 2; // deprecated
|
||||
FILTER_NEAREST = 3; //deprecated
|
||||
FILTER_BILINEAR = 4; //deprecated
|
||||
FILTER_GAUSSIAN = 5; //deprecated
|
||||
FILTER_SENTINEL = 6; //deprecated
|
||||
FILTER_LINEAR = 7;
|
||||
FILTER_POINT = 8;
|
||||
}
|
||||
message Size {
|
||||
optional int32 w = 1;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <string.h>
|
||||
#include "nsColor.h"
|
||||
#include "nsColorNames.h"
|
||||
#include "prprf.h"
|
||||
#include "mozilla/Snprintf.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
@@ -71,7 +71,7 @@ void RunColorTests() {
|
||||
rgb = NS_RGB(r, g, b);
|
||||
}
|
||||
char cbuf[50];
|
||||
PR_snprintf(cbuf, sizeof(cbuf), "%02x%02x%02x", r, g, b);
|
||||
snprintf_literal(cbuf, "%02x%02x%02x", r, g, b);
|
||||
nscolor hexrgb;
|
||||
ASSERT_TRUE(NS_HexToRGB(NS_ConvertASCIItoUTF16(cbuf), &hexrgb)) <<
|
||||
"hex conversion to color of '" << cbuf << "'";
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/layers/BufferTexture.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxImageSurface.h"
|
||||
@@ -148,8 +149,6 @@ void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface)
|
||||
|
||||
// client allocation
|
||||
ASSERT_TRUE(texture->CanExposeDrawTarget());
|
||||
texture->AllocateForSurface(surface->GetSize());
|
||||
ASSERT_TRUE(texture->IsAllocated());
|
||||
|
||||
ASSERT_TRUE(texture->Lock(OpenMode::OPEN_READ_WRITE));
|
||||
// client painting
|
||||
@@ -199,18 +198,8 @@ void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface)
|
||||
|
||||
// Same as above, for YCbCr surfaces
|
||||
void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) {
|
||||
|
||||
// client allocation
|
||||
ASSERT_TRUE(client->AsTextureClientYCbCr() != nullptr);
|
||||
TextureClientYCbCr* texture = client->AsTextureClientYCbCr();
|
||||
texture->AllocateForYCbCr(ycbcrData.mYSize,
|
||||
ycbcrData.mCbCrSize,
|
||||
ycbcrData.mStereoMode);
|
||||
ASSERT_TRUE(client->IsAllocated());
|
||||
|
||||
ASSERT_TRUE(client->Lock(OpenMode::OPEN_READ_WRITE));
|
||||
// client painting
|
||||
texture->UpdateYCbCr(ycbcrData);
|
||||
client->Lock(OpenMode::OPEN_READ_WRITE);
|
||||
UpdateYCbCrTextureClient(client, ycbcrData);
|
||||
client->Unlock();
|
||||
|
||||
// client serialization
|
||||
@@ -273,11 +262,15 @@ TEST(Layers, TextureSerialization) {
|
||||
SetupSurface(surface.get());
|
||||
AssertSurfacesEqual(surface, surface);
|
||||
|
||||
RefPtr<TextureClient> client
|
||||
= new MemoryTextureClient(nullptr,
|
||||
mozilla::gfx::ImageFormatToSurfaceFormat(surface->Format()),
|
||||
gfx::BackendType::CAIRO,
|
||||
TextureFlags::DEALLOCATE_CLIENT);
|
||||
auto texData = BufferTextureData::Create(surface->GetSize(),
|
||||
gfx::ImageFormatToSurfaceFormat(surface->Format()),
|
||||
gfx::BackendType::CAIRO, TextureFlags::DEALLOCATE_CLIENT, ALLOC_DEFAULT, nullptr
|
||||
);
|
||||
ASSERT_TRUE(!!texData);
|
||||
|
||||
RefPtr<TextureClient> client = new ClientTexture(
|
||||
texData, TextureFlags::DEALLOCATE_CLIENT, nullptr
|
||||
);
|
||||
|
||||
TestTextureClientSurface(client, surface);
|
||||
|
||||
@@ -310,11 +303,8 @@ TEST(Layers, TextureYCbCrSerialization) {
|
||||
clientData.mPicX = 0;
|
||||
clientData.mPicX = 0;
|
||||
|
||||
RefPtr<TextureClient> client
|
||||
= new MemoryTextureClient(nullptr,
|
||||
mozilla::gfx::SurfaceFormat::YUV,
|
||||
gfx::BackendType::CAIRO,
|
||||
TextureFlags::DEALLOCATE_CLIENT);
|
||||
RefPtr<TextureClient> client = TextureClient::CreateForYCbCr(nullptr, clientData.mYSize, clientData.mCbCrSize,
|
||||
StereoMode::MONO, TextureFlags::DEALLOCATE_CLIENT);
|
||||
|
||||
TestTextureClientYCbCr(client, clientData);
|
||||
|
||||
|
||||
@@ -2183,7 +2183,8 @@ nsPresContext::UpdateIsChrome()
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, uint32_t ruleTypeMask) const
|
||||
nsPresContext::HasAuthorSpecifiedRules(const nsIFrame *aFrame,
|
||||
uint32_t ruleTypeMask) const
|
||||
{
|
||||
return
|
||||
nsRuleNode::HasAuthorSpecifiedRules(aFrame->StyleContext(),
|
||||
|
||||
@@ -868,7 +868,8 @@ public:
|
||||
void UpdateIsChrome();
|
||||
|
||||
// Public API for native theme code to get style internals.
|
||||
virtual bool HasAuthorSpecifiedRules(nsIFrame *aFrame, uint32_t ruleTypeMask) const;
|
||||
virtual bool HasAuthorSpecifiedRules(const nsIFrame *aFrame,
|
||||
uint32_t ruleTypeMask) const;
|
||||
|
||||
// Is it OK to let the page specify colors and backgrounds?
|
||||
bool UseDocumentColors() const {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-print">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style type="text/css">
|
||||
#menu { position: fixed; left: 0px; top: 0px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<svg id="canvas" width="2427" height="2295.5" version="1.1" xmlns="http://www.w3.org/2000/svg"></svg>
|
||||
|
||||
<div id="menu">
|
||||
<input id="chooseSize" type="range">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -62,3 +62,5 @@ load 960277-2.html
|
||||
load 997709-1.html
|
||||
load 1102791.html
|
||||
load 1140216.html
|
||||
load 1182414.html
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user