From 75dd89485e48420544ed294dfab63c3f5440616b Mon Sep 17 00:00:00 2001 From: roytam1 Date: Thu, 24 Dec 2020 10:05:34 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1176414 - Clean up/rename various column index variables in nsTableRowFrame and nsTableFrame. r=dholbert (d8e33d549) - Bug 1176105 - Remove the (largely gutted) nsTableIterator class, and replace with simple frame-list iteration. r=dholbert (46a15df19) - Bug 1176555 - Replace explicit bit-twiddling of frame state flags by human-readable nsIFrame state-manipulation methods in table layout code. r=dholbert (aef9fb035) - Bug 1176354 - Rename nsTableRowFrame::GetBSize to differentiate better from nsIFrame::BSize. r=dholbert (9b67203a0) - Bug 1177600 - Properly adjust table row and cell positions when their containing block-size changes in vertical-rl writing mode. r=dholbert (413148d55) - Bug 1177925: Use range-based for loops for nsFrameList iteration, in various places in layout. r=tn (6db450285) - Bug 1148582 - Recycle mask layers attached to FrameMetrics. r=mattwoodrow (91360fbd8) - Bug 1148582 - Apply async transforms to (ancestor) mask layers correctly. r=botond (d6fca66fb) - Bug 1143575. Add some #includes to avoid unified-build issues on Windows. r=nical (ff78b76a3) - Bug 1143575. Add some #includes to avoid more unified-build issues on Windows. r=nical (99e0548f4) - Bug 1181832 - Keep gfxPrefs.h out of header files. r=kats (341f0aea0) - Bug 1181832 - Include gfxPrefs.h from nsImageLoadingContet.cpp to fix bustage on a CLOSED TREE. r=bustage (d61a18ab9) - Bug 1137557 - Part 0: TextEventDispatcher shouldn't forward keyboard events coming from TextInputProcessor to the parent process. r=smaug (87f70fcc4) - Bug 1172405 - Fix build error when adding files to dom/workers and gfx/layers. r=nical (8e114b8bb) - Bug 1061393 - Export display list info to layer scope viewer. r=kamidphish (60fd247f0) - Bug 1072313 - Check for more leaks in the layers code. r=mstange (aacbb2e1c) - Bug 1198979 - GC unused IPDL struct member. r=jmuizelaar (79c3113fb) - add missing semicolon (17ba58b45) - Bug 1153348 - Add an analysis to prohibit operator bools which aren't marked as either explicit or MOZ_IMPLICIT; r=jrmuizel (903dca970) - Bug 1170388 - Restrict the static analysis error given about raw pointers to refcounted objects inside a lambda, to the case where the raw pointer is captured. r=ehsan (cbbd3174c) - Bug 1180993 - Part 1: Add an analysis to help catch unused return values of specific types. r=ehsan (2420face4) - Bug 1180993 - Part 2: Add the MOZ_MUST_USE attribute to mfbt, and use it to verify usage of already_AddRefed. r=ehsan (b72785a60) - Bug 1123907 - Part 1: Add an analysis to ensure that a class marked MOZ_NEEDS_NO_VTABLE_TYPE cannot be instantiated by a class with a VTable; r=ehsan (0f5730c04) - Bug 1123907 - Part 2: Add MOZ_NEEDS_NO_VTABLE_TYPE to Attributes.h, and use it to verify the EntryType argument of nsTHashtable; r=ehsan (2e80fc581) - Bug 1159433 - Part 1: Add an analysis to ensure that some template arguments cannot be non-memmovable types; r=ehsan (3602e950f) - uniform MOZ_MUST_USE, it will be renamed in patch 1267550 (3b5ebd4c5) - add missing part of Bug 1187073 - Use MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS to validate the usage of AlignedStorage2. r=ehsan (3b451bfb7) - Bug 1159433 - Part 2: Add the MOZ_NON_MEMMOVABLE and MOZ_NEEDS_MEMMOVABLE_TYPE macros to MFBT; r=froydnj (171c23ec4) - Bug 1159433 - Part 3: Make nsTArray_CopyChooser only accept memmovable argument types by default; r=froydnj (40cb4aa67) - Bug 1159433 - Part 4: Mark nsTAutoString_CharT and nsAutoArrayBase as non-memmovable; r=froydnj (7dc6bd220) --- build/clang-plugin/clang-plugin.cpp | 403 ++++++++- .../tests/TestExplicitOperatorBool.cpp | 11 + build/clang-plugin/tests/TestMustUse.cpp | 156 ++++ .../tests/TestNeedsNoVTableType.cpp | 94 ++ .../tests/TestNoRefcountedInsideLambdas.cpp | 72 +- .../clang-plugin/tests/TestNonMemMovable.cpp | 812 ++++++++++++++++++ build/clang-plugin/tests/moz.build | 4 + dom/base/TextInputProcessor.cpp | 26 +- dom/base/TextInputProcessor.h | 6 +- dom/base/nsContentUtils.cpp | 1 + dom/base/nsImageLoadingContent.cpp | 2 + dom/bindings/CallbackObject.h | 2 +- dom/canvas/CanvasRenderingContext2D.cpp | 1 + dom/gamepad/linux/udev.h | 2 +- dom/html/HTMLMediaElement.h | 2 +- dom/media/SelfRef.h | 2 +- dom/plugins/base/nsNPAPIPluginInstance.cpp | 2 +- dom/plugins/ipc/PluginScriptableObjectUtils.h | 2 +- dom/workers/ServiceWorkerContainer.cpp | 1 + gfx/layers/FrameMetrics.cpp | 22 + gfx/layers/FrameMetrics.h | 8 +- gfx/layers/ImageLayers.cpp | 2 +- gfx/layers/LayerScope.cpp | 68 +- gfx/layers/LayerScope.h | 5 +- gfx/layers/Layers.cpp | 95 +- gfx/layers/Layers.h | 24 +- gfx/layers/YCbCrImageDataSerializer.cpp | 1 + gfx/layers/apz/util/APZEventState.cpp | 14 + gfx/layers/apz/util/APZEventState.h | 1 + gfx/layers/basic/BasicContainerLayer.cpp | 4 +- gfx/layers/basic/BasicPaintedLayer.h | 2 +- .../basic/MacIOSurfaceTextureHostBasic.cpp | 5 +- gfx/layers/client/ClientContainerLayer.h | 1 - gfx/layers/client/TiledContentClient.h | 1 - .../composite/AsyncCompositionManager.cpp | 33 + gfx/layers/composite/ImageLayerComposite.cpp | 2 +- gfx/layers/composite/TextureHost.cpp | 5 +- gfx/layers/ipc/CompositorParent.cpp | 4 + gfx/layers/ipc/LayerTransactionParent.cpp | 2 + gfx/layers/ipc/LayersMessages.ipdlh | 3 +- gfx/layers/ipc/ShadowLayers.cpp | 4 + gfx/layers/moz.build | 1 + gfx/layers/opengl/CompositorOGL.cpp | 2 +- .../opengl/MacIOSurfaceTextureHostOGL.cpp | 14 +- .../opengl/MacIOSurfaceTextureHostOGL.h | 1 + gfx/layers/protobuf/LayerScopePacket.pb.cc | 207 ++++- gfx/layers/protobuf/LayerScopePacket.pb.h | 245 ++++++ gfx/layers/protobuf/LayerScopePacket.proto | 5 + gfx/thebes/gfxPlatform.cpp | 12 + gfx/thebes/gfxPlatform.h | 11 +- layout/base/FrameLayerBuilder.cpp | 56 +- layout/base/nsDisplayList.cpp | 12 + layout/base/nsDisplayList.h | 11 +- layout/base/nsLayoutDebugger.cpp | 10 - layout/base/nsLayoutUtils.cpp | 10 +- layout/generic/ScrollVelocityQueue.cpp | 1 + layout/generic/nsAbsoluteContainingBlock.cpp | 4 +- layout/generic/nsBlockFrame.cpp | 11 +- layout/generic/nsContainerFrame.cpp | 9 +- layout/generic/nsFontInflationData.cpp | 6 +- layout/generic/nsFrame.h | 6 - layout/generic/nsFrameSetFrame.cpp | 3 +- layout/generic/nsGfxScrollFrame.cpp | 2 +- layout/generic/nsHTMLReflowState.cpp | 2 +- layout/generic/nsInlineFrame.cpp | 2 +- layout/generic/nsSubDocumentFrame.cpp | 2 + layout/generic/nsTextFrame.cpp | 6 +- layout/generic/nsVideoFrame.cpp | 8 +- layout/mathml/nsMathMLmtableFrame.cpp | 4 +- layout/tables/nsTableCellFrame.cpp | 16 +- layout/tables/nsTableCellFrame.h | 14 +- layout/tables/nsTableFrame.cpp | 249 +++--- layout/tables/nsTableFrame.h | 17 - layout/tables/nsTableOuterFrame.cpp | 6 +- layout/tables/nsTableRowFrame.cpp | 156 ++-- layout/tables/nsTableRowFrame.h | 9 +- layout/tables/nsTableRowGroupFrame.cpp | 54 +- layout/tables/nsTableRowGroupFrame.h | 14 +- memory/replace/logalloc/replay/Replay.cpp | 2 +- mfbt/Alignment.h | 3 +- mfbt/AlreadyAddRefed.h | 2 +- mfbt/Atomics.h | 2 +- netwerk/base/AutoClose.h | 2 +- netwerk/socket/nsSOCKSIOLayer.cpp | 2 +- security/sandbox/linux/LinuxCapabilities.h | 2 +- toolkit/system/gnome/nsPackageKitService.cpp | 3 +- widget/TextEventDispatcher.cpp | 40 +- widget/TextEventDispatcher.h | 43 +- widget/windows/nsWindow.cpp | 1 + xpcom/build/FileLocation.h | 4 +- xpcom/glue/nsTArray.h | 5 +- xpcom/glue/nsTHashtable.h | 3 +- xpcom/string/nsTString.h | 2 +- 93 files changed, 2716 insertions(+), 505 deletions(-) create mode 100644 build/clang-plugin/tests/TestExplicitOperatorBool.cpp create mode 100644 build/clang-plugin/tests/TestMustUse.cpp create mode 100644 build/clang-plugin/tests/TestNeedsNoVTableType.cpp create mode 100644 build/clang-plugin/tests/TestNonMemMovable.cpp create mode 100644 gfx/layers/FrameMetrics.cpp diff --git a/build/clang-plugin/clang-plugin.cpp b/build/clang-plugin/clang-plugin.cpp index 07208eab6a..9bc2fb070c 100644 --- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -1,6 +1,7 @@ /* 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 "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" @@ -82,7 +83,22 @@ private: class RefCountedInsideLambdaChecker : public MatchFinder::MatchCallback { public: virtual void run(const MatchFinder::MatchResult &Result); - } + }; + + class ExplicitOperatorBoolChecker : public MatchFinder::MatchCallback { + public: + virtual void run(const MatchFinder::MatchResult &Result); + }; + + class NeedsNoVTableTypeChecker : public MatchFinder::MatchCallback { + public: + virtual void run(const MatchFinder::MatchResult &Result); + }; + + class NonMemMovableChecker : public MatchFinder::MatchCallback { + public: + virtual void run(const MatchFinder::MatchResult &Result); + }; ScopeChecker stackClassChecker; ScopeChecker globalClassChecker; @@ -92,16 +108,19 @@ private: NaNExprChecker nanExprChecker; NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker; RefCountedInsideLambdaChecker refCountedInsideLambdaChecker; + ExplicitOperatorBoolChecker explicitOperatorBoolChecker; + NeedsNoVTableTypeChecker needsNoVTableTypeChecker; + NonMemMovableChecker nonMemMovableChecker; MatchFinder astMatcher; }; namespace { -bool isInIgnoredNamespace(const Decl *decl) { +std::string getDeclarationNamespace(const Decl *decl) { const DeclContext *DC = decl->getDeclContext()->getEnclosingNamespaceContext(); const NamespaceDecl *ND = dyn_cast(DC); if (!ND) { - return false; + return ""; } while (const DeclContext *ParentDC = ND->getParent()) { @@ -112,8 +131,15 @@ bool isInIgnoredNamespace(const Decl *decl) { } const auto& name = ND->getName(); + return name; +} + +bool isInIgnoredNamespaceForImplicitCtor(const Decl *decl) { + std::string name = getDeclarationNamespace(decl); + if (name == "") { + return false; + } - // namespace std and icu are ignored for now return name == "std" || // standard C++ lib name == "__gnu_cxx" || // gnu C++ lib name == "boost" || // boost @@ -129,7 +155,19 @@ bool isInIgnoredNamespace(const Decl *decl) { name == "testing"; // gtest } -bool isIgnoredPath(const Decl *decl) { +bool isInIgnoredNamespaceForImplicitConversion(const Decl *decl) { + std::string name = getDeclarationNamespace(decl); + if (name == "") { + return false; + } + + return name == "std" || // standard C++ lib + name == "__gnu_cxx" || // gnu C++ lib + name == "google_breakpad" || // breakpad + name == "testing"; // gtest +} + +bool isIgnoredPathForImplicitCtor(const Decl *decl) { decl = decl->getCanonicalDecl(); SourceLocation Loc = decl->getLocation(); const SourceManager &SM = decl->getASTContext().getSourceManager(); @@ -150,9 +188,30 @@ bool isIgnoredPath(const Decl *decl) { return false; } -bool isInterestingDecl(const Decl *decl) { - return !isInIgnoredNamespace(decl) && - !isIgnoredPath(decl); +bool isIgnoredPathForImplicitConversion(const Decl *decl) { + decl = decl->getCanonicalDecl(); + SourceLocation Loc = decl->getLocation(); + const SourceManager &SM = decl->getASTContext().getSourceManager(); + SmallString<1024> FileName = SM.getFilename(Loc); + llvm::sys::fs::make_absolute(FileName); + llvm::sys::path::reverse_iterator begin = llvm::sys::path::rbegin(FileName), + end = llvm::sys::path::rend(FileName); + for (; begin != end; ++begin) { + if (begin->compare_lower(StringRef("graphite2")) == 0) { + return true; + } + } + return false; +} + +bool isInterestingDeclForImplicitCtor(const Decl *decl) { + return !isInIgnoredNamespaceForImplicitCtor(decl) && + !isIgnoredPathForImplicitCtor(decl); +} + +bool isInterestingDeclForImplicitConversion(const Decl *decl) { + return !isInIgnoredNamespaceForImplicitConversion(decl) && + !isIgnoredPathForImplicitConversion(decl); } } @@ -180,6 +239,25 @@ public: return attr->getAnnotation() == spelling; } + void HandleUnusedExprResult(const Stmt *stmt) { + const Expr* E = dyn_cast_or_null(stmt); + if (E) { + // XXX It would be nice if we could use getAsTagDecl, + // but our version of clang is too old. + // (getAsTagDecl would also cover enums etc.) + QualType T = E->getType(); + CXXRecordDecl *decl = T->getAsCXXRecordDecl(); + if (decl) { + decl = decl->getDefinition(); + if (decl && hasCustomAnnotation(decl, "moz_must_use")) { + unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Error, "Unused MOZ_MUST_USE value of type %0"); + Diag.Report(E->getLocStart(), errorID) << T; + } + } + } + } + bool VisitCXXRecordDecl(CXXRecordDecl *d) { // We need definitions, not declarations if (!d->isThisDeclarationADefinition()) return true; @@ -232,7 +310,7 @@ public: } } - if (!d->isAbstract() && isInterestingDecl(d)) { + if (!d->isAbstract() && isInterestingDeclForImplicitCtor(d)) { for (CXXRecordDecl::ctor_iterator ctor = d->ctor_begin(), e = d->ctor_end(); ctor != e; ++ctor) { // Ignore non-converting ctors @@ -262,6 +340,41 @@ public: return true; } + + bool VisitSwitchCase(SwitchCase* stmt) { + HandleUnusedExprResult(stmt->getSubStmt()); + return true; + } + bool VisitCompoundStmt(CompoundStmt* stmt) { + for (CompoundStmt::body_iterator it = stmt->body_begin(), e = stmt->body_end(); + it != e; ++it) { + HandleUnusedExprResult(*it); + } + return true; + } + bool VisitIfStmt(IfStmt* Stmt) { + HandleUnusedExprResult(Stmt->getThen()); + HandleUnusedExprResult(Stmt->getElse()); + return true; + } + bool VisitWhileStmt(WhileStmt* Stmt) { + HandleUnusedExprResult(Stmt->getBody()); + return true; + } + bool VisitDoStmt(DoStmt* Stmt) { + HandleUnusedExprResult(Stmt->getBody()); + return true; + } + bool VisitForStmt(ForStmt* Stmt) { + HandleUnusedExprResult(Stmt->getBody()); + HandleUnusedExprResult(Stmt->getInit()); + HandleUnusedExprResult(Stmt->getInc()); + return true; + } + bool VisitBinComma(BinaryOperator* Op) { + HandleUnusedExprResult(Op->getLHS()); + return true; + } }; /** @@ -416,6 +529,104 @@ bool isClassRefCounted(QualType T) { return clazz ? isClassRefCounted(clazz) : RegularClass; } +/// A cached data of whether classes are memmovable, and if not, what declaration +/// makes them non-movable +typedef DenseMap InferredMovability; +InferredMovability inferredMovability; + +bool isClassNonMemMovable(QualType T); +const CXXRecordDecl* isClassNonMemMovableWorker(QualType T); + +const CXXRecordDecl* isClassNonMemMovableWorker(const CXXRecordDecl *D) { + // If we have a definition, then we want to standardize our reference to point + // to the definition node. If we don't have a definition, that means that either + // we only have a forward declaration of the type in our file, or we are being + // passed a template argument which is not used, and thus never instantiated by + // clang. + // As the argument isn't used, we can't memmove it (as we don't know it's size), + // which means not reporting an error is OK. + if (!D->hasDefinition()) { + return 0; + } + D = D->getDefinition(); + + // Are we explicitly marked as non-memmovable class? + if (MozChecker::hasCustomAnnotation(D, "moz_non_memmovable")) { + return D; + } + + // Look through all base cases to figure out if the parent is a non-memmovable class. + for (CXXRecordDecl::base_class_const_iterator base = D->bases_begin(); + base != D->bases_end(); ++base) { + const CXXRecordDecl *result = isClassNonMemMovableWorker(base->getType()); + if (result) { + return result; + } + } + + // Look through all members to figure out if a member is a non-memmovable class. + for (RecordDecl::field_iterator field = D->field_begin(), e = D->field_end(); + field != e; ++field) { + const CXXRecordDecl *result = isClassNonMemMovableWorker(field->getType()); + if (result) { + return result; + } + } + + return 0; +} + +const CXXRecordDecl* isClassNonMemMovableWorker(QualType T) { + while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe()) + T = arrTy->getElementType(); + const CXXRecordDecl *clazz = T->getAsCXXRecordDecl(); + return clazz ? isClassNonMemMovableWorker(clazz) : 0; +} + +bool isClassNonMemMovable(const CXXRecordDecl *D) { + InferredMovability::iterator it = + inferredMovability.find(D); + if (it != inferredMovability.end()) + return !!it->second; + const CXXRecordDecl *result = isClassNonMemMovableWorker(D); + inferredMovability.insert(std::make_pair(D, result)); + return !!result; +} + +bool isClassNonMemMovable(QualType T) { + while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe()) + T = arrTy->getElementType(); + const CXXRecordDecl *clazz = T->getAsCXXRecordDecl(); + return clazz ? isClassNonMemMovable(clazz) : false; +} + +const CXXRecordDecl* findWhyClassIsNonMemMovable(QualType T) { + while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe()) + T = arrTy->getElementType(); + CXXRecordDecl *clazz = T->getAsCXXRecordDecl(); + InferredMovability::iterator it = + inferredMovability.find(clazz); + assert(it != inferredMovability.end()); + return it->second; +} + +template +bool IsInSystemHeader(const ASTContext &AC, const T &D) { + auto &SourceManager = AC.getSourceManager(); + auto ExpansionLoc = SourceManager.getExpansionLoc(D.getLocStart()); + if (ExpansionLoc.isInvalid()) { + return false; + } + return SourceManager.isInSystemHeader(ExpansionLoc); +} + +bool typeHasVTable(QualType T) { + while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe()) + T = arrTy->getElementType(); + CXXRecordDecl* offender = T->getAsCXXRecordDecl(); + return offender && offender->hasDefinition() && offender->isDynamicClass(); +} + } namespace clang { @@ -515,12 +726,7 @@ AST_MATCHER(QualType, isFloat) { /// isExpansionInSystemHeader in newer clangs, but modified in order to work /// with old clangs that we use on infra. AST_MATCHER(BinaryOperator, isInSystemHeader) { - auto &SourceManager = Finder->getASTContext().getSourceManager(); - auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart()); - if (ExpansionLoc.isInvalid()) { - return false; - } - return SourceManager.isInSystemHeader(ExpansionLoc); + return IsInSystemHeader(Finder->getASTContext(), Node); } /// This matcher will match locations in SkScalar.h. This header contains a @@ -548,6 +754,51 @@ AST_MATCHER(QualType, isRefCounted) { return isClassRefCounted(Node); } +#if CLANG_VERSION_FULL < 304 + +/// The 'equalsBoundeNode' matcher was added in clang 3.4. +/// Since infra runs clang 3.3, we polyfill it here. +AST_POLYMORPHIC_MATCHER_P(equalsBoundNode, + std::string, ID) { + BoundNodesTree bindings = Builder->build(); + bool haveMatchingResult = false; + struct Visitor : public BoundNodesTree::Visitor { + const NodeType &Node; + std::string ID; + bool &haveMatchingResult; + Visitor(const NodeType &Node, const std::string &ID, bool &haveMatchingResult) + : Node(Node), ID(ID), haveMatchingResult(haveMatchingResult) {} + void visitMatch(const BoundNodes &BoundNodesView) override { + if (BoundNodesView.getNodeAs(ID) == &Node) { + haveMatchingResult = true; + } + } + }; + Visitor visitor(Node, ID, haveMatchingResult); + bindings.visitMatches(&visitor); + return haveMatchingResult; +} + +#endif + +AST_MATCHER(QualType, hasVTable) { + return typeHasVTable(Node); +} + +AST_MATCHER(CXXRecordDecl, hasNeedsNoVTableTypeAttr) { + return MozChecker::hasCustomAnnotation(&Node, "moz_needs_no_vtable_type"); +} + +/// This matcher will select classes which are non-memmovable +AST_MATCHER(QualType, isNonMemMovable) { + return isClassNonMemMovable(Node); +} + +/// This matcher will select classes which require a memmovable template arg +AST_MATCHER(CXXRecordDecl, needsMemMovable) { + return MozChecker::hasCustomAnnotation(&Node, "moz_needs_memmovable_type"); +} + } } @@ -645,10 +896,35 @@ DiagnosticsMatcher::DiagnosticsMatcher() )).bind("node"), &noAddRefReleaseOnReturnChecker); + // Match declrefs with type "pointer to object of ref-counted type" inside a + // lambda, where the declaration they reference is not inside the lambda. + // This excludes arguments and local variables, leaving only captured + // variables. astMatcher.addMatcher(lambdaExpr( - hasDescendant(declRefExpr(hasType(pointerType(pointee(isRefCounted())))).bind("node")) + hasDescendant(declRefExpr(hasType(pointerType(pointee(isRefCounted()))), + to(decl().bind("decl"))).bind("declref")), + unless(hasDescendant(decl(equalsBoundNode("decl")))) ), &refCountedInsideLambdaChecker); + + // Older clang versions such as the ones used on the infra recognize these + // conversions as 'operator _Bool', but newer clang versions recognize these + // as 'operator bool'. + astMatcher.addMatcher(methodDecl(anyOf(hasName("operator bool"), + hasName("operator _Bool"))).bind("node"), + &explicitOperatorBoolChecker); + + astMatcher.addMatcher(classTemplateSpecializationDecl( + allOf(hasAnyTemplateArgument(refersToType(hasVTable())), + hasNeedsNoVTableTypeAttr())).bind("node"), + &needsNoVTableTypeChecker); + + // Handle non-mem-movable template specializations + astMatcher.addMatcher(classTemplateSpecializationDecl( + allOf(needsMemMovable(), + hasAnyTemplateArgument(refersToType(isNonMemMovable()))) + ).bind("specialization"), + &nonMemMovableChecker); } void DiagnosticsMatcher::ScopeChecker::run( @@ -851,14 +1127,99 @@ void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "Refcounted variable %0 of type %1 cannot be used inside a lambda"); + DiagnosticIDs::Error, "Refcounted variable %0 of type %1 cannot be captured by a lambda"); unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Note, "Please consider using a smart pointer"); - const DeclRefExpr *node = Result.Nodes.getNodeAs("node"); + const DeclRefExpr *declref = Result.Nodes.getNodeAs("declref"); - Diag.Report(node->getLocStart(), errorID) << node->getFoundDecl() << - node->getType()->getPointeeType(); - Diag.Report(node->getLocStart(), noteID); + Diag.Report(declref->getLocStart(), errorID) << declref->getFoundDecl() << + declref->getType()->getPointeeType(); + Diag.Report(declref->getLocStart(), noteID); +} + +void DiagnosticsMatcher::ExplicitOperatorBoolChecker::run( + const MatchFinder::MatchResult &Result) { + DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); + unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Error, "bad implicit conversion operator for %0"); + unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Note, "consider adding the explicit keyword to %0"); + const CXXConversionDecl *method = Result.Nodes.getNodeAs("node"); + const CXXRecordDecl *clazz = method->getParent(); + + if (!method->isExplicitSpecified() && + !MozChecker::hasCustomAnnotation(method, "moz_implicit") && + !IsInSystemHeader(method->getASTContext(), *method) && + isInterestingDeclForImplicitConversion(method)) { + Diag.Report(method->getLocStart(), errorID) << clazz; + Diag.Report(method->getLocStart(), noteID) << "'operator bool'"; + } +} + +void DiagnosticsMatcher::NeedsNoVTableTypeChecker::run( + const MatchFinder::MatchResult &Result) { + DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); + unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Error, "%0 cannot be instantiated because %1 has a VTable"); + unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Note, "bad instantiation of %0 requested here"); + + const ClassTemplateSpecializationDecl *specialization = + Result.Nodes.getNodeAs("node"); + + // Get the offending template argument + QualType offender; + const TemplateArgumentList &args = + specialization->getTemplateInstantiationArgs(); + for (unsigned i = 0; i < args.size(); ++i) { + offender = args[i].getAsType(); + if (typeHasVTable(offender)) { + break; + } + } + + Diag.Report(specialization->getLocStart(), errorID) << specialization << offender; + Diag.Report(specialization->getPointOfInstantiation(), noteID) << specialization; +} + +void DiagnosticsMatcher::NonMemMovableChecker::run( + const MatchFinder::MatchResult &Result) { + DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); + unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Error, "Cannot instantiate %0 with non-memmovable template argument %1"); + unsigned note1ID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Note, "instantiation of %0 requested here"); + unsigned note2ID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Note, "%0 is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on %1"); + unsigned note3ID = Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note, "%0"); + + // Get the specialization + const ClassTemplateSpecializationDecl *specialization = + Result.Nodes.getNodeAs("specialization"); + SourceLocation requestLoc = specialization->getPointOfInstantiation(); + const CXXRecordDecl *templ = + specialization->getSpecializedTemplate()->getTemplatedDecl(); + + // Report an error for every template argument which is non-memmovable + const TemplateArgumentList &args = + specialization->getTemplateInstantiationArgs(); + for (unsigned i = 0; i < args.size(); ++i) { + QualType argType = args[i].getAsType(); + if (isClassNonMemMovable(args[i].getAsType())) { + const CXXRecordDecl *reason = findWhyClassIsNonMemMovable(argType); + Diag.Report(specialization->getLocation(), errorID) + << specialization << argType; + // XXX It would be really nice if we could get the instantiation stack information + // from Sema such that we could print a full template instantiation stack, however, + // it seems as though that information is thrown out by the time we get here so we + // can only report one level of template specialization (which in many cases won't + // be useful) + Diag.Report(requestLoc, note1ID) + << specialization; + Diag.Report(reason->getLocation(), note2ID) + << argType << reason; + } + } } class MozCheckAction : public PluginASTAction { diff --git a/build/clang-plugin/tests/TestExplicitOperatorBool.cpp b/build/clang-plugin/tests/TestExplicitOperatorBool.cpp new file mode 100644 index 0000000000..bc4b43a7d0 --- /dev/null +++ b/build/clang-plugin/tests/TestExplicitOperatorBool.cpp @@ -0,0 +1,11 @@ +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +struct Bad { + operator bool(); // expected-error {{bad implicit conversion operator for 'Bad'}} expected-note {{consider adding the explicit keyword to 'operator bool'}} +}; +struct Good { + explicit operator bool(); +}; +struct Okay { + MOZ_IMPLICIT operator bool(); +}; diff --git a/build/clang-plugin/tests/TestMustUse.cpp b/build/clang-plugin/tests/TestMustUse.cpp new file mode 100644 index 0000000000..edcdb1a508 --- /dev/null +++ b/build/clang-plugin/tests/TestMustUse.cpp @@ -0,0 +1,156 @@ +#define MOZ_MUST_USE __attribute__((annotate("moz_must_use"))) + +class MOZ_MUST_USE MustUse {}; +class MayUse {}; + +MustUse producesMustUse(); +MustUse *producesMustUsePointer(); +MustUse &producesMustUseRef(); + +MayUse producesMayUse(); +MayUse *producesMayUsePointer(); +MayUse &producesMayUseRef(); + +void use(MustUse*); +void use(MustUse&); +void use(MustUse&&); +void use(MayUse*); +void use(MayUse&); +void use(MayUse&&); +void use(bool); + +void foo() { + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + { + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + } + if (true) { + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + } else { + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + } + + if(true) producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + else producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + if(true) producesMustUsePointer(); + else producesMustUsePointer(); + if(true) producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + else producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + if(true) producesMayUse(); + else producesMayUse(); + if(true) producesMayUsePointer(); + else producesMayUsePointer(); + if(true) producesMayUseRef(); + else producesMayUseRef(); + + while (true) producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + while (true) producesMustUsePointer(); + while (true) producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + while (true) producesMayUse(); + while (true) producesMayUsePointer(); + while (true) producesMayUseRef(); + + do producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + while (true); + do producesMustUsePointer(); + while (true); + do producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + while (true); + do producesMayUse(); + while (true); + do producesMayUsePointer(); + while (true); + do producesMayUseRef(); + while (true); + + for (;;) producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (;;) producesMustUsePointer(); + for (;;) producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (;;) producesMayUse(); + for (;;) producesMayUsePointer(); + for (;;) producesMayUseRef(); + + for (producesMustUse();;); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (producesMustUsePointer();;); + for (producesMustUseRef();;); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (producesMayUse();;); + for (producesMayUsePointer();;); + for (producesMayUseRef();;); + + for (;;producesMustUse()); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (;;producesMustUsePointer()); + for (;;producesMustUseRef()); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + for (;;producesMayUse()); + for (;;producesMayUsePointer()); + for (;;producesMayUseRef()); + + use((producesMustUse(), false)); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + use((producesMustUsePointer(), false)); + use((producesMustUseRef(), false)); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + use((producesMayUse(), false)); + use((producesMayUsePointer(), false)); + use((producesMayUseRef(), false)); + + switch (1) { + case 1: + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + case 2: + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + case 3: + producesMustUsePointer(); + case 4: + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + case 5: + producesMayUse(); + case 6: + producesMayUsePointer(); + case 7: + producesMayUseRef(); + default: + producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMustUsePointer(); + producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}} + producesMayUse(); + producesMayUsePointer(); + producesMayUseRef(); + } + + use(producesMustUse()); + use(producesMustUsePointer()); + use(producesMustUseRef()); + use(producesMayUse()); + use(producesMayUsePointer()); + use(producesMayUseRef()); + + MustUse a = producesMustUse(); + MustUse *b = producesMustUsePointer(); + MustUse &c = producesMustUseRef(); + MayUse d = producesMayUse(); + MayUse *e = producesMayUsePointer(); + MayUse &f = producesMayUseRef(); +} diff --git a/build/clang-plugin/tests/TestNeedsNoVTableType.cpp b/build/clang-plugin/tests/TestNeedsNoVTableType.cpp new file mode 100644 index 0000000000..531a1c82a1 --- /dev/null +++ b/build/clang-plugin/tests/TestNeedsNoVTableType.cpp @@ -0,0 +1,94 @@ +#define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type"))) + +template +struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer { // expected-error {{'PickyConsumer' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer' cannot be instantiated because 'G' has a VTable}} + T *m; +}; + +template +struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer_A { // expected-error {{'PickyConsumer_A' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer_A' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer_A' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer_A' cannot be instantiated because 'G' has a VTable}} + T *m; +}; +template +struct PickyConsumerWrapper { + PickyConsumer_A m; // expected-note {{bad instantiation of 'PickyConsumer_A' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A' requested here}} +}; + +template +struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer_B { // expected-error {{'PickyConsumer_B' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer_B' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer_B' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer_B' cannot be instantiated because 'G' has a VTable}} + T *m; +}; +template +struct PickyConsumerSubclass : PickyConsumer_B {}; // expected-note {{bad instantiation of 'PickyConsumer_B' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B' requested here}} + +template +struct NonPickyConsumer { + T *m; +}; + +struct A {}; +struct B : virtual A {}; +struct C : A {}; +struct D { + void d(); +}; +struct E { + virtual void e(); +}; +struct F : E { + virtual void e() final; +}; +struct G { + virtual void e() = 0; +}; + +void f() { + { + PickyConsumer a1; + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; // expected-note {{bad instantiation of 'PickyConsumer' requested here}} + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; // expected-note {{bad instantiation of 'PickyConsumer' requested here}} + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; // expected-note {{bad instantiation of 'PickyConsumer' requested here}} + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } + + { + PickyConsumer a1; // expected-note {{bad instantiation of 'PickyConsumer' requested here}} + PickyConsumerWrapper a2; + PickyConsumerSubclass a3; + NonPickyConsumer a4; + } +} diff --git a/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp index 9cc92cf935..20486bbcae 100644 --- a/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp +++ b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp @@ -19,40 +19,76 @@ void take(...); void foo() { R* ptr; SmartPtr sp; - take([&]() { - ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}} + take([&](R* argptr) { + R* localptr; + ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + argptr->method(); + localptr->method(); }); - take([&]() { + take([&](SmartPtr argsp) { + SmartPtr localsp; sp->method(); + argsp->method(); + localsp->method(); }); - take([&]() { - take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}} + take([&](R* argptr) { + R* localptr; + take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + take(argptr); + take(localptr); }); - take([&]() { + take([&](SmartPtr argsp) { + SmartPtr localsp; take(sp); + take(argsp); + take(localsp); }); - take([=]() { - ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}} + take([=](R* argptr) { + R* localptr; + ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + argptr->method(); + localptr->method(); }); - take([=]() { + take([=](SmartPtr argsp) { + SmartPtr localsp; sp->method(); + argsp->method(); + localsp->method(); }); - take([=]() { - take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}} + take([=](R* argptr) { + R* localptr; + take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + take(argptr); + take(localptr); }); - take([=]() { + take([=](SmartPtr argsp) { + SmartPtr localsp; take(sp); + take(argsp); + take(localsp); }); - take([ptr]() { - ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}} + take([ptr](R* argptr) { + R* localptr; + ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + argptr->method(); + localptr->method(); }); - take([sp]() { + take([sp](SmartPtr argsp) { + SmartPtr localsp; sp->method(); + argsp->method(); + localsp->method(); }); - take([ptr]() { - take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}} + take([ptr](R* argptr) { + R* localptr; + take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + take(argptr); + take(localptr); }); - take([sp]() { + take([sp](SmartPtr argsp) { + SmartPtr localsp; take(sp); + take(argsp); + take(localsp); }); } diff --git a/build/clang-plugin/tests/TestNonMemMovable.cpp b/build/clang-plugin/tests/TestNonMemMovable.cpp new file mode 100644 index 0000000000..7f36b2e634 --- /dev/null +++ b/build/clang-plugin/tests/TestNonMemMovable.cpp @@ -0,0 +1,812 @@ +#define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable"))) +#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) + +/* + These are a bunch of structs with variable levels of memmovability. + They will be used as template parameters to the various NeedyTemplates +*/ +struct MOZ_NON_MEMMOVABLE NonMovable {}; // expected-note-re + {{'{{.*}}' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'NonMovable'}} +struct Movable {}; + +// Subclasses +struct S_NonMovable : NonMovable {}; +struct S_Movable : Movable {}; + +// Members +struct W_NonMovable { + NonMovable m; +}; +struct W_Movable { + Movable m; +}; + +// Wrapped Subclasses +struct WS_NonMovable { + S_NonMovable m; +}; +struct WS_Movable { + S_Movable m; +}; + +// Combinations of the above +struct SW_NonMovable : W_NonMovable {}; +struct SW_Movable : W_Movable {}; + +struct SWS_NonMovable : WS_NonMovable {}; +struct SWS_Movable : WS_Movable {}; + +// Basic templated wrapper +template +struct Template_Inline { + T m; +}; + +template +struct Template_Ref { + T* m; +}; + +template +struct Template_Unused {}; + +template +struct MOZ_NON_MEMMOVABLE Template_NonMovable {}; // expected-note-re + {{'{{.*}}' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'Template_NonMovable<{{.*}}>'}} + +/* + These tests take the following form: + DECLARATIONS => Declarations of the templates which are either marked with MOZ_NEEDS_MEMMOVABLE_TYPE + or which instantiate a MOZ_NEEDS_MEMMOVABLE_TYPE through some mechanism. + BAD N => Instantiations of the wrapper template with each of the non-memmovable types. + The prefix S_ means subclass, W_ means wrapped. Each of these rows should produce an error + on the NeedyTemplate in question, and a note at the instantiation location of that template. + Unfortunately, on every case more complicated than bad1, the instantiation location is + within another template. Thus, the notes are expected on the template in question which + actually instantiates the MOZ_NEEDS_MEMMOVABLE_TYPE template. + GOOD N => Instantiations of the wrapper template with each of the memmovable types. + This is meant as a sanity check to ensure that we don't reject valid instantiations of + templates. + + + Note 1: Each set uses it's own types to ensure that they don't re-use each-other's template specializations. + If they did, then some of the error messages would not be emitted (as error messages are emitted for template + specializations, rather than for variable declarations) + + Note 2: Every instance of NeedyTemplate contains a member of type T. This is to ensure that T is actually + instantiated (if T is a template) by clang. If T isn't instantiated, then we can't actually tell if it is + NON_MEMMOVABLE. (This is OK in practice, as you cannot memmove a type which you don't know the size of). + + Note 3: There are a set of tests for specializations of NeedyTemplate at the bottom. For each set of tests, + these tests contribute two expected errors to the templates. +*/ + +// +// 1 - Unwrapped MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate1 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate1<{{.*}}>' with non-memmovable template argument '{{.*}}'}} + +void bad1() { + NeedyTemplate1 a1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 a2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 a3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 a4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 a5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 a6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + + NeedyTemplate1 > b1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > b2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > b3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > b4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > b5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > b6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + + NeedyTemplate1 > c1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c7; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c8; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c9; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c10; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c11; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1 > c12; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} +} + +void good1() { + NeedyTemplate1 a1; + NeedyTemplate1 a2; + NeedyTemplate1 a3; + NeedyTemplate1 a4; + NeedyTemplate1 a5; + NeedyTemplate1 a6; + + NeedyTemplate1 > b1; + NeedyTemplate1 > b2; + NeedyTemplate1 > b3; + NeedyTemplate1 > b4; + NeedyTemplate1 > b5; + NeedyTemplate1 > b6; + + NeedyTemplate1 > c1; + NeedyTemplate1 > c2; + NeedyTemplate1 > c3; + NeedyTemplate1 > c4; + NeedyTemplate1 > c5; + NeedyTemplate1 > c6; + NeedyTemplate1 > c7; + NeedyTemplate1 > c8; + NeedyTemplate1 > c9; + NeedyTemplate1 > c10; + NeedyTemplate1 > c11; + NeedyTemplate1 > c12; + + NeedyTemplate1 > d1; + NeedyTemplate1 > d2; + NeedyTemplate1 > d3; + NeedyTemplate1 > d4; + NeedyTemplate1 > d5; + NeedyTemplate1 > d6; + NeedyTemplate1 > d7; + NeedyTemplate1 > d8; + NeedyTemplate1 > d9; + NeedyTemplate1 > d10; + NeedyTemplate1 > d11; + NeedyTemplate1 > d12; +} + +// +// 2 - Subclassed MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate2 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate2<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template +struct S_NeedyTemplate2 : NeedyTemplate2 {}; // expected-note-re 26 {{instantiation of 'NeedyTemplate2<{{.*}}>' requested here}} + +void bad2() { + S_NeedyTemplate2 a1; + S_NeedyTemplate2 a2; + S_NeedyTemplate2 a3; + S_NeedyTemplate2 a4; + S_NeedyTemplate2 a5; + S_NeedyTemplate2 a6; + + S_NeedyTemplate2 > b1; + S_NeedyTemplate2 > b2; + S_NeedyTemplate2 > b3; + S_NeedyTemplate2 > b4; + S_NeedyTemplate2 > b5; + S_NeedyTemplate2 > b6; + + S_NeedyTemplate2 > c1; + S_NeedyTemplate2 > c2; + S_NeedyTemplate2 > c3; + S_NeedyTemplate2 > c4; + S_NeedyTemplate2 > c5; + S_NeedyTemplate2 > c6; + S_NeedyTemplate2 > c7; + S_NeedyTemplate2 > c8; + S_NeedyTemplate2 > c9; + S_NeedyTemplate2 > c10; + S_NeedyTemplate2 > c11; + S_NeedyTemplate2 > c12; +} + +void good2() { + S_NeedyTemplate2 a1; + S_NeedyTemplate2 a2; + S_NeedyTemplate2 a3; + S_NeedyTemplate2 a4; + S_NeedyTemplate2 a5; + S_NeedyTemplate2 a6; + + S_NeedyTemplate2 > b1; + S_NeedyTemplate2 > b2; + S_NeedyTemplate2 > b3; + S_NeedyTemplate2 > b4; + S_NeedyTemplate2 > b5; + S_NeedyTemplate2 > b6; + + S_NeedyTemplate2 > c1; + S_NeedyTemplate2 > c2; + S_NeedyTemplate2 > c3; + S_NeedyTemplate2 > c4; + S_NeedyTemplate2 > c5; + S_NeedyTemplate2 > c6; + S_NeedyTemplate2 > c7; + S_NeedyTemplate2 > c8; + S_NeedyTemplate2 > c9; + S_NeedyTemplate2 > c10; + S_NeedyTemplate2 > c11; + S_NeedyTemplate2 > c12; + + S_NeedyTemplate2 > d1; + S_NeedyTemplate2 > d2; + S_NeedyTemplate2 > d3; + S_NeedyTemplate2 > d4; + S_NeedyTemplate2 > d5; + S_NeedyTemplate2 > d6; + S_NeedyTemplate2 > d7; + S_NeedyTemplate2 > d8; + S_NeedyTemplate2 > d9; + S_NeedyTemplate2 > d10; + S_NeedyTemplate2 > d11; + S_NeedyTemplate2 > d12; +} + +// +// 3 - Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate3 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate3<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template +struct W_NeedyTemplate3 { + NeedyTemplate3 m; // expected-note-re 26 {{instantiation of 'NeedyTemplate3<{{.*}}>' requested here}} +}; +void bad3() { + W_NeedyTemplate3 a1; + W_NeedyTemplate3 a2; + W_NeedyTemplate3 a3; + W_NeedyTemplate3 a4; + W_NeedyTemplate3 a5; + W_NeedyTemplate3 a6; + + W_NeedyTemplate3 > b1; + W_NeedyTemplate3 > b2; + W_NeedyTemplate3 > b3; + W_NeedyTemplate3 > b4; + W_NeedyTemplate3 > b5; + W_NeedyTemplate3 > b6; + + W_NeedyTemplate3 > c1; + W_NeedyTemplate3 > c2; + W_NeedyTemplate3 > c3; + W_NeedyTemplate3 > c4; + W_NeedyTemplate3 > c5; + W_NeedyTemplate3 > c6; + W_NeedyTemplate3 > c7; + W_NeedyTemplate3 > c8; + W_NeedyTemplate3 > c9; + W_NeedyTemplate3 > c10; + W_NeedyTemplate3 > c11; + W_NeedyTemplate3 > c12; +} + +void good3() { + W_NeedyTemplate3 a1; + W_NeedyTemplate3 a2; + W_NeedyTemplate3 a3; + W_NeedyTemplate3 a4; + W_NeedyTemplate3 a5; + W_NeedyTemplate3 a6; + + W_NeedyTemplate3 > b1; + W_NeedyTemplate3 > b2; + W_NeedyTemplate3 > b3; + W_NeedyTemplate3 > b4; + W_NeedyTemplate3 > b5; + W_NeedyTemplate3 > b6; + + W_NeedyTemplate3 > c1; + W_NeedyTemplate3 > c2; + W_NeedyTemplate3 > c3; + W_NeedyTemplate3 > c4; + W_NeedyTemplate3 > c5; + W_NeedyTemplate3 > c6; + W_NeedyTemplate3 > c7; + W_NeedyTemplate3 > c8; + W_NeedyTemplate3 > c9; + W_NeedyTemplate3 > c10; + W_NeedyTemplate3 > c11; + W_NeedyTemplate3 > c12; + + W_NeedyTemplate3 > d1; + W_NeedyTemplate3 > d2; + W_NeedyTemplate3 > d3; + W_NeedyTemplate3 > d4; + W_NeedyTemplate3 > d5; + W_NeedyTemplate3 > d6; + W_NeedyTemplate3 > d7; + W_NeedyTemplate3 > d8; + W_NeedyTemplate3 > d9; + W_NeedyTemplate3 > d10; + W_NeedyTemplate3 > d11; + W_NeedyTemplate3 > d12; +} + +// +// 4 - Wrapped Subclassed MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate4 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate4<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template +struct S_NeedyTemplate4 : NeedyTemplate4 {}; // expected-note-re 26 {{instantiation of 'NeedyTemplate4<{{.*}}>' requested here}} +template +struct WS_NeedyTemplate4 { + S_NeedyTemplate4 m; +}; +void bad4() { + WS_NeedyTemplate4 a1; + WS_NeedyTemplate4 a2; + WS_NeedyTemplate4 a3; + WS_NeedyTemplate4 a4; + WS_NeedyTemplate4 a5; + WS_NeedyTemplate4 a6; + + WS_NeedyTemplate4 > b1; + WS_NeedyTemplate4 > b2; + WS_NeedyTemplate4 > b3; + WS_NeedyTemplate4 > b4; + WS_NeedyTemplate4 > b5; + WS_NeedyTemplate4 > b6; + + WS_NeedyTemplate4 > c1; + WS_NeedyTemplate4 > c2; + WS_NeedyTemplate4 > c3; + WS_NeedyTemplate4 > c4; + WS_NeedyTemplate4 > c5; + WS_NeedyTemplate4 > c6; + WS_NeedyTemplate4 > c7; + WS_NeedyTemplate4 > c8; + WS_NeedyTemplate4 > c9; + WS_NeedyTemplate4 > c10; + WS_NeedyTemplate4 > c11; + WS_NeedyTemplate4 > c12; +} + +void good4() { + WS_NeedyTemplate4 a1; + WS_NeedyTemplate4 a2; + WS_NeedyTemplate4 a3; + WS_NeedyTemplate4 a4; + WS_NeedyTemplate4 a5; + WS_NeedyTemplate4 a6; + + WS_NeedyTemplate4 > b1; + WS_NeedyTemplate4 > b2; + WS_NeedyTemplate4 > b3; + WS_NeedyTemplate4 > b4; + WS_NeedyTemplate4 > b5; + WS_NeedyTemplate4 > b6; + + WS_NeedyTemplate4 > c1; + WS_NeedyTemplate4 > c2; + WS_NeedyTemplate4 > c3; + WS_NeedyTemplate4 > c4; + WS_NeedyTemplate4 > c5; + WS_NeedyTemplate4 > c6; + WS_NeedyTemplate4 > c7; + WS_NeedyTemplate4 > c8; + WS_NeedyTemplate4 > c9; + WS_NeedyTemplate4 > c10; + WS_NeedyTemplate4 > c11; + WS_NeedyTemplate4 > c12; + + WS_NeedyTemplate4 > d1; + WS_NeedyTemplate4 > d2; + WS_NeedyTemplate4 > d3; + WS_NeedyTemplate4 > d4; + WS_NeedyTemplate4 > d5; + WS_NeedyTemplate4 > d6; + WS_NeedyTemplate4 > d7; + WS_NeedyTemplate4 > d8; + WS_NeedyTemplate4 > d9; + WS_NeedyTemplate4 > d10; + WS_NeedyTemplate4 > d11; + WS_NeedyTemplate4 > d12; +} + +// +// 5 - Subclassed Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate5 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate5<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template +struct W_NeedyTemplate5 { + NeedyTemplate5 m; // expected-note-re 26 {{instantiation of 'NeedyTemplate5<{{.*}}>' requested here}} +}; +template +struct SW_NeedyTemplate5 : W_NeedyTemplate5 {}; +void bad5() { + SW_NeedyTemplate5 a1; + SW_NeedyTemplate5 a2; + SW_NeedyTemplate5 a3; + SW_NeedyTemplate5 a4; + SW_NeedyTemplate5 a5; + SW_NeedyTemplate5 a6; + + SW_NeedyTemplate5 > b1; + SW_NeedyTemplate5 > b2; + SW_NeedyTemplate5 > b3; + SW_NeedyTemplate5 > b4; + SW_NeedyTemplate5 > b5; + SW_NeedyTemplate5 > b6; + + SW_NeedyTemplate5 > c1; + SW_NeedyTemplate5 > c2; + SW_NeedyTemplate5 > c3; + SW_NeedyTemplate5 > c4; + SW_NeedyTemplate5 > c5; + SW_NeedyTemplate5 > c6; + SW_NeedyTemplate5 > c7; + SW_NeedyTemplate5 > c8; + SW_NeedyTemplate5 > c9; + SW_NeedyTemplate5 > c10; + SW_NeedyTemplate5 > c11; + SW_NeedyTemplate5 > c12; +} + +void good5() { + SW_NeedyTemplate5 a1; + SW_NeedyTemplate5 a2; + SW_NeedyTemplate5 a3; + SW_NeedyTemplate5 a4; + SW_NeedyTemplate5 a5; + SW_NeedyTemplate5 a6; + + SW_NeedyTemplate5 > b1; + SW_NeedyTemplate5 > b2; + SW_NeedyTemplate5 > b3; + SW_NeedyTemplate5 > b4; + SW_NeedyTemplate5 > b5; + SW_NeedyTemplate5 > b6; + + SW_NeedyTemplate5 > c1; + SW_NeedyTemplate5 > c2; + SW_NeedyTemplate5 > c3; + SW_NeedyTemplate5 > c4; + SW_NeedyTemplate5 > c5; + SW_NeedyTemplate5 > c6; + SW_NeedyTemplate5 > c7; + SW_NeedyTemplate5 > c8; + SW_NeedyTemplate5 > c9; + SW_NeedyTemplate5 > c10; + SW_NeedyTemplate5 > c11; + SW_NeedyTemplate5 > c12; + + SW_NeedyTemplate5 > d1; + SW_NeedyTemplate5 > d2; + SW_NeedyTemplate5 > d3; + SW_NeedyTemplate5 > d4; + SW_NeedyTemplate5 > d5; + SW_NeedyTemplate5 > d6; + SW_NeedyTemplate5 > d7; + SW_NeedyTemplate5 > d8; + SW_NeedyTemplate5 > d9; + SW_NeedyTemplate5 > d10; + SW_NeedyTemplate5 > d11; + SW_NeedyTemplate5 > d12; +} + +// +// 6 - MOZ_NEEDS_MEMMOVABLE_TYPE instantiated with default template argument +// +// Note: This has an extra error, because it also includes a test with the default template argument. +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate6 {T m;}; // expected-error-re 27 {{Cannot instantiate 'NeedyTemplate6<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template +struct W_NeedyTemplate6 { + NeedyTemplate6 m; // expected-note-re 27 {{instantiation of 'NeedyTemplate6<{{.*}}>' requested here}} +}; +template +struct SW_NeedyTemplate6 : W_NeedyTemplate6 {}; +// We create a different NonMovable type here, as NeedyTemplate6 will already be instantiated with NonMovable +struct MOZ_NON_MEMMOVABLE NonMovable2 {}; // expected-note {{'NonMovable2' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'NonMovable2'}} +template +struct Defaulted_SW_NeedyTemplate6 { + SW_NeedyTemplate6 m; +}; +void bad6() { + Defaulted_SW_NeedyTemplate6 a1; + Defaulted_SW_NeedyTemplate6 a2; + Defaulted_SW_NeedyTemplate6 a3; + Defaulted_SW_NeedyTemplate6 a4; + Defaulted_SW_NeedyTemplate6 a5; + Defaulted_SW_NeedyTemplate6 a6; + + Defaulted_SW_NeedyTemplate6 > b1; + Defaulted_SW_NeedyTemplate6 > b2; + Defaulted_SW_NeedyTemplate6 > b3; + Defaulted_SW_NeedyTemplate6 > b4; + Defaulted_SW_NeedyTemplate6 > b5; + Defaulted_SW_NeedyTemplate6 > b6; + + Defaulted_SW_NeedyTemplate6 > c1; + Defaulted_SW_NeedyTemplate6 > c2; + Defaulted_SW_NeedyTemplate6 > c3; + Defaulted_SW_NeedyTemplate6 > c4; + Defaulted_SW_NeedyTemplate6 > c5; + Defaulted_SW_NeedyTemplate6 > c6; + Defaulted_SW_NeedyTemplate6 > c7; + Defaulted_SW_NeedyTemplate6 > c8; + Defaulted_SW_NeedyTemplate6 > c9; + Defaulted_SW_NeedyTemplate6 > c10; + Defaulted_SW_NeedyTemplate6 > c11; + Defaulted_SW_NeedyTemplate6 > c12; + + Defaulted_SW_NeedyTemplate6<> c13; +} + +void good6() { + Defaulted_SW_NeedyTemplate6 a1; + Defaulted_SW_NeedyTemplate6 a2; + Defaulted_SW_NeedyTemplate6 a3; + Defaulted_SW_NeedyTemplate6 a4; + Defaulted_SW_NeedyTemplate6 a5; + Defaulted_SW_NeedyTemplate6 a6; + + Defaulted_SW_NeedyTemplate6 > b1; + Defaulted_SW_NeedyTemplate6 > b2; + Defaulted_SW_NeedyTemplate6 > b3; + Defaulted_SW_NeedyTemplate6 > b4; + Defaulted_SW_NeedyTemplate6 > b5; + Defaulted_SW_NeedyTemplate6 > b6; + + Defaulted_SW_NeedyTemplate6 > c1; + Defaulted_SW_NeedyTemplate6 > c2; + Defaulted_SW_NeedyTemplate6 > c3; + Defaulted_SW_NeedyTemplate6 > c4; + Defaulted_SW_NeedyTemplate6 > c5; + Defaulted_SW_NeedyTemplate6 > c6; + Defaulted_SW_NeedyTemplate6 > c7; + Defaulted_SW_NeedyTemplate6 > c8; + Defaulted_SW_NeedyTemplate6 > c9; + Defaulted_SW_NeedyTemplate6 > c10; + Defaulted_SW_NeedyTemplate6 > c11; + Defaulted_SW_NeedyTemplate6 > c12; + + Defaulted_SW_NeedyTemplate6 > d1; + Defaulted_SW_NeedyTemplate6 > d2; + Defaulted_SW_NeedyTemplate6 > d3; + Defaulted_SW_NeedyTemplate6 > d4; + Defaulted_SW_NeedyTemplate6 > d5; + Defaulted_SW_NeedyTemplate6 > d6; + Defaulted_SW_NeedyTemplate6 > d7; + Defaulted_SW_NeedyTemplate6 > d8; + Defaulted_SW_NeedyTemplate6 > d9; + Defaulted_SW_NeedyTemplate6 > d10; + Defaulted_SW_NeedyTemplate6 > d11; + Defaulted_SW_NeedyTemplate6 > d12; +} + +// +// 7 - MOZ_NEEDS_MEMMOVABLE_TYPE instantiated as default template argument +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate7 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate7<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template > +struct Defaulted_Templated_NeedyTemplate7 {Q m;}; // expected-note-re 26 {{instantiation of 'NeedyTemplate7<{{.*}}>' requested here}} +void bad7() { + Defaulted_Templated_NeedyTemplate7 a1; + Defaulted_Templated_NeedyTemplate7 a2; + Defaulted_Templated_NeedyTemplate7 a3; + Defaulted_Templated_NeedyTemplate7 a4; + Defaulted_Templated_NeedyTemplate7 a5; + Defaulted_Templated_NeedyTemplate7 a6; + + Defaulted_Templated_NeedyTemplate7 > b1; + Defaulted_Templated_NeedyTemplate7 > b2; + Defaulted_Templated_NeedyTemplate7 > b3; + Defaulted_Templated_NeedyTemplate7 > b4; + Defaulted_Templated_NeedyTemplate7 > b5; + Defaulted_Templated_NeedyTemplate7 > b6; + + Defaulted_Templated_NeedyTemplate7 > c1; + Defaulted_Templated_NeedyTemplate7 > c2; + Defaulted_Templated_NeedyTemplate7 > c3; + Defaulted_Templated_NeedyTemplate7 > c4; + Defaulted_Templated_NeedyTemplate7 > c5; + Defaulted_Templated_NeedyTemplate7 > c6; + Defaulted_Templated_NeedyTemplate7 > c7; + Defaulted_Templated_NeedyTemplate7 > c8; + Defaulted_Templated_NeedyTemplate7 > c9; + Defaulted_Templated_NeedyTemplate7 > c10; + Defaulted_Templated_NeedyTemplate7 > c11; + Defaulted_Templated_NeedyTemplate7 > c12; +} + +void good7() { + Defaulted_Templated_NeedyTemplate7 a1; + Defaulted_Templated_NeedyTemplate7 a2; + Defaulted_Templated_NeedyTemplate7 a3; + Defaulted_Templated_NeedyTemplate7 a4; + Defaulted_Templated_NeedyTemplate7 a5; + Defaulted_Templated_NeedyTemplate7 a6; + + Defaulted_Templated_NeedyTemplate7 > b1; + Defaulted_Templated_NeedyTemplate7 > b2; + Defaulted_Templated_NeedyTemplate7 > b3; + Defaulted_Templated_NeedyTemplate7 > b4; + Defaulted_Templated_NeedyTemplate7 > b5; + Defaulted_Templated_NeedyTemplate7 > b6; + + Defaulted_Templated_NeedyTemplate7 > c1; + Defaulted_Templated_NeedyTemplate7 > c2; + Defaulted_Templated_NeedyTemplate7 > c3; + Defaulted_Templated_NeedyTemplate7 > c4; + Defaulted_Templated_NeedyTemplate7 > c5; + Defaulted_Templated_NeedyTemplate7 > c6; + Defaulted_Templated_NeedyTemplate7 > c7; + Defaulted_Templated_NeedyTemplate7 > c8; + Defaulted_Templated_NeedyTemplate7 > c9; + Defaulted_Templated_NeedyTemplate7 > c10; + Defaulted_Templated_NeedyTemplate7 > c11; + Defaulted_Templated_NeedyTemplate7 > c12; + + Defaulted_Templated_NeedyTemplate7 > d1; + Defaulted_Templated_NeedyTemplate7 > d2; + Defaulted_Templated_NeedyTemplate7 > d3; + Defaulted_Templated_NeedyTemplate7 > d4; + Defaulted_Templated_NeedyTemplate7 > d5; + Defaulted_Templated_NeedyTemplate7 > d6; + Defaulted_Templated_NeedyTemplate7 > d7; + Defaulted_Templated_NeedyTemplate7 > d8; + Defaulted_Templated_NeedyTemplate7 > d9; + Defaulted_Templated_NeedyTemplate7 > d10; + Defaulted_Templated_NeedyTemplate7 > d11; + Defaulted_Templated_NeedyTemplate7 > d12; +} + +// +// 8 - Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE instantiated as default template argument +// + +template +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate8 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate8<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template > +struct Defaulted_Templated_NeedyTemplate8 {Q m;}; // expected-note-re 26 {{instantiation of 'NeedyTemplate8<{{.*}}>' requested here}} +template +struct W_Defaulted_Templated_NeedyTemplate8 { + Defaulted_Templated_NeedyTemplate8 m; +}; +void bad8() { + W_Defaulted_Templated_NeedyTemplate8 a1; + W_Defaulted_Templated_NeedyTemplate8 a2; + W_Defaulted_Templated_NeedyTemplate8 a3; + W_Defaulted_Templated_NeedyTemplate8 a4; + W_Defaulted_Templated_NeedyTemplate8 a5; + W_Defaulted_Templated_NeedyTemplate8 a6; + + W_Defaulted_Templated_NeedyTemplate8 > b1; + W_Defaulted_Templated_NeedyTemplate8 > b2; + W_Defaulted_Templated_NeedyTemplate8 > b3; + W_Defaulted_Templated_NeedyTemplate8 > b4; + W_Defaulted_Templated_NeedyTemplate8 > b5; + W_Defaulted_Templated_NeedyTemplate8 > b6; + + W_Defaulted_Templated_NeedyTemplate8 > c1; + W_Defaulted_Templated_NeedyTemplate8 > c2; + W_Defaulted_Templated_NeedyTemplate8 > c3; + W_Defaulted_Templated_NeedyTemplate8 > c4; + W_Defaulted_Templated_NeedyTemplate8 > c5; + W_Defaulted_Templated_NeedyTemplate8 > c6; + W_Defaulted_Templated_NeedyTemplate8 > c7; + W_Defaulted_Templated_NeedyTemplate8 > c8; + W_Defaulted_Templated_NeedyTemplate8 > c9; + W_Defaulted_Templated_NeedyTemplate8 > c10; + W_Defaulted_Templated_NeedyTemplate8 > c11; + W_Defaulted_Templated_NeedyTemplate8 > c12; +} + +void good8() { + W_Defaulted_Templated_NeedyTemplate8 a1; + W_Defaulted_Templated_NeedyTemplate8 a2; + W_Defaulted_Templated_NeedyTemplate8 a3; + W_Defaulted_Templated_NeedyTemplate8 a4; + W_Defaulted_Templated_NeedyTemplate8 a5; + W_Defaulted_Templated_NeedyTemplate8 a6; + + W_Defaulted_Templated_NeedyTemplate8 > b1; + W_Defaulted_Templated_NeedyTemplate8 > b2; + W_Defaulted_Templated_NeedyTemplate8 > b3; + W_Defaulted_Templated_NeedyTemplate8 > b4; + W_Defaulted_Templated_NeedyTemplate8 > b5; + W_Defaulted_Templated_NeedyTemplate8 > b6; + + W_Defaulted_Templated_NeedyTemplate8 > c1; + W_Defaulted_Templated_NeedyTemplate8 > c2; + W_Defaulted_Templated_NeedyTemplate8 > c3; + W_Defaulted_Templated_NeedyTemplate8 > c4; + W_Defaulted_Templated_NeedyTemplate8 > c5; + W_Defaulted_Templated_NeedyTemplate8 > c6; + W_Defaulted_Templated_NeedyTemplate8 > c7; + W_Defaulted_Templated_NeedyTemplate8 > c8; + W_Defaulted_Templated_NeedyTemplate8 > c9; + W_Defaulted_Templated_NeedyTemplate8 > c10; + W_Defaulted_Templated_NeedyTemplate8 > c11; + W_Defaulted_Templated_NeedyTemplate8 > c12; + + W_Defaulted_Templated_NeedyTemplate8 > d1; + W_Defaulted_Templated_NeedyTemplate8 > d2; + W_Defaulted_Templated_NeedyTemplate8 > d3; + W_Defaulted_Templated_NeedyTemplate8 > d4; + W_Defaulted_Templated_NeedyTemplate8 > d5; + W_Defaulted_Templated_NeedyTemplate8 > d6; + W_Defaulted_Templated_NeedyTemplate8 > d7; + W_Defaulted_Templated_NeedyTemplate8 > d8; + W_Defaulted_Templated_NeedyTemplate8 > d9; + W_Defaulted_Templated_NeedyTemplate8 > d10; + W_Defaulted_Templated_NeedyTemplate8 > d11; + W_Defaulted_Templated_NeedyTemplate8 > d12; +} + +/* + SpecializedNonMovable is a non-movable class which has an explicit specialization of NeedyTemplate + for it. Instantiations of NeedyTemplateN should be legal as the explicit + specialization isn't annotated with MOZ_NEEDS_MEMMOVABLE_TYPE. + + However, as it is MOZ_NON_MEMMOVABLE, derived classes and members shouldn't be able to be used to + instantiate NeedyTemplate. +*/ + +struct MOZ_NON_MEMMOVABLE SpecializedNonMovable {}; // expected-note 8 {{'S_SpecializedNonMovable' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'SpecializedNonMovable'}} expected-note 8 {{'Template_Inline' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'SpecializedNonMovable'}} +struct S_SpecializedNonMovable : SpecializedNonMovable {}; + +// Specialize all of the NeedyTemplates with SpecializedNonMovable. +template <> +struct NeedyTemplate1 {}; +template <> +struct NeedyTemplate2 {}; +template <> +struct NeedyTemplate3 {}; +template <> +struct NeedyTemplate4 {}; +template <> +struct NeedyTemplate5 {}; +template <> +struct NeedyTemplate6 {}; +template <> +struct NeedyTemplate7 {}; +template <> +struct NeedyTemplate8 {}; + +void specialization() { + /* + SpecializedNonMovable has a specialization for every variant of NeedyTemplate, + so these templates are valid, even though SpecializedNonMovable isn't + memmovable + */ + NeedyTemplate1 a1; + S_NeedyTemplate2 a2; + W_NeedyTemplate3 a3; + WS_NeedyTemplate4 a4; + SW_NeedyTemplate5 a5; + Defaulted_SW_NeedyTemplate6 a6; + Defaulted_Templated_NeedyTemplate7 a7; + W_Defaulted_Templated_NeedyTemplate8 a8; + + /* + These entries contain an element which is SpecializedNonMovable, and are non-movable + as there is no valid specialization, and their member is non-memmovable + */ + NeedyTemplate1 > b1; // expected-note {{instantiation of 'NeedyTemplate1 >' requested here}} + S_NeedyTemplate2 > b2; + W_NeedyTemplate3 > b3; + WS_NeedyTemplate4 > b4; + SW_NeedyTemplate5 > b5; + Defaulted_SW_NeedyTemplate6 > b6; + Defaulted_Templated_NeedyTemplate7 > b7; + W_Defaulted_Templated_NeedyTemplate8 > b8; + + /* + The subclass of SpecializedNonMovable, is also non-memmovable, + as there is no valid specialization. + */ + NeedyTemplate1 c1; // expected-note {{instantiation of 'NeedyTemplate1' requested here}} + S_NeedyTemplate2 c2; + W_NeedyTemplate3 c3; + WS_NeedyTemplate4 c4; + SW_NeedyTemplate5 c5; + Defaulted_SW_NeedyTemplate6 c6; + Defaulted_Templated_NeedyTemplate7 c7; + W_Defaulted_Templated_NeedyTemplate8 c8; +} diff --git a/build/clang-plugin/tests/moz.build b/build/clang-plugin/tests/moz.build index c52fc5c7e5..b14bd73a23 100644 --- a/build/clang-plugin/tests/moz.build +++ b/build/clang-plugin/tests/moz.build @@ -10,13 +10,17 @@ Library('clang-plugin-tests') SOURCES += [ 'TestBadImplicitConversionCtor.cpp', 'TestCustomHeap.cpp', + 'TestExplicitOperatorBool.cpp', 'TestGlobalClass.cpp', 'TestMustOverride.cpp', + 'TestMustUse.cpp', 'TestNANTestingExpr.cpp', 'TestNANTestingExprC.c', + 'TestNeedsNoVTableType.cpp', 'TestNoAddRefReleaseOnReturn.cpp', 'TestNoArithmeticExprInArgument.cpp', 'TestNonHeapClass.cpp', + 'TestNonMemMovable.cpp', 'TestNoRefcountedInsideLambdas.cpp', 'TestStackClass.cpp', 'TestTrivialCtorDtor.cpp', diff --git a/dom/base/TextInputProcessor.cpp b/dom/base/TextInputProcessor.cpp index 78bde607c5..afd5c17a56 100644 --- a/dom/base/TextInputProcessor.cpp +++ b/dom/base/TextInputProcessor.cpp @@ -4,6 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "gfxPrefs.h" #include "mozilla/EventForwards.h" #include "mozilla/TextEventDispatcher.h" #include "mozilla/TextEvents.h" @@ -765,6 +766,23 @@ TextInputProcessor::Keydown(nsIDOMKeyEvent* aDOMKeyEvent, return KeydownInternal(*originalKeyEvent, aKeyFlags, true, *aDoDefault); } +TextEventDispatcher::DispatchTo +TextInputProcessor::GetDispatchTo() const +{ + // Support asynchronous tests. + if (mForTests) { + return gfxPrefs::TestEventsAsyncEnabled() ? + TextEventDispatcher::eDispatchToParentProcess : + TextEventDispatcher::eDispatchToCurrentProcess; + } + + // Otherwise, TextInputProcessor supports only keyboard apps on B2G. + // Keyboard apps on B2G doesn't want to dispatch keyboard events to + // chrome process. Therefore, this should dispatch key events only in + // the current process. + return TextEventDispatcher::eDispatchToCurrentProcess; +} + nsresult TextInputProcessor::KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent, uint32_t aKeyFlags, @@ -809,14 +827,15 @@ TextInputProcessor::KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent, nsEventStatus status = aDoDefault ? nsEventStatus_eIgnore : nsEventStatus_eConsumeNoDefault; - if (!mDispatcher->DispatchKeyboardEvent(NS_KEY_DOWN, keyEvent, status)) { + if (!mDispatcher->DispatchKeyboardEvent(NS_KEY_DOWN, keyEvent, status, + GetDispatchTo())) { // If keydown event isn't dispatched, we don't need to dispatch keypress // events. return NS_OK; } if (aAllowToDispatchKeypress) { - mDispatcher->MaybeDispatchKeypressEvents(keyEvent, status); + mDispatcher->MaybeDispatchKeypressEvents(keyEvent, status, GetDispatchTo()); } aDoDefault = (status != nsEventStatus_eConsumeNoDefault); @@ -883,7 +902,8 @@ TextInputProcessor::KeyupInternal(const WidgetKeyboardEvent& aKeyboardEvent, nsEventStatus status = aDoDefault ? nsEventStatus_eIgnore : nsEventStatus_eConsumeNoDefault; - mDispatcher->DispatchKeyboardEvent(NS_KEY_UP, keyEvent, status); + mDispatcher->DispatchKeyboardEvent(NS_KEY_UP, keyEvent, status, + GetDispatchTo()); aDoDefault = (status != nsEventStatus_eConsumeNoDefault); return NS_OK; } diff --git a/dom/base/TextInputProcessor.h b/dom/base/TextInputProcessor.h index 14b7a2fb5d..7359f026b0 100644 --- a/dom/base/TextInputProcessor.h +++ b/dom/base/TextInputProcessor.h @@ -9,6 +9,7 @@ #include "mozilla/Attributes.h" #include "mozilla/EventForwards.h" +#include "mozilla/TextEventDispatcher.h" #include "mozilla/TextEventDispatcherListener.h" #include "nsAutoPtr.h" #include "nsITextInputProcessor.h" @@ -17,10 +18,6 @@ namespace mozilla { -namespace widget{ -class TextEventDispatcher; -} // namespace widget - class TextInputProcessor final : public nsITextInputProcessor , public widget::TextEventDispatcherListener { @@ -64,6 +61,7 @@ private: nsresult KeyupInternal(const WidgetKeyboardEvent& aKeyboardEvent, uint32_t aKeyFlags, bool& aDoDefault); + TextEventDispatcher::DispatchTo GetDispatchTo() const; nsresult IsValidStateForComposition(); void UnlinkFromTextEventDispatcher(); nsresult PrepareKeyboardEventToDispatch(WidgetKeyboardEvent& aKeyboardEvent, diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 651e6994ca..7686034d5e 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -26,6 +26,7 @@ #include "MediaDecoder.h" // nsNPAPIPluginInstance must be included before nsIDocument.h, which is included in mozAutoDocUpdate.h. #include "nsNPAPIPluginInstance.h" +#include "gfxPrefs.h" #include "mozAutoDocUpdate.h" #include "mozilla/ArrayUtils.h" #include "mozilla/Attributes.h" diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index beae5da358..d975539719 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -41,6 +41,8 @@ #include "nsIContentPolicy.h" #include "nsSVGEffects.h" +#include "gfxPrefs.h" + #include "mozAutoDocUpdate.h" #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/EventStates.h" diff --git a/dom/bindings/CallbackObject.h b/dom/bindings/CallbackObject.h index f9a387c36f..37aea20df9 100644 --- a/dom/bindings/CallbackObject.h +++ b/dom/bindings/CallbackObject.h @@ -304,7 +304,7 @@ public: } // Boolean conversion operator so people can use this in boolean tests - operator bool() const + explicit operator bool() const { return GetISupports(); } diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 358f4cab7f..405605a184 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -53,6 +53,7 @@ #include "gfxPlatform.h" #include "gfxFont.h" #include "gfxBlur.h" +#include "gfxPrefs.h" #include "gfxUtils.h" #include "nsFrameLoader.h" diff --git a/dom/gamepad/linux/udev.h b/dom/gamepad/linux/udev.h index d2be4d27fb..18da9f7dc7 100644 --- a/dom/gamepad/linux/udev.h +++ b/dom/gamepad/linux/udev.h @@ -65,7 +65,7 @@ class udev_lib { } } - operator bool() { + explicit operator bool() { return udev; } diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index 847bc38d15..d0f04a5db7 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -643,7 +643,7 @@ protected: void SetOuter(HTMLMediaElement* outer) { mOuter = outer; } void SetCanPlay(bool aCanPlay); - operator bool() const { return mValue; } + MOZ_IMPLICIT operator bool() const { return mValue; } WakeLockBoolWrapper& operator=(bool val); diff --git a/dom/media/SelfRef.h b/dom/media/SelfRef.h index 7c0327cb49..ca9d0b749f 100644 --- a/dom/media/SelfRef.h +++ b/dom/media/SelfRef.h @@ -35,7 +35,7 @@ public: } } - operator bool() const { return mHeld; } + MOZ_IMPLICIT operator bool() const { return mHeld; } SelfReference(const SelfReference& aOther) = delete; void operator=(const SelfReference& aOther) = delete; diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 4b8c1fd86c..d6dcb4ca5e 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -1167,7 +1167,7 @@ public: if (plugin) mLibrary = plugin->GetLibrary(); } - operator bool() { return !!mLibrary; } + explicit operator bool() { return !!mLibrary; } PluginLibrary* operator->() { return mLibrary; } private: diff --git a/dom/plugins/ipc/PluginScriptableObjectUtils.h b/dom/plugins/ipc/PluginScriptableObjectUtils.h index 432c53b777..bef2113c79 100644 --- a/dom/plugins/ipc/PluginScriptableObjectUtils.h +++ b/dom/plugins/ipc/PluginScriptableObjectUtils.h @@ -277,7 +277,7 @@ public: return mActor; } - operator bool() + explicit operator bool() { return !!mActor; } diff --git a/dom/workers/ServiceWorkerContainer.cpp b/dom/workers/ServiceWorkerContainer.cpp index e2c7a342c7..6b4ec84e18 100644 --- a/dom/workers/ServiceWorkerContainer.cpp +++ b/dom/workers/ServiceWorkerContainer.cpp @@ -8,6 +8,7 @@ #include "nsIDocument.h" #include "nsIServiceWorkerManager.h" +#include "nsNetUtil.h" #include "nsPIDOMWindow.h" #include "mozilla/Services.h" diff --git a/gfx/layers/FrameMetrics.cpp b/gfx/layers/FrameMetrics.cpp new file mode 100644 index 0000000000..a4cf2b579a --- /dev/null +++ b/gfx/layers/FrameMetrics.cpp @@ -0,0 +1,22 @@ +/* -*- 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 "FrameMetrics.h" +#include "gfxPrefs.h" + +namespace mozilla { +namespace layers { + +const FrameMetrics::ViewID FrameMetrics::NULL_SCROLL_ID = 0; +const FrameMetrics FrameMetrics::sNullMetrics; + +void +FrameMetrics::SetUsesContainerScrolling(bool aValue) { + MOZ_ASSERT_IF(aValue, gfxPrefs::LayoutUseContainersForRootFrames()); + mUsesContainerScrolling = aValue; +} + +} +} \ No newline at end of file diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index 68c95e2ea8..a12c08018f 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -14,7 +14,6 @@ #include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor #include "mozilla/gfx/Logging.h" // for Log #include "gfxColor.h" -#include "gfxPrefs.h" // for LayoutUseContainersForRootFrames #include "nsString.h" namespace IPC { @@ -554,10 +553,9 @@ public: return mIsLayersIdRoot; } - void SetUsesContainerScrolling(bool aValue) { - MOZ_ASSERT_IF(aValue, gfxPrefs::LayoutUseContainersForRootFrames()); - mUsesContainerScrolling = aValue; - } + // Implemented out of line because the implementation needs gfxPrefs.h + // and we don't want to include that from FrameMetrics.h. + void SetUsesContainerScrolling(bool aValue); bool UsesContainerScrolling() const { return mUsesContainerScrolling; } diff --git a/gfx/layers/ImageLayers.cpp b/gfx/layers/ImageLayers.cpp index 0b46aa8b3a..d02ec48466 100644 --- a/gfx/layers/ImageLayers.cpp +++ b/gfx/layers/ImageLayers.cpp @@ -57,7 +57,7 @@ void ImageLayer::ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSu mEffectiveTransformForBuffer = mEffectiveTransform; } - ComputeEffectiveTransformForMaskLayer(aTransformToSurface); + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); } } // namespace layers diff --git a/gfx/layers/LayerScope.cpp b/gfx/layers/LayerScope.cpp index 349d141acc..f78a55d50c 100644 --- a/gfx/layers/LayerScope.cpp +++ b/gfx/layers/LayerScope.cpp @@ -191,6 +191,8 @@ public: gfx::Matrix4x4 mMVMatrix; size_t mRects; gfx::Rect mLayerRects[4]; + gfx::Rect mTextureRects[4]; + std::list mTexIDs; }; class ContentMonitor { @@ -289,6 +291,18 @@ public: return *mSession; } + void SetPixelScale(double scale) { + mScale = scale; + } + + double GetPixelScale() const { + return mScale; + } + + LayerScopeManager() + : mScale(1.0) + { + } private: friend class CreateServerSocketRunnable; class CreateServerSocketRunnable : public nsRunnable @@ -310,6 +324,7 @@ private: mozilla::UniquePtr mWebSocketManager; mozilla::UniquePtr mSession; mozilla::UniquePtr mContentMonitor; + double mScale; }; LayerScopeManager gLayerScopeManager; @@ -367,6 +382,8 @@ public: FramePacket* fp = packet.mutable_frame(); fp->set_value(static_cast(mFrameStamp)); + fp->set_scale(gLayerScopeManager.GetPixelScale()); + return WriteToStream(packet); } @@ -623,16 +640,20 @@ public: const gfx::Matrix4x4& aMVMatrix, size_t aRects, const gfx::Rect* aLayerRects, + const gfx::Rect* aTextureRects, + const std::list aTexIDs, void* aLayerRef) : DebugGLData(Packet::DRAW), mOffsetX(aOffsetX), mOffsetY(aOffsetY), mMVMatrix(aMVMatrix), mRects(aRects), + mTexIDs(aTexIDs), mLayerRef(reinterpret_cast(aLayerRef)) { for (size_t i = 0; i < mRects; i++){ mLayerRects[i] = aLayerRects[i]; + mTextureRects[i] = aTextureRects[i]; } } @@ -654,11 +675,23 @@ 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); + + // 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); + } + + for (GLuint texId: mTexIDs) { + dp->add_texids(texId); } return WriteToStream(packet); @@ -670,6 +703,8 @@ protected: gfx::Matrix4x4 mMVMatrix; size_t mRects; gfx::Rect mLayerRects[4]; + gfx::Rect mTextureRects[4]; + std::list mTexIDs; uint64_t mLayerRef; }; @@ -955,6 +990,8 @@ SenderHelper::SendTextureSource(GLContext* aGLContext, aTexID, img)); sTextureIdList.push_back(aTexID); + gLayerScopeManager.CurrentSession().mTexIDs.push_back(aTexID); + } #ifdef MOZ_WIDGET_GONK @@ -983,6 +1020,8 @@ SenderHelper::SendGraphicBuffer(void* aLayerRef, gLayerScopeManager.GetSocketManager()->AppendDebugData(package.release()); sTextureIdList.push_back(aTexID); + gLayerScopeManager.CurrentSession().mTexIDs.push_back(aTexID); + gLayerScopeManager.GetContentMonitor()->ClearChangedHost(aEffect->mState.mTexture); return true; } @@ -1585,7 +1624,8 @@ LayerScope::DrawBegin() gLayerScopeManager.NewDrawSession(); } -void LayerScope::SetRenderOffset(float aX, float aY) +void +LayerScope::SetRenderOffset(float aX, float aY) { if (!CheckSendable()) { return; @@ -1595,7 +1635,8 @@ void LayerScope::SetRenderOffset(float aX, float aY) gLayerScopeManager.CurrentSession().mOffsetY = aY; } -void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix) +void +LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix) { if (!CheckSendable()) { return; @@ -1604,7 +1645,10 @@ void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix) gLayerScopeManager.CurrentSession().mMVMatrix = aMatrix; } -void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects) +void +LayerScope::SetDrawRects(size_t aRects, + const gfx::Rect* aLayerRects, + const gfx::Rect* aTextureRects) { if (!CheckSendable()) { return; @@ -1617,6 +1661,7 @@ void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects) for (size_t i = 0; i < aRects; i++){ gLayerScopeManager.CurrentSession().mLayerRects[i] = aLayerRects[i]; + gLayerScopeManager.CurrentSession().mTextureRects[i] = aTextureRects[i]; } } @@ -1631,17 +1676,20 @@ LayerScope::DrawEnd(gl::GLContext* aGLContext, return; } - // 1. Send parameters of draw call, such as uniforms and attributes of + // 1. Send textures. + SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight); + + // 2. Send parameters of draw call, such as uniforms and attributes of // vertex adnd fragment shader. DrawSession& draws = gLayerScopeManager.CurrentSession(); gLayerScopeManager.GetSocketManager()->AppendDebugData( new DebugGLDrawData(draws.mOffsetX, draws.mOffsetY, draws.mMVMatrix, draws.mRects, draws.mLayerRects, + draws.mTextureRects, + draws.mTexIDs, aEffectChain.mLayerRef)); - // 2. Send textures. - SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight); } void @@ -1703,6 +1751,11 @@ LayerScope::SetHWComposed() } } +void +LayerScope::SetPixelScale(double devPixelsPerCSSPixel) +{ + gLayerScopeManager.SetPixelScale(devPixelsPerCSSPixel); +} // ---------------------------------------------- // LayerScopeAutoFrame implementation // ---------------------------------------------- @@ -1721,11 +1774,10 @@ LayerScopeAutoFrame::~LayerScopeAutoFrame() void LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp) { - SenderHelper::ClearTextureIdList(); - if (!LayerScope::CheckSendable()) { return; } + SenderHelper::ClearTextureIdList(); gLayerScopeManager.GetSocketManager()->AppendDebugData( new DebugGLFrameStatusData(Packet::FRAMESTART, aFrameStamp)); diff --git a/gfx/layers/LayerScope.h b/gfx/layers/LayerScope.h index 42e778a4d8..0f258cdb68 100644 --- a/gfx/layers/LayerScope.h +++ b/gfx/layers/LayerScope.h @@ -26,7 +26,9 @@ public: static void DrawBegin(); static void SetRenderOffset(float aX, float aY); static void SetLayerTransform(const gfx::Matrix4x4& aMatrix); - static void SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects); + static void SetDrawRects(size_t aRects, + const gfx::Rect* aLayerRects, + const gfx::Rect* aTextureRects); static void DrawEnd(gl::GLContext* aGLContext, const EffectChain& aEffectChain, int aWidth, @@ -40,6 +42,7 @@ public: static void CleanLayer(); static void SetHWComposed(); + static void SetPixelScale(double devPixelsPerCSSPixel); static void ContentChanged(TextureHost *host); private: static void Init(); diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 3d5abf92bf..906fc995fb 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -36,6 +36,7 @@ #include "nsPrintfCString.h" // for nsPrintfCString #include "nsStyleStruct.h" // for nsTimingFunction, etc #include "protobuf/LayerScopePacket.pb.h" +#include "mozilla/Compression.h" uint8_t gLayerManagerLayerBuilder; @@ -49,10 +50,9 @@ FILEOrDefault(FILE* aFile) } typedef FrameMetrics::ViewID ViewID; -const ViewID FrameMetrics::NULL_SCROLL_ID = 0; -const FrameMetrics FrameMetrics::sNullMetrics; using namespace mozilla::gfx; +using namespace mozilla::Compression; //-------------------------------------------------- // LayerManager @@ -227,10 +227,14 @@ Layer::Layer(LayerManager* aManager, void* aImplData) : mIsScrollbarContainer(false), mDebugColorIndex(0), mAnimationGeneration(0) -{} +{ + MOZ_COUNT_CTOR(Layer); +} Layer::~Layer() -{} +{ + MOZ_COUNT_DTOR(Layer); +} Animation* Layer::AddAnimation() @@ -857,21 +861,31 @@ Layer::DeprecatedGetEffectiveMixBlendMode() } void -Layer::ComputeEffectiveTransformForMaskLayer(const Matrix4x4& aTransformToSurface) +Layer::ComputeEffectiveTransformForMaskLayers(const gfx::Matrix4x4& aTransformToSurface) { - if (mMaskLayer) { - mMaskLayer->mEffectiveTransform = aTransformToSurface; + if (GetMaskLayer()) { + ComputeEffectiveTransformForMaskLayer(GetMaskLayer(), aTransformToSurface); + } + for (size_t i = 0; i < GetAncestorMaskLayerCount(); i++) { + Layer* maskLayer = GetAncestorMaskLayerAt(i); + ComputeEffectiveTransformForMaskLayer(maskLayer, aTransformToSurface); + } +} + +/* static */ void +Layer::ComputeEffectiveTransformForMaskLayer(Layer* aMaskLayer, const gfx::Matrix4x4& aTransformToSurface) +{ + aMaskLayer->mEffectiveTransform = aTransformToSurface; #ifdef DEBUG - bool maskIs2D = mMaskLayer->GetTransform().CanDraw2D(); - NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!"); + bool maskIs2D = aMaskLayer->GetTransform().CanDraw2D(); + NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!"); #endif - // The mask layer can have an async transform applied to it in some - // situations, so be sure to use its GetLocalTransform() rather than - // its GetTransform(). - mMaskLayer->mEffectiveTransform = mMaskLayer->GetLocalTransform() * - mMaskLayer->mEffectiveTransform; - } + // The mask layer can have an async transform applied to it in some + // situations, so be sure to use its GetLocalTransform() rather than + // its GetTransform(). + aMaskLayer->mEffectiveTransform = aMaskLayer->GetLocalTransform() * + aMaskLayer->mEffectiveTransform; } RenderTargetRect @@ -981,10 +995,14 @@ ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData) mChildrenChanged(false), mEventRegionsOverride(EventRegionsOverride::NoOverride) { + MOZ_COUNT_CTOR(ContainerLayer); mContentFlags = 0; // Clear NO_TEXT, NO_TEXT_OVER_TRANSPARENT } -ContainerLayer::~ContainerLayer() {} +ContainerLayer::~ContainerLayer() +{ + MOZ_COUNT_DTOR(ContainerLayer); +} bool ContainerLayer::InsertAfter(Layer* aChild, Layer* aAfter) @@ -1236,9 +1254,9 @@ ContainerLayer::DefaultComputeEffectiveTransforms(const Matrix4x4& aTransformToS } if (idealTransform.CanDraw2D()) { - ComputeEffectiveTransformForMaskLayer(aTransformToSurface); + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); } else { - ComputeEffectiveTransformForMaskLayer(Matrix4x4()); + ComputeEffectiveTransformForMaskLayers(Matrix4x4()); } } @@ -1575,6 +1593,35 @@ Layer::Dump(layerscope::LayersPacket* aPacket, const void* aParent) } } +void +Layer::SetDisplayListLog(const char* log) +{ + if (gfxUtils::DumpDisplayList()) { + mDisplayListLog = log; + } +} + +void +Layer::GetDisplayListLog(nsCString& log) +{ + log.SetLength(0); + + if (gfxUtils::DumpDisplayList()) { + // This function returns a plain text string which consists of two things + // 1. DisplayList log. + // 2. Memory address of this layer. + // We know the target layer of each display item by information in #1. + // Here is an example of a Text display item line log in #1 + // Text p=0xa9850c00 f=0x0xaa405b00(..... + // f keeps the address of the target client layer of a display item. + // For LayerScope, display-item-to-client-layer mapping is not enough since + // LayerScope, which lives in the chrome process, knows only composite layers. + // As so, we need display-item-to-client-layer-to-layer-composite + // mapping. That's the reason we insert #2 into the log + log.AppendPrintf("0x%p\n%s",(void*) this, mDisplayListLog.get()); + } +} + void Layer::Log(const char* aPrefix) { @@ -1791,10 +1838,22 @@ Layer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent) LayersPacket::Layer::HORIZONTAL); layer->set_barid(GetScrollbarTargetContainerId()); } + // Mask layer if (mMaskLayer) { layer->set_mask(reinterpret_cast(mMaskLayer.get())); } + + // DisplayList log. + if (mDisplayListLog.Length() > 0) { + layer->set_displaylistloglength(mDisplayListLog.Length()); + auto compressedData = + MakeUnique(LZ4::maxCompressedSize(mDisplayListLog.Length())); + int compressedSize = LZ4::compress((char*)mDisplayListLog.get(), + mDisplayListLog.Length(), + compressedData.get()); + layer->set_displaylistlog(compressedData.get(), compressedSize); + } } void diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index de24d1a584..416b6881c9 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -1506,9 +1506,11 @@ public: virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) = 0; /** - * computes the effective transform for a mask layer, if this layer has one + * Computes the effective transform for mask layers, if this layer has any. */ - void ComputeEffectiveTransformForMaskLayer(const gfx::Matrix4x4& aTransformToSurface); + void ComputeEffectiveTransformForMaskLayers(const gfx::Matrix4x4& aTransformToSurface); + static void ComputeEffectiveTransformForMaskLayer(Layer* aMaskLayer, + const gfx::Matrix4x4& aTransformToSurface); /** * Calculate the scissor rect required when rendering this layer. @@ -1574,6 +1576,16 @@ public: // instead of a StringStream. It is also internally used to implement Dump(); virtual void DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent); + /** + * Store display list log. + */ + void SetDisplayListLog(const char *log); + + /** + * Return display list log. + */ + void GetDisplayListLog(nsCString& log); + static bool IsLogEnabled() { return LayerManager::IsLogEnabled(); } /** @@ -1762,6 +1774,8 @@ protected: #ifdef MOZ_DUMP_PAINTING nsTArray mExtraDumpInfo; #endif + // Store display list log. + nsCString mDisplayListLog; }; /** @@ -1824,7 +1838,7 @@ public: "Residual translation out of range"); mValidRegion.SetEmpty(); } - ComputeEffectiveTransformForMaskLayer(aTransformToSurface); + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); } LayerManager::PaintedLayerCreationHint GetCreationHint() const { return mCreationHint; } @@ -2135,7 +2149,7 @@ public: { gfx::Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface; mEffectiveTransform = SnapTransformTranslation(idealTransform, nullptr); - ComputeEffectiveTransformForMaskLayer(aTransformToSurface); + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); } protected: @@ -2287,7 +2301,7 @@ public: SnapTransform(GetLocalTransform(), gfxRect(0, 0, mBounds.width, mBounds.height), nullptr)* SnapTransformTranslation(aTransformToSurface, nullptr); - ComputeEffectiveTransformForMaskLayer(aTransformToSurface); + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); } protected: diff --git a/gfx/layers/YCbCrImageDataSerializer.cpp b/gfx/layers/YCbCrImageDataSerializer.cpp index afe535aec0..c357e48cb1 100644 --- a/gfx/layers/YCbCrImageDataSerializer.cpp +++ b/gfx/layers/YCbCrImageDataSerializer.cpp @@ -10,6 +10,7 @@ #include "mozilla/gfx/Logging.h" // for gfxDebug #include "mozilla/gfx/Types.h" #include "mozilla/mozalloc.h" // for operator delete +#include "nsDebug.h" // for NS_WARN_IF #include "yuv_convert.h" // for ConvertYCbCrToRGB32, etc #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3) diff --git a/gfx/layers/apz/util/APZEventState.cpp b/gfx/layers/apz/util/APZEventState.cpp index b6cff64241..73059e646c 100644 --- a/gfx/layers/apz/util/APZEventState.cpp +++ b/gfx/layers/apz/util/APZEventState.cpp @@ -6,15 +6,29 @@ #include "APZEventState.h" #include "ActiveElementManager.h" +#include "APZCCallbackHelper.h" +#include "gfxPrefs.h" #include "mozilla/BasicEvents.h" #include "mozilla/Preferences.h" +#include "mozilla/TouchEvents.h" +#include "mozilla/layers/APZCCallbackHelper.h" #include "nsCOMPtr.h" #include "nsDocShell.h" +#include "nsIDOMMouseEvent.h" #include "nsIDOMWindowUtils.h" +#include "nsIScrollableFrame.h" +#include "nsIScrollbarMediator.h" #include "nsITimer.h" #include "nsIWeakReferenceUtils.h" #include "nsIWidget.h" +#include "nsLayoutUtils.h" +#include "nsQueryFrame.h" #include "TouchManager.h" +#include "nsIDOMMouseEvent.h" +#include "nsLayoutUtils.h" +#include "nsIScrollableFrame.h" +#include "nsIScrollbarMediator.h" +#include "mozilla/TouchEvents.h" #define APZES_LOG(...) // #define APZES_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__) diff --git a/gfx/layers/apz/util/APZEventState.h b/gfx/layers/apz/util/APZEventState.h index adbf5feb61..17d37659b9 100644 --- a/gfx/layers/apz/util/APZEventState.h +++ b/gfx/layers/apz/util/APZEventState.h @@ -18,6 +18,7 @@ #include "mozilla/nsRefPtr.h" template class nsCOMPtr; +class nsIDocument; class nsIPresShell; class nsIWidget; diff --git a/gfx/layers/basic/BasicContainerLayer.cpp b/gfx/layers/basic/BasicContainerLayer.cpp index 8609f6534b..7e2abf3a8e 100644 --- a/gfx/layers/basic/BasicContainerLayer.cpp +++ b/gfx/layers/basic/BasicContainerLayer.cpp @@ -44,7 +44,7 @@ BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSur if (!idealTransform.CanDraw2D()) { mEffectiveTransform = idealTransform; ComputeEffectiveTransformsForChildren(Matrix4x4()); - ComputeEffectiveTransformForMaskLayer(Matrix4x4()); + ComputeEffectiveTransformForMaskLayers(Matrix4x4()); mUseIntermediateSurface = true; return; } @@ -54,7 +54,7 @@ BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSur // need to apply any compensation using the residual from SnapTransformTranslation. ComputeEffectiveTransformsForChildren(idealTransform); - ComputeEffectiveTransformForMaskLayer(aTransformToSurface); + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); Layer* child = GetFirstChild(); bool hasSingleBlendingChild = false; diff --git a/gfx/layers/basic/BasicPaintedLayer.h b/gfx/layers/basic/BasicPaintedLayer.h index 932c66af9d..5095c5ffa1 100644 --- a/gfx/layers/basic/BasicPaintedLayer.h +++ b/gfx/layers/basic/BasicPaintedLayer.h @@ -86,7 +86,7 @@ public: mResidualTranslation = gfxPoint(0,0); mValidRegion.SetEmpty(); } - ComputeEffectiveTransformForMaskLayer(aTransformToSurface); + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); return; } PaintedLayer::ComputeEffectiveTransforms(aTransformToSurface); diff --git a/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp index b72f45d6bf..f76e62488a 100644 --- a/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp +++ b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp @@ -14,10 +14,13 @@ MacIOSurfaceTextureSourceBasic::MacIOSurfaceTextureSourceBasic( MacIOSurface* aSurface) : mCompositor(aCompositor) , mSurface(aSurface) -{} +{ + MOZ_COUNT_CTOR(MacIOSurfaceTextureSourceBasic); +} MacIOSurfaceTextureSourceBasic::~MacIOSurfaceTextureSourceBasic() { + MOZ_COUNT_DTOR(MacIOSurfaceTextureSourceBasic); } gfx::IntSize diff --git a/gfx/layers/client/ClientContainerLayer.h b/gfx/layers/client/ClientContainerLayer.h index 64bd05483a..ac67566e9a 100644 --- a/gfx/layers/client/ClientContainerLayer.h +++ b/gfx/layers/client/ClientContainerLayer.h @@ -9,7 +9,6 @@ #include // for uint32_t #include "ClientLayerManager.h" // for ClientLayerManager, etc #include "Layers.h" // for Layer, ContainerLayer, etc -#include "gfxPrefs.h" // for gfxPrefs #include "nsDebug.h" // for NS_ASSERTION #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc #include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h index 1cab99fdd4..d393006287 100644 --- a/gfx/layers/client/TiledContentClient.h +++ b/gfx/layers/client/TiledContentClient.h @@ -36,7 +36,6 @@ #include "mozilla/layers/ISurfaceAllocator.h" #include "gfxReusableSurfaceWrapper.h" #include "pratom.h" // For PR_ATOMIC_INCREMENT/DECREMENT -#include "gfxPrefs.h" namespace mozilla { namespace layers { diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 4e7083fc75..0ce5c49b72 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -632,6 +632,18 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer) // The final clip for the layer is the intersection of these clips. Maybe asyncClip = aLayer->GetClipRect(); + // The transform of a mask layer is relative to the masked layer's parent + // layer. So whenever we apply an async transform to a layer, we need to + // apply that same transform to the layer's own mask layer. + // A layer can also have "ancestor" mask layers for any rounded clips from + // its ancestor scroll frames. A scroll frame mask layer only needs to be + // async transformed for async scrolls of this scroll frame's ancestor + // scroll frames, not for async scrolls of this scroll frame itself. + // In the loop below, we iterate over scroll frames from inside to outside. + // At each iteration, this array contains the layer's ancestor mask layers + // of all scroll frames inside the current one. + nsTArray ancestorMaskLayers; + for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) { AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(i); if (!controller) { @@ -694,6 +706,21 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer) } } + // Do the same for the ancestor mask layers: ancestorMaskLayers contains + // the ancestor mask layers for scroll frames *inside* the current scroll + // frame, so these are the ones we need to shift by our async transform. + for (Layer* ancestorMaskLayer : ancestorMaskLayers) { + SetShadowTransform(ancestorMaskLayer, + ancestorMaskLayer->GetLocalTransform() * asyncTransform); + } + + // Append the ancestor mask layer for this scroll frame to ancestorMaskLayers. + if (metrics.GetMaskLayerIndex()) { + size_t maskLayerIndex = metrics.GetMaskLayerIndex().value(); + Layer* ancestorMaskLayer = aLayer->GetAncestorMaskLayerAt(maskLayerIndex); + ancestorMaskLayers.AppendElement(ancestorMaskLayer); + } + combinedAsyncTransformWithoutOverscroll *= asyncTransformWithoutOverscroll; combinedAsyncTransform *= asyncTransform; } @@ -710,6 +737,12 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer) SetShadowTransform(aLayer, aLayer->GetLocalTransform() * AdjustForClip(combinedAsyncTransform, aLayer)); + // Do the same for the layer's own mask layer, if it has one. + if (Layer* maskLayer = aLayer->GetMaskLayer()) { + SetShadowTransform(maskLayer, + maskLayer->GetLocalTransform() * combinedAsyncTransform); + } + const FrameMetrics& bottom = LayerMetricsWrapper::BottommostScrollableMetrics(aLayer); MOZ_ASSERT(bottom.IsScrollable()); // must be true because hasAsyncTransform is true diff --git a/gfx/layers/composite/ImageLayerComposite.cpp b/gfx/layers/composite/ImageLayerComposite.cpp index 95064a8aab..76e02103f9 100644 --- a/gfx/layers/composite/ImageLayerComposite.cpp +++ b/gfx/layers/composite/ImageLayerComposite.cpp @@ -143,7 +143,7 @@ ImageLayerComposite::ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransform mEffectiveTransformForBuffer = mEffectiveTransform; } - ComputeEffectiveTransformForMaskLayer(aTransformToSurface); + ComputeEffectiveTransformForMaskLayers(aTransformToSurface); } CompositableHost* diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp index 9db5d5db26..91a2026112 100644 --- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -296,10 +296,13 @@ TextureHost::TextureHost(TextureFlags aFlags) : mActor(nullptr) , mFlags(aFlags) , mCompositableCount(0) -{} +{ + MOZ_COUNT_CTOR(TextureHost); +} TextureHost::~TextureHost() { + MOZ_COUNT_DTOR(TextureHost); } void TextureHost::Finalize() diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index fd51ce7384..f9d078fe47 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -70,6 +70,8 @@ #include "GeckoTouchDispatcher.h" #endif +#include "LayerScope.h" + namespace mozilla { namespace layers { @@ -675,6 +677,8 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, } gfxPlatform::GetPlatform()->ComputeTileSize(); + + LayerScope::SetPixelScale(mWidget->GetDefaultScale().scale); } bool diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index 70b049564d..988220f9db 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -13,6 +13,7 @@ #include "Layers.h" // for Layer, ContainerLayer, etc #include "ShadowLayerParent.h" // for ShadowLayerParent #include "CompositableTransactionParent.h" // for EditReplyVector +#include "gfxPrefs.h" #include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D #include "mozilla/layers/CanvasLayerComposite.h" #include "mozilla/layers/ColorLayerComposite.h" @@ -351,6 +352,7 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray&& cset, layer->SetAnimations(common.animations()); layer->SetInvalidRegion(common.invalidRegion()); layer->SetFrameMetrics(common.metrics()); + layer->SetDisplayListLog(common.displayListLog().get()); nsTArray> maskLayers; for (size_t i = 0; i < common.ancestorMaskLayersParent().Length(); i++) { diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index dfaeb978c9..8ce9f2d466 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -41,7 +41,6 @@ using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h"; using struct mozilla::layers::FrameMetrics from "FrameMetrics.h"; using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h"; using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h"; -using std::string from "string"; namespace mozilla { namespace layers { @@ -230,7 +229,7 @@ struct CommonLayerAttributes { Animation[] animations; nsIntRegion invalidRegion; FrameMetrics[] metrics; - string contentDescription; + nsCString displayListLog; }; struct PaintedLayerAttributes { diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index c635aec5da..c4c0646dd3 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -611,6 +611,10 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray* aReplies, auto layer = Shadow(mutant->GetAncestorMaskLayerAt(i)->AsShadowableLayer()); common.ancestorMaskLayersChild().AppendElement(layer); } + nsCString log; + mutant->GetDisplayListLog(log); + common.displayListLog() = log; + attrs.specific() = null_t(); mutant->FillSpecificAttributes(attrs.specific()); diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 96284343cc..2171062fc9 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -287,6 +287,7 @@ UNIFIED_SOURCES += [ 'Compositor.cpp', 'CopyableCanvasLayer.cpp', 'Effects.cpp', + 'FrameMetrics.cpp', 'GLImages.cpp', 'ImageDataSerializer.cpp', 'ImageLayers.cpp', diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index 5f61e926c6..eefcdefb3c 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -1478,7 +1478,7 @@ CompositorOGL::BindAndDrawQuads(ShaderProgramOGL *aProg, // We are using GL_TRIANGLES here because the Mac Intel drivers fail to properly // process uniform arrays with GL_TRIANGLE_STRIP. Go figure. mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads); - LayerScope::SetLayerRects(aQuads, aLayerRects); + LayerScope::SetDrawRects(aQuads, aLayerRects, aTextureRects); } GLBlitTextureImageHelper* diff --git a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp index 687374b269..a307983b3e 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp +++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp @@ -14,11 +14,17 @@ MacIOSurfaceTextureHostOGL::MacIOSurfaceTextureHostOGL(TextureFlags aFlags, const SurfaceDescriptorMacIOSurface& aDescriptor) : TextureHost(aFlags) { + MOZ_COUNT_CTOR(MacIOSurfaceTextureHostOGL); mSurface = MacIOSurface::LookupSurface(aDescriptor.surfaceId(), aDescriptor.scaleFactor(), !aDescriptor.isOpaque()); } +MacIOSurfaceTextureHostOGL::~MacIOSurfaceTextureHostOGL() +{ + MOZ_COUNT_DTOR(MacIOSurfaceTextureHostOGL); +} + bool MacIOSurfaceTextureHostOGL::Lock() { @@ -77,10 +83,14 @@ MacIOSurfaceTextureSourceOGL::MacIOSurfaceTextureSourceOGL( MacIOSurface* aSurface) : mCompositor(aCompositor) , mSurface(aSurface) -{} +{ + MOZ_COUNT_CTOR(MacIOSurfaceTextureSourceOGL); +} MacIOSurfaceTextureSourceOGL::~MacIOSurfaceTextureSourceOGL() -{} +{ + MOZ_COUNT_DTOR(MacIOSurfaceTextureSourceOGL); +} gfx::IntSize MacIOSurfaceTextureSourceOGL::GetSize() const diff --git a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h index 14fa2ff15f..b201e78ec9 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h +++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h @@ -64,6 +64,7 @@ class MacIOSurfaceTextureHostOGL : public TextureHost public: MacIOSurfaceTextureHostOGL(TextureFlags aFlags, const SurfaceDescriptorMacIOSurface& aDescriptor); + virtual ~MacIOSurfaceTextureHostOGL(); // MacIOSurfaceTextureSourceOGL doesn't own any GL texture virtual void DeallocateDeviceData() override {} diff --git a/gfx/layers/protobuf/LayerScopePacket.pb.cc b/gfx/layers/protobuf/LayerScopePacket.pb.cc index 0bc11b1c9e..28e7f42526 100644 --- a/gfx/layers/protobuf/LayerScopePacket.pb.cc +++ b/gfx/layers/protobuf/LayerScopePacket.pb.cc @@ -99,6 +99,7 @@ struct StaticDescriptorInitializer_LayerScopePacket_2eproto { #ifndef _MSC_VER const int FramePacket::kValueFieldNumber; +const int FramePacket::kScaleFieldNumber; #endif // !_MSC_VER FramePacket::FramePacket() @@ -120,6 +121,7 @@ FramePacket::FramePacket(const FramePacket& from) void FramePacket::SharedCtor() { _cached_size_ = 0; value_ = GOOGLE_ULONGLONG(0); + scale_ = 0; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -158,7 +160,21 @@ FramePacket* FramePacket::New() const { } void FramePacket::Clear() { - value_ = GOOGLE_ULONGLONG(0); +#define OFFSET_OF_FIELD_(f) (reinterpret_cast( \ + &reinterpret_cast(16)->f) - \ + reinterpret_cast(16)) + +#define ZR_(first, last) do { \ + size_t f = OFFSET_OF_FIELD_(first); \ + size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last); \ + ::memset(&first, 0, n); \ + } while (0) + + ZR_(value_, scale_); + +#undef OFFSET_OF_FIELD_ +#undef ZR_ + ::memset(_has_bits_, 0, sizeof(_has_bits_)); mutable_unknown_fields()->clear(); } @@ -187,6 +203,21 @@ bool FramePacket::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(21)) goto parse_scale; + break; + } + + // optional float scale = 2; + case 2: { + if (tag == 21) { + parse_scale: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>( + input, &scale_))); + set_has_scale(); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -221,6 +252,11 @@ void FramePacket::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->value(), output); } + // optional float scale = 2; + if (has_scale()) { + ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->scale(), output); + } + output->WriteRaw(unknown_fields().data(), unknown_fields().size()); // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.FramePacket) @@ -237,6 +273,11 @@ int FramePacket::ByteSize() const { this->value()); } + // optional float scale = 2; + if (has_scale()) { + total_size += 1 + 4; + } + } total_size += unknown_fields().size(); @@ -257,6 +298,9 @@ void FramePacket::MergeFrom(const FramePacket& from) { if (from.has_value()) { set_value(from.value()); } + if (from.has_scale()) { + set_scale(from.scale()); + } } mutable_unknown_fields()->append(from.unknown_fields()); } @@ -275,6 +319,7 @@ bool FramePacket::IsInitialized() const { void FramePacket::Swap(FramePacket* other) { if (other != this) { std::swap(value_, other->value_); + std::swap(scale_, other->scale_); std::swap(_has_bits_[0], other->_has_bits_[0]); _unknown_fields_.swap(other->_unknown_fields_); std::swap(_cached_size_, other->_cached_size_); @@ -2459,6 +2504,8 @@ const int LayersPacket_Layer::kColorFieldNumber; const int LayersPacket_Layer::kFilterFieldNumber; const int LayersPacket_Layer::kRefIDFieldNumber; const int LayersPacket_Layer::kSizeFieldNumber; +const int LayersPacket_Layer::kDisplayListLogLengthFieldNumber; +const int LayersPacket_Layer::kDisplayListLogFieldNumber; #endif // !_MSC_VER LayersPacket_Layer::LayersPacket_Layer() @@ -2544,6 +2591,7 @@ LayersPacket_Layer::LayersPacket_Layer(const LayersPacket_Layer& from) } void LayersPacket_Layer::SharedCtor() { + ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; type_ = 0; ptr_ = GOOGLE_ULONGLONG(0); @@ -2568,6 +2616,8 @@ void LayersPacket_Layer::SharedCtor() { filter_ = 0; refid_ = GOOGLE_ULONGLONG(0); size_ = NULL; + displaylistloglength_ = 0u; + displaylistlog_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -2577,6 +2627,9 @@ LayersPacket_Layer::~LayersPacket_Layer() { } void LayersPacket_Layer::SharedDtor() { + if (displaylistlog_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + delete displaylistlog_; + } #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER if (this != &default_instance()) { #else @@ -2657,7 +2710,7 @@ void LayersPacket_Layer::Clear() { if (noactionregion_ != NULL) noactionregion_->::mozilla::layers::layerscope::LayersPacket_Layer_Region::Clear(); } } - if (_has_bits_[16 / 32] & 8323072) { + if (_has_bits_[16 / 32] & 16711680) { ZR_(color_, refid_); if (has_hpanregion()) { if (hpanregion_ != NULL) hpanregion_->::mozilla::layers::layerscope::LayersPacket_Layer_Region::Clear(); @@ -2671,6 +2724,12 @@ void LayersPacket_Layer::Clear() { if (has_size()) { if (size_ != NULL) size_->::mozilla::layers::layerscope::LayersPacket_Layer_Size::Clear(); } + displaylistloglength_ = 0u; + } + if (has_displaylistlog()) { + if (displaylistlog_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + displaylistlog_->clear(); + } } #undef OFFSET_OF_FIELD_ @@ -3030,6 +3089,34 @@ bool LayersPacket_Layer::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(840)) goto parse_displayListLogLength; + break; + } + + // optional uint32 displayListLogLength = 105; + case 105: { + if (tag == 840) { + parse_displayListLogLength: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( + input, &displaylistloglength_))); + set_has_displaylistloglength(); + } else { + goto handle_unusual; + } + if (input->ExpectTag(850)) goto parse_displayListLog; + break; + } + + // optional bytes displayListLog = 106; + case 106: { + if (tag == 850) { + parse_displayListLog: + DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( + input, this->mutable_displaylistlog())); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -3188,6 +3275,17 @@ void LayersPacket_Layer::SerializeWithCachedSizes( 104, this->size(), output); } + // optional uint32 displayListLogLength = 105; + if (has_displaylistloglength()) { + ::google::protobuf::internal::WireFormatLite::WriteUInt32(105, this->displaylistloglength(), output); + } + + // optional bytes displayListLog = 106; + if (has_displaylistlog()) { + ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( + 106, this->displaylistlog(), output); + } + output->WriteRaw(unknown_fields().data(), unknown_fields().size()); // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.LayersPacket.Layer) @@ -3353,6 +3451,22 @@ int LayersPacket_Layer::ByteSize() const { this->size()); } + // optional uint32 displayListLogLength = 105; + if (has_displaylistloglength()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::UInt32Size( + this->displaylistloglength()); + } + + } + if (_has_bits_[24 / 32] & (0xffu << (24 % 32))) { + // optional bytes displayListLog = 106; + if (has_displaylistlog()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::BytesSize( + this->displaylistlog()); + } + } total_size += unknown_fields().size(); @@ -3443,6 +3557,14 @@ void LayersPacket_Layer::MergeFrom(const LayersPacket_Layer& from) { if (from.has_size()) { mutable_size()->::mozilla::layers::layerscope::LayersPacket_Layer_Size::MergeFrom(from.size()); } + if (from.has_displaylistloglength()) { + set_displaylistloglength(from.displaylistloglength()); + } + } + if (from._has_bits_[24 / 32] & (0xffu << (24 % 32))) { + if (from.has_displaylistlog()) { + set_displaylistlog(from.displaylistlog()); + } } mutable_unknown_fields()->append(from.unknown_fields()); } @@ -3484,6 +3606,8 @@ void LayersPacket_Layer::Swap(LayersPacket_Layer* other) { std::swap(filter_, other->filter_); std::swap(refid_, other->refid_); std::swap(size_, other->size_); + std::swap(displaylistloglength_, other->displaylistloglength_); + std::swap(displaylistlog_, other->displaylistlog_); std::swap(_has_bits_[0], other->_has_bits_[0]); _unknown_fields_.swap(other->_unknown_fields_); std::swap(_cached_size_, other->_cached_size_); @@ -4177,6 +4301,8 @@ const int DrawPacket::kMvMatrixFieldNumber; const int DrawPacket::kTotalRectsFieldNumber; const int DrawPacket::kLayerRectFieldNumber; const int DrawPacket::kLayerrefFieldNumber; +const int DrawPacket::kTexIDsFieldNumber; +const int DrawPacket::kTextureRectFieldNumber; #endif // !_MSC_VER DrawPacket::DrawPacket() @@ -4249,14 +4375,19 @@ void DrawPacket::Clear() { ::memset(&first, 0, n); \ } while (0) - ZR_(offsetx_, offsety_); - ZR_(layerref_, totalrects_); + if (_has_bits_[0 / 32] & 43) { + ZR_(offsetx_, offsety_); + totalrects_ = 0u; + layerref_ = GOOGLE_ULONGLONG(0); + } #undef OFFSET_OF_FIELD_ #undef ZR_ mvmatrix_.Clear(); layerrect_.Clear(); + texids_.Clear(); + texturerect_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); mutable_unknown_fields()->clear(); } @@ -4363,6 +4494,39 @@ bool DrawPacket::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(56)) goto parse_texIDs; + break; + } + + // repeated uint32 texIDs = 7; + case 7: { + if (tag == 56) { + parse_texIDs: + DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive< + ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( + 1, 56, input, this->mutable_texids()))); + } else if (tag == 58) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline< + ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( + input, this->mutable_texids()))); + } else { + goto handle_unusual; + } + if (input->ExpectTag(56)) goto parse_texIDs; + if (input->ExpectTag(66)) goto parse_textureRect; + break; + } + + // repeated .mozilla.layers.layerscope.DrawPacket.Rect textureRect = 8; + case 8: { + if (tag == 66) { + parse_textureRect: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_texturerect())); + } else { + goto handle_unusual; + } + if (input->ExpectTag(66)) goto parse_textureRect; if (input->ExpectAtEnd()) goto success; break; } @@ -4424,6 +4588,18 @@ void DrawPacket::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteUInt64(6, this->layerref(), output); } + // repeated uint32 texIDs = 7; + for (int i = 0; i < this->texids_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteUInt32( + 7, this->texids(i), output); + } + + // repeated .mozilla.layers.layerscope.DrawPacket.Rect textureRect = 8; + for (int i = 0; i < this->texturerect_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessage( + 8, this->texturerect(i), output); + } + output->WriteRaw(unknown_fields().data(), unknown_fields().size()); // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.DrawPacket) @@ -4473,6 +4649,24 @@ int DrawPacket::ByteSize() const { this->layerrect(i)); } + // repeated uint32 texIDs = 7; + { + int data_size = 0; + for (int i = 0; i < this->texids_size(); i++) { + data_size += ::google::protobuf::internal::WireFormatLite:: + UInt32Size(this->texids(i)); + } + total_size += 1 * this->texids_size() + data_size; + } + + // repeated .mozilla.layers.layerscope.DrawPacket.Rect textureRect = 8; + total_size += 1 * this->texturerect_size(); + for (int i = 0; i < this->texturerect_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->texturerect(i)); + } + total_size += unknown_fields().size(); GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); @@ -4490,6 +4684,8 @@ void DrawPacket::MergeFrom(const DrawPacket& from) { GOOGLE_CHECK_NE(&from, this); mvmatrix_.MergeFrom(from.mvmatrix_); layerrect_.MergeFrom(from.layerrect_); + texids_.MergeFrom(from.texids_); + texturerect_.MergeFrom(from.texturerect_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_offsetx()) { set_offsetx(from.offsetx()); @@ -4517,6 +4713,7 @@ bool DrawPacket::IsInitialized() const { if ((_has_bits_[0] & 0x0000002b) != 0x0000002b) return false; if (!::google::protobuf::internal::AllAreInitialized(this->layerrect())) return false; + if (!::google::protobuf::internal::AllAreInitialized(this->texturerect())) return false; return true; } @@ -4528,6 +4725,8 @@ void DrawPacket::Swap(DrawPacket* other) { std::swap(totalrects_, other->totalrects_); layerrect_.Swap(&other->layerrect_); std::swap(layerref_, other->layerref_); + texids_.Swap(&other->texids_); + texturerect_.Swap(&other->texturerect_); std::swap(_has_bits_[0], other->_has_bits_[0]); _unknown_fields_.swap(other->_unknown_fields_); std::swap(_cached_size_, other->_cached_size_); diff --git a/gfx/layers/protobuf/LayerScopePacket.pb.h b/gfx/layers/protobuf/LayerScopePacket.pb.h index 9e27d8a44f..6cbb1d1447 100644 --- a/gfx/layers/protobuf/LayerScopePacket.pb.h +++ b/gfx/layers/protobuf/LayerScopePacket.pb.h @@ -183,16 +183,26 @@ class FramePacket : public ::google::protobuf::MessageLite { inline ::google::protobuf::uint64 value() const; inline void set_value(::google::protobuf::uint64 value); + // optional float scale = 2; + inline bool has_scale() const; + inline void clear_scale(); + static const int kScaleFieldNumber = 2; + inline float scale() const; + inline void set_scale(float value); + // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.FramePacket) private: inline void set_has_value(); inline void clear_has_value(); + inline void set_has_scale(); + inline void clear_has_scale(); ::std::string _unknown_fields_; ::google::protobuf::uint32 _has_bits_[1]; mutable int _cached_size_; ::google::protobuf::uint64 value_; + float scale_; #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER friend void protobuf_AddDesc_LayerScopePacket_2eproto_impl(); #else @@ -1351,6 +1361,25 @@ class LayersPacket_Layer : public ::google::protobuf::MessageLite { inline ::mozilla::layers::layerscope::LayersPacket_Layer_Size* release_size(); inline void set_allocated_size(::mozilla::layers::layerscope::LayersPacket_Layer_Size* size); + // optional uint32 displayListLogLength = 105; + inline bool has_displaylistloglength() const; + inline void clear_displaylistloglength(); + static const int kDisplayListLogLengthFieldNumber = 105; + inline ::google::protobuf::uint32 displaylistloglength() const; + inline void set_displaylistloglength(::google::protobuf::uint32 value); + + // optional bytes displayListLog = 106; + inline bool has_displaylistlog() const; + inline void clear_displaylistlog(); + static const int kDisplayListLogFieldNumber = 106; + inline const ::std::string& displaylistlog() const; + inline void set_displaylistlog(const ::std::string& value); + inline void set_displaylistlog(const char* value); + inline void set_displaylistlog(const void* value, size_t size); + inline ::std::string* mutable_displaylistlog(); + inline ::std::string* release_displaylistlog(); + inline void set_allocated_displaylistlog(::std::string* displaylistlog); + // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.LayersPacket.Layer) private: inline void set_has_type(); @@ -1399,6 +1428,10 @@ class LayersPacket_Layer : public ::google::protobuf::MessageLite { inline void clear_has_refid(); inline void set_has_size(); inline void clear_has_size(); + inline void set_has_displaylistloglength(); + inline void clear_has_displaylistloglength(); + inline void set_has_displaylistlog(); + inline void clear_has_displaylistlog(); ::std::string _unknown_fields_; @@ -1427,6 +1460,8 @@ class LayersPacket_Layer : public ::google::protobuf::MessageLite { int filter_; ::google::protobuf::uint64 refid_; ::mozilla::layers::layerscope::LayersPacket_Layer_Size* size_; + ::std::string* displaylistlog_; + ::google::protobuf::uint32 displaylistloglength_; #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER friend void protobuf_AddDesc_LayerScopePacket_2eproto_impl(); #else @@ -1863,6 +1898,30 @@ class DrawPacket : public ::google::protobuf::MessageLite { inline ::google::protobuf::uint64 layerref() const; inline void set_layerref(::google::protobuf::uint64 value); + // repeated uint32 texIDs = 7; + inline int texids_size() const; + inline void clear_texids(); + static const int kTexIDsFieldNumber = 7; + inline ::google::protobuf::uint32 texids(int index) const; + inline void set_texids(int index, ::google::protobuf::uint32 value); + inline void add_texids(::google::protobuf::uint32 value); + inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >& + texids() const; + inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >* + mutable_texids(); + + // repeated .mozilla.layers.layerscope.DrawPacket.Rect textureRect = 8; + inline int texturerect_size() const; + inline void clear_texturerect(); + static const int kTextureRectFieldNumber = 8; + inline const ::mozilla::layers::layerscope::DrawPacket_Rect& texturerect(int index) const; + inline ::mozilla::layers::layerscope::DrawPacket_Rect* mutable_texturerect(int index); + inline ::mozilla::layers::layerscope::DrawPacket_Rect* add_texturerect(); + inline const ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >& + texturerect() const; + inline ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >* + mutable_texturerect(); + // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.DrawPacket) private: inline void set_has_offsetx(); @@ -1883,6 +1942,8 @@ class DrawPacket : public ::google::protobuf::MessageLite { ::google::protobuf::RepeatedField< float > mvmatrix_; ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect > layerrect_; ::google::protobuf::uint64 layerref_; + ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > texids_; + ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect > texturerect_; ::google::protobuf::uint32 totalrects_; #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER friend void protobuf_AddDesc_LayerScopePacket_2eproto_impl(); @@ -2222,6 +2283,30 @@ inline void FramePacket::set_value(::google::protobuf::uint64 value) { // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.FramePacket.value) } +// optional float scale = 2; +inline bool FramePacket::has_scale() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void FramePacket::set_has_scale() { + _has_bits_[0] |= 0x00000002u; +} +inline void FramePacket::clear_has_scale() { + _has_bits_[0] &= ~0x00000002u; +} +inline void FramePacket::clear_scale() { + scale_ = 0; + clear_has_scale(); +} +inline float FramePacket::scale() const { + // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.FramePacket.scale) + return scale_; +} +inline void FramePacket::set_scale(float value) { + set_has_scale(); + scale_ = value; + // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.FramePacket.scale) +} + // ------------------------------------------------------------------- // ColorPacket @@ -3791,6 +3876,106 @@ inline void LayersPacket_Layer::set_allocated_size(::mozilla::layers::layerscope // @@protoc_insertion_point(field_set_allocated:mozilla.layers.layerscope.LayersPacket.Layer.size) } +// optional uint32 displayListLogLength = 105; +inline bool LayersPacket_Layer::has_displaylistloglength() const { + return (_has_bits_[0] & 0x00800000u) != 0; +} +inline void LayersPacket_Layer::set_has_displaylistloglength() { + _has_bits_[0] |= 0x00800000u; +} +inline void LayersPacket_Layer::clear_has_displaylistloglength() { + _has_bits_[0] &= ~0x00800000u; +} +inline void LayersPacket_Layer::clear_displaylistloglength() { + displaylistloglength_ = 0u; + clear_has_displaylistloglength(); +} +inline ::google::protobuf::uint32 LayersPacket_Layer::displaylistloglength() const { + // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.LayersPacket.Layer.displayListLogLength) + return displaylistloglength_; +} +inline void LayersPacket_Layer::set_displaylistloglength(::google::protobuf::uint32 value) { + set_has_displaylistloglength(); + displaylistloglength_ = value; + // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.LayersPacket.Layer.displayListLogLength) +} + +// optional bytes displayListLog = 106; +inline bool LayersPacket_Layer::has_displaylistlog() const { + return (_has_bits_[0] & 0x01000000u) != 0; +} +inline void LayersPacket_Layer::set_has_displaylistlog() { + _has_bits_[0] |= 0x01000000u; +} +inline void LayersPacket_Layer::clear_has_displaylistlog() { + _has_bits_[0] &= ~0x01000000u; +} +inline void LayersPacket_Layer::clear_displaylistlog() { + if (displaylistlog_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + displaylistlog_->clear(); + } + clear_has_displaylistlog(); +} +inline const ::std::string& LayersPacket_Layer::displaylistlog() const { + // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog) + return *displaylistlog_; +} +inline void LayersPacket_Layer::set_displaylistlog(const ::std::string& value) { + set_has_displaylistlog(); + if (displaylistlog_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + displaylistlog_ = new ::std::string; + } + displaylistlog_->assign(value); + // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog) +} +inline void LayersPacket_Layer::set_displaylistlog(const char* value) { + set_has_displaylistlog(); + if (displaylistlog_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + displaylistlog_ = new ::std::string; + } + displaylistlog_->assign(value); + // @@protoc_insertion_point(field_set_char:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog) +} +inline void LayersPacket_Layer::set_displaylistlog(const void* value, size_t size) { + set_has_displaylistlog(); + if (displaylistlog_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + displaylistlog_ = new ::std::string; + } + displaylistlog_->assign(reinterpret_cast(value), size); + // @@protoc_insertion_point(field_set_pointer:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog) +} +inline ::std::string* LayersPacket_Layer::mutable_displaylistlog() { + set_has_displaylistlog(); + if (displaylistlog_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + displaylistlog_ = new ::std::string; + } + // @@protoc_insertion_point(field_mutable:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog) + return displaylistlog_; +} +inline ::std::string* LayersPacket_Layer::release_displaylistlog() { + clear_has_displaylistlog(); + if (displaylistlog_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + return NULL; + } else { + ::std::string* temp = displaylistlog_; + displaylistlog_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return temp; + } +} +inline void LayersPacket_Layer::set_allocated_displaylistlog(::std::string* displaylistlog) { + if (displaylistlog_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + delete displaylistlog_; + } + if (displaylistlog) { + set_has_displaylistlog(); + displaylistlog_ = displaylistlog; + } else { + clear_has_displaylistlog(); + displaylistlog_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + } + // @@protoc_insertion_point(field_set_allocated:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog) +} + // ------------------------------------------------------------------- // LayersPacket @@ -4113,6 +4298,66 @@ inline void DrawPacket::set_layerref(::google::protobuf::uint64 value) { // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.DrawPacket.layerref) } +// repeated uint32 texIDs = 7; +inline int DrawPacket::texids_size() const { + return texids_.size(); +} +inline void DrawPacket::clear_texids() { + texids_.Clear(); +} +inline ::google::protobuf::uint32 DrawPacket::texids(int index) const { + // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.DrawPacket.texIDs) + return texids_.Get(index); +} +inline void DrawPacket::set_texids(int index, ::google::protobuf::uint32 value) { + texids_.Set(index, value); + // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.DrawPacket.texIDs) +} +inline void DrawPacket::add_texids(::google::protobuf::uint32 value) { + texids_.Add(value); + // @@protoc_insertion_point(field_add:mozilla.layers.layerscope.DrawPacket.texIDs) +} +inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >& +DrawPacket::texids() const { + // @@protoc_insertion_point(field_list:mozilla.layers.layerscope.DrawPacket.texIDs) + return texids_; +} +inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >* +DrawPacket::mutable_texids() { + // @@protoc_insertion_point(field_mutable_list:mozilla.layers.layerscope.DrawPacket.texIDs) + return &texids_; +} + +// repeated .mozilla.layers.layerscope.DrawPacket.Rect textureRect = 8; +inline int DrawPacket::texturerect_size() const { + return texturerect_.size(); +} +inline void DrawPacket::clear_texturerect() { + texturerect_.Clear(); +} +inline const ::mozilla::layers::layerscope::DrawPacket_Rect& DrawPacket::texturerect(int index) const { + // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.DrawPacket.textureRect) + return texturerect_.Get(index); +} +inline ::mozilla::layers::layerscope::DrawPacket_Rect* DrawPacket::mutable_texturerect(int index) { + // @@protoc_insertion_point(field_mutable:mozilla.layers.layerscope.DrawPacket.textureRect) + return texturerect_.Mutable(index); +} +inline ::mozilla::layers::layerscope::DrawPacket_Rect* DrawPacket::add_texturerect() { + // @@protoc_insertion_point(field_add:mozilla.layers.layerscope.DrawPacket.textureRect) + return texturerect_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >& +DrawPacket::texturerect() const { + // @@protoc_insertion_point(field_list:mozilla.layers.layerscope.DrawPacket.textureRect) + return texturerect_; +} +inline ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >* +DrawPacket::mutable_texturerect() { + // @@protoc_insertion_point(field_mutable_list:mozilla.layers.layerscope.DrawPacket.textureRect) + return &texturerect_; +} + // ------------------------------------------------------------------- // Packet diff --git a/gfx/layers/protobuf/LayerScopePacket.proto b/gfx/layers/protobuf/LayerScopePacket.proto index 9beaafc81b..206833e5a7 100644 --- a/gfx/layers/protobuf/LayerScopePacket.proto +++ b/gfx/layers/protobuf/LayerScopePacket.proto @@ -9,6 +9,7 @@ package mozilla.layers.layerscope; // =============================== message FramePacket { optional uint64 value = 1; + optional float scale = 2; } message ColorPacket { @@ -114,6 +115,8 @@ message LayersPacket { optional uint64 refID = 103; // Readback Layer optional Size size = 104; + optional uint32 displayListLogLength = 105; + optional bytes displayListLog = 106; } repeated Layer layer = 1; } @@ -136,6 +139,8 @@ message DrawPacket { required uint32 totalRects = 4; repeated Rect layerRect = 5; required uint64 layerref = 6; + repeated uint32 texIDs = 7; + repeated Rect textureRect = 8; } // We only need to use this Packet. diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index a375e41333..b86279f97c 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -2484,3 +2484,15 @@ gfxPlatform::AsyncPanZoomEnabled() #endif return gfxPrefs::AsyncPanZoomEnabledDoNotUseDirectly(); } + +/*virtual*/ bool +gfxPlatform::UseProgressivePaint() +{ + return gfxPrefs::ProgressivePaintDoNotUseDirectly(); +} + +/*static*/ bool +gfxPlatform::PerfWarnings() +{ + return gfxPrefs::PerfWarnings(); +} diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 5f15092b64..f9589aca92 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -13,7 +13,6 @@ #include "nsCOMPtr.h" #include "nsAutoPtr.h" -#include "gfxPrefs.h" #include "gfxTypes.h" #include "gfxFontFamilyList.h" #include "gfxBlur.h" @@ -62,7 +61,7 @@ BackendTypeBit(BackendType b) #define MOZ_PERFORMANCE_WARNING(module, ...) \ do { \ - if (gfxPrefs::PerfWarnings()) { \ + if (gfxPlatform::PerfWarnings()) { \ printf_stderr("[" module "] " __VA_ARGS__); \ } \ } while (0) @@ -288,7 +287,7 @@ public: /// These should be used instead of directly accessing the preference, /// as different platforms may override the behaviour. - virtual bool UseProgressivePaint() { return gfxPrefs::ProgressivePaintDoNotUseDirectly(); } + virtual bool UseProgressivePaint(); static bool AsyncPanZoomEnabled(); @@ -649,6 +648,12 @@ public: const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat); + /** + * Wrapper around gfxPrefs::PerfWarnings(). + * Extracted into a function to avoid including gfxPrefs.h from this file. + */ + static bool PerfWarnings(); + protected: gfxPlatform(); virtual ~gfxPlatform(); diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index e50cb263ba..9e1146b29d 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -1046,8 +1046,14 @@ protected: * Grab a recyclable ImageLayer for use as a mask layer for aLayer (that is a * mask layer which has been used for aLayer before), or create one if such * a layer doesn't exist. + * + * Since mask layers can exist either on the layer directly, or as a side- + * attachment to FrameMetrics (for ancestor scrollframe clips), we key the + * recycle operation on both the originating layer and the mask layer's + * index in the layer, if any. */ - already_AddRefed CreateOrRecycleMaskImageLayerFor(Layer* aLayer, const Maybe& aForAncestorMaskLayer); + struct MaskLayerKey; + already_AddRefed CreateOrRecycleMaskImageLayerFor(const MaskLayerKey& aKey); /** * Grabs all PaintedLayers and ColorLayers from the ContainerLayer and makes them * available for recycling. @@ -1187,11 +1193,33 @@ protected: typedef nsAutoTArray AutoLayersArray; AutoLayersArray mNewChildLayers; nsTHashtable> mPaintedLayersAvailableForRecycling; - nsDataHashtable, nsRefPtr > - mRecycledMaskImageLayers; nscoord mAppUnitsPerDevPixel; bool mSnappingEnabled; bool mFlattenToSingleLayer; + + struct MaskLayerKey { + MaskLayerKey() : mLayer(nullptr) {} + MaskLayerKey(Layer* aLayer, const Maybe& aAncestorIndex) + : mLayer(aLayer), + mAncestorIndex(aAncestorIndex) + {} + + PLDHashNumber Hash() const { + // Hash the layer and add the layer index to the hash. + return (NS_PTR_TO_UINT32(mLayer) >> 2) + + (mAncestorIndex ? (*mAncestorIndex + 1) : 0); + } + bool operator ==(const MaskLayerKey& aOther) const { + return mLayer == aOther.mLayer && + mAncestorIndex == aOther.mAncestorIndex; + } + + Layer* mLayer; + Maybe mAncestorIndex; + }; + + nsDataHashtable, nsRefPtr> + mRecycledMaskImageLayers; }; class PaintedDisplayItemLayerUserData : public LayerUserData @@ -1883,12 +1911,12 @@ ContainerState::CreateOrRecycleImageLayer(PaintedLayer *aPainted) } already_AddRefed -ContainerState::CreateOrRecycleMaskImageLayerFor(Layer* aLayer, const Maybe& aForAncestorMaskLayer) +ContainerState::CreateOrRecycleMaskImageLayerFor(const MaskLayerKey& aKey) { - nsRefPtr result = mRecycledMaskImageLayers.Get(aLayer); - if (result && !aForAncestorMaskLayer) { - mRecycledMaskImageLayers.Remove(aLayer); - aLayer->ClearExtraDumpInfo(); + nsRefPtr result = mRecycledMaskImageLayers.Get(aKey); + if (result) { + mRecycledMaskImageLayers.Remove(aKey); + aKey.mLayer->ClearExtraDumpInfo(); // XXX if we use clip on mask layers, null it out here } else { // Create a new layer @@ -4227,7 +4255,14 @@ ContainerState::CollectOldLayers() if (Layer* maskLayer = layer->GetMaskLayer()) { NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE, "Could not recycle mask layer, unsupported layer type."); - mRecycledMaskImageLayers.Put(layer, static_cast(maskLayer)); + mRecycledMaskImageLayers.Put(MaskLayerKey(layer, Nothing()), static_cast(maskLayer)); + } + for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) { + Layer* maskLayer = layer->GetAncestorMaskLayerAt(i); + + NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE, + "Could not recycle mask layer, unsupported layer type."); + mRecycledMaskImageLayers.Put(MaskLayerKey(layer, Some(i)), static_cast(maskLayer)); } } } @@ -5573,7 +5608,8 @@ ContainerState::CreateMaskLayer(Layer *aLayer, uint32_t aRoundedRectClipCount) { // check if we can re-use the mask layer - nsRefPtr maskLayer = CreateOrRecycleMaskImageLayerFor(aLayer, aForAncestorMaskLayer); + MaskLayerKey recycleKey(aLayer, aForAncestorMaskLayer); + nsRefPtr maskLayer = CreateOrRecycleMaskImageLayerFor(recycleKey); MaskLayerUserData* userData = GetMaskLayerUserData(maskLayer); MaskLayerUserData newData; diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index b22f9811d2..c5ff51acc9 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -1273,6 +1273,18 @@ nsDisplayListBuilder::GetDirtyRectForScrolledContents(const nsIFrame* aScrollabl return result; } +bool +nsDisplayListBuilder::IsBuildingLayerEventRegions() +{ + if (mMode == PAINTING) { + // Note: this is the only place that gets to query LayoutEventRegionsEnabled + // 'directly' - other code should call this function. + return gfxPrefs::LayoutEventRegionsEnabledDoNotUseDirectly() || + mAsyncPanZoomEnabled; + } + return false; +} + void nsDisplayListSet::MoveTo(const nsDisplayListSet& aDestination) const { aDestination.BorderBackground()->AppendToTop(BorderBackground()); diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index db36c7cedf..ec031b0f61 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -346,16 +346,7 @@ public: { mLayerEventRegions = aItem; } - bool IsBuildingLayerEventRegions() - { - if (mMode == PAINTING) { - // Note: this is the only place that gets to query LayoutEventRegionsEnabled - // 'directly' - other code should call this function. - return gfxPrefs::LayoutEventRegionsEnabledDoNotUseDirectly() || - mAsyncPanZoomEnabled; - } - return false; - } + bool IsBuildingLayerEventRegions(); bool IsInsidePointerEventsNoneDoc() { return CurrentPresShellState()->mInsidePointerEventsNoneDoc; diff --git a/layout/base/nsLayoutDebugger.cpp b/layout/base/nsLayoutDebugger.cpp index ecfadf9c8b..b6fb928bb6 100644 --- a/layout/base/nsLayoutDebugger.cpp +++ b/layout/base/nsLayoutDebugger.cpp @@ -250,16 +250,6 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList, } } -void -nsFrame::PrintDisplayItem(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem, - std::stringstream& aStream, - bool aDumpSublist, - bool aDumpHtml) -{ - PrintDisplayItemTo(aBuilder, aItem, aStream, 0, aDumpSublist, aDumpHtml); -} - void nsFrame::PrintDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList, diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 984d776559..3463d06d16 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -3355,6 +3355,10 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram gfxUtils::sDumpPaintFile = savedDumpFile; gPaintCount++; #endif + + std::stringstream lsStream; + nsFrame::PrintDisplayList(&builder, list, lsStream); + layerManager->GetRoot()->SetDisplayListLog(lsStream.str().c_str()); } #ifdef MOZ_DUMP_PAINTING @@ -3496,7 +3500,7 @@ AddBoxesForFrame(nsIFrame* aFrame, pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock || pseudoType == nsCSSAnonBoxes::mozMathMLAnonymousBlock || pseudoType == nsCSSAnonBoxes::mozXULAnonymousBlock) { - for (nsIFrame* kid = aFrame->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) { + for (nsIFrame* kid : aFrame->PrincipalChildList()) { AddBoxesForFrame(kid, aCallback); } } else { @@ -3535,7 +3539,7 @@ nsLayoutUtils::GetFirstNonAnonymousFrame(nsIFrame* aFrame) pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock || pseudoType == nsCSSAnonBoxes::mozMathMLAnonymousBlock || pseudoType == nsCSSAnonBoxes::mozXULAnonymousBlock) { - for (nsIFrame* kid = aFrame->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) { + for (nsIFrame* kid : aFrame->PrincipalChildList()) { nsIFrame* f = GetFirstNonAnonymousFrame(kid); if (f) { return f; @@ -6961,7 +6965,7 @@ nsLayoutUtils::GetEditableRootContentByContentEditable(nsIDocument* aDocument) nsLayoutUtils::AssertNoDuplicateContinuations(nsIFrame* aContainer, const nsFrameList& aFrameList) { - for (nsIFrame* f = aFrameList.FirstChild(); f ; f = f->GetNextSibling()) { + for (nsIFrame* f : aFrameList) { // Check only later continuations of f; we deal with checking the // earlier continuations when we hit those earlier continuations in // the frame list. diff --git a/layout/generic/ScrollVelocityQueue.cpp b/layout/generic/ScrollVelocityQueue.cpp index a9d6d77d2d..820e6cb5ca 100644 --- a/layout/generic/ScrollVelocityQueue.cpp +++ b/layout/generic/ScrollVelocityQueue.cpp @@ -6,6 +6,7 @@ #include "ScrollVelocityQueue.h" +#include "gfxPrefs.h" #include "nsPresContext.h" #include "nsRefreshDriver.h" diff --git a/layout/generic/nsAbsoluteContainingBlock.cpp b/layout/generic/nsAbsoluteContainingBlock.cpp index 59aed179d2..bb9ca012af 100644 --- a/layout/generic/nsAbsoluteContainingBlock.cpp +++ b/layout/generic/nsAbsoluteContainingBlock.cpp @@ -320,9 +320,7 @@ nsAbsoluteContainingBlock::MarkAllFramesDirty() void nsAbsoluteContainingBlock::DoMarkFramesDirty(bool aMarkAllDirty) { - for (nsIFrame* kidFrame = mAbsoluteFrames.FirstChild(); - kidFrame; - kidFrame = kidFrame->GetNextSibling()) { + for (nsIFrame* kidFrame : mAbsoluteFrames) { if (aMarkAllDirty) { kidFrame->AddStateBits(NS_FRAME_IS_DIRTY); } else if (FrameDependsOnContainer(kidFrame, true, true)) { diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index dd5fefd3bf..766add6d46 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -1312,15 +1312,14 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, line != end; line++) { UpdateLineContainerWidth(line, containerWidth); } - for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) { + for (nsIFrame* f : mFloats) { nsPoint physicalDelta(deltaX, 0); f->MovePositionBy(physicalDelta); } nsFrameList* bulletList = GetOutsideBulletList(); if (bulletList) { nsPoint physicalDelta(deltaX, 0); - for (nsIFrame* f = bulletList->FirstChild(); f; - f = f->GetNextSibling()) { + for (nsIFrame* f : *bulletList) { f->MovePositionBy(physicalDelta); } } @@ -2034,7 +2033,7 @@ nsBlockFrame::ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent, nsFrameList list; aOldParent->CollectFloats(aFirstFrame, list, aReparentSiblings); if (list.NotEmpty()) { - for (nsIFrame* f = list.FirstChild(); f; f = f->GetNextSibling()) { + for (nsIFrame* f : list) { ReparentFrame(f, aOldParent, this); } mFloats.AppendFrames(nullptr, list); @@ -6507,7 +6506,7 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, if (GetPrevInFlow()) { DisplayOverflowContainers(aBuilder, aDirtyRect, aLists); - for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) { + for (nsIFrame* f : mFloats) { if (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT) BuildDisplayListForChild(aBuilder, f, aDirtyRect, aLists); } @@ -7272,7 +7271,7 @@ nsBlockFrame::CheckFloats(nsBlockReflowState& aState) nsAutoTArray storedFloats; bool equal = true; uint32_t i = 0; - for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) { + for (nsIFrame* f : mFloats) { if (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT) continue; storedFloats.AppendElement(f); diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 8ded7940fe..0d09dcb05e 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -846,8 +846,7 @@ nsContainerFrame::DoInlineIntrinsicISize(nsRenderingContext *aRenderingContext, if (aData->currentLine == 0) { aData->currentLine = clonePBM; } - for (nsIFrame *kid = nif->mFrames.FirstChild(); kid; - kid = kid->GetNextSibling()) { + for (nsIFrame* kid : nif->mFrames) { if (aType == nsLayoutUtils::MIN_ISIZE) kid->AddInlineMinISize(aRenderingContext, static_cast(aData)); @@ -1210,8 +1209,7 @@ nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPres nsOverflowContinuationTracker tracker(this, false, false); bool shouldReflowAllKids = aReflowState.ShouldReflowAllKids(); - for (nsIFrame* frame = overflowContainers->FirstChild(); frame; - frame = frame->GetNextSibling()) { + for (nsIFrame* frame : *overflowContainers) { if (frame->GetPrevInFlow()->GetParent() != GetPrevInFlow()) { // frame's prevInFlow has moved, skip reflowing this frame; // it will get reflowed once it's been placed @@ -1301,8 +1299,7 @@ nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder* aBuilder, { nsFrameList* overflowconts = GetPropTableFrames(OverflowContainersProperty()); if (overflowconts) { - for (nsIFrame* frame = overflowconts->FirstChild(); frame; - frame = frame->GetNextSibling()) { + for (nsIFrame* frame : *overflowconts) { BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists); } } diff --git a/layout/generic/nsFontInflationData.cpp b/layout/generic/nsFontInflationData.cpp index b6c7ec2310..5654485571 100644 --- a/layout/generic/nsFontInflationData.cpp +++ b/layout/generic/nsFontInflationData.cpp @@ -289,16 +289,14 @@ static uint32_t DoCharCountOfLargestOption(nsIFrame *aContainer) { uint32_t result = 0; - for (nsIFrame* option = aContainer->GetFirstPrincipalChild(); - option; option = option->GetNextSibling()) { + for (nsIFrame* option : aContainer->PrincipalChildList()) { uint32_t optionResult; if (option->GetContent()->IsHTMLElement(nsGkAtoms::optgroup)) { optionResult = DoCharCountOfLargestOption(option); } else { // REVIEW: Check the frame structure for this! optionResult = 0; - for (nsIFrame *optionChild = option->GetFirstPrincipalChild(); - optionChild; optionChild = optionChild->GetNextSibling()) { + for (nsIFrame* optionChild : option->PrincipalChildList()) { if (optionChild->GetType() == nsGkAtoms::textFrame) { optionResult += nsTextFrameUtils:: ComputeApproximateLengthWithWhitespaceCompression( diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index fc5edc0131..a7565b2351 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -733,12 +733,6 @@ public: public: - static void PrintDisplayItem(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem, - std::stringstream& aStream, - bool aDumpSublist = false, - bool aDumpHtml = false); - static void PrintDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList, bool aDumpHtml = false) diff --git a/layout/generic/nsFrameSetFrame.cpp b/layout/generic/nsFrameSetFrame.cpp index 4381765962..747d694b47 100644 --- a/layout/generic/nsFrameSetFrame.cpp +++ b/layout/generic/nsFrameSetFrame.cpp @@ -675,8 +675,7 @@ void nsHTMLFramesetFrame::GetSizeOfChild(nsIFrame* aChild, // Reflow only creates children frames for and content. // this assumption is used here int i = 0; - for (nsIFrame* child = mFrames.FirstChild(); child; - child = child->GetNextSibling()) { + for (nsIFrame* child : mFrames) { if (aChild == child) { nsIntPoint ignore; GetSizeOfChildAt(i, aWM, aSize, ignore); diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index c01f5d4f60..5329454e62 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -2542,7 +2542,7 @@ ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder, LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0; nsAutoTArray scrollParts; - for (nsIFrame* kid = mOuter->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) { + for (nsIFrame* kid : mOuter->PrincipalChildList()) { if (kid == mScrolledFrame || (kid->IsAbsPosContaininingBlock() || overlayScrollbars) != aPositioned) continue; diff --git a/layout/generic/nsHTMLReflowState.cpp b/layout/generic/nsHTMLReflowState.cpp index 76cd3b28dc..9bda2f30b3 100644 --- a/layout/generic/nsHTMLReflowState.cpp +++ b/layout/generic/nsHTMLReflowState.cpp @@ -1161,7 +1161,7 @@ static bool AreAllEarlierInFlowFramesEmpty(nsIFrame* aFrame, *aFound = false; return false; } - for (nsIFrame* f = aFrame->GetFirstPrincipalChild(); f; f = f->GetNextSibling()) { + for (nsIFrame* f : aFrame->PrincipalChildList()) { bool allEmpty = AreAllEarlierInFlowFramesEmpty(f, aDescendant, aFound); if (*aFound || !allEmpty) { return allEmpty; diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index c77122e8cb..f82ac09acf 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -165,7 +165,7 @@ nsInlineFrame::IsEmpty() return false; } - for (nsIFrame *kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { + for (nsIFrame* kid : mFrames) { if (!kid->IsEmpty()) return false; } diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 940ab66024..2d803781eb 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -10,6 +10,8 @@ #include "nsSubDocumentFrame.h" +#include "gfxPrefs.h" + #include "mozilla/layout/RenderFrameParent.h" #include "nsCOMPtr.h" diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index aa7a3467e3..a32b53eb2d 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -1311,10 +1311,8 @@ BuildTextRuns(gfxContext* aContext, nsTextFrame* aForFrame, // just one line scanner.SetAtStartOfLine(); scanner.SetCommonAncestorWithLastFrame(nullptr); - nsIFrame* child = textRunContainer->GetFirstPrincipalChild(); - while (child) { + for (nsIFrame* child : textRunContainer->PrincipalChildList()) { scanner.ScanFrame(child); - child = child->GetNextSibling(); } // Set mStartOfLine so FlushFrames knows its textrun ends a line scanner.SetAtStartOfLine(); @@ -4649,7 +4647,7 @@ public: aInvalidRegion->Or(oldRect, newRect); } } - + virtual void DisableComponentAlpha() override { mDisableSubpixelAA = true; } diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp index 8d665fa9b5..6e032e1d4a 100644 --- a/layout/generic/nsVideoFrame.cpp +++ b/layout/generic/nsVideoFrame.cpp @@ -307,9 +307,7 @@ nsVideoFrame::Reflow(nsPresContext* aPresContext, // Reflow the child frames. We may have up to two, an image frame // which is the poster, and a box frame, which is the video controls. - for (nsIFrame *child = mFrames.FirstChild(); - child; - child = child->GetNextSibling()) { + for (nsIFrame* child : mFrames) { if (child->GetContent() == mPosterImage) { // Reflow the poster frame. nsImageFrame* imageFrame = static_cast(child); @@ -481,9 +479,7 @@ nsVideoFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // Add child frames to display list. We expect various children, // but only want to draw mPosterImage conditionally. Others we // always add to the display list. - for (nsIFrame *child = mFrames.FirstChild(); - child; - child = child->GetNextSibling()) { + for (nsIFrame* child : mFrames) { if (child->GetContent() != mPosterImage || shouldDisplayPoster) { child->BuildDisplayListForStackingContext(aBuilder, aDirtyRect - child->GetOffsetTo(this), diff --git a/layout/mathml/nsMathMLmtableFrame.cpp b/layout/mathml/nsMathMLmtableFrame.cpp index b3935a66f8..fba6e2dcbb 100644 --- a/layout/mathml/nsMathMLmtableFrame.cpp +++ b/layout/mathml/nsMathMLmtableFrame.cpp @@ -772,9 +772,7 @@ nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext* aPresContext, nsIFrame* rgFrame = tableFrame->GetFirstPrincipalChild(); if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame) return nullptr; - nsTableIterator rowIter(*rgFrame); - nsIFrame* rowFrame = rowIter.First(); - for ( ; rowFrame; rowFrame = rowIter.Next()) { + for (nsIFrame* rowFrame : rgFrame->PrincipalChildList()) { if (aRowIndex == 0) { DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW); if (rowFrame->GetType() != nsGkAtoms::tableRowFrame) diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index 142561bbbb..477638b3e8 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -82,7 +82,7 @@ nsTableCellFrame::Init(nsIContent* aContent, // Let the base class do its initialization nsContainerFrame::Init(aContent, aParent, aPrevInFlow); - if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) { + if (HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER)) { AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT); } @@ -98,7 +98,7 @@ nsTableCellFrame::Init(nsIContent* aContent, void nsTableCellFrame::DestroyFrom(nsIFrame* aDestructRoot) { - if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { + if (HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) { nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot); } @@ -133,8 +133,8 @@ nsTableCellFrame::NotifyPercentBSize(const nsHTMLReflowState& aReflowState) if (nsTableFrame::AncestorsHaveStyleBSize(*cellRS) || (GetTableFrame()->GetEffectiveRowSpan(*this) == 1 && - (cellRS->parentReflowState->frame->GetStateBits() & - NS_ROW_HAS_CELL_WITH_STYLE_BSIZE))) { + cellRS->parentReflowState->frame-> + HasAnyStateBits(NS_ROW_HAS_CELL_WITH_STYLE_BSIZE))) { for (const nsHTMLReflowState *rs = aReflowState.parentReflowState; rs != cellRS; @@ -938,7 +938,7 @@ nsTableCellFrame::Reflow(nsPresContext* aPresContext, kidReflowState.mFlags.mSpecialBSizeReflow = false; if (aReflowState.mFlags.mSpecialBSizeReflow || - (FirstInFlow()->GetStateBits() & NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) { + FirstInFlow()->HasAnyStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) { // We need to force the kid to have mBResize set if we've had a // special reflow in the past, since the non-special reflow needs to // resize back to what it was without the special bsize reflow. @@ -957,7 +957,7 @@ nsTableCellFrame::Reflow(nsPresContext* aPresContext, borderPadding.BStart(wm)); nsRect origRect = firstKid->GetRect(); nsRect origVisualOverflow = firstKid->GetVisualOverflowRect(); - bool firstReflow = (firstKid->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; + bool firstReflow = firstKid->HasAnyStateBits(NS_FRAME_FIRST_REFLOW); ReflowChild(firstKid, aPresContext, kidSize, kidReflowState, wm, kidOrigin, containerWidth, 0, aStatus); @@ -969,7 +969,7 @@ nsTableCellFrame::Reflow(nsPresContext* aPresContext, } // XXXbz is this invalidate actually needed, really? - if (GetStateBits() & NS_FRAME_IS_DIRTY) { + if (HasAnyStateBits(NS_FRAME_IS_DIRTY)) { InvalidateFrameSubtree(); } @@ -1030,7 +1030,7 @@ nsTableCellFrame::Reflow(nsPresContext* aPresContext, // If our parent is in initial reflow, it'll handle invalidating our // entire overflow rect. - if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) && + if (!GetParent()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW) && nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) { InvalidateFrame(); } diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h index d454546e9c..8302b3c883 100644 --- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -280,31 +280,29 @@ inline void nsTableCellFrame::SetDesiredSize(const nsHTMLReflowMetrics & aDesire inline bool nsTableCellFrame::GetContentEmpty() { - return (mState & NS_TABLE_CELL_CONTENT_EMPTY) == - NS_TABLE_CELL_CONTENT_EMPTY; + return HasAnyStateBits(NS_TABLE_CELL_CONTENT_EMPTY); } inline void nsTableCellFrame::SetContentEmpty(bool aContentEmpty) { if (aContentEmpty) { - mState |= NS_TABLE_CELL_CONTENT_EMPTY; + AddStateBits(NS_TABLE_CELL_CONTENT_EMPTY); } else { - mState &= ~NS_TABLE_CELL_CONTENT_EMPTY; + RemoveStateBits(NS_TABLE_CELL_CONTENT_EMPTY); } } inline bool nsTableCellFrame::HasPctOverBSize() { - return (mState & NS_TABLE_CELL_HAS_PCT_OVER_BSIZE) == - NS_TABLE_CELL_HAS_PCT_OVER_BSIZE; + return HasAnyStateBits(NS_TABLE_CELL_HAS_PCT_OVER_BSIZE); } inline void nsTableCellFrame::SetHasPctOverBSize(bool aValue) { if (aValue) { - mState |= NS_TABLE_CELL_HAS_PCT_OVER_BSIZE; + AddStateBits(NS_TABLE_CELL_HAS_PCT_OVER_BSIZE); } else { - mState &= ~NS_TABLE_CELL_HAS_PCT_OVER_BSIZE; + RemoveStateBits(NS_TABLE_CELL_HAS_PCT_OVER_BSIZE); } } diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 0557f37ba4..ac6cfa7068 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -215,7 +215,7 @@ IsRepeatedFrame(nsIFrame* kidFrame) { return (kidFrame->GetType() == nsGkAtoms::tableRowFrame || kidFrame->GetType() == nsGkAtoms::tableRowGroupFrame) && - (kidFrame->GetStateBits() & NS_REPEATED_ROW_OR_ROWGROUP); + kidFrame->HasAnyStateBits(NS_REPEATED_ROW_OR_ROWGROUP); } bool @@ -395,8 +395,8 @@ nsTableFrame::GetEffectiveColCount() const return 0; } // don't count cols at the end that don't have originating cells - for (int32_t colX = colCount - 1; colX >= 0; colX--) { - if (cellMap->GetNumCellsOriginatingInCol(colX) > 0) { + for (int32_t colIdx = colCount - 1; colIdx >= 0; colIdx--) { + if (cellMap->GetNumCellsOriginatingInCol(colIdx) > 0) { break; } colCount--; @@ -410,11 +410,11 @@ nsTableFrame::GetIndexOfLastRealCol() { int32_t numCols = mColFrames.Length(); if (numCols > 0) { - for (int32_t colX = numCols - 1; colX >= 0; colX--) { - nsTableColFrame* colFrame = GetColFrame(colX); + for (int32_t colIdx = numCols - 1; colIdx >= 0; colIdx--) { + nsTableColFrame* colFrame = GetColFrame(colIdx); if (colFrame) { if (eColAnonymousCell != colFrame->GetColType()) { - return colX; + return colIdx; } } } @@ -828,15 +828,15 @@ nsTableFrame::DestroyAnonymousColFrames(int32_t aNumFrames) int32_t endIndex = mColFrames.Length() - 1; int32_t startIndex = (endIndex - aNumFrames) + 1; int32_t numColsRemoved = 0; - for (int32_t colX = endIndex; colX >= startIndex; colX--) { - nsTableColFrame* colFrame = GetColFrame(colX); + for (int32_t colIdx = endIndex; colIdx >= startIndex; colIdx--) { + nsTableColFrame* colFrame = GetColFrame(colIdx); if (colFrame && (eColAnonymousCell == colFrame->GetColType())) { nsTableColGroupFrame* cgFrame = static_cast(colFrame->GetParent()); // remove the frame from the colgroup cgFrame->RemoveChild(*colFrame, false); // remove the frame from the cache, but not the cell map - RemoveCol(nullptr, colX, true, false); + RemoveCol(nullptr, colIdx, true, false); numColsRemoved++; } else { @@ -1430,18 +1430,15 @@ nsTableFrame::SetColumnDimensions(nscoord aBSize, WritingMode aWM, LogicalPoint colGroupOrigin(aWM, aBorderPadding.IStart(aWM) + GetColSpacing(-1), aBorderPadding.BStart(aWM) + GetRowSpacing(-1)); - nsTableIterator iter(mColGroups); nsTableFrame* fif = static_cast(FirstInFlow()); - for (nsIFrame* colGroupFrame = iter.First(); colGroupFrame; - colGroupFrame = iter.Next()) { + for (nsIFrame* colGroupFrame : mColGroups) { MOZ_ASSERT(colGroupFrame->GetType() == nsGkAtoms::tableColGroupFrame); // first we need to figure out the size of the colgroup int32_t groupFirstCol = colIdx; nscoord colGroupISize = 0; nscoord cellSpacingI = 0; - nsTableIterator iterCol(*colGroupFrame); - for (nsIFrame* colFrame = iterCol.First(); colFrame; - colFrame = iterCol.Next()) { + const nsFrameList& columnList = colGroupFrame->PrincipalChildList(); + for (nsIFrame* colFrame : columnList) { if (NS_STYLE_DISPLAY_TABLE_COLUMN == colFrame->StyleDisplay()->mDisplay) { NS_ASSERTION(colIdx < GetColCount(), "invalid number of columns"); @@ -1463,8 +1460,7 @@ nsTableFrame::SetColumnDimensions(nscoord aBSize, WritingMode aWM, // then we can place the columns correctly within the group colIdx = groupFirstCol; LogicalPoint colOrigin(aWM); - for (nsIFrame* colFrame = iterCol.First(); colFrame; - colFrame = iterCol.Next()) { + for (nsIFrame* colFrame : columnList) { if (NS_STYLE_DISPLAY_TABLE_COLUMN == colFrame->StyleDisplay()->mDisplay) { nscoord colISize = fif->GetColumnISizeFromFirstInFlow(colIdx); @@ -1833,6 +1829,7 @@ nsTableFrame::Reflow(nsPresContext* aPresContext, // constrained initial reflow and other reflows which require either a strategy init or balance. // This isn't done during an unconstrained reflow, because it will occur later when the parent // reflows with a constrained isize. + bool fixupKidPositions = false; if (NS_SUBTREE_DIRTY(this) || aReflowState.ShouldReflowAllKids() || IsGeometryDirty() || @@ -1845,7 +1842,7 @@ nsTableFrame::Reflow(nsPresContext* aPresContext, // NS_UNCONSTRAINEDSIZE, but without a style change in between). aReflowState.IsBResize()) { // XXX Eventually, we should modify DistributeBSizeToRows to use - // nsTableRowFrame::GetBSize instead of nsIFrame::BSize(). + // nsTableRowFrame::GetInitialBSize instead of nsIFrame::BSize(). // That way, it will make its calculations based on internal table // frame bsizes as they are before they ever had any extra bsize // distributed to them. In the meantime, this reflows all the @@ -1855,7 +1852,7 @@ nsTableFrame::Reflow(nsPresContext* aPresContext, } bool needToInitiateSpecialReflow = - !!(GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_BSIZE); + HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE); // see if an extra reflow will be necessary in pagination mode // when there is a specified table bsize if (isPaginated && !GetPrevInFlow() && (NS_UNCONSTRAINEDSIZE != aReflowState.AvailableBSize())) { @@ -1882,9 +1879,14 @@ nsTableFrame::Reflow(nsPresContext* aPresContext, ReflowTable(aDesiredSize, aReflowState, availBSize, lastChildReflowed, aStatus); + // If ComputedWidth is unconstrained, we may need to fix child positions + // later (in vertical-rl mode) due to use of 0 as a fake containerWidth + // during ReflowChildren. + fixupKidPositions = wm.IsVerticalRL() && + aReflowState.ComputedWidth() == NS_UNCONSTRAINEDSIZE; // reevaluate special bsize reflow conditions - if (GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_BSIZE) { + if (HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)) { needToInitiateSpecialReflow = true; } @@ -1931,6 +1933,15 @@ nsTableFrame::Reflow(nsPresContext* aPresContext, ProcessRowInserted(aDesiredSize.BSize(wm)); } + if (fixupKidPositions) { + // If we didn't already know the containerWidth (and so used zero during + // ReflowChildren), then we need to update the block-position of our kids. + for (nsIFrame* kid : mFrames) { + kid->MovePositionBy(nsPoint(aDesiredSize.Width(), 0)); + RePositionViews(kid); + } + } + LogicalMargin borderPadding = GetChildAreaOffset(wm, &aReflowState); SetColumnDimensions(aDesiredSize.BSize(wm), wm, borderPadding, aDesiredSize.Width()); @@ -1953,7 +1964,7 @@ nsTableFrame::Reflow(nsPresContext* aPresContext, } aDesiredSize.mOverflowAreas.UnionAllWith(tableRect); - if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) || + if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW) || nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) { nsIFrame::InvalidateFrame(); } @@ -2207,15 +2218,16 @@ nsTableFrame::GetCollapsedISize(const WritingMode aWM, for (nsTableColFrame* colFrame = cgFrame->GetFirstColumn(); colFrame; colFrame = colFrame->GetNextCol()) { const nsStyleDisplay* colDisplay = colFrame->StyleDisplay(); - int32_t colX = colFrame->GetColIndex(); + nscoord colIdx = colFrame->GetColIndex(); if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) { const nsStyleVisibility* colVis = colFrame->StyleVisibility(); bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible); - nscoord colISize = fif->GetColumnISizeFromFirstInFlow(colX); + nscoord colISize = fif->GetColumnISizeFromFirstInFlow(colIdx); if (!collapseGroup && !collapseCol) { iSize += colISize; - if (ColumnHasCellSpacingBefore(colX)) - iSize += GetColSpacing(colX-1); + if (ColumnHasCellSpacingBefore(colIdx)) { + iSize += GetColSpacing(colIdx - 1); + } } else { SetNeedToCollapse(true); @@ -2505,11 +2517,11 @@ nsTableFrame::DoRemoveFrame(ChildListID aListID, mColGroups.DestroyFrame(aOldFrame); nsTableColGroupFrame::ResetColIndices(nextColGroupFrame, firstColIndex); // remove the cols from the table - int32_t colX; - for (colX = lastColIndex; colX >= firstColIndex; colX--) { - nsTableColFrame* colFrame = mColFrames.SafeElementAt(colX); + int32_t colIdx; + for (colIdx = lastColIndex; colIdx >= firstColIndex; colIdx--) { + nsTableColFrame* colFrame = mColFrames.SafeElementAt(colIdx); if (colFrame) { - RemoveCol(colGroup, colX, true, false); + RemoveCol(colGroup, colIdx, true, false); } } @@ -2739,7 +2751,7 @@ nsTableFrame::PlaceChild(nsTableReflowState& aReflowState, { WritingMode wm = aReflowState.reflowState.GetWritingMode(); bool isFirstReflow = - (aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; + aKidFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW); // Place and size the child FinishReflowChild(aKidFrame, PresContext(), aKidDesiredSize, nullptr, @@ -2965,14 +2977,11 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, if (containerWidth == NS_UNCONSTRAINEDSIZE) { NS_WARN_IF_FALSE(wm.IsVertical(), "shouldn't have unconstrained width in horizontal mode"); - if (wm.IsVerticalRL()) { - nsHTMLReflowMetrics desiredSize(wm); - CalcDesiredBSize(aReflowState.reflowState, desiredSize); - containerWidth = desiredSize.Width(); - } else { - // in vertical-lr mode, containerWidth won't actually be used - containerWidth = 0; - } + // We won't know the containerWidth until we've reflowed our contents, + // so use zero for now; in vertical-rl mode, this will mean the children + // are misplaced in the block-direction, and will need to be moved + // rightwards by the true containerWidth once we know it. + containerWidth = 0; } else { containerWidth += aReflowState.reflowState.ComputedPhysicalBorderPadding().LeftRight(); @@ -3032,7 +3041,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, if (reflowAllKids || NS_SUBTREE_DIRTY(kidFrame) || (aReflowState.reflowState.mFlags.mSpecialBSizeReflow && - (isPaginated || (kidFrame->GetStateBits() & + (isPaginated || kidFrame->HasAnyStateBits( NS_FRAME_CONTAINS_RELATIVE_BSIZE)))) { if (pageBreak) { if (allowRepeatedFooter) { @@ -3405,7 +3414,7 @@ nsTableFrame::DistributeBSizeToRows(const nsHTMLReflowState& aReflowState, LogicalRect rowNormalRect(wm, rowFrame->GetNormalRect(), 0); nscoord cellSpacingB = GetRowSpacing(rowFrame->GetRowIndex()); if ((amountUsed < aAmount) && rowFrame->HasPctBSize()) { - nscoord pctBSize = rowFrame->GetBSize(pctBasis); + nscoord pctBSize = rowFrame->GetInitialBSize(pctBasis); nscoord amountForRow = std::min(aAmount - amountUsed, pctBSize - rowNormalRect.BSize(wm)); if (amountForRow > 0) { @@ -3427,7 +3436,7 @@ nsTableFrame::DistributeBSizeToRows(const nsHTMLReflowState& aReflowState, } else { if (amountUsed > 0 && bOriginRow != rowNormalRect.BStart(wm) && - !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + !HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) { rowFrame->InvalidateFrameSubtree(); rowFrame->MovePositionBy(wm, LogicalPoint(wm, 0, bOriginRow - rowNormalRect.BStart(wm))); @@ -3915,10 +3924,10 @@ nsTableFrame::Dump(bool aDumpRows, // dump the columns widths array printf("mColWidths="); int32_t numCols = GetColCount(); - int32_t colX; + int32_t colIdx; nsTableFrame* fif = static_cast(FirstInFlow()); - for (colX = 0; colX < numCols; colX++) { - printf("%d ", fif->GetColumnISizeFromFirstInFlow(colX)); + for (colIdx = 0; colIdx < numCols; colIdx++) { + printf("%d ", fif->GetColumnISizeFromFirstInFlow(colIdx)); } printf("\n"); @@ -3933,12 +3942,12 @@ nsTableFrame::Dump(bool aDumpRows, if (aDumpCols) { // output col frame cache printf("\n col frame cache ->"); - for (colX = 0; colX < numCols; colX++) { - nsTableColFrame* colFrame = mColFrames.ElementAt(colX); - if (0 == (colX % 8)) { + for (colIdx = 0; colIdx < numCols; colIdx++) { + nsTableColFrame* colFrame = mColFrames.ElementAt(colIdx); + if (0 == (colIdx % 8)) { printf("\n"); } - printf ("%d=%p ", colX, static_cast(colFrame)); + printf ("%d=%p ", colIdx, static_cast(colFrame)); nsTableColType colType = colFrame->GetColType(); switch (colType) { case eColContent: @@ -3962,9 +3971,9 @@ nsTableFrame::Dump(bool aDumpRows, colGroupFrame->Dump(1); } } - for (colX = 0; colX < numCols; colX++) { + for (colIdx = 0; colIdx < numCols; colIdx++) { printf("\n"); - nsTableColFrame* colFrame = GetColFrame(colX); + nsTableColFrame* colFrame = GetColFrame(colIdx); colFrame->Dump(1); } } @@ -3976,60 +3985,6 @@ nsTableFrame::Dump(bool aDumpRows, } #endif -// nsTableIterator -nsTableIterator::nsTableIterator(nsIFrame& aSource) -{ - nsIFrame* firstChild = aSource.GetFirstPrincipalChild(); - Init(firstChild); -} - -nsTableIterator::nsTableIterator(nsFrameList& aSource) -{ - nsIFrame* firstChild = aSource.FirstChild(); - Init(firstChild); -} - -void -nsTableIterator::Init(nsIFrame* aFirstChild) -{ - mFirstListChild = aFirstChild; - mFirstChild = aFirstChild; - mCurrentChild = nullptr; - mCount = -1; -} - -nsIFrame* -nsTableIterator::First() -{ - mCurrentChild = mFirstChild; - return mCurrentChild; -} - -nsIFrame* -nsTableIterator::Next() -{ - if (!mCurrentChild) { - return nullptr; - } - - mCurrentChild = mCurrentChild->GetNextSibling(); - return mCurrentChild; -} - -int32_t -nsTableIterator::Count() -{ - if (-1 == mCount) { - mCount = 0; - nsIFrame* child = mFirstListChild; - while (nullptr != child) { - mCount++; - child = child->GetNextSibling(); - } - } - return mCount; -} - bool nsTableFrame::ColumnHasCellSpacingBefore(int32_t aColIndex) const { @@ -5812,28 +5767,28 @@ nsTableFrame::CalcBCBorders() propData->mTopBorderWidth = 0; tableBorderReset[NS_SIDE_TOP] = true; } - for (int32_t colX = info.mColIndex; colX <= info.GetCellEndColIndex(); - colX++) { - info.SetColumn(colX); + for (int32_t colIdx = info.mColIndex; + colIdx <= info.GetCellEndColIndex(); colIdx++) { + info.SetColumn(colIdx); currentBorder = info.GetBStartEdgeBorder(); // update/store the top left & top right corners of the seg - BCCornerInfo& tlCorner = topCorners[colX]; // top left - if (0 == colX) { + BCCornerInfo& tlCorner = topCorners[colIdx]; // top left + if (0 == colIdx) { // we are on right hand side of the corner tlCorner.Set(NS_SIDE_RIGHT, currentBorder); } else { tlCorner.Update(NS_SIDE_RIGHT, currentBorder); - tableCellMap->SetBCBorderCorner(eTopLeft, *iter.mCellMap, 0, 0, colX, + tableCellMap->SetBCBorderCorner(eTopLeft, *iter.mCellMap, 0, 0, colIdx, mozilla::css::Side(tlCorner.ownerSide), tlCorner.subWidth, tlCorner.bevel); } - topCorners[colX + 1].Set(NS_SIDE_LEFT, currentBorder); // top right + topCorners[colIdx + 1].Set(NS_SIDE_LEFT, currentBorder); // top right // update lastTopBorder and see if a new segment starts startSeg = SetHorBorder(currentBorder, tlCorner, lastTopBorder); // store the border segment in the cell map - tableCellMap->SetBCBorderEdge(NS_SIDE_TOP, *iter.mCellMap, 0, 0, colX, + tableCellMap->SetBCBorderEdge(NS_SIDE_TOP, *iter.mCellMap, 0, 0, colIdx, 1, currentBorder.owner, currentBorder.width, startSeg); @@ -6016,9 +5971,9 @@ nsTableFrame::CalcBCBorders() priorAjaInfo = ajaInfo; } } - for (int32_t colX = info.mColIndex + 1; colX <= info.GetCellEndColIndex(); - colX++) { - lastVerBorders[colX].Reset(0,1); + for (int32_t colIdx = info.mColIndex + 1; + colIdx <= info.GetCellEndColIndex(); colIdx++) { + lastVerBorders[colIdx].Reset(0,1); } // find the dominant border considering the cell's bottom border, adjacent @@ -6029,25 +5984,25 @@ nsTableFrame::CalcBCBorders() propData->mBottomBorderWidth = 0; tableBorderReset[NS_SIDE_BOTTOM] = true; } - for (int32_t colX = info.mColIndex; colX <= info.GetCellEndColIndex(); - colX++) { - info.SetColumn(colX); + for (int32_t colIdx = info.mColIndex; + colIdx <= info.GetCellEndColIndex(); colIdx++) { + info.SetColumn(colIdx); currentBorder = info.GetBEndEdgeBorder(); // update/store the bottom left & bottom right corners - BCCornerInfo& blCorner = bottomCorners[colX]; // bottom left + BCCornerInfo& blCorner = bottomCorners[colIdx]; // bottom left blCorner.Update(NS_SIDE_RIGHT, currentBorder); tableCellMap->SetBCBorderCorner(eBottomLeft, *iter.mCellMap, iter.mRowGroupStart, info.GetCellEndRowIndex(), - colX, + colIdx, mozilla::css::Side(blCorner.ownerSide), blCorner.subWidth, blCorner.bevel); - BCCornerInfo& brCorner = bottomCorners[colX + 1]; // bottom right + BCCornerInfo& brCorner = bottomCorners[colIdx + 1]; // bottom right brCorner.Update(NS_SIDE_LEFT, currentBorder); - if (info.mNumTableCols == colX + 1) { // lower right corner of the table + if (info.mNumTableCols == colIdx + 1) { // lower right corner of the table tableCellMap->SetBCBorderCorner(eBottomRight, *iter.mCellMap, iter.mRowGroupStart, - info.GetCellEndRowIndex(),colX, + info.GetCellEndRowIndex(), colIdx, mozilla::css::Side(brCorner.ownerSide), brCorner.subWidth, brCorner.bevel, true); @@ -6066,12 +6021,12 @@ nsTableFrame::CalcBCBorders() tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *iter.mCellMap, iter.mRowGroupStart, info.GetCellEndRowIndex(), - colX, 1, currentBorder.owner, + colIdx, 1, currentBorder.owner, currentBorder.width, startSeg); // update lastBottomBorders lastBottomBorder.rowIndex = info.GetCellEndRowIndex() + 1; lastBottomBorder.rowSpan = info.mRowSpan; - lastBottomBorders[colX] = lastBottomBorder; + lastBottomBorders[colIdx] = lastBottomBorder; info.SetBEndBorderWidths(currentBorder.width); info.SetTableBEndBorderWidth(currentBorder.width); @@ -6082,23 +6037,23 @@ nsTableFrame::CalcBCBorders() } else { int32_t segLength = 0; - for (int32_t colX = info.mColIndex; colX <= info.GetCellEndColIndex(); - colX += segLength) { - iter.PeekBottom(info, colX, ajaInfo); + for (int32_t colIdx = info.mColIndex; + colIdx <= info.GetCellEndColIndex(); colIdx += segLength) { + iter.PeekBottom(info, colIdx, ajaInfo); currentBorder = info.GetBEndInternalBorder(); adjacentBorder = ajaInfo.GetBStartInternalBorder(); currentBorder = CompareBorders(!CELL_CORNER, currentBorder, adjacentBorder, HORIZONTAL); - segLength = std::max(1, ajaInfo.mColIndex + ajaInfo.mColSpan - colX); - segLength = std::min(segLength, info.mColIndex + info.mColSpan - colX); + segLength = std::max(1, ajaInfo.mColIndex + ajaInfo.mColSpan - colIdx); + segLength = std::min(segLength, info.mColIndex + info.mColSpan - colIdx); // update, store the bottom left corner - BCCornerInfo& blCorner = bottomCorners[colX]; // bottom left - bool hitsSpanBelow = (colX > ajaInfo.mColIndex) && - (colX < ajaInfo.mColIndex + ajaInfo.mColSpan); + BCCornerInfo& blCorner = bottomCorners[colIdx]; // bottom left + bool hitsSpanBelow = (colIdx > ajaInfo.mColIndex) && + (colIdx < ajaInfo.mColIndex + ajaInfo.mColSpan); bool update = true; - if (colX == info.mColIndex && colX > damageArea.StartCol()) { - int32_t prevRowIndex = lastBottomBorders[colX - 1].rowIndex; + if (colIdx == info.mColIndex && colIdx > damageArea.StartCol()) { + int32_t prevRowIndex = lastBottomBorders[colIdx - 1].rowIndex; if (prevRowIndex > info.GetCellEndRowIndex() + 1) { // hits a rowspan on the right update = false; @@ -6106,7 +6061,7 @@ nsTableFrame::CalcBCBorders() } else if (prevRowIndex < info.GetCellEndRowIndex() + 1) { // spans below the cell to the left - topCorners[colX] = blCorner; + topCorners[colIdx] = blCorner; blCorner.Set(NS_SIDE_RIGHT, currentBorder); update = false; } @@ -6115,21 +6070,21 @@ nsTableFrame::CalcBCBorders() blCorner.Update(NS_SIDE_RIGHT, currentBorder); } if (info.GetCellEndRowIndex() < damageArea.EndRow() && - colX >= damageArea.StartCol()) { + colIdx >= damageArea.StartCol()) { if (hitsSpanBelow) { tableCellMap->SetBCBorderCorner(eBottomLeft, *iter.mCellMap, iter.mRowGroupStart, - info.GetCellEndRowIndex(), colX, + info.GetCellEndRowIndex(), colIdx, mozilla::css::Side(blCorner.ownerSide), blCorner.subWidth, blCorner.bevel); } // store any corners this cell spans together with the aja cell - for (int32_t cX = colX + 1; cX < colX + segLength; cX++) { - BCCornerInfo& corner = bottomCorners[cX]; + for (int32_t c = colIdx + 1; c < colIdx + segLength; c++) { + BCCornerInfo& corner = bottomCorners[c]; corner.Set(NS_SIDE_RIGHT, currentBorder); tableCellMap->SetBCBorderCorner(eBottomLeft, *iter.mCellMap, iter.mRowGroupStart, - info.GetCellEndRowIndex(), cX, + info.GetCellEndRowIndex(), c, mozilla::css::Side(corner.ownerSide), corner.subWidth, false); @@ -6147,23 +6102,23 @@ nsTableFrame::CalcBCBorders() } lastBottomBorder.rowIndex = info.GetCellEndRowIndex() + 1; lastBottomBorder.rowSpan = info.mRowSpan; - for (int32_t cX = colX; cX < colX + segLength; cX++) { - lastBottomBorders[cX] = lastBottomBorder; + for (int32_t c = colIdx; c < colIdx + segLength; c++) { + lastBottomBorders[c] = lastBottomBorder; } // store the border segment the cell map and update cellBorders if (info.GetCellEndRowIndex() < damageArea.EndRow() && - colX >= damageArea.StartCol() && colX < damageArea.EndCol()) { + colIdx >= damageArea.StartCol() && colIdx < damageArea.EndCol()) { tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *iter.mCellMap, iter.mRowGroupStart, info.GetCellEndRowIndex(), - colX, segLength, currentBorder.owner, + colIdx, segLength, currentBorder.owner, currentBorder.width, startSeg); info.SetBEndBorderWidths(currentBorder.width); ajaInfo.SetBStartBorderWidths(currentBorder.width); } // update bottom right corner - BCCornerInfo& brCorner = bottomCorners[colX + segLength]; + BCCornerInfo& brCorner = bottomCorners[colIdx + segLength]; brCorner.Update(NS_SIDE_LEFT, currentBorder); } if (!gotRowBorder && 1 == info.mRowSpan && @@ -7508,7 +7463,7 @@ nsTableFrame::InvalidateTableFrame(nsIFrame* aFrame, nsIFrame* parent = aFrame->GetParent(); NS_ASSERTION(parent, "What happened here?"); - if (parent->GetStateBits() & NS_FRAME_FIRST_REFLOW) { + if (parent->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) { // Don't bother; we'll invalidate the parent's overflow rect when // we finish reflowing it. return; diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index 61f7201542..ba790f23dc 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -1007,23 +1007,6 @@ inline void nsTableFrame::SetContinuousLeftBCBorderWidth(nscoord aValue) mBits.mLeftContBCBorder = (unsigned) aValue; } -class nsTableIterator -{ -public: - explicit nsTableIterator(nsIFrame& aSource); - explicit nsTableIterator(nsFrameList& aSource); - nsIFrame* First(); - nsIFrame* Next(); - int32_t Count(); - -protected: - void Init(nsIFrame* aFirstChild); - nsIFrame* mFirstListChild; - nsIFrame* mFirstChild; - nsIFrame* mCurrentChild; - int32_t mCount; -}; - #define ABORT0() \ {NS_ASSERTION(false, "CellIterator program error"); \ return;} diff --git a/layout/tables/nsTableOuterFrame.cpp b/layout/tables/nsTableOuterFrame.cpp index 088da77ab7..6095d3eb3a 100644 --- a/layout/tables/nsTableOuterFrame.cpp +++ b/layout/tables/nsTableOuterFrame.cpp @@ -796,7 +796,7 @@ nsTableOuterFrame::Reflow(nsPresContext* aPresContext, aDesiredSize.ClearSize(); aStatus = NS_FRAME_COMPLETE; - if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) { // Set up our kids. They're already present, on an overflow list, // or there are none so we'll create them now MoveOverflowToChildList(); @@ -808,7 +808,7 @@ nsTableOuterFrame::Reflow(nsPresContext* aPresContext, nsRect origInnerRect = InnerTableFrame()->GetRect(); nsRect origInnerVisualOverflow = InnerTableFrame()->GetVisualOverflowRect(); bool innerFirstReflow = - (InnerTableFrame()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; + InnerTableFrame()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW); nsRect origCaptionRect; nsRect origCaptionVisualOverflow; bool captionFirstReflow; @@ -817,7 +817,7 @@ nsTableOuterFrame::Reflow(nsPresContext* aPresContext, origCaptionVisualOverflow = mCaptionFrames.FirstChild()->GetVisualOverflowRect(); captionFirstReflow = - (mCaptionFrames.FirstChild()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; + mCaptionFrames.FirstChild()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW); } // ComputeAutoSize has to match this logic. diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index 868b03e261..5516caa0fc 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -158,7 +158,7 @@ nsTableRowFrame::Init(nsIContent* aContent, void nsTableRowFrame::DestroyFrom(nsIFrame* aDestructRoot) { - if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { + if (HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) { nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot); } @@ -303,13 +303,11 @@ GetBSizeOfRowsSpannedBelowFirst(nsTableCellFrame& aTableCellFrame, nsTableCellFrame* nsTableRowFrame::GetFirstCell() { - nsIFrame* childFrame = mFrames.FirstChild(); - while (childFrame) { + for (nsIFrame* childFrame : mFrames) { nsTableCellFrame *cellFrame = do_QueryFrame(childFrame); if (cellFrame) { return cellFrame; } - childFrame = childFrame->GetNextSibling(); } return nullptr; } @@ -322,26 +320,59 @@ nsTableRowFrame::DidResize() { // Resize and re-align the cell frames based on our row bsize nsTableFrame* tableFrame = GetTableFrame(); - nsTableIterator iter(*this); - nsIFrame* childFrame = iter.First(); WritingMode wm = GetWritingMode(); nsHTMLReflowMetrics desiredSize(wm); desiredSize.SetSize(wm, GetLogicalSize(wm)); desiredSize.SetOverflowAreasToDesiredBounds(); - while (childFrame) { + nscoord containerWidth = mRect.width; + + for (nsIFrame* childFrame : mFrames) { nsTableCellFrame *cellFrame = do_QueryFrame(childFrame); if (cellFrame) { nscoord cellBSize = BSize(wm) + GetBSizeOfRowsSpannedBelowFirst(*cellFrame, *tableFrame, wm); - // resize the cell's bsize + // If the bsize for the cell has changed, we need to reset it; + // and in vertical-rl mode, we need to update the cell's block position + // to account for the containerWidth, which may not have been known + // earlier, so we always apply it here. LogicalSize cellSize = cellFrame->GetLogicalSize(wm); - nsRect cellVisualOverflow = cellFrame->GetVisualOverflowRect(); - if (cellSize.BSize(wm) != cellBSize) { - cellSize.BSize(wm) = cellBSize; + if (cellSize.BSize(wm) != cellBSize || wm.IsVerticalRL()) { nsRect cellOldRect = cellFrame->GetRect(); + nsRect cellVisualOverflow = cellFrame->GetVisualOverflowRect(); + + if (wm.IsVerticalRL()) { + // Get the old position of the cell, as we want to preserve its + // inline coordinate. + LogicalPoint oldPos = + cellFrame->GetLogicalPosition(wm, containerWidth); + + // The cell should normally be aligned with the row's block-start, + // so set the B component of the position to zero: + LogicalPoint newPos(wm, oldPos.I(wm), 0); + + // ...unless relative positioning is in effect, in which case the + // cell may have been moved away from the row's block-start + if (cellFrame->IsRelativelyPositioned()) { + // Find out where the cell would have been without relative + // positioning. + LogicalPoint oldNormalPos = + cellFrame->GetLogicalNormalPosition(wm, containerWidth); + // The difference (if any) between oldPos and oldNormalPos reflects + // relative positioning that was applied to the cell, and which we + // need to incorporate when resetting the position. + newPos.B(wm) = oldPos.B(wm) - oldNormalPos.B(wm); + } + + if (oldPos != newPos) { + cellFrame->SetPosition(wm, newPos, containerWidth); + nsTableFrame::RePositionViews(cellFrame); + } + } + + cellSize.BSize(wm) = cellBSize; cellFrame->SetSize(wm, cellSize); nsTableFrame::InvalidateTableFrame(cellFrame, cellOldRect, cellVisualOverflow, @@ -359,8 +390,6 @@ nsTableRowFrame::DidResize() // Note that if the cell's *content* needs to change in response // to this height, it will get a special bsize reflow. } - // Get the next child - childFrame = iter.Next(); } FinishAndStoreOverflow(&desiredSize); if (HasView()) { @@ -402,25 +431,21 @@ nscoord nsTableRowFrame::GetRowBaseline(WritingMode aWM) // bppppppppppppppppb // bbbbbbbbbbbbbbbbbb - nsTableIterator iter(*this); - nsIFrame* childFrame = iter.First(); nscoord ascent = 0; nscoord containerWidth = GetRect().width; - while (childFrame) { + for (nsIFrame* childFrame : mFrames) { if (IS_TABLE_CELL(childFrame->GetType())) { nsIFrame* firstKid = childFrame->GetFirstPrincipalChild(); ascent = std::max(ascent, LogicalRect(aWM, firstKid->GetNormalRect(), containerWidth).BEnd(aWM)); } - // Get the next child - childFrame = iter.Next(); } return ascent; } nscoord -nsTableRowFrame::GetBSize(nscoord aPctBasis) const +nsTableRowFrame::GetInitialBSize(nscoord aPctBasis) const { nscoord bsize = 0; if ((aPctBasis > 0) && HasPctBSize()) { @@ -463,7 +488,7 @@ nsTableRowFrame::UpdateBSize(nscoord aBSize, if (aBSize != NS_UNCONSTRAINEDSIZE) { if (!(aCellFrame->HasVerticalAlignBaseline())) { // only the cell's height matters - if (GetBSize() < aBSize) { + if (GetInitialBSize() < aBSize) { int32_t rowSpan = aTableFrame->GetEffectiveRowSpan(*aCellFrame); if (rowSpan == 1) { SetContentBSize(aBSize); @@ -485,7 +510,7 @@ nsTableRowFrame::UpdateBSize(nscoord aBSize, } } // keep the tallest bsize in sync - if (GetBSize() < mMaxCellAscent + mMaxCellDescent) { + if (GetInitialBSize() < mMaxCellAscent + mMaxCellDescent) { SetContentBSize(mMaxCellAscent + mMaxCellDescent); } } @@ -511,8 +536,7 @@ nsTableRowFrame::CalcBSize(const nsHTMLReflowState& aReflowState) } // calc() with percentages is treated like 'auto' on table rows. - for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame; - kidFrame = kidFrame->GetNextSibling()) { + for (nsIFrame* kidFrame : mFrames) { nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame); if (cellFrame) { MOZ_ASSERT(cellFrame->GetWritingMode() == wm); @@ -530,7 +554,7 @@ nsTableRowFrame::CalcBSize(const nsHTMLReflowState& aReflowState) UpdateBSize(desSize.BSize(wm), ascent, descent, tableFrame, cellFrame); } } - return GetBSize(); + return GetInitialBSize(); } /** @@ -723,16 +747,16 @@ GetSpaceBetween(int32_t aPrevColIndex, bool aCheckVisibility) { nscoord space = 0; - int32_t colX; + int32_t colIdx; nsTableFrame* fifTable = static_cast(aTableFrame.FirstInFlow()); - for (colX = aPrevColIndex + 1; aColIndex > colX; colX++) { + for (colIdx = aPrevColIndex + 1; aColIndex > colIdx; colIdx++) { bool isCollapsed = false; if (!aCheckVisibility) { - space += fifTable->GetColumnISizeFromFirstInFlow(colX); + space += fifTable->GetColumnISizeFromFirstInFlow(colIdx); } else { - nsTableColFrame* colFrame = aTableFrame.GetColFrame(colX); + nsTableColFrame* colFrame = aTableFrame.GetColFrame(colIdx); const nsStyleVisibility* colVis = colFrame->StyleVisibility(); bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible); nsIFrame* cgFrame = colFrame->GetParent(); @@ -741,10 +765,10 @@ GetSpaceBetween(int32_t aPrevColIndex, groupVis->mVisible); isCollapsed = collapseCol || collapseGroup; if (!isCollapsed) - space += fifTable->GetColumnISizeFromFirstInFlow(colX); + space += fifTable->GetColumnISizeFromFirstInFlow(colIdx); } - if (!isCollapsed && aTableFrame.ColumnHasCellSpacingBefore(colX)) { - space += aTableFrame.GetColSpacing(colX - 1); + if (!isCollapsed && aTableFrame.ColumnHasCellSpacingBefore(colIdx)) { + space += aTableFrame.GetColSpacing(colIdx - 1); } } return space; @@ -784,10 +808,8 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, int32_t cellColSpan = 1; // must be defined here so it's set properly for non-cell kids - nsTableIterator iter(*this); // remember the col index of the previous cell to handle rowspans into this row - int32_t firstPrevColIndex = -1; - int32_t prevColIndex = firstPrevColIndex; + int32_t prevColIndex = -1; nscoord iCoord = 0; // running total of children inline-coord offset // This computes the max of all cell bsizes @@ -802,7 +824,7 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, containerWidth += aReflowState.ComputedPhysicalBorderPadding().LeftRight(); } - for (nsIFrame* kidFrame = iter.First(); kidFrame; kidFrame = iter.Next()) { + for (nsIFrame* kidFrame : mFrames) { nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame); if (!cellFrame) { // XXXldb nsCSSFrameConstructor needs to enforce this! @@ -838,8 +860,8 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, } } if (aReflowState.mFlags.mSpecialBSizeReflow) { - if (!isPaginated && !(cellFrame->GetStateBits() & - NS_FRAME_CONTAINS_RELATIVE_BSIZE)) { + if (!isPaginated && + !cellFrame->HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)) { continue; } } @@ -863,14 +885,15 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, kidFrame->GetLogicalNormalPosition(wm, containerWidth); // All cells' no-relative-positioning position should be snapped to the // row's bstart edge. - // XXX This currently doesn't hold in vertical-rl mode, which is probably - // a bug, but to enable progress with testing I'm temporarily neutering - // the assertion in that case (bug 1174711). - MOZ_ASSERT(origKidNormalPosition.B(wm) == 0 || wm.IsVerticalRL()); + // This doesn't hold in vertical-rl mode, where we don't yet know the + // correct containerWidth for the row frame. In that case, we'll have to + // fix up child positions later, after determining our desiredSize. + NS_ASSERTION(origKidNormalPosition.B(wm) == 0 || wm.IsVerticalRL(), + "unexpected kid position"); + nsRect kidVisualOverflow = kidFrame->GetVisualOverflowRect(); LogicalPoint kidPosition(wm, iCoord, 0); - bool firstReflow = - (kidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; + bool firstReflow = kidFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW); if (doReflowChild) { // Calculate the available isize for the table cell using the known @@ -889,13 +912,13 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, NS_ASSERTION(cellFrame->GetWritingMode() == wm, "expected consistent writing-mode within table"); LogicalSize cellDesiredSize = cellFrame->GetDesiredSize(); - if ((availCellISize != cellFrame->GetPriorAvailISize()) || + if ((availCellISize != cellFrame->GetPriorAvailISize()) || (cellDesiredSize.ISize(wm) > cellFrame->GetPriorAvailISize()) || - (GetStateBits() & NS_FRAME_IS_DIRTY) || - isPaginated || - NS_SUBTREE_DIRTY(cellFrame) || + HasAnyStateBits(NS_FRAME_IS_DIRTY) || + isPaginated || + NS_SUBTREE_DIRTY(cellFrame) || // See if it needs a special reflow, or if it had one that we need to undo. - (cellFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_BSIZE) || + cellFrame->HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE) || HasPctBSize()) { // Reflow the cell to fit the available isize, bsize // XXX The old IR_ChildIsDirty code used availCellISize here. @@ -1051,7 +1074,7 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, // Any children whose width was not the same as our final // aDesiredSize.BSize will have been misplaced earlier at the // FinishReflowChild stage. So fix them up now. - for (nsIFrame* kidFrame = iter.First(); kidFrame; kidFrame = iter.Next()) { + for (nsIFrame* kidFrame : mFrames) { nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame); if (!cellFrame) { continue; @@ -1110,7 +1133,7 @@ nsTableRowFrame::Reflow(nsPresContext* aPresContext, // If our parent is in initial reflow, it'll handle invalidating our // entire overflow rect. - if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) && + if (!GetParent()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW) && nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) { InvalidateFrame(); } @@ -1175,8 +1198,8 @@ nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext, nsTableFrame::InvalidateTableFrame(aCellFrame, cellRect.GetPhysicalRect(wm, containerWidth), cellVisualOverflow, - (aCellFrame->GetStateBits() & - NS_FRAME_FIRST_REFLOW) != 0); + aCellFrame-> + HasAnyStateBits(NS_FRAME_FIRST_REFLOW)); aCellFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED); @@ -1242,19 +1265,14 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, rowRect.BSize(wm) = 0; } else { // row is not collapsed - nsTableIterator iter(*this); // remember the col index of the previous cell to handle rowspans into this // row - int32_t firstPrevColIndex = -1; - int32_t prevColIndex = firstPrevColIndex; + int32_t prevColIndex = -1; nscoord iPos = 0; // running total of children inline-axis offset nsTableFrame* fifTable = static_cast(tableFrame->FirstInFlow()); - int32_t colIncrement = 1; - - nsIFrame* kidFrame = iter.First(); - while (kidFrame) { + for (nsIFrame* kidFrame : mFrames) { nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame); if (cellFrame) { int32_t cellColIndex; @@ -1271,13 +1289,12 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, // remember the last (iend-wards-most) column this cell spans into prevColIndex = cellColIndex + cellColSpan - 1; - int32_t startIndex = cellColIndex; int32_t actualColSpan = cellColSpan; bool isVisible = false; - for (int32_t colX = startIndex; actualColSpan > 0; - colX += colIncrement, actualColSpan--) { + for (int32_t colIdx = cellColIndex; actualColSpan > 0; + colIdx++, actualColSpan--) { - nsTableColFrame* colFrame = tableFrame->GetColFrame(colX); + nsTableColFrame* colFrame = tableFrame->GetColFrame(colIdx); const nsStyleVisibility* colVis = colFrame->StyleVisibility(); bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible); @@ -1287,15 +1304,15 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, groupVis->mVisible); bool isCollapsed = collapseCol || collapseGroup; if (!isCollapsed) { - cRect.ISize(wm) += fifTable->GetColumnISizeFromFirstInFlow(colX); + cRect.ISize(wm) += fifTable->GetColumnISizeFromFirstInFlow(colIdx); isVisible = true; if ((actualColSpan > 1)) { nsTableColFrame* nextColFrame = - tableFrame->GetColFrame(colX + colIncrement); + tableFrame->GetColFrame(colIdx + 1); const nsStyleVisibility* nextColVis = nextColFrame->StyleVisibility(); if ( (NS_STYLE_VISIBILITY_COLLAPSE != nextColVis->mVisible) && - tableFrame->ColumnHasCellSpacingBefore(colX + colIncrement)) { + tableFrame->ColumnHasCellSpacingBefore(colIdx + 1)) { cRect.ISize(wm) += tableFrame->GetColSpacing(cellColIndex); } } @@ -1351,7 +1368,6 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, oldCellVisualOverflow, false); } } - kidFrame = iter.Next(); // Get the next child } } @@ -1375,8 +1391,7 @@ nsTableRowFrame::InsertCellFrame(nsTableCellFrame* aFrame, { // Find the cell frame where col index < aColIndex nsTableCellFrame* priorCell = nullptr; - for (nsIFrame* child = mFrames.FirstChild(); child; - child = child->GetNextSibling()) { + for (nsIFrame* child : mFrames) { nsTableCellFrame *cellFrame = do_QueryFrame(child); if (cellFrame) { int32_t colIndex; @@ -1461,10 +1476,9 @@ nsTableRowFrame::AccessibleType() */ void nsTableRowFrame::InitHasCellWithStyleBSize(nsTableFrame* aTableFrame) { - nsTableIterator iter(*this); WritingMode wm = GetWritingMode(); - for (nsIFrame* kidFrame = iter.First(); kidFrame; kidFrame = iter.Next()) { + for (nsIFrame* kidFrame : mFrames) { nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame); if (!cellFrame) { NS_NOTREACHED("Table row has a non-cell child."); diff --git a/layout/tables/nsTableRowFrame.h b/layout/tables/nsTableRowFrame.h index 18d775d2e6..b969d86d04 100644 --- a/layout/tables/nsTableRowFrame.h +++ b/layout/tables/nsTableRowFrame.h @@ -203,7 +203,7 @@ public: void SetPctBSize(float aPctValue, bool aForce = false); - nscoord GetBSize(nscoord aBasis = 0) const; + nscoord GetInitialBSize(nscoord aBasis = 0) const; nsTableRowFrame* GetNextRow() const; @@ -391,16 +391,15 @@ inline float nsTableRowFrame::GetPctBSize() const inline bool nsTableRowFrame::HasUnpaginatedBSize() { - return (mState & NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE) == - NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE; + return HasAnyStateBits(NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE); } inline void nsTableRowFrame::SetHasUnpaginatedBSize(bool aValue) { if (aValue) { - mState |= NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE; + AddStateBits(NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE); } else { - mState &= ~NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE; + RemoveStateBits(NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE); } } diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 7cceb13570..1a0d88c567 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -37,7 +37,7 @@ nsTableRowGroupFrame::~nsTableRowGroupFrame() void nsTableRowGroupFrame::DestroyFrom(nsIFrame* aDestructRoot) { - if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { + if (HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) { nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot); } @@ -83,8 +83,7 @@ int32_t nsTableRowGroupFrame::GetStartRowIndex() void nsTableRowGroupFrame::AdjustRowIndices(int32_t aRowIndex, int32_t anAdjustment) { - nsIFrame* rowFrame = GetFirstPrincipalChild(); - for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) { + for (nsIFrame* rowFrame : mFrames) { if (NS_STYLE_DISPLAY_TABLE_ROW==rowFrame->StyleDisplay()->mDisplay) { int32_t index = ((nsTableRowFrame*)rowFrame)->GetRowIndex(); if (index >= aRowIndex) @@ -267,8 +266,7 @@ nsTableRowGroupFrame::PlaceChild(nsPresContext* aPresContext, const nsRect& aOriginalKidRect, const nsRect& aOriginalKidVisualOverflow) { - bool isFirstReflow = - (aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; + bool isFirstReflow = aKidFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW); // Place and size the child FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, nullptr, @@ -343,7 +341,10 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext, bool haveRow = false; bool reflowAllKids = aReflowState.reflowState.ShouldReflowAllKids() || tableFrame->IsGeometryDirty(); - bool needToCalcRowBSizes = reflowAllKids; + + // in vertical-rl mode, we always need the row bsizes in order to + // get the necessary containerWidth for placing our kids + bool needToCalcRowBSizes = reflowAllKids || wm.IsVerticalRL(); nscoord containerWidth = aReflowState.reflowState.ComputedWidth(); if (containerWidth == NS_UNCONSTRAINEDSIZE) { @@ -370,8 +371,8 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext, if (reflowAllKids || NS_SUBTREE_DIRTY(kidFrame) || (aReflowState.reflowState.mFlags.mSpecialBSizeReflow && - (isPaginated || (kidFrame->GetStateBits() & - NS_FRAME_CONTAINS_RELATIVE_BSIZE)))) { + (isPaginated || + kidFrame->HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)))) { LogicalRect oldKidRect = kidFrame->GetLogicalRect(wm, containerWidth); nsRect oldKidVisualOverflow = kidFrame->GetVisualOverflowRect(); @@ -418,7 +419,7 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext, aReflowState.bCoord += cellSpacingB; if (!reflowAllKids) { - if (IsSimpleRowFrame(aReflowState.tableFrame, kidFrame)) { + if (IsSimpleRowFrame(aReflowState.tableFrame, rowFrame)) { // Inform the row of its new bsize. rowFrame->DidResize(); // the overflow area may have changed inflate the overflow area @@ -483,8 +484,7 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext, nsTableRowFrame* nsTableRowGroupFrame::GetFirstRow() { - for (nsIFrame* childFrame = mFrames.FirstChild(); childFrame; - childFrame = childFrame->GetNextSibling()) { + for (nsIFrame* childFrame : mFrames) { nsTableRowFrame *rowFrame = do_QueryFrame(childFrame); if (rowFrame) { return rowFrame; @@ -590,7 +590,7 @@ nsTableRowGroupFrame::CalculateRowBSizes(nsPresContext* aPresContext, if (!rowFrame->GetPrevInFlow()) { if (rowFrame->HasPctBSize()) { rowInfo[rowIndex].hasPctBSize = true; - rowInfo[rowIndex].pctBSize = rowFrame->GetBSize(pctBSizeBasis); + rowInfo[rowIndex].pctBSize = rowFrame->GetInitialBSize(pctBSizeBasis); } rowInfo[rowIndex].hasStyleBSize = rowFrame->HasStyleBSize(); nonPctBSize = std::max(nonPctBSize, rowFrame->GetFixedBSize()); @@ -1384,7 +1384,7 @@ nsTableRowGroupFrame::Reflow(nsPresContext* aPresContext, // If our parent is in initial reflow, it'll handle invalidating our // entire overflow rect. - if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) && + if (!GetParent()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW) && nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) { InvalidateFrame(); } @@ -1582,20 +1582,16 @@ nsTableRowGroupFrame::GetBSizeBasis(const nsHTMLReflowState& aReflowState) bool nsTableRowGroupFrame::IsSimpleRowFrame(nsTableFrame* aTableFrame, - nsIFrame* aFrame) + nsTableRowFrame* aRowFrame) { - // Make sure it's a row frame and not a row group frame - nsTableRowFrame *rowFrame = do_QueryFrame(aFrame); - if (rowFrame) { - int32_t rowIndex = rowFrame->GetRowIndex(); + int32_t rowIndex = aRowFrame->GetRowIndex(); - // It's a simple row frame if there are no cells that span into or - // across the row - int32_t numEffCols = aTableFrame->GetEffectiveColCount(); - if (!aTableFrame->RowIsSpannedInto(rowIndex, numEffCols) && - !aTableFrame->RowHasSpanningCells(rowIndex, numEffCols)) { - return true; - } + // It's a simple row frame if there are no cells that span into or + // across the row + int32_t numEffCols = aTableFrame->GetEffectiveColCount(); + if (!aTableFrame->RowIsSpannedInto(rowIndex, numEffCols) && + !aTableFrame->RowHasSpanningCells(rowIndex, numEffCols)) { + return true; } return false; @@ -1867,8 +1863,9 @@ NS_DECLARE_FRAME_PROPERTY(RowCursorProperty, void nsTableRowGroupFrame::ClearRowCursor() { - if (!(GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR)) + if (!HasAnyStateBits(NS_ROWGROUP_HAS_ROW_CURSOR)) { return; + } RemoveStateBits(NS_ROWGROUP_HAS_ROW_CURSOR); Properties().Delete(RowCursorProperty()); @@ -1877,7 +1874,7 @@ nsTableRowGroupFrame::ClearRowCursor() nsTableRowGroupFrame::FrameCursorData* nsTableRowGroupFrame::SetupRowCursor() { - if (GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR) { + if (HasAnyStateBits(NS_ROWGROUP_HAS_ROW_CURSOR)) { // We already have a valid row cursor. Don't waste time rebuilding it. return nullptr; } @@ -1903,8 +1900,9 @@ nsTableRowGroupFrame::SetupRowCursor() nsIFrame* nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove) { - if (!(GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR)) + if (!HasAnyStateBits(NS_ROWGROUP_HAS_ROW_CURSOR)) { return nullptr; + } FrameCursorData* property = static_cast (Properties().Get(RowCursorProperty())); diff --git a/layout/tables/nsTableRowGroupFrame.h b/layout/tables/nsTableRowGroupFrame.h index fc8ec82a21..a60669eead 100644 --- a/layout/tables/nsTableRowGroupFrame.h +++ b/layout/tables/nsTableRowGroupFrame.h @@ -404,7 +404,7 @@ protected: nsIFrame** aContRowFrame); bool IsSimpleRowFrame(nsTableFrame* aTableFrame, - nsIFrame* aFrame); + nsTableRowFrame* aRowFrame); void GetNextRowSibling(nsIFrame** aRowFrame); @@ -429,29 +429,29 @@ public: inline bool nsTableRowGroupFrame::IsRepeatable() const { - return (mState & NS_ROWGROUP_REPEATABLE) == NS_ROWGROUP_REPEATABLE; + return HasAnyStateBits(NS_ROWGROUP_REPEATABLE); } inline void nsTableRowGroupFrame::SetRepeatable(bool aRepeatable) { if (aRepeatable) { - mState |= NS_ROWGROUP_REPEATABLE; + AddStateBits(NS_ROWGROUP_REPEATABLE); } else { - mState &= ~NS_ROWGROUP_REPEATABLE; + RemoveStateBits(NS_ROWGROUP_REPEATABLE); } } inline bool nsTableRowGroupFrame::HasStyleBSize() const { - return (mState & NS_ROWGROUP_HAS_STYLE_BSIZE) == NS_ROWGROUP_HAS_STYLE_BSIZE; + return HasAnyStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE); } inline void nsTableRowGroupFrame::SetHasStyleBSize(bool aValue) { if (aValue) { - mState |= NS_ROWGROUP_HAS_STYLE_BSIZE; + AddStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE); } else { - mState &= ~NS_ROWGROUP_HAS_STYLE_BSIZE; + RemoveStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE); } } diff --git a/memory/replace/logalloc/replay/Replay.cpp b/memory/replace/logalloc/replay/Replay.cpp index 75db8fb1e7..a047d4152b 100644 --- a/memory/replace/logalloc/replay/Replay.cpp +++ b/memory/replace/logalloc/replay/Replay.cpp @@ -176,7 +176,7 @@ public: } /* Returns whether the buffer is empty. */ - operator bool() { return mLength; } + explicit operator bool() { return mLength; } /* Returns the memory location of the buffer. */ const char* get() { return mBuf; } diff --git a/mfbt/Alignment.h b/mfbt/Alignment.h index 0ac8a48779..4098b1d4e5 100644 --- a/mfbt/Alignment.h +++ b/mfbt/Alignment.h @@ -9,6 +9,7 @@ #ifndef mozilla_Alignment_h #define mozilla_Alignment_h +#include "mozilla/Attributes.h" #include #include @@ -122,7 +123,7 @@ struct AlignedStorage }; template -struct AlignedStorage2 +struct MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS AlignedStorage2 { union U { diff --git a/mfbt/AlreadyAddRefed.h b/mfbt/AlreadyAddRefed.h index 417cfc945e..099a3d51fe 100644 --- a/mfbt/AlreadyAddRefed.h +++ b/mfbt/AlreadyAddRefed.h @@ -29,7 +29,7 @@ struct unused_t; * because of the sheer number of usages of already_AddRefed. */ template -struct already_AddRefed +struct MOZ_MUST_USE already_AddRefed { /* * We want to allow returning nullptr from functions returning diff --git a/mfbt/Atomics.h b/mfbt/Atomics.h index 1056cef954..f10da56272 100644 --- a/mfbt/Atomics.h +++ b/mfbt/Atomics.h @@ -1126,7 +1126,7 @@ public: explicit MOZ_CONSTEXPR Atomic(bool aInit) : Base(aInit) {} // We provide boolean wrappers for the underlying AtomicBase methods. - operator bool() const + MOZ_IMPLICIT operator bool() const { return Base::Intrinsics::load(Base::mValue); } diff --git a/netwerk/base/AutoClose.h b/netwerk/base/AutoClose.h index 9e8dc8278c..491156b11a 100644 --- a/netwerk/base/AutoClose.h +++ b/netwerk/base/AutoClose.h @@ -24,7 +24,7 @@ public: CloseAndRelease(); } - operator bool() + explicit operator bool() { MutexAutoLock lock(mMutex); return mPtr; diff --git a/netwerk/socket/nsSOCKSIOLayer.cpp b/netwerk/socket/nsSOCKSIOLayer.cpp index cd6827b585..2e2d882671 100644 --- a/netwerk/socket/nsSOCKSIOLayer.cpp +++ b/netwerk/socket/nsSOCKSIOLayer.cpp @@ -240,7 +240,7 @@ public: return mLength; } - operator bool() { return !!mBuf; } + explicit operator bool() { return !!mBuf; } private: template friend class Buffer; diff --git a/security/sandbox/linux/LinuxCapabilities.h b/security/sandbox/linux/LinuxCapabilities.h index 8d9bd874dc..f8eb720fb0 100644 --- a/security/sandbox/linux/LinuxCapabilities.h +++ b/security/sandbox/linux/LinuxCapabilities.h @@ -43,7 +43,7 @@ public: BitRef(__u32& aWord, uint32_t aMask) : mWord(aWord), mMask(aMask) { } BitRef(const BitRef& aBit) : mWord(aBit.mWord), mMask(aBit.mMask) { } public: - operator bool() const { + MOZ_IMPLICIT operator bool() const { return mWord & mMask; } BitRef& operator=(bool aSetTo) { diff --git a/toolkit/system/gnome/nsPackageKitService.cpp b/toolkit/system/gnome/nsPackageKitService.cpp index bc30d01e5b..ed89153fa3 100644 --- a/toolkit/system/gnome/nsPackageKitService.cpp +++ b/toolkit/system/gnome/nsPackageKitService.cpp @@ -11,6 +11,7 @@ #include "nsPackageKitService.h" #include "nsStringAPI.h" #include "prlink.h" +#include "mozilla/unused.h" #include #include @@ -157,7 +158,7 @@ InstallPackagesProxyCallCallback(GObject *aSourceObject, } g_object_unref(proxy); - observer->Release(); + unused << observer.forget().take(); } static void diff --git a/widget/TextEventDispatcher.cpp b/widget/TextEventDispatcher.cpp index 459b40632e..a9bef7a425 100644 --- a/widget/TextEventDispatcher.cpp +++ b/widget/TextEventDispatcher.cpp @@ -120,16 +120,34 @@ nsresult TextEventDispatcher::DispatchEvent(nsIWidget* aWidget, WidgetGUIEvent& aEvent, nsEventStatus& aStatus) +{ + MOZ_ASSERT(!aEvent.AsInputEvent(), "Use DispatchInputEvent()"); + + nsRefPtr kungFuDeathGrip(this); + nsCOMPtr widget(aWidget); + mDispatchingEvent++; + nsresult rv = widget->DispatchEvent(&aEvent, aStatus); + mDispatchingEvent--; + return rv; +} + +nsresult +TextEventDispatcher::DispatchInputEvent(nsIWidget* aWidget, + WidgetInputEvent& aEvent, + nsEventStatus& aStatus, + DispatchTo aDispatchTo) { nsRefPtr kungFuDeathGrip(this); nsCOMPtr widget(aWidget); mDispatchingEvent++; + // If the event is dispatched via nsIWidget::DispatchInputEvent(), it + // sends the event to the parent process first since APZ needs to handle it + // first. However, some callers (e.g., keyboard apps on B2G and tests + // expecting synchronous dispatch) don't want this to do that. nsresult rv = NS_OK; - if (aEvent.AsInputEvent() && - (!aEvent.mFlags.mIsSynthesizedForTests || gfxPrefs::TestEventsAsyncEnabled())) - { - aStatus = widget->DispatchInputEvent(aEvent.AsInputEvent()); + if (aDispatchTo == eDispatchToParentProcess) { + aStatus = widget->DispatchInputEvent(&aEvent); } else { rv = widget->DispatchEvent(&aEvent, aStatus); } @@ -266,9 +284,11 @@ bool TextEventDispatcher::DispatchKeyboardEvent( uint32_t aMessage, const WidgetKeyboardEvent& aKeyboardEvent, - nsEventStatus& aStatus) + nsEventStatus& aStatus, + DispatchTo aDispatchTo) { - return DispatchKeyboardEventInternal(aMessage, aKeyboardEvent, aStatus); + return DispatchKeyboardEventInternal(aMessage, aKeyboardEvent, aStatus, + aDispatchTo); } bool @@ -276,6 +296,7 @@ TextEventDispatcher::DispatchKeyboardEventInternal( uint32_t aMessage, const WidgetKeyboardEvent& aKeyboardEvent, nsEventStatus& aStatus, + DispatchTo aDispatchTo, uint32_t aIndexOfKeypress) { MOZ_ASSERT(aMessage == NS_KEY_DOWN || aMessage == NS_KEY_UP || @@ -354,14 +375,15 @@ TextEventDispatcher::DispatchKeyboardEventInternal( keyEvent.mPluginEvent.Clear(); // TODO: Manage mUniqueId here. - DispatchEvent(mWidget, keyEvent, aStatus); + DispatchInputEvent(mWidget, keyEvent, aStatus, aDispatchTo); return true; } bool TextEventDispatcher::MaybeDispatchKeypressEvents( const WidgetKeyboardEvent& aKeyboardEvent, - nsEventStatus& aStatus) + nsEventStatus& aStatus, + DispatchTo aDispatchTo) { // If the key event was consumed, keypress event shouldn't be fired. if (aStatus == nsEventStatus_eConsumeNoDefault) { @@ -381,7 +403,7 @@ TextEventDispatcher::MaybeDispatchKeypressEvents( for (size_t i = 0; i < keypressCount; i++) { aStatus = nsEventStatus_eIgnore; if (!DispatchKeyboardEventInternal(NS_KEY_PRESS, aKeyboardEvent, - aStatus, i)) { + aStatus, aDispatchTo, i)) { // The widget must have been gone. break; } diff --git a/widget/TextEventDispatcher.h b/widget/TextEventDispatcher.h index f8affde856..c576376c27 100644 --- a/widget/TextEventDispatcher.h +++ b/widget/TextEventDispatcher.h @@ -172,6 +172,26 @@ public: */ nsresult NotifyIME(const IMENotification& aIMENotification); + + /** + * DispatchTo indicates whether the event may be dispatched to its parent + * process first (if there is) or not. If the event is dispatched to the + * parent process, APZ will handle it first. Otherwise, the event won't be + * handled by APZ if it's in a child process. + */ + enum DispatchTo + { + // The event may be dispatched to its parent process if there is a parent. + // In such case, the event will be handled asynchronously. Additionally, + // the event may be sent to its child process if a child process (including + // the dispatching process) has focus. + eDispatchToParentProcess = 0, + // The event must be dispatched in the current process. But of course, + // the event may be sent to a child process when it has focus. If there is + // no child process, the event may be handled synchronously. + eDispatchToCurrentProcess = 1 + }; + /** * DispatchKeyboardEvent() maybe dispatches aKeyboardEvent. * @@ -184,11 +204,13 @@ public: * set nsEventStatus_eIgnore. After dispatching * a event and it's consumed this returns * nsEventStatus_eConsumeNoDefault. + * @param aDispatchTo See comments of DispatchTo. * @return true if an event is dispatched. Otherwise, false. */ bool DispatchKeyboardEvent(uint32_t aMessage, const WidgetKeyboardEvent& aKeyboardEvent, - nsEventStatus& aStatus); + nsEventStatus& aStatus, + DispatchTo aDispatchTo = eDispatchToParentProcess); /** * MaybeDispatchKeypressEvents() maybe dispatches a keypress event which is @@ -202,11 +224,14 @@ public: * When this method dispatches one or more keypress * events and one of them is consumed, this returns * nsEventStatus_eConsumeNoDefault. + * @param aDispatchTo See comments of DispatchTo. * @return true if one or more events are dispatched. * Otherwise, false. */ bool MaybeDispatchKeypressEvents(const WidgetKeyboardEvent& aKeyboardEvent, - nsEventStatus& aStatus); + nsEventStatus& aStatus, + DispatchTo aDispatchTo = + eDispatchToParentProcess); private: // mWidget is owner of the instance. When this is created, this is set. @@ -265,6 +290,7 @@ private: */ void InitEvent(WidgetGUIEvent& aEvent) const; + /** * DispatchEvent() dispatches aEvent on aWidget. */ @@ -272,6 +298,16 @@ private: WidgetGUIEvent& aEvent, nsEventStatus& aStatus); + /** + * DispatchInputEvent() dispatches aEvent on aWidget. + * + * @param aDispatchTo See comments of DispatchTo. + */ + nsresult DispatchInputEvent(nsIWidget* aWidget, + WidgetInputEvent& aEvent, + nsEventStatus& aStatus, + DispatchTo aDispatchTo); + /** * StartCompositionAutomaticallyIfNecessary() starts composition if it hasn't * been started it yet. @@ -300,6 +336,7 @@ private: * set nsEventStatus_eIgnore. After dispatching * a event and it's consumed this returns * nsEventStatus_eConsumeNoDefault. + * @param aDispatchTo See comments of DispatchTo. * @param aIndexOfKeypress This must be 0 if aMessage isn't NS_KEY_PRESS or * aKeyboard.mKeyNameIndex isn't * KEY_NAME_INDEX_USE_STRING. Otherwise, i.e., @@ -312,6 +349,8 @@ private: bool DispatchKeyboardEventInternal(uint32_t aMessage, const WidgetKeyboardEvent& aKeyboardEvent, nsEventStatus& aStatus, + DispatchTo aDispatchTo = + eDispatchToParentProcess, uint32_t aIndexOfKeypress = 0); }; diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 74490eb73e..813db8e9fa 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -56,6 +56,7 @@ #include "gfx2DGlue.h" #include "gfxPlatform.h" +#include "gfxPrefs.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/MiscEvents.h" #include "mozilla/MouseEvents.h" diff --git a/xpcom/build/FileLocation.h b/xpcom/build/FileLocation.h index 4afd6ad57e..7f9b18c5d8 100644 --- a/xpcom/build/FileLocation.h +++ b/xpcom/build/FileLocation.h @@ -88,9 +88,9 @@ public: * or not. */ #if defined(MOZILLA_XPCOMRT_API) - operator bool() const { return mBaseFile; } + explicit operator bool() const { return mBaseFile; } #else - operator bool() const { return mBaseFile || mBaseZip; } + explicit operator bool() const { return mBaseFile || mBaseZip; } #endif // defined(MOZILLA_XPCOMRT_API) /** diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index 45f5730701..bb9dcb737b 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -10,6 +10,7 @@ #include "nsTArrayForwardDeclare.h" #include "mozilla/Alignment.h" #include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" #include "mozilla/BinarySearch.h" #include "mozilla/fallible.h" #include "mozilla/MathAlgorithms.h" @@ -660,7 +661,7 @@ struct nsTArray_CopyWithConstructors // The default behaviour is to use memcpy/memmove for everything. // template -struct nsTArray_CopyChooser +struct MOZ_NEEDS_MEMMOVABLE_TYPE nsTArray_CopyChooser { typedef nsTArray_CopyWithMemutils Type; }; @@ -2109,7 +2110,7 @@ public: // You shouldn't use this class directly. // template -class nsAutoArrayBase : public TArrayBase +class MOZ_NON_MEMMOVABLE nsAutoArrayBase : public TArrayBase { static_assert(N != 0, "nsAutoArrayBase should be specialized"); public: diff --git a/xpcom/glue/nsTHashtable.h b/xpcom/glue/nsTHashtable.h index 1a00cf8bc8..61a03d4696 100644 --- a/xpcom/glue/nsTHashtable.h +++ b/xpcom/glue/nsTHashtable.h @@ -16,6 +16,7 @@ #include "mozilla/Move.h" #include "mozilla/fallible.h" #include "mozilla/PodOperations.h" +#include "mozilla/Attributes.h" #include @@ -79,7 +80,7 @@ PLDHashOperator PL_DHashStubEnumRemove(PLDHashTable* aTable, */ template -class nsTHashtable +class MOZ_NEEDS_NO_VTABLE_TYPE nsTHashtable { typedef mozilla::fallible_t fallible_t; diff --git a/xpcom/string/nsTString.h b/xpcom/string/nsTString.h index 54ee1e2a0e..8b1072beb1 100644 --- a/xpcom/string/nsTString.h +++ b/xpcom/string/nsTString.h @@ -560,7 +560,7 @@ protected: * nsAutoString for wide characters * nsAutoCString for narrow characters */ -class nsTAutoString_CharT : public nsTFixedString_CharT +class MOZ_NON_MEMMOVABLE nsTAutoString_CharT : public nsTFixedString_CharT { public: