Bug 1472897: Adjust <details> pseudos to the spec. r?mats draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 19 May 2018 13:12:59 +0200
changeset 813399 7b24be6f941242f78ab1a2552c64664481f32c21
parent 813398 0c494be19160652ed2feda6c837e6494280bea38
push id114879
push userbmo:emilio@crisal.io
push dateTue, 03 Jul 2018 01:34:22 +0000
reviewersmats
bugs1472897
milestone63.0a1
Bug 1472897: Adjust <details> pseudos to the spec. r?mats Remove the summary assertion, because it only asserts that the first frame in a frame list is a summary, and I don't think it's worth complicating it. MozReview-Commit-ID: 8SoqkRgGiYO
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/generic/DetailsFrame.cpp
layout/generic/DetailsFrame.h
layout/reftests/details-summary/reftest.list
testing/web-platform/meta/html/rendering/the-details-element/details-after.html.ini
testing/web-platform/meta/html/rendering/the-details-element/details-before.html.ini
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2561,20 +2561,23 @@ nsCSSFrameConstructor::ConstructDocEleme
     // function to this FrameConstructionData.
 
     // XXXbz on the other hand, if we converted this whole function to
     // FrameConstructionData/Item, then we'd need the right function
     // here... but would probably be able to get away with less code in this
     // function in general.
     // Use a null PendingBinding, since our binding is not in fact pending.
     static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nullptr);
-    already_AddRefed<ComputedStyle> extraRef =
-      RefPtr<ComputedStyle>(computedStyle).forget();
-    AutoFrameConstructionItem item(this, &rootSVGData, aDocElement,
-                                   nullptr, extraRef, true, nullptr);
+    AutoFrameConstructionItem item(this,
+                                   &rootSVGData,
+                                   aDocElement,
+                                   nullptr,
+                                   RefPtr<ComputedStyle>(computedStyle).forget(),
+                                   true,
+                                   nullptr);
 
     nsFrameItems frameItems;
     contentFrame = static_cast<nsContainerFrame*>(
       ConstructOuterSVG(state, item, mDocElementContainingBlock,
                         computedStyle->StyleDisplay(),
                         frameItems));
     newFrame = frameItems.FirstChild();
     NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
@@ -2611,20 +2614,23 @@ nsCSSFrameConstructor::ConstructDocEleme
     // function to this FrameConstructionData.
 
     // XXXbz on the other hand, if we converted this whole function to
     // FrameConstructionData/Item, then we'd need the right function
     // here... but would probably be able to get away with less code in this
     // function in general.
     // Use a null PendingBinding, since our binding is not in fact pending.
     static const FrameConstructionData rootTableData = FCDATA_DECL(0, nullptr);
-    already_AddRefed<ComputedStyle> extraRef =
-      RefPtr<ComputedStyle>(computedStyle).forget();
-    AutoFrameConstructionItem item(this, &rootTableData, aDocElement,
-                                   nullptr, extraRef, true, nullptr);
+    AutoFrameConstructionItem item(this,
+                                   &rootTableData,
+                                   aDocElement,
+                                   nullptr,
+                                   RefPtr<ComputedStyle>(computedStyle).forget(),
+                                   true,
+                                   nullptr);
 
     nsFrameItems frameItems;
     // if the document is a table then just populate it.
     contentFrame = static_cast<nsContainerFrame*>(
       ConstructTable(state, item, mDocElementContainingBlock,
                      computedStyle->StyleDisplay(),
                      frameItems));
     newFrame = frameItems.FirstChild();
@@ -5613,20 +5619,18 @@ ShouldSuppressFrameInNonOpenDetails(cons
     return true;
   }
 
   auto* summary = HTMLSummaryElement::FromNode(aChild);
   if (summary && summary->IsMainSummary()) {
     return false;
   }
 
-  // Don't suppress NAC, unless it's ::before or ::after.
-  if (aChild->IsRootOfAnonymousSubtree() &&
-      !aChild->IsGeneratedContentContainerForBefore() &&
-      !aChild->IsGeneratedContentContainerForAfter()) {
+  // Don't suppress NAC, even if it's ::before or ::after.
+  if (aChild->IsRootOfAnonymousSubtree()) {
     return false;
   }
 
   return true;
 }
 
 static bool
 ShouldCreateImageFrameForContent(ComputedStyle& aStyle)
@@ -5634,16 +5638,28 @@ ShouldCreateImageFrameForContent(Compute
   auto& content = *aStyle.StyleContent();
   if (content.ContentCount() != 1) {
     return false;
   }
 
   return content.ContentAt(0).GetType() == StyleContentType::Image;
 }
 
+static bool
+IsMainSummaryInOpenDetails(const HTMLDetailsElement* aDetails,
+                           const nsIContent* aChild)
+{
+  if (!aDetails || !aDetails->Open()) {
+    return false;
+  }
+
+  auto* summary = HTMLSummaryElement::FromNode(aChild);
+  return summary && summary->IsMainSummary();
+}
+
 void
 nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
                                                          nsIContent* aContent,
                                                          nsContainerFrame* aParentFrame,
                                                          bool aSuppressWhiteSpaceOptimizations,
                                                          ComputedStyle* aComputedStyle,
                                                          uint32_t aFlags,
                                                          nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
@@ -5855,33 +5871,22 @@ nsCSSFrameConstructor::AddFrameConstruct
     !display->IsAbsolutelyPositionedStyle() &&
     !(aParentFrame && aParentFrame->IsGridContainerFrame()) &&
     !(bits & FCDATA_IS_TABLE_PART) && !(bits & FCDATA_IS_SVG_TEXT);
 
   if (canHavePageBreak && display->mBreakBefore) {
     AddPageBreakItem(aContent, aItems);
   }
 
-  if (details && details->Open()) {
-    auto* summary = HTMLSummaryElement::FromNode(aContent);
-    if (summary && summary->IsMainSummary()) {
-      // If details is open, the main summary needs to be rendered as if it is
-      // the first child, so add the item to the front of the item list.
-      item = aItems.PrependItem(this, data, aContent, pendingBinding,
-                                computedStyle.forget(),
-                                aSuppressWhiteSpaceOptimizations,
-                                aAnonChildren);
-    }
-  }
-
-  if (!item) {
-    item = aItems.AppendItem(this, data, aContent, pendingBinding,
-                             computedStyle.forget(),
-                             aSuppressWhiteSpaceOptimizations, aAnonChildren);
-  }
+  item = new (this) FrameConstructionItem(data,
+                                          aContent,
+                                          pendingBinding,
+                                          computedStyle.forget(),
+                                          aSuppressWhiteSpaceOptimizations,
+                                          aAnonChildren);
   item->mIsText = isText;
   item->mIsGeneratedContent = isGeneratedContent;
   item->mIsAnonymousContentCreatorContent =
     aFlags & ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT;
   if (isGeneratedContent) {
     // We need to keep this alive until the frame takes ownership.
     // This corresponds to the Release in ConstructFramesFromItem.
     item->mContent->AddRef();
@@ -5891,20 +5896,16 @@ nsCSSFrameConstructor::AddFrameConstruct
     aContent->IsRootOfNativeAnonymousSubtree();
   if (item->mIsRootPopupgroup) {
     aState.mHavePendingPopupgroup = true;
   }
   item->mIsPopup = isPopup;
   item->mIsForSVGAElement = namespaceId == kNameSpaceID_SVG &&
                             tag == nsGkAtoms::a;
 
-  if (canHavePageBreak && display->mBreakAfter) {
-    AddPageBreakItem(aContent, aItems);
-  }
-
   if (bits & FCDATA_IS_INLINE) {
     // To correctly set item->mIsAllInline we need to build up our child items
     // right now.
     BuildInlineChildItems(aState, *item,
                           aFlags & ITEM_IS_WITHIN_SVG_TEXT,
                           aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD);
     item->mHasInlineEnds = true;
     item->mIsBlock = false;
@@ -5950,31 +5951,42 @@ nsCSSFrameConstructor::AddFrameConstruct
     // out-of-flow, we can't use it here.  But we _can_ say that the frame will
     // for sure end up in-flow if it's not floated or absolutely positioned.
     item->mIsBlock = !isInline &&
                      !display->IsAbsolutelyPositionedStyle() &&
                      !display->IsFloatingStyle() &&
                      !(bits & FCDATA_IS_SVG_TEXT);
   }
 
-  if (item->mIsAllInline) {
-    aItems.InlineItemAdded();
-  } else if (item->mIsBlock) {
-    aItems.BlockItemAdded();
-  }
-
   // Our item should be treated as a line participant if we have the relevant
   // bit and are going to be in-flow.  Note that this really only matters if
   // our ancestor is a box or some such, so the fact that we might have an
   // inline ancestor that might become a containing block is not relevant here.
   if ((bits & FCDATA_IS_LINE_PARTICIPANT) &&
       ((bits & FCDATA_DISALLOW_OUT_OF_FLOW) ||
        !aState.GetGeometricParent(display, nullptr))) {
     item->mIsLineParticipant = true;
-    aItems.LineParticipantItemAdded();
+  }
+
+  FrameConstructionItemList::Iterator iter(aItems);
+  if (IsMainSummaryInOpenDetails(details, aContent)) {
+    if (!iter.IsDone() &&
+        iter.item().mIsGeneratedContent &&
+        iter.item().mContent->IsGeneratedContentContainerForBefore() &&
+        iter.item().mContent->GetParent() == details) {
+      iter.Next();
+    }
+  } else {
+    iter.SetToEnd();
+  }
+
+  iter.InsertItem(item);
+
+  if (canHavePageBreak && display->mBreakAfter) {
+    AddPageBreakItem(aContent, aItems);
   }
 }
 
 /**
  * Return true if the frame construction item pointed to by aIter will
  * create a frame adjacent to a line boundary in the frame tree, and that
  * line boundary is induced by a content node adjacent to the frame's
  * content node in the content tree. The latter condition is necessary so
@@ -9466,34 +9478,34 @@ nsCSSFrameConstructor::CreateNeededAnonF
 
     // Now, we create the anonymous flex or grid item to contain the children
     // between |iter| and |endIter|.
     nsAtom* pseudoType = (aParentFrame->IsFlexContainerFrame())
                             ? nsCSSAnonBoxes::anonymousFlexItem
                             : nsCSSAnonBoxes::anonymousGridItem;
     ComputedStyle* parentStyle = aParentFrame->Style();
     nsIContent* parentContent = aParentFrame->GetContent();
-    already_AddRefed<ComputedStyle> wrapperStyle =
+    RefPtr<ComputedStyle> wrapperStyle =
       mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(pseudoType,
                                                                  parentStyle);
 
     static const FrameConstructionData sBlockFormattingContextFCData =
       FCDATA_DECL(FCDATA_SKIP_FRAMESET |
                   FCDATA_USE_CHILD_ITEMS |
                   FCDATA_IS_WRAPPER_ANON_BOX,
                   NS_NewBlockFormattingContext);
 
     FrameConstructionItem* newItem =
       new (this) FrameConstructionItem(&sBlockFormattingContextFCData,
-                                // Use the content of our parent frame
-                                parentContent,
-                                // no pending binding
-                                nullptr,
-                                wrapperStyle,
-                                true, nullptr);
+                                       // Use the content of our parent frame
+                                       parentContent,
+                                       // no pending binding
+                                       nullptr,
+                                       wrapperStyle.forget(),
+                                       true, nullptr);
 
     newItem->mIsAllInline = newItem->mHasInlineEnds =
       newItem->mComputedStyle->StyleDisplay()->IsInlineOutsideStyle();
     newItem->mIsBlock = !newItem->mIsAllInline;
 
     MOZ_ASSERT(!newItem->mIsAllInline && newItem->mIsBlock,
                "expecting anonymous flex/grid items to be block-level "
                "(this will make a difference when we encounter "
@@ -9968,34 +9980,34 @@ nsCSSFrameConstructor::WrapItemsInPseudo
 
   if (pseudoType == nsCSSAnonBoxes::table &&
       (parentDisplay == StyleDisplay::Inline ||
        parentDisplay == StyleDisplay::RubyBase ||
        parentDisplay == StyleDisplay::RubyText)) {
     pseudoType = nsCSSAnonBoxes::inlineTable;
   }
 
-  already_AddRefed<ComputedStyle> wrapperStyle;
+  RefPtr<ComputedStyle> wrapperStyle;
   if (pseudoData.mFCData.mBits & FCDATA_IS_WRAPPER_ANON_BOX) {
     wrapperStyle =
       mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(pseudoType,
                                                                  aParentStyle);
   } else {
     wrapperStyle =
       mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(pseudoType);
   }
 
   FrameConstructionItem* newItem =
     new (this) FrameConstructionItem(&pseudoData.mFCData,
-                              // Use the content of our parent frame
-                              aParentContent,
-                              // no pending binding
-                              nullptr,
-                              wrapperStyle,
-                              true, nullptr);
+                                     // Use the content of our parent frame
+                                     aParentContent,
+                                     // no pending binding
+                                     nullptr,
+                                     wrapperStyle.forget(),
+                                     true, nullptr);
 
   const nsStyleDisplay* disp = newItem->mComputedStyle->StyleDisplay();
   // Here we're cheating a tad... technically, table-internal items should be
   // inline if aParentFrame is inline, but they'll get wrapped in an
   // inline-table in the end, so it'll all work out.  In any case, arguably
   // we don't need to maintain this state at this point... but it's better
   // to, I guess.
   newItem->mIsAllInline = newItem->mHasInlineEnds =
@@ -10040,26 +10052,26 @@ nsCSSFrameConstructor::CreateNeededPseud
   if (firstDisplay == StyleDisplay::RubyBaseContainer) {
     return;
   }
   NS_ASSERTION(firstDisplay == StyleDisplay::RubyTextContainer,
                "Child of ruby frame should either a rbc or a rtc");
 
   const PseudoParentData& pseudoData =
     sPseudoParentData[eTypeRubyBaseContainer];
-  already_AddRefed<ComputedStyle> pseudoStyle = mPresShell->StyleSet()->
+  RefPtr<ComputedStyle> pseudoStyle = mPresShell->StyleSet()->
     ResolveInheritingAnonymousBoxStyle(*pseudoData.mPseudoType,
                                        aParentFrame->Style());
   FrameConstructionItem* newItem =
     new (this) FrameConstructionItem(&pseudoData.mFCData,
                                      // Use the content of the parent frame
                                      aParentFrame->GetContent(),
                                      // no pending binding
                                      nullptr,
-                                     pseudoStyle,
+                                     pseudoStyle.forget(),
                                      true, nullptr);
   newItem->mIsAllInline = true;
   newItem->mChildItems.SetParentHasNoXBLChildren(true);
   iter.InsertItem(newItem);
 }
 
 #ifdef DEBUG
 /**
@@ -10192,17 +10204,17 @@ nsCSSFrameConstructor::AddFCItemsForAnon
                                       true, computedStyle, flags,
                                       anonChildren, aItemsToConstruct);
   }
 }
 
 void
 nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
                                        nsIContent*              aContent,
-                                       ComputedStyle*          aComputedStyle,
+                                       ComputedStyle*           aComputedStyle,
                                        nsContainerFrame*        aFrame,
                                        const bool               aCanHaveGeneratedContent,
                                        nsFrameItems&            aFrameItems,
                                        const bool               aAllowBlockStyles,
                                        PendingBinding*          aPendingBinding,
                                        nsIFrame*                aPossiblyLeafFrame)
 {
   MOZ_ASSERT(aFrame, "Must have parent frame here");
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -850,49 +850,26 @@ private:
                                       nsIContent* aContent,
                                       PendingBinding* aPendingBinding,
                                       already_AddRefed<ComputedStyle>&& aComputedStyle,
                                       bool aSuppressWhiteSpaceOptimizations,
                                       nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren)
     {
       FrameConstructionItem* item =
         new (aFCtor) FrameConstructionItem(aFCData, aContent,
-                                           aPendingBinding, aComputedStyle,
+                                           aPendingBinding,
+                                           std::move(aComputedStyle),
                                            aSuppressWhiteSpaceOptimizations,
                                            aAnonChildren);
       mItems.insertBack(item);
       ++mItemCount;
       ++mDesiredParentCounts[item->DesiredParentType()];
       return item;
     }
 
-    // Arguments are the same as AppendItem().
-    FrameConstructionItem* PrependItem(nsCSSFrameConstructor* aFCtor,
-                                       const FrameConstructionData* aFCData,
-                                       nsIContent* aContent,
-                                       PendingBinding* aPendingBinding,
-                                       already_AddRefed<ComputedStyle>&& aComputedStyle,
-                                       bool aSuppressWhiteSpaceOptimizations,
-                                       nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren)
-    {
-      FrameConstructionItem* item =
-        new (aFCtor) FrameConstructionItem(aFCData, aContent,
-                                           aPendingBinding, aComputedStyle,
-                                           aSuppressWhiteSpaceOptimizations,
-                                           aAnonChildren);
-      mItems.insertFront(item);
-      ++mItemCount;
-      ++mDesiredParentCounts[item->DesiredParentType()];
-      return item;
-    }
-
-    void InlineItemAdded() { ++mInlineCount; }
-    void BlockItemAdded() { ++mBlockCount; }
-    void LineParticipantItemAdded() { ++mLineParticipantCount; }
-
     class Iterator {
     public:
       explicit Iterator(FrameConstructionItemList& aList)
         : mCurrent(aList.mItems.getFirst())
         , mList(aList)
       {}
       Iterator(const Iterator& aOther) :
         mCurrent(aOther.mCurrent),
@@ -1098,17 +1075,17 @@ private:
    * frame other than the parent frame and whatever would be stored in the
    * frame constructor state.  You probably want to use
    * AutoFrameConstructionItem instead of this struct. */
   struct FrameConstructionItem final
     : public mozilla::LinkedListElement<FrameConstructionItem> {
     FrameConstructionItem(const FrameConstructionData* aFCData,
                           nsIContent* aContent,
                           PendingBinding* aPendingBinding,
-                          already_AddRefed<ComputedStyle>& aComputedStyle,
+                          already_AddRefed<ComputedStyle> aComputedStyle,
                           bool aSuppressWhiteSpaceOptimizations,
                           nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren) :
       mFCData(aFCData), mContent(aContent),
       mPendingBinding(aPendingBinding), mComputedStyle(aComputedStyle),
       mSuppressWhiteSpaceOptimizations(aSuppressWhiteSpaceOptimizations),
       mIsText(false), mIsGeneratedContent(false),
       mIsAnonymousContentCreatorContent(false),
       mIsRootPopupgroup(false), mIsAllInline(false), mIsBlock(false),
--- a/layout/generic/DetailsFrame.cpp
+++ b/layout/generic/DetailsFrame.cpp
@@ -31,60 +31,17 @@ NS_NewDetailsFrame(nsIPresShell* aPresSh
 
 namespace mozilla {
 
 DetailsFrame::DetailsFrame(ComputedStyle* aStyle)
   : nsBlockFrame(aStyle, kClassID)
 {
 }
 
-DetailsFrame::~DetailsFrame()
-{
-}
-
-void
-DetailsFrame::SetInitialChildList(ChildListID aListID, nsFrameList& aChildList)
-{
-#ifdef DEBUG
-  if (aListID == kPrincipalList) {
-    CheckValidMainSummary(aChildList);
-  }
-#endif
-
-  nsBlockFrame::SetInitialChildList(aListID, aChildList);
-}
-
-#ifdef DEBUG
-bool
-DetailsFrame::CheckValidMainSummary(const nsFrameList& aFrameList) const
-{
-  for (nsIFrame* child : aFrameList) {
-    HTMLSummaryElement* summary =
-      HTMLSummaryElement::FromNode(child->GetContent());
-
-    if (child == aFrameList.FirstChild()) {
-      if (summary && summary->IsMainSummary()) {
-        return true;
-      } else if (child->GetContent() == GetContent()) {
-        // The child frame's content is the same as our content, which means
-        // it's a kind of wrapper frame. Descend into its child list to find
-        // main summary.
-        if (CheckValidMainSummary(child->PrincipalChildList())) {
-          return true;
-        }
-      }
-    } else {
-      NS_ASSERTION(!summary || !summary->IsMainSummary(),
-                   "Rest of the children are either not summary element "
-                   "or are not the main summary!");
-    }
-  }
-  return false;
-}
-#endif
+DetailsFrame::~DetailsFrame() = default;
 
 void
 DetailsFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData)
 {
   aPostDestroyData.AddAnonymousContent(mDefaultSummary.forget());
   nsBlockFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
 }
 
--- a/layout/generic/DetailsFrame.h
+++ b/layout/generic/DetailsFrame.h
@@ -31,25 +31,16 @@ public:
 
 #ifdef DEBUG_FRAME_DUMP
   nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("Details"), aResult);
   }
 #endif
 
-#ifdef DEBUG
-  // Check the frame of the main summary element is the first child in the frame
-  // list. Returns true if we found the main summary frame; false otherwise.
-  bool CheckValidMainSummary(const nsFrameList& aFrameList) const;
-#endif
-
-  void SetInitialChildList(ChildListID aListID,
-                           nsFrameList& aChildList) override;
-
   void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
 
   // nsIAnonymousContentCreator
   nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
 
   void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                 uint32_t aFilter) override;
   // Returns true if |aSummaryFrame| is the main summary (i.e. the first child
--- a/layout/reftests/details-summary/reftest.list
+++ b/layout/reftests/details-summary/reftest.list
@@ -92,16 +92,16 @@ fuzzy(1,1) == mouse-click-twice-float-de
 
 # Dispatch keyboard event to summary
 == key-enter-single-summary.html open-single-summary.html
 == key-enter-open-second-summary.html open-multiple-summary.html
 == key-enter-prevent-default.html single-summary.html
 == key-space-single-summary.html open-single-summary.html
 
 # Generated content bits
-== details-after.html single-summary.html
-== details-before.html single-summary.html
+!= details-after.html single-summary.html
+!= details-before.html single-summary.html
+!= open-details-before.html open-single-summary.html
 == open-details-after.html open-single-summary.html
-== open-details-before.html open-single-summary.html
 
 # Move summary element
 == move-float-summary-to-different-details.html move-float-summary-to-different-details-ref.html
 == move-position-absolute-summary-to-different-details.html move-position-absolute-summary-to-different-details-ref.html
deleted file mode 100644
--- a/testing/web-platform/meta/html/rendering/the-details-element/details-after.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[details-after.html]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/html/rendering/the-details-element/details-before.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[details-before.html]
-  disabled:
-    if verify and (os == "mac"): fails in verify mode
-
-  expected:
-    if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): PASS
-    if not debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): PASS
-    FAIL