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:
2023-01-30 12:47:09 +08:00
parent 6a4edbe796
commit 89d38b5d7a
112 changed files with 6226 additions and 2370 deletions
+21
View File
@@ -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,
+7 -59
View File
@@ -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;
}
-41
View File
@@ -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().
+35 -64
View File
@@ -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)
{
-25
View File
@@ -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;
+7 -3
View File
@@ -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;
}
+3 -2
View File
@@ -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
+8 -23
View File
@@ -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.
+15
View File
@@ -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
+1 -1
View File
@@ -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;
+50 -6
View File
@@ -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++;
}
+9 -19
View File
@@ -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:
+7 -7
View File
@@ -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
};
/**
+277 -169
View File
@@ -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;
}
+35 -32
View File
@@ -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.
*/
+4 -4
View File
@@ -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>
+2
View File
@@ -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);
+7 -8
View File
@@ -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);
+11 -9
View File
@@ -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(
+4 -4
View File
@@ -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;
}
+13 -8
View File
@@ -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) {
+449
View File
@@ -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
+81
View File
@@ -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
+16 -23
View File
@@ -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;
}
+2 -2
View File
@@ -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
+27 -30
View File
@@ -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);
+1 -1
View File
@@ -8,7 +8,7 @@
#include "mozilla/RefPtr.h"
#include "ImageContainer.h"
#include "Mfidl.h"
#include "mfidl.h"
namespace mozilla {
namespace layers {
+2
View File
@@ -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
View File
@@ -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));
+6 -2
View File
@@ -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;
}
+2 -2
View File
@@ -54,5 +54,5 @@ LayerRenderState::LayerRenderState(android::GraphicBuffer* aSurface,
{}
#endif
} // namespace
} // namespace
} // namespace layers
} // namespace mozilla
+21 -5
View File
@@ -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
};
+2 -2
View File
@@ -22,5 +22,5 @@ PersistentBufferProviderBasic::PersistentBufferProviderBasic(gfx::IntSize aSize,
mDrawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(aBackend, aSize, aFormat);
}
}
}
} // namespace layers
} // namespace mozilla
+9 -7
View File
@@ -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);
+6 -5
View File
@@ -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;
}
+4 -4
View File
@@ -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);
+84 -97
View File
@@ -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
+30 -31
View File
@@ -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
+18 -10
View File
@@ -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
+1 -1
View File
@@ -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,
+1 -2
View File
@@ -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,
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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();
+1 -1
View File
@@ -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.
+6 -5
View File
@@ -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.");
}
+2 -2
View File
@@ -148,5 +148,5 @@ FrameUniformityData::ToJS(JS::MutableHandleValue aOutValue, JSContext* aContext)
return dom::ToJSValue(aContext, results, aOutValue);
}
}
}
} // namespace layers
} // namespace mozilla
+3 -3
View File
@@ -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_
+1 -1
View File
@@ -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
+1 -2
View File
@@ -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
+6 -2
View File
@@ -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);
+1 -1
View File
@@ -23,7 +23,7 @@ public:
NS_INLINE_DECL_REFCOUNTING(TextRenderer)
explicit TextRenderer(Compositor *aCompositor)
: mCompositor(aCompositor)
: mCompositor(aCompositor), mMap({nullptr, 0})
{
}
+217 -159
View File
@@ -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(&region);
#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(&region);
#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());
+18 -25
View File
@@ -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,
+76 -3
View File
@@ -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)
{
+15 -5
View File
@@ -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;
}
+38 -1
View File
@@ -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();
+8 -16
View File
@@ -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
+39 -1
View File
@@ -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();
+3 -10
View File
@@ -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;
+2
View File
@@ -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,
+17 -2
View File
@@ -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
+41 -19
View File
@@ -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;
}
+1 -2
View File
@@ -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;
};
+5 -13
View File
@@ -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)
{
+1 -4
View File
@@ -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
+2
View File
@@ -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
+288 -280
View File
@@ -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
+77 -95
View File
@@ -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
+9 -2
View File
@@ -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
+44 -6
View File
@@ -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;
+2 -2
View File
@@ -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 << "'";
+14 -24
View File
@@ -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);
+2 -1
View File
@@ -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(),
+2 -1
View File
@@ -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 {
+17
View File
@@ -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>
+2
View File
@@ -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