mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	Bug 1542807 part 1 - Create generated content and use normal box construction for list-style-type/list-style-image ::markers. r=emilio
The change from 0x25FE to 0x25AA for list-style-type:square was approved here: https://github.com/w3c/csswg-drafts/issues/6200#issuecomment-828616747 Differential Revision: https://phabricator.services.mozilla.com/D111691
This commit is contained in:
		
							parent
							
								
									f62193272a
								
							
						
					
					
						commit
						a901b05850
					
				
					 21 changed files with 555 additions and 122 deletions
				
			
		| 
						 | 
				
			
			@ -1129,11 +1129,10 @@ LocalAccessible* nsAccessibilityService::CreateAccessible(
 | 
			
		|||
      }
 | 
			
		||||
    } else if (content->IsGeneratedContentContainerForMarker()) {
 | 
			
		||||
      if (aContext->IsHTMLListItem()) {
 | 
			
		||||
        const nsStyleList* styleList = frame->StyleList();
 | 
			
		||||
        if (!styleList->mListStyleImage.IsNone() ||
 | 
			
		||||
            !styleList->mCounterStyle.IsNone()) {
 | 
			
		||||
          newAcc = new HTMLListBulletAccessible(content, document);
 | 
			
		||||
        }
 | 
			
		||||
        newAcc = new HTMLListBulletAccessible(content, document);
 | 
			
		||||
      }
 | 
			
		||||
      if (aIsSubtreeHidden) {
 | 
			
		||||
        *aIsSubtreeHidden = true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -422,8 +422,8 @@ uint32_t HyperTextAccessible::TransformOffset(LocalAccessible* aDescendant,
 | 
			
		|||
      // We manually set the offset so the error doesn't propagate up.
 | 
			
		||||
      if (offset == 0 && parent && parent->IsHTMLListItem() &&
 | 
			
		||||
          descendant->LocalPrevSibling() &&
 | 
			
		||||
          descendant->LocalPrevSibling()->GetFrame() &&
 | 
			
		||||
          descendant->LocalPrevSibling()->GetFrame()->IsBulletFrame()) {
 | 
			
		||||
          descendant->LocalPrevSibling() ==
 | 
			
		||||
              parent->AsHTMLListItem()->Bullet()) {
 | 
			
		||||
        offset = 0;
 | 
			
		||||
      } else {
 | 
			
		||||
        offset = (offset > 0 || descendant->IndexInParent() > 0) ? 1 : 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,11 +10,10 @@
 | 
			
		|||
#include "DocAccessible.h"
 | 
			
		||||
#include "EventTree.h"
 | 
			
		||||
#include "nsAccUtils.h"
 | 
			
		||||
#include "nsTextEquivUtils.h"
 | 
			
		||||
#include "nsPersistentProperties.h"
 | 
			
		||||
#include "Role.h"
 | 
			
		||||
#include "States.h"
 | 
			
		||||
 | 
			
		||||
#include "nsBulletFrame.h"
 | 
			
		||||
#include "nsLayoutUtils.h"
 | 
			
		||||
 | 
			
		||||
using namespace mozilla;
 | 
			
		||||
| 
						 | 
				
			
			@ -90,24 +89,7 @@ HTMLListBulletAccessible::HTMLListBulletAccessible(nsIContent* aContent,
 | 
			
		|||
// HTMLListBulletAccessible: LocalAccessible
 | 
			
		||||
 | 
			
		||||
ENameValueFlag HTMLListBulletAccessible::Name(nsString& aName) const {
 | 
			
		||||
  aName.Truncate();
 | 
			
		||||
 | 
			
		||||
  // Native anonymous content, ARIA can't be used. Get list bullet text.
 | 
			
		||||
  if (nsBulletFrame* frame = do_QueryFrame(GetFrame())) {
 | 
			
		||||
    if (!frame->StyleList()->mListStyleImage.IsNone()) {
 | 
			
		||||
      // Bullet is an image, so use default bullet character.
 | 
			
		||||
      const char16_t kDiscCharacter = 0x2022;
 | 
			
		||||
      aName.Assign(kDiscCharacter);
 | 
			
		||||
      aName.Append(' ');
 | 
			
		||||
      return eNameOK;
 | 
			
		||||
    }
 | 
			
		||||
    frame->GetSpokenText(aName);
 | 
			
		||||
  } else {
 | 
			
		||||
    // If marker is not a bullet frame but instead has content
 | 
			
		||||
    nsTextEquivUtils::AppendFromDOMChildren(mContent, &aName);
 | 
			
		||||
    aName.CompressWhitespace();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  nsLayoutUtils::GetMarkerSpokenText(mContent, aName);
 | 
			
		||||
  return eNameOK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,11 @@ already_AddRefed<GeneratedImageContent> GeneratedImageContent::Create(
 | 
			
		|||
  return image.forget();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
already_AddRefed<GeneratedImageContent>
 | 
			
		||||
GeneratedImageContent::CreateForListStyleImage(Document& aDocument) {
 | 
			
		||||
  return Create(aDocument, uint32_t(-1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JSObject* GeneratedImageContent::WrapNode(JSContext* aCx,
 | 
			
		||||
                                          JS::Handle<JSObject*> aGivenProto) {
 | 
			
		||||
  return dom::HTMLElement_Binding::Wrap(aCx, this, aGivenProto);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,9 @@ class GeneratedImageContent final : public nsGenericHTMLElement {
 | 
			
		|||
 public:
 | 
			
		||||
  static already_AddRefed<GeneratedImageContent> Create(Document&,
 | 
			
		||||
                                                        uint32_t aContentIndex);
 | 
			
		||||
  // An image created from 'list-style-image' for a ::marker pseudo.
 | 
			
		||||
  static already_AddRefed<GeneratedImageContent> CreateForListStyleImage(
 | 
			
		||||
      Document&);
 | 
			
		||||
 | 
			
		||||
  explicit GeneratedImageContent(already_AddRefed<dom::NodeInfo>&& aNodeInfo)
 | 
			
		||||
      : nsGenericHTMLElement(std::move(aNodeInfo)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +33,13 @@ class GeneratedImageContent final : public nsGenericHTMLElement {
 | 
			
		|||
               "Someone messed up our nodeinfo");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  EventStates IntrinsicState() const override {
 | 
			
		||||
    EventStates state = nsGenericHTMLElement::IntrinsicState();
 | 
			
		||||
    if (mBroken) {
 | 
			
		||||
      state |= NS_EVENT_STATE_BROKEN;
 | 
			
		||||
    }
 | 
			
		||||
    return state;
 | 
			
		||||
  }
 | 
			
		||||
  nsresult Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const final;
 | 
			
		||||
 | 
			
		||||
  nsresult CopyInnerTo(GeneratedImageContent* aDest) {
 | 
			
		||||
| 
						 | 
				
			
			@ -39,14 +49,25 @@ class GeneratedImageContent final : public nsGenericHTMLElement {
 | 
			
		|||
    return NS_OK;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Is this an image created from 'list-style-image'?
 | 
			
		||||
  bool IsForListStyleImageMarker() const { return Index() == uint32_t(-1); }
 | 
			
		||||
 | 
			
		||||
  // @note we use -1 for images created from 'list-style-image'
 | 
			
		||||
  uint32_t Index() const { return mIndex; }
 | 
			
		||||
 | 
			
		||||
  // Notify this image failed to load.
 | 
			
		||||
  void NotifyLoadFailed() {
 | 
			
		||||
    mBroken = true;
 | 
			
		||||
    UpdateState(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  virtual ~GeneratedImageContent() = default;
 | 
			
		||||
  uint32_t mIndex = 0;
 | 
			
		||||
  bool mBroken = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace dom
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,6 @@
 | 
			
		|||
#include "Layers.h"
 | 
			
		||||
#include "nsAnimationManager.h"
 | 
			
		||||
#include "nsBlockFrame.h"
 | 
			
		||||
#include "nsBulletFrame.h"
 | 
			
		||||
#include "nsContentUtils.h"
 | 
			
		||||
#include "nsCSSFrameConstructor.h"
 | 
			
		||||
#include "nsCSSRendering.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -465,7 +464,11 @@ static bool StateChangeMayAffectFrame(const Element& aElement,
 | 
			
		|||
                                      const nsIFrame& aFrame,
 | 
			
		||||
                                      EventStates aStates) {
 | 
			
		||||
  if (aFrame.IsGeneratedContentFrame()) {
 | 
			
		||||
    // If it's generated content, ignore LOADING/etc state changes on it.
 | 
			
		||||
    if (aElement.IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)) {
 | 
			
		||||
      return aStates.HasState(NS_EVENT_STATE_BROKEN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If it's other generated content, ignore LOADING/etc state changes on it.
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1961,7 +1964,7 @@ static const nsIFrame* ExpectedOwnerForChild(const nsIFrame* aFrame) {
 | 
			
		|||
 | 
			
		||||
  parent = FirstContinuationOrPartOfIBSplit(parent);
 | 
			
		||||
 | 
			
		||||
  // We've handled already anon boxes and bullet frames, so now we're looking at
 | 
			
		||||
  // We've handled already anon boxes, so now we're looking at
 | 
			
		||||
  // a frame of a DOM element or pseudo. Hop through anon and line-boxes
 | 
			
		||||
  // generated by our DOM parent, and go find the owner frame for it.
 | 
			
		||||
  while (parent && (IsAnonBox(parent) || parent->IsLineFrame())) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -268,8 +268,8 @@ nsIFrame* NS_NewScrollbarButtonFrame(PresShell* aPresShell,
 | 
			
		|||
                                     ComputedStyle* aStyle);
 | 
			
		||||
 | 
			
		||||
nsIFrame* NS_NewImageFrameForContentProperty(PresShell*, ComputedStyle*);
 | 
			
		||||
 | 
			
		||||
nsIFrame* NS_NewImageFrameForGeneratedContentIndex(PresShell*, ComputedStyle*);
 | 
			
		||||
nsIFrame* NS_NewImageFrameForListStyleImage(PresShell*, ComputedStyle*);
 | 
			
		||||
 | 
			
		||||
// Returns true if aFrame is an anonymous flex/grid item.
 | 
			
		||||
static inline bool IsAnonymousFlexOrGridItem(const nsIFrame* aFrame) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1600,6 +1600,66 @@ already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGeneratedContent(
 | 
			
		|||
  return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nsCSSFrameConstructor::CreateGeneratedContentFromListStyle(
 | 
			
		||||
    nsFrameConstructorState& aState, const ComputedStyle& aPseudoStyle,
 | 
			
		||||
    const FunctionRef<void(nsIContent*)> aAddChild) {
 | 
			
		||||
  const nsStyleList* styleList = aPseudoStyle.StyleList();
 | 
			
		||||
  if (!styleList->mListStyleImage.IsNone()) {
 | 
			
		||||
    RefPtr<nsIContent> child =
 | 
			
		||||
        GeneratedImageContent::CreateForListStyleImage(*mDocument);
 | 
			
		||||
    aAddChild(child);
 | 
			
		||||
    child = CreateGenConTextNode(aState, u" "_ns, nullptr);
 | 
			
		||||
    aAddChild(child);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  CreateGeneratedContentFromListStyleType(aState, aPseudoStyle, aAddChild);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nsCSSFrameConstructor::CreateGeneratedContentFromListStyleType(
 | 
			
		||||
    nsFrameConstructorState& aState, const ComputedStyle& aPseudoStyle,
 | 
			
		||||
    const FunctionRef<void(nsIContent*)> aAddChild) {
 | 
			
		||||
  const nsStyleList* styleList = aPseudoStyle.StyleList();
 | 
			
		||||
  CounterStyle* counterStyle =
 | 
			
		||||
      mPresShell->GetPresContext()->CounterStyleManager()->ResolveCounterStyle(
 | 
			
		||||
          styleList->mCounterStyle);
 | 
			
		||||
  bool needUseNode = false;
 | 
			
		||||
  switch (counterStyle->GetStyle()) {
 | 
			
		||||
    case NS_STYLE_LIST_STYLE_NONE:
 | 
			
		||||
      return;
 | 
			
		||||
    case NS_STYLE_LIST_STYLE_DISC:
 | 
			
		||||
    case NS_STYLE_LIST_STYLE_CIRCLE:
 | 
			
		||||
    case NS_STYLE_LIST_STYLE_SQUARE:
 | 
			
		||||
    case NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED:
 | 
			
		||||
    case NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN:
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      const auto* anonStyle = counterStyle->AsAnonymous();
 | 
			
		||||
      if (!anonStyle || !anonStyle->IsSingleString()) {
 | 
			
		||||
        needUseNode = true;
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto node = MakeUnique<nsCounterUseNode>(nsCounterUseNode::ForLegacyBullet,
 | 
			
		||||
                                           styleList->mCounterStyle);
 | 
			
		||||
  if (!needUseNode) {
 | 
			
		||||
    nsAutoString text;
 | 
			
		||||
    node->GetText(WritingMode(&aPseudoStyle), counterStyle, text);
 | 
			
		||||
    // Note that we're done with 'node' in this case.  It's not inserted into
 | 
			
		||||
    // any list so it's deleted when we return.
 | 
			
		||||
    RefPtr<nsIContent> child = CreateGenConTextNode(aState, text, nullptr);
 | 
			
		||||
    aAddChild(child);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  nsCounterList* counterList =
 | 
			
		||||
      mCounterManager.CounterListFor(nsGkAtoms::list_item);
 | 
			
		||||
  auto initializer = MakeUnique<nsGenConInitializer>(
 | 
			
		||||
      std::move(node), counterList, &nsCSSFrameConstructor::CountersDirty);
 | 
			
		||||
  RefPtr<nsIContent> child =
 | 
			
		||||
      CreateGenConTextNode(aState, EmptyString(), std::move(initializer));
 | 
			
		||||
  aAddChild(child);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * aParentFrame - the frame that should be the parent of the generated
 | 
			
		||||
 *   content.  This is the frame for the corresponding content node,
 | 
			
		||||
| 
						 | 
				
			
			@ -1660,8 +1720,10 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem(
 | 
			
		|||
      MOZ_ASSERT_UNREACHABLE("unexpected aPseudoElement");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // |ProbePseudoStyleFor| checked the 'display' property and the
 | 
			
		||||
  // |ContentCount()| of the 'content' property for us.
 | 
			
		||||
  // |ProbePseudoElementStyle| checked the 'display' property and the
 | 
			
		||||
  // |ContentCount()| of the 'content' property for us, and for ::marker
 | 
			
		||||
  // also that we have either a 'list-style-type' or 'list-style-image'
 | 
			
		||||
  // non-initial value in case we have no 'content'.
 | 
			
		||||
  RefPtr<NodeInfo> nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(
 | 
			
		||||
      elemName, nullptr, kNameSpaceID_None, nsINode::ELEMENT_NODE);
 | 
			
		||||
  RefPtr<Element> container;
 | 
			
		||||
| 
						 | 
				
			
			@ -1704,26 +1766,31 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem(
 | 
			
		|||
    pseudoStyle = ServoStyleSet::ResolveServoStyle(*container);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint32_t contentCount = pseudoStyle->StyleContent()->ContentCount();
 | 
			
		||||
  for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
 | 
			
		||||
    nsCOMPtr<nsIContent> content = CreateGeneratedContent(
 | 
			
		||||
        aState, aOriginatingElement, *pseudoStyle, contentIndex);
 | 
			
		||||
    if (!content) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
  auto AppendChild = [&container, this](nsIContent* aChild) {
 | 
			
		||||
    // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
 | 
			
		||||
    // here; it would get set under AppendChildTo.  But AppendChildTo might
 | 
			
		||||
    // think that we're going from not being anonymous to being anonymous and
 | 
			
		||||
    // do some extra work; setting the flag here avoids that.
 | 
			
		||||
    content->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
 | 
			
		||||
    container->AppendChildTo(content, false, IgnoreErrors());
 | 
			
		||||
    if (auto* element = Element::FromNode(content)) {
 | 
			
		||||
    aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
 | 
			
		||||
    container->AppendChildTo(aChild, false, IgnoreErrors());
 | 
			
		||||
    if (auto* childElement = Element::FromNode(aChild)) {
 | 
			
		||||
      // If we created any children elements, Servo needs to traverse them, but
 | 
			
		||||
      // the root is already set up.
 | 
			
		||||
      mPresShell->StyleSet()->StyleNewSubtree(element);
 | 
			
		||||
      mPresShell->StyleSet()->StyleNewSubtree(childElement);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  const uint32_t contentCount = pseudoStyle->StyleContent()->ContentCount();
 | 
			
		||||
  for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
 | 
			
		||||
    if (RefPtr<nsIContent> content = CreateGeneratedContent(
 | 
			
		||||
            aState, aOriginatingElement, *pseudoStyle, contentIndex)) {
 | 
			
		||||
      AppendChild(content);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // If a ::marker has no 'content' then generate it from its 'list-style-*'.
 | 
			
		||||
  if (contentCount == 0 && aPseudoElement == PseudoStyleType::marker) {
 | 
			
		||||
    CreateGeneratedContentFromListStyle(aState, *pseudoStyle, AppendChild);
 | 
			
		||||
  }
 | 
			
		||||
  AddFrameConstructionItemsInternal(aState, container, aParentFrame, true,
 | 
			
		||||
                                    pseudoStyle, {ItemFlag::IsGeneratedContent},
 | 
			
		||||
                                    aItems);
 | 
			
		||||
| 
						 | 
				
			
			@ -3354,6 +3421,13 @@ nsCSSFrameConstructor::FindGeneratedImageData(const Element& aElement,
 | 
			
		|||
    return nullptr;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto& generatedContent = static_cast<const GeneratedImageContent&>(aElement);
 | 
			
		||||
  if (generatedContent.IsForListStyleImageMarker()) {
 | 
			
		||||
    static const FrameConstructionData sImgData =
 | 
			
		||||
        SIMPLE_FCDATA(NS_NewImageFrameForListStyleImage);
 | 
			
		||||
    return &sImgData;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static const FrameConstructionData sImgData =
 | 
			
		||||
      SIMPLE_FCDATA(NS_NewImageFrameForGeneratedContentIndex);
 | 
			
		||||
  return &sImgData;
 | 
			
		||||
| 
						 | 
				
			
			@ -3807,16 +3881,6 @@ void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (computedStyle->GetPseudoType() == PseudoStyleType::marker &&
 | 
			
		||||
      newFrame->IsBulletFrame()) {
 | 
			
		||||
    MOZ_ASSERT(!computedStyle->StyleContent()->ContentCount());
 | 
			
		||||
    auto* node = new nsCounterUseNode(nsCounterUseNode::ForLegacyBullet);
 | 
			
		||||
    auto* list = mCounterManager.CounterListFor(nsGkAtoms::list_item);
 | 
			
		||||
    if (node->InitBullet(list, newFrame)) {
 | 
			
		||||
      CountersDirty();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NS_ASSERTION(newFrame->IsFrameOfType(nsIFrame::eLineParticipant) ==
 | 
			
		||||
                   ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),
 | 
			
		||||
               "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
 | 
			
		||||
| 
						 | 
				
			
			@ -5231,16 +5295,6 @@ nsCSSFrameConstructor::FindElementTagData(const Element& aElement,
 | 
			
		|||
                                          ComputedStyle& aStyle,
 | 
			
		||||
                                          nsIFrame* aParentFrame,
 | 
			
		||||
                                          ItemFlags aFlags) {
 | 
			
		||||
  // A ::marker pseudo creates a nsBulletFrame, unless 'content' was set.
 | 
			
		||||
  if (aStyle.GetPseudoType() == PseudoStyleType::marker &&
 | 
			
		||||
      aStyle.StyleContent()->ContentCount() == 0) {
 | 
			
		||||
    static const FrameConstructionData data = FCDATA_DECL(
 | 
			
		||||
        FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH |
 | 
			
		||||
            FCDATA_DISALLOW_GENERATED_CONTENT | FCDATA_IS_LINE_PARTICIPANT |
 | 
			
		||||
            FCDATA_IS_INLINE | FCDATA_USE_CHILD_ITEMS,
 | 
			
		||||
        NS_NewBulletFrame);
 | 
			
		||||
    return &data;
 | 
			
		||||
  }
 | 
			
		||||
  switch (aElement.GetNameSpaceID()) {
 | 
			
		||||
    case kNameSpaceID_XHTML:
 | 
			
		||||
      return FindHTMLData(aElement, aParentFrame, aStyle);
 | 
			
		||||
| 
						 | 
				
			
			@ -7063,6 +7117,48 @@ void nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aStartChild,
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // This handles fallback to 'list-style-type' when a 'list-style-image' fails
 | 
			
		||||
  // to load.
 | 
			
		||||
  if (aStartChild->IsInNativeAnonymousSubtree() &&
 | 
			
		||||
      aStartChild->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)) {
 | 
			
		||||
    MOZ_ASSERT(isSingleInsert);
 | 
			
		||||
    MOZ_ASSERT(insertion.mParentFrame->Style()->GetPseudoType() ==
 | 
			
		||||
                   PseudoStyleType::marker,
 | 
			
		||||
               "we can only handle ::marker fallback for now");
 | 
			
		||||
    nsIContent* const nextSibling = aStartChild->GetNextSibling();
 | 
			
		||||
    MOZ_ASSERT(nextSibling && nextSibling->IsText(),
 | 
			
		||||
               "expected a text node after the list-style-image image");
 | 
			
		||||
    RemoveFrame(kPrincipalList, nextSibling->GetPrimaryFrame());
 | 
			
		||||
    auto* const container = aStartChild->GetParent()->AsElement();
 | 
			
		||||
    nsIContent* firstNewChild = nullptr;
 | 
			
		||||
    auto InsertChild = [this, container, nextSibling,
 | 
			
		||||
                        &firstNewChild](RefPtr<nsIContent>&& aChild) {
 | 
			
		||||
      // We don't strictly have to set NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE
 | 
			
		||||
      // here; it would get set under AppendChildTo.  But AppendChildTo might
 | 
			
		||||
      // think that we're going from not being anonymous to being anonymous and
 | 
			
		||||
      // do some extra work; setting the flag here avoids that.
 | 
			
		||||
      aChild->SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
 | 
			
		||||
      container->InsertChildBefore(aChild, nextSibling, false, IgnoreErrors());
 | 
			
		||||
      if (auto* childElement = Element::FromNode(aChild)) {
 | 
			
		||||
        // If we created any children elements, Servo needs to traverse them,
 | 
			
		||||
        // but the root is already set up.
 | 
			
		||||
        mPresShell->StyleSet()->StyleNewSubtree(childElement);
 | 
			
		||||
      }
 | 
			
		||||
      if (!firstNewChild) {
 | 
			
		||||
        firstNewChild = aChild;
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    CreateGeneratedContentFromListStyleType(
 | 
			
		||||
        state, *insertion.mParentFrame->Style(), InsertChild);
 | 
			
		||||
    if (!firstNewChild) {
 | 
			
		||||
      // No fallback content - we're done.
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    aStartChild = firstNewChild;
 | 
			
		||||
    MOZ_ASSERT(firstNewChild->GetNextSibling() == nextSibling,
 | 
			
		||||
               "list-style-type should only create one child");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  AutoFrameConstructionItemList items(this);
 | 
			
		||||
  ParentType parentType = GetParentType(frameType);
 | 
			
		||||
  FlattenedChildIterator iter(insertion.mContainer);
 | 
			
		||||
| 
						 | 
				
			
			@ -9575,6 +9671,13 @@ void nsCSSFrameConstructor::ProcessChildren(
 | 
			
		|||
          listItem->SetMarkerFrameForListItem(childFrame);
 | 
			
		||||
          MOZ_ASSERT(listItem->HasAnyStateBits(
 | 
			
		||||
                         NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER) == isOutsideMarker);
 | 
			
		||||
#ifdef ACCESSIBILITY
 | 
			
		||||
          if (nsAccessibilityService* accService =
 | 
			
		||||
                  PresShell::GetAccessibilityService()) {
 | 
			
		||||
            auto* marker = markerFrame->GetContent();
 | 
			
		||||
            accService->ContentRangeInserted(mPresShell, marker, nullptr);
 | 
			
		||||
          }
 | 
			
		||||
#endif
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
 | 
			
		||||
#include "mozilla/ArenaAllocator.h"
 | 
			
		||||
#include "mozilla/Attributes.h"
 | 
			
		||||
#include "mozilla/FunctionRef.h"
 | 
			
		||||
#include "mozilla/LinkedList.h"
 | 
			
		||||
#include "mozilla/Maybe.h"
 | 
			
		||||
#include "mozilla/RestyleManager.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -333,8 +334,10 @@ class nsCSSFrameConstructor final : public nsFrameManager {
 | 
			
		|||
 | 
			
		||||
  void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
 | 
			
		||||
 | 
			
		||||
  // temporary - please don't add external uses outside of nsBulletFrame
 | 
			
		||||
  nsCounterManager* CounterManager() { return &mCounterManager; }
 | 
			
		||||
#ifdef ACCESSIBILITY
 | 
			
		||||
  // Exposed only for nsLayoutUtils::GetMarkerSpokenText to use.
 | 
			
		||||
  const nsCounterManager* CounterManager() const { return &mCounterManager; }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  struct FrameConstructionItem;
 | 
			
		||||
| 
						 | 
				
			
			@ -460,6 +463,19 @@ class nsCSSFrameConstructor final : public nsFrameManager {
 | 
			
		|||
      nsFrameConstructorState& aState, const Element& aOriginatingElement,
 | 
			
		||||
      ComputedStyle& aComputedStyle, uint32_t aContentIndex);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Create child content nodes for a ::marker from its 'list-style-*' values.
 | 
			
		||||
   */
 | 
			
		||||
  void CreateGeneratedContentFromListStyle(
 | 
			
		||||
      nsFrameConstructorState& aState, const ComputedStyle& aPseudoStyle,
 | 
			
		||||
      const mozilla::FunctionRef<void(nsIContent*)> aAddChild);
 | 
			
		||||
  /**
 | 
			
		||||
   * Create child content nodes for a ::marker from its 'list-style-type'.
 | 
			
		||||
   */
 | 
			
		||||
  void CreateGeneratedContentFromListStyleType(
 | 
			
		||||
      nsFrameConstructorState& aState, const ComputedStyle& aPseudoStyle,
 | 
			
		||||
      const mozilla::FunctionRef<void(nsIContent*)> aAddChild);
 | 
			
		||||
 | 
			
		||||
  // aParentFrame may be null; this method doesn't use it directly in any case.
 | 
			
		||||
  void CreateGeneratedContentItem(nsFrameConstructorState& aState,
 | 
			
		||||
                                  nsContainerFrame* aParentFrame,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,6 @@
 | 
			
		|||
#include "mozilla/PresShell.h"
 | 
			
		||||
#include "mozilla/StaticPrefs_layout.h"
 | 
			
		||||
#include "mozilla/WritingModes.h"
 | 
			
		||||
#include "nsBulletFrame.h"  // legacy location for list style type to text code
 | 
			
		||||
#include "nsContentUtils.h"
 | 
			
		||||
#include "nsIContent.h"
 | 
			
		||||
#include "nsTArray.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -43,13 +42,6 @@ bool nsCounterUseNode::InitTextFrame(nsGenConList* aList,
 | 
			
		|||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nsCounterUseNode::InitBullet(nsGenConList* aList, nsIFrame* aBullet) {
 | 
			
		||||
  MOZ_ASSERT(aBullet->IsBulletFrame());
 | 
			
		||||
  MOZ_ASSERT(aBullet->Style()->GetPseudoType() == PseudoStyleType::marker);
 | 
			
		||||
  MOZ_ASSERT(mForLegacyBullet);
 | 
			
		||||
  return InitTextFrame(aList, aBullet, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// assign the correct |mValueAfter| value to a node that has been inserted
 | 
			
		||||
// Should be called immediately after calling |Insert|.
 | 
			
		||||
void nsCounterUseNode::Calc(nsCounterList* aList, bool aNotify) {
 | 
			
		||||
| 
						 | 
				
			
			@ -59,11 +51,6 @@ void nsCounterUseNode::Calc(nsCounterList* aList, bool aNotify) {
 | 
			
		|||
    nsAutoString contentString;
 | 
			
		||||
    GetText(contentString);
 | 
			
		||||
    mText->SetText(contentString, aNotify);
 | 
			
		||||
  } else if (mForLegacyBullet) {
 | 
			
		||||
    MOZ_ASSERT_IF(mPseudoFrame, mPseudoFrame->IsBulletFrame());
 | 
			
		||||
    if (nsBulletFrame* f = do_QueryFrame(mPseudoFrame)) {
 | 
			
		||||
      f->SetOrdinal(mValueAfter, aNotify);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -82,9 +69,34 @@ void nsCounterChangeNode::Calc(nsCounterList* aList) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The text that should be displayed for this counter.
 | 
			
		||||
void nsCounterUseNode::GetText(nsString& aResult) {
 | 
			
		||||
  aResult.Truncate();
 | 
			
		||||
  CounterStyle* style =
 | 
			
		||||
      mPseudoFrame->PresContext()->CounterStyleManager()->ResolveCounterStyle(
 | 
			
		||||
          mCounterStyle);
 | 
			
		||||
  GetText(mPseudoFrame->GetWritingMode(), style, aResult);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nsCounterUseNode::GetText(WritingMode aWM, CounterStyle* aStyle,
 | 
			
		||||
                               nsString& aResult) {
 | 
			
		||||
  const bool isBidiRTL = aWM.IsBidiRTL();
 | 
			
		||||
  auto AppendCounterText = [&aResult, isBidiRTL](const nsAutoString& aText,
 | 
			
		||||
                                                 bool aIsRTL) {
 | 
			
		||||
    if (MOZ_LIKELY(isBidiRTL == aIsRTL)) {
 | 
			
		||||
      aResult.Append(aText);
 | 
			
		||||
    } else {
 | 
			
		||||
      // RLM = 0x200f, LRM = 0x200e
 | 
			
		||||
      const char16_t mark = aIsRTL ? 0x200f : 0x200e;
 | 
			
		||||
      aResult.Append(mark);
 | 
			
		||||
      aResult.Append(aText);
 | 
			
		||||
      aResult.Append(mark);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (mForLegacyBullet) {
 | 
			
		||||
    nsAutoString prefix;
 | 
			
		||||
    aStyle->GetPrefix(prefix);
 | 
			
		||||
    aResult.Assign(prefix);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  AutoTArray<nsCounterNode*, 8> stack;
 | 
			
		||||
  stack.AppendElement(static_cast<nsCounterNode*>(this));
 | 
			
		||||
| 
						 | 
				
			
			@ -95,21 +107,26 @@ void nsCounterUseNode::GetText(nsString& aResult) {
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  WritingMode wm = mPseudoFrame->GetWritingMode();
 | 
			
		||||
  CounterStyle* style =
 | 
			
		||||
      mPseudoFrame->PresContext()->CounterStyleManager()->ResolveCounterStyle(
 | 
			
		||||
          mCounterStyle);
 | 
			
		||||
  for (uint32_t i = stack.Length() - 1;; --i) {
 | 
			
		||||
    nsCounterNode* n = stack[i];
 | 
			
		||||
  for (nsCounterNode* n : Reversed(stack)) {
 | 
			
		||||
    nsAutoString text;
 | 
			
		||||
    bool isTextRTL;
 | 
			
		||||
    style->GetCounterText(n->mValueAfter, wm, text, isTextRTL);
 | 
			
		||||
    aResult.Append(text);
 | 
			
		||||
    if (i == 0) {
 | 
			
		||||
    aStyle->GetCounterText(n->mValueAfter, aWM, text, isTextRTL);
 | 
			
		||||
    if (!mForLegacyBullet || aStyle->IsBullet()) {
 | 
			
		||||
      aResult.Append(text);
 | 
			
		||||
    } else {
 | 
			
		||||
      AppendCounterText(text, isTextRTL);
 | 
			
		||||
    }
 | 
			
		||||
    if (n == this) {
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    aResult.Append(mSeparator);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (mForLegacyBullet) {
 | 
			
		||||
    nsAutoString suffix;
 | 
			
		||||
    aStyle->GetSuffix(suffix);
 | 
			
		||||
    aResult.Append(suffix);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nsCounterList::SetScope(nsCounterNode* aNode) {
 | 
			
		||||
| 
						 | 
				
			
			@ -340,6 +357,41 @@ bool nsCounterManager::DestroyNodesFor(nsIFrame* aFrame) {
 | 
			
		|||
  return destroyedAny;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef ACCESSIBILITY
 | 
			
		||||
void nsCounterManager::GetSpokenCounterText(nsIFrame* aFrame,
 | 
			
		||||
                                            nsAString& aText) const {
 | 
			
		||||
  CounterValue ordinal = 1;
 | 
			
		||||
  if (const auto* list = mNames.Get(nsGkAtoms::list_item)) {
 | 
			
		||||
    for (nsCounterNode* n = list->GetFirstNodeFor(aFrame);
 | 
			
		||||
         n && n->mPseudoFrame == aFrame; n = list->Next(n)) {
 | 
			
		||||
      if (n->mType == nsCounterNode::USE) {
 | 
			
		||||
        ordinal = n->mValueAfter;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  CounterStyle* counterStyle =
 | 
			
		||||
      aFrame->PresContext()->CounterStyleManager()->ResolveCounterStyle(
 | 
			
		||||
          aFrame->StyleList()->mCounterStyle);
 | 
			
		||||
  nsAutoString text;
 | 
			
		||||
  bool isBullet;
 | 
			
		||||
  counterStyle->GetSpokenCounterText(ordinal, aFrame->GetWritingMode(), text,
 | 
			
		||||
                                     isBullet);
 | 
			
		||||
  if (isBullet) {
 | 
			
		||||
    aText = text;
 | 
			
		||||
    if (!counterStyle->IsNone()) {
 | 
			
		||||
      aText.Append(' ');
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    counterStyle->GetPrefix(aText);
 | 
			
		||||
    aText += text;
 | 
			
		||||
    nsAutoString suffix;
 | 
			
		||||
    counterStyle->GetSuffix(suffix);
 | 
			
		||||
    aText += suffix;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
void nsCounterManager::Dump() {
 | 
			
		||||
  printf("\n\nCounter Manager Lists:\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,6 +62,7 @@ struct nsCounterNode : public nsGenConNode {
 | 
			
		|||
  // 'counter-reset', 'counter-increment' or 'counter-set'  property
 | 
			
		||||
  // instead of within the 'content' property but offset to ensure
 | 
			
		||||
  // that (reset, increment, set, use) sort in that order.
 | 
			
		||||
  // It is zero for legacy bullet USE counter nodes.
 | 
			
		||||
  // (This slight weirdness allows sharing a lot of code with 'quotes'.)
 | 
			
		||||
  nsCounterNode(int32_t aContentIndex, Type aType)
 | 
			
		||||
      : nsGenConNode(aContentIndex), mType(aType) {}
 | 
			
		||||
| 
						 | 
				
			
			@ -83,10 +84,10 @@ struct nsCounterUseNode : public nsCounterNode {
 | 
			
		|||
  bool mForLegacyBullet = false;
 | 
			
		||||
 | 
			
		||||
  enum ForLegacyBullet { ForLegacyBullet };
 | 
			
		||||
  explicit nsCounterUseNode(enum ForLegacyBullet)
 | 
			
		||||
      : nsCounterNode(0, USE), mForLegacyBullet(true) {
 | 
			
		||||
    mCounterStyle = nsGkAtoms::list_item;
 | 
			
		||||
  }
 | 
			
		||||
  nsCounterUseNode(enum ForLegacyBullet, mozilla::CounterStylePtr aCounterStyle)
 | 
			
		||||
      : nsCounterNode(0, USE),
 | 
			
		||||
        mCounterStyle(std::move(aCounterStyle)),
 | 
			
		||||
        mForLegacyBullet(true) {}
 | 
			
		||||
 | 
			
		||||
  // args go directly to member variables here and of nsGenConNode
 | 
			
		||||
  nsCounterUseNode(mozilla::CounterStylePtr aCounterStyle, nsString aSeparator,
 | 
			
		||||
| 
						 | 
				
			
			@ -98,10 +99,8 @@ struct nsCounterUseNode : public nsCounterNode {
 | 
			
		|||
    NS_ASSERTION(aContentIndex <= INT32_MAX, "out of range");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual bool InitTextFrame(nsGenConList* aList, nsIFrame* aPseudoFrame,
 | 
			
		||||
                             nsIFrame* aTextFrame) override;
 | 
			
		||||
 | 
			
		||||
  bool InitBullet(nsGenConList* aList, nsIFrame* aBulletFrame);
 | 
			
		||||
  bool InitTextFrame(nsGenConList* aList, nsIFrame* aPseudoFrame,
 | 
			
		||||
                     nsIFrame* aTextFrame) override;
 | 
			
		||||
 | 
			
		||||
  // assign the correct |mValueAfter| value to a node that has been inserted,
 | 
			
		||||
  // and update the value of the text node, notifying if `aNotify` is true.
 | 
			
		||||
| 
						 | 
				
			
			@ -110,6 +109,8 @@ struct nsCounterUseNode : public nsCounterNode {
 | 
			
		|||
 | 
			
		||||
  // The text that should be displayed for this counter.
 | 
			
		||||
  void GetText(nsString& aResult);
 | 
			
		||||
  void GetText(mozilla::WritingMode aWM, mozilla::CounterStyle* aStyle,
 | 
			
		||||
               nsString& aResult);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct nsCounterChangeNode : public nsCounterNode {
 | 
			
		||||
| 
						 | 
				
			
			@ -171,6 +172,11 @@ class nsCounterList : public nsGenConList {
 | 
			
		|||
 public:
 | 
			
		||||
  nsCounterList() : nsGenConList(), mDirty(false) {}
 | 
			
		||||
 | 
			
		||||
  // Return the first node for aFrame on this list, or nullptr.
 | 
			
		||||
  nsCounterNode* GetFirstNodeFor(nsIFrame* aFrame) const {
 | 
			
		||||
    return static_cast<nsCounterNode*>(nsGenConList::GetFirstNodeFor(aFrame));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Insert(nsCounterNode* aNode) {
 | 
			
		||||
    nsGenConList::Insert(aNode);
 | 
			
		||||
    // Don't SetScope if we're dirty -- we'll reset all the scopes anyway,
 | 
			
		||||
| 
						 | 
				
			
			@ -235,6 +241,11 @@ class nsCounterManager {
 | 
			
		|||
  // Clear all data.
 | 
			
		||||
  void Clear() { mNames.Clear(); }
 | 
			
		||||
 | 
			
		||||
#ifdef ACCESSIBILITY
 | 
			
		||||
  // Returns the spoken text for the 'list-item' counter for aFrame in aText.
 | 
			
		||||
  void GetSpokenCounterText(nsIFrame* aFrame, nsAString& aText) const;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
  void Dump();
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,6 @@ struct nsGenConNode : public mozilla::LinkedListElement<nsGenConNode> {
 | 
			
		|||
  // null for:
 | 
			
		||||
  //  * content: no-open-quote / content: no-close-quote
 | 
			
		||||
  //  * counter nodes for increments and resets
 | 
			
		||||
  //  * counter nodes for bullets (mPseudoFrame->IsBulletFrame()).
 | 
			
		||||
  RefPtr<nsTextNode> mText;
 | 
			
		||||
 | 
			
		||||
  explicit nsGenConNode(int32_t aContentIndex)
 | 
			
		||||
| 
						 | 
				
			
			@ -65,12 +64,9 @@ struct nsGenConNode : public mozilla::LinkedListElement<nsGenConNode> {
 | 
			
		|||
  void CheckFrameAssertions() {
 | 
			
		||||
    NS_ASSERTION(
 | 
			
		||||
        mContentIndex < int32_t(mPseudoFrame->StyleContent()->ContentCount()) ||
 | 
			
		||||
            // Special-case for the use node created for the legacy markers,
 | 
			
		||||
            // Special-case for the USE node created for the legacy markers,
 | 
			
		||||
            // which don't use the content property.
 | 
			
		||||
            (mPseudoFrame->IsBulletFrame() && mContentIndex == 0 &&
 | 
			
		||||
             mPseudoFrame->Style()->GetPseudoType() ==
 | 
			
		||||
                 mozilla::PseudoStyleType::marker &&
 | 
			
		||||
             !mPseudoFrame->StyleContent()->ContentCount()),
 | 
			
		||||
            mContentIndex == 0,
 | 
			
		||||
        "index out of range");
 | 
			
		||||
    // We allow negative values of mContentIndex for 'counter-reset' and
 | 
			
		||||
    // 'counter-increment'.
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +108,11 @@ class nsGenConList {
 | 
			
		|||
  // have been destroyed; otherwise false.
 | 
			
		||||
  bool DestroyNodesFor(nsIFrame* aFrame);
 | 
			
		||||
 | 
			
		||||
  // Return the first node for aFrame on this list, or nullptr.
 | 
			
		||||
  nsGenConNode* GetFirstNodeFor(nsIFrame* aFrame) const {
 | 
			
		||||
    return mNodes.Get(aFrame);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Return true if |aNode1| is after |aNode2|.
 | 
			
		||||
  static bool NodeAfter(const nsGenConNode* aNode1, const nsGenConNode* aNode2);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -893,6 +893,40 @@ nsIFrame* nsLayoutUtils::GetMarkerFrame(const nsIContent* aContent) {
 | 
			
		|||
  return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef ACCESSIBILITY
 | 
			
		||||
void nsLayoutUtils::GetMarkerSpokenText(const nsIContent* aContent,
 | 
			
		||||
                                        nsAString& aText) {
 | 
			
		||||
  MOZ_ASSERT(aContent && aContent->IsGeneratedContentContainerForMarker());
 | 
			
		||||
 | 
			
		||||
  aText.Truncate();
 | 
			
		||||
 | 
			
		||||
  nsIFrame* frame = aContent->GetPrimaryFrame();
 | 
			
		||||
  if (!frame) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (frame->StyleContent()->ContentCount() > 0) {
 | 
			
		||||
    for (nsIFrame* child : frame->PrincipalChildList()) {
 | 
			
		||||
      nsIFrame::RenderedText text = child->GetRenderedText();
 | 
			
		||||
      aText += text.mString;
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!frame->StyleList()->mListStyleImage.IsNone()) {
 | 
			
		||||
    // ::marker is an image, so use default bullet character.
 | 
			
		||||
    static const char16_t kDiscMarkerString[] = {0x2022, ' ', 0};
 | 
			
		||||
    aText.AssignLiteral(kDiscMarkerString);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  frame->PresContext()
 | 
			
		||||
      ->FrameConstructor()
 | 
			
		||||
      ->CounterManager()
 | 
			
		||||
      ->GetSpokenCounterText(frame, aText);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// static
 | 
			
		||||
nsIFrame* nsLayoutUtils::GetClosestFrameOfType(nsIFrame* aFrame,
 | 
			
		||||
                                               LayoutFrameType aFrameType,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -273,6 +273,14 @@ class nsLayoutUtils {
 | 
			
		|||
   */
 | 
			
		||||
  static nsIFrame* GetMarkerFrame(const nsIContent* aContent);
 | 
			
		||||
 | 
			
		||||
#ifdef ACCESSIBILITY
 | 
			
		||||
  /**
 | 
			
		||||
   * Set aText to the spoken text for the given ::marker content (aContent)
 | 
			
		||||
   * if it has a frame, or the empty string otherwise.
 | 
			
		||||
   */
 | 
			
		||||
  static void GetMarkerSpokenText(const nsIContent* aContent, nsAString& aText);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Given a frame, search up the frame tree until we find an
 | 
			
		||||
   * ancestor that (or the frame itself) is of type aFrameType, if any.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7395,6 +7395,11 @@ void nsBlockFrame::SetMarkerFrameForListItem(nsIFrame* aMarkerFrame) {
 | 
			
		|||
    SetProperty(InsideMarkerProperty(), aMarkerFrame);
 | 
			
		||||
    AddStateBits(NS_BLOCK_FRAME_HAS_INSIDE_MARKER);
 | 
			
		||||
  } else {
 | 
			
		||||
    if (nsBlockFrame* marker = do_QueryFrame(aMarkerFrame)) {
 | 
			
		||||
      // An outside ::marker needs to be an independent formatting context
 | 
			
		||||
      // to avoid being influenced by the float manager etc.
 | 
			
		||||
      marker->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
 | 
			
		||||
    }
 | 
			
		||||
    SetProperty(OutsideMarkerProperty(),
 | 
			
		||||
                new (PresShell()) nsFrameList(aMarkerFrame, aMarkerFrame));
 | 
			
		||||
    AddStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,7 @@
 | 
			
		|||
#include "nsFontMetrics.h"
 | 
			
		||||
#include "nsIImageLoadingContent.h"
 | 
			
		||||
#include "nsImageLoadingContent.h"
 | 
			
		||||
#include "nsImageRenderer.h"
 | 
			
		||||
#include "nsString.h"
 | 
			
		||||
#include "nsPrintfCString.h"
 | 
			
		||||
#include "nsPresContext.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -98,6 +99,89 @@ using namespace mozilla::layers;
 | 
			
		|||
 | 
			
		||||
using mozilla::layout::TextDrawTarget;
 | 
			
		||||
 | 
			
		||||
class nsDisplayGradient final : public nsPaintedDisplayItem {
 | 
			
		||||
 public:
 | 
			
		||||
  nsDisplayGradient(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame)
 | 
			
		||||
      : nsPaintedDisplayItem(aBuilder, aFrame) {
 | 
			
		||||
    MOZ_COUNT_CTOR(nsDisplayGradient);
 | 
			
		||||
  }
 | 
			
		||||
  ~nsDisplayGradient() final { MOZ_COUNT_DTOR(nsDisplayGradient); }
 | 
			
		||||
 | 
			
		||||
  nsDisplayItemGeometry* AllocateGeometry(
 | 
			
		||||
      nsDisplayListBuilder* aBuilder) final {
 | 
			
		||||
    return new nsDisplayItemGenericImageGeometry(this, aBuilder);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  nsRect GetBounds(bool* aSnap) const {
 | 
			
		||||
    *aSnap = true;
 | 
			
		||||
 | 
			
		||||
    auto* imageFrame = static_cast<nsImageFrame*>(mFrame);
 | 
			
		||||
    return imageFrame->GetInnerArea() + ToReferenceFrame();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  nsRect GetBounds(nsDisplayListBuilder*, bool* aSnap) const final {
 | 
			
		||||
    return GetBounds(aSnap);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Paint(nsDisplayListBuilder*, gfxContext* aCtx) final;
 | 
			
		||||
 | 
			
		||||
  bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder&,
 | 
			
		||||
                               mozilla::wr::IpcResourceUpdateQueue&,
 | 
			
		||||
                               const StackingContextHelper&,
 | 
			
		||||
                               mozilla::layers::RenderRootStateManager*,
 | 
			
		||||
                               nsDisplayListBuilder*) final;
 | 
			
		||||
 | 
			
		||||
  NS_DISPLAY_DECL_NAME("Gradient", TYPE_GRADIENT)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void nsDisplayGradient::Paint(nsDisplayListBuilder* aBuilder,
 | 
			
		||||
                              gfxContext* aCtx) {
 | 
			
		||||
  auto* frame = static_cast<nsImageFrame*>(Frame());
 | 
			
		||||
  nsImageRenderer imageRenderer(frame, frame->GetImageFromStyle(),
 | 
			
		||||
                                aBuilder->GetImageRendererFlags());
 | 
			
		||||
  nsSize size = frame->GetSize();
 | 
			
		||||
  imageRenderer.SetPreferredSize({}, size);
 | 
			
		||||
 | 
			
		||||
  ImgDrawResult result;
 | 
			
		||||
  if (!imageRenderer.PrepareImage()) {
 | 
			
		||||
    result = imageRenderer.PrepareResult();
 | 
			
		||||
  } else {
 | 
			
		||||
    nsRect dest(ToReferenceFrame(), size);
 | 
			
		||||
    result = imageRenderer.DrawLayer(frame->PresContext(), *aCtx, dest, dest,
 | 
			
		||||
                                     dest.TopLeft(), GetPaintRect(),
 | 
			
		||||
                                     dest.Size(), /* aOpacity = */ 1.0f);
 | 
			
		||||
  }
 | 
			
		||||
  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nsDisplayGradient::CreateWebRenderCommands(
 | 
			
		||||
    wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
 | 
			
		||||
    const StackingContextHelper& aSc,
 | 
			
		||||
    mozilla::layers::RenderRootStateManager* aManager,
 | 
			
		||||
    nsDisplayListBuilder* aDisplayListBuilder) {
 | 
			
		||||
  auto* frame = static_cast<nsImageFrame*>(Frame());
 | 
			
		||||
  nsImageRenderer imageRenderer(frame, frame->GetImageFromStyle(),
 | 
			
		||||
                                aDisplayListBuilder->GetImageRendererFlags());
 | 
			
		||||
  nsSize size = frame->GetSize();
 | 
			
		||||
  imageRenderer.SetPreferredSize({}, size);
 | 
			
		||||
 | 
			
		||||
  ImgDrawResult result;
 | 
			
		||||
  if (!imageRenderer.PrepareImage()) {
 | 
			
		||||
    result = imageRenderer.PrepareResult();
 | 
			
		||||
  } else {
 | 
			
		||||
    nsRect dest(ToReferenceFrame(), size);
 | 
			
		||||
    result = imageRenderer.BuildWebRenderDisplayItemsForLayer(
 | 
			
		||||
        frame->PresContext(), aBuilder, aResources, aSc, aManager, this, dest,
 | 
			
		||||
        dest, dest.TopLeft(), dest, dest.Size(),
 | 
			
		||||
        /* aOpacity = */ 1.0f);
 | 
			
		||||
    if (result == ImgDrawResult::NOT_SUPPORTED) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sizes (pixels) for image icon, padding and border frame
 | 
			
		||||
#define ICON_SIZE (16)
 | 
			
		||||
#define ICON_PADDING (3)
 | 
			
		||||
| 
						 | 
				
			
			@ -178,6 +262,12 @@ nsIFrame* NS_NewImageFrameForGeneratedContentIndex(PresShell* aPresShell,
 | 
			
		|||
                   nsImageFrame::Kind::ContentPropertyAtIndex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nsIFrame* NS_NewImageFrameForListStyleImage(PresShell* aPresShell,
 | 
			
		||||
                                            ComputedStyle* aStyle) {
 | 
			
		||||
  return new (aPresShell) nsImageFrame(aStyle, aPresShell->GetPresContext(),
 | 
			
		||||
                                       nsImageFrame::Kind::ListStyleImage);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nsImageFrame::ShouldShowBrokenImageIcon() const {
 | 
			
		||||
  // NOTE(emilio, https://github.com/w3c/csswg-drafts/issues/2832): WebKit and
 | 
			
		||||
  // Blink behave differently here for content: url(..), for now adapt to
 | 
			
		||||
| 
						 | 
				
			
			@ -241,6 +331,11 @@ NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
 | 
			
		|||
 | 
			
		||||
#ifdef ACCESSIBILITY
 | 
			
		||||
a11y::AccType nsImageFrame::AccessibleType() {
 | 
			
		||||
  if (mKind == Kind::ListStyleImage) {
 | 
			
		||||
    // This is an HTMLListBulletAccessible.
 | 
			
		||||
    return a11y::eNoType;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Don't use GetImageMap() to avoid reentrancy into accessibility.
 | 
			
		||||
  if (HasImageMap()) {
 | 
			
		||||
    return a11y::eHTMLImageMapType;
 | 
			
		||||
| 
						 | 
				
			
			@ -327,6 +422,12 @@ void nsImageFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
 | 
			
		|||
 | 
			
		||||
  MaybeRecordContentUrlOnImageTelemetry();
 | 
			
		||||
 | 
			
		||||
  // A ::marker's default size is calculated from the font's em-size.
 | 
			
		||||
  if (IsForMarkerPseudo()) {
 | 
			
		||||
    mIntrinsicSize = IntrinsicSize(0, 0);
 | 
			
		||||
    UpdateIntrinsicSize();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto newOrientation = StyleVisibility()->mImageOrientation;
 | 
			
		||||
 | 
			
		||||
  // We need to update our orientation either if we had no ComputedStyle before
 | 
			
		||||
| 
						 | 
				
			
			@ -361,8 +462,15 @@ static bool SizeIsAvailable(imgIRequest* aRequest) {
 | 
			
		|||
 | 
			
		||||
const StyleImage* nsImageFrame::GetImageFromStyle() const {
 | 
			
		||||
  if (mKind == Kind::ImageElement) {
 | 
			
		||||
    MOZ_ASSERT_UNREACHABLE("Don't call me");
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  }
 | 
			
		||||
  if (mKind == Kind::ListStyleImage) {
 | 
			
		||||
    MOZ_ASSERT(
 | 
			
		||||
        GetParent()->GetContent()->IsGeneratedContentContainerForMarker());
 | 
			
		||||
    MOZ_ASSERT(mContent->IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage));
 | 
			
		||||
    return &StyleList()->mListStyleImage;
 | 
			
		||||
  }
 | 
			
		||||
  uint32_t contentIndex = 0;
 | 
			
		||||
  const nsStyleContent* styleContent = StyleContent();
 | 
			
		||||
  if (mKind == Kind::ContentPropertyAtIndex) {
 | 
			
		||||
| 
						 | 
				
			
			@ -414,12 +522,14 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
 | 
			
		|||
    imageLoader->FrameCreated(this);
 | 
			
		||||
  } else {
 | 
			
		||||
    const StyleImage* image = GetImageFromStyle();
 | 
			
		||||
    MOZ_ASSERT(image->IsImageRequestType(),
 | 
			
		||||
    MOZ_ASSERT(mKind == Kind::ListStyleImage || image->IsImageRequestType(),
 | 
			
		||||
               "Content image should only parse url() type");
 | 
			
		||||
    Document* doc = PresContext()->Document();
 | 
			
		||||
    if (imgRequestProxy* proxy = image->GetImageRequest()) {
 | 
			
		||||
      proxy->Clone(mListener, doc, getter_AddRefs(mContentURLRequest));
 | 
			
		||||
      SetupForContentURLRequest();
 | 
			
		||||
    if (image->IsImageRequestType()) {
 | 
			
		||||
      if (imgRequestProxy* proxy = image->GetImageRequest()) {
 | 
			
		||||
        proxy->Clone(mListener, PresContext()->Document(),
 | 
			
		||||
                     getter_AddRefs(mContentURLRequest));
 | 
			
		||||
        SetupForContentURLRequest();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -491,6 +601,22 @@ static void ScaleIntrinsicSizeForDensity(imgIContainer* aImage,
 | 
			
		|||
  ScaleIntrinsicSizeForDensity(aSize, resolution);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static nscoord ListImageDefaultLength(const nsImageFrame& aFrame) {
 | 
			
		||||
  // https://drafts.csswg.org/css-lists-3/#image-markers
 | 
			
		||||
  // The spec says we should use 1em x 1em, but that seems too large.
 | 
			
		||||
  // See disussion in https://github.com/w3c/csswg-drafts/issues/4207
 | 
			
		||||
  auto* pc = aFrame.PresContext();
 | 
			
		||||
  RefPtr<nsFontMetrics> fm =
 | 
			
		||||
      nsLayoutUtils::GetFontMetricsForComputedStyle(aFrame.Style(), pc);
 | 
			
		||||
  auto emAU = fm->GetThebesFontGroup()
 | 
			
		||||
                  ->GetFirstValidFont()
 | 
			
		||||
                  ->GetMetrics(fm->Orientation())
 | 
			
		||||
                  .emHeight *
 | 
			
		||||
              pc->AppUnitsPerDevPixel();
 | 
			
		||||
  return std::max(NSToCoordRound(0.4f * emAU),
 | 
			
		||||
                  nsPresContext::CSSPixelsToAppUnits(1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static IntrinsicSize ComputeIntrinsicSize(imgIContainer* aImage,
 | 
			
		||||
                                          bool aUseMappedRatio,
 | 
			
		||||
                                          nsImageFrame::Kind aKind,
 | 
			
		||||
| 
						 | 
				
			
			@ -505,6 +631,17 @@ static IntrinsicSize ComputeIntrinsicSize(imgIContainer* aImage,
 | 
			
		|||
    IntrinsicSize intrinsicSize;
 | 
			
		||||
    intrinsicSize.width = size.width == -1 ? Nothing() : Some(size.width);
 | 
			
		||||
    intrinsicSize.height = size.height == -1 ? Nothing() : Some(size.height);
 | 
			
		||||
    if (aKind == nsImageFrame::Kind::ListStyleImage) {
 | 
			
		||||
      if (intrinsicSize.width.isNothing() || intrinsicSize.height.isNothing()) {
 | 
			
		||||
        nscoord defaultLength = ListImageDefaultLength(aFrame);
 | 
			
		||||
        if (intrinsicSize.width.isNothing()) {
 | 
			
		||||
          intrinsicSize.width = Some(defaultLength);
 | 
			
		||||
        }
 | 
			
		||||
        if (intrinsicSize.height.isNothing()) {
 | 
			
		||||
          intrinsicSize.height = Some(defaultLength);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (aKind == nsImageFrame::Kind::ImageElement) {
 | 
			
		||||
      ScaleIntrinsicSizeForDensity(aImage, *aFrame.GetContent(), intrinsicSize);
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -514,6 +651,12 @@ static IntrinsicSize ComputeIntrinsicSize(imgIContainer* aImage,
 | 
			
		|||
    return intrinsicSize;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (aKind == nsImageFrame::Kind::ListStyleImage) {
 | 
			
		||||
    // Note: images are handled above, this handles gradients etc.
 | 
			
		||||
    nscoord defaultLength = ListImageDefaultLength(aFrame);
 | 
			
		||||
    return IntrinsicSize(defaultLength, defaultLength);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (aFrame.ShouldShowBrokenImageIcon()) {
 | 
			
		||||
    nscoord edgeLengthToUse = nsPresContext::CSSPixelsToAppUnits(
 | 
			
		||||
        ICON_SIZE + (2 * (ICON_PADDING + ALT_BORDER_WIDTH)));
 | 
			
		||||
| 
						 | 
				
			
			@ -780,6 +923,13 @@ void nsImageFrame::UpdateImage(imgIRequest* aRequest, imgIContainer* aImage) {
 | 
			
		|||
  } else {
 | 
			
		||||
    // We no longer have a valid image, so release our stored image container.
 | 
			
		||||
    mImage = mPrevImage = nullptr;
 | 
			
		||||
    if (mKind == Kind::ListStyleImage) {
 | 
			
		||||
      auto* genContent = static_cast<GeneratedImageContent*>(GetContent());
 | 
			
		||||
      genContent->NotifyLoadFailed();
 | 
			
		||||
      // No need to continue below since the above state change will destroy
 | 
			
		||||
      // this frame.
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // NOTE(emilio): Intentionally using `|` instead of `||` to avoid
 | 
			
		||||
  // short-circuiting.
 | 
			
		||||
| 
						 | 
				
			
			@ -796,8 +946,10 @@ void nsImageFrame::UpdateImage(imgIRequest* aRequest, imgIContainer* aImage) {
 | 
			
		|||
    // already gotten the initial reflow.
 | 
			
		||||
    if (!(mState & IMAGE_SIZECONSTRAINED)) {
 | 
			
		||||
#ifdef ACCESSIBILITY
 | 
			
		||||
      if (nsAccessibilityService* accService = GetAccService()) {
 | 
			
		||||
        accService->NotifyOfImageSizeAvailable(PresShell(), mContent);
 | 
			
		||||
      if (mKind != Kind::ListStyleImage) {
 | 
			
		||||
        if (nsAccessibilityService* accService = GetAccService()) {
 | 
			
		||||
          accService->NotifyOfImageSizeAvailable(PresShell(), mContent);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
#endif
 | 
			
		||||
      PresShell()->FrameNeedsReflow(this, IntrinsicDirty::StyleChange,
 | 
			
		||||
| 
						 | 
				
			
			@ -955,6 +1107,14 @@ nsRect nsImageFrame::PredictedDestRect(const nsRect& aFrameContentBox) {
 | 
			
		|||
                                              mIntrinsicRatio, StylePosition());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nsImageFrame::IsForMarkerPseudo() const {
 | 
			
		||||
  if (mKind == Kind::ImageElement) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  auto* subtreeRoot = GetContent()->GetClosestNativeAnonymousSubtreeRoot();
 | 
			
		||||
  return subtreeRoot && subtreeRoot->IsGeneratedContentContainerForMarker();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nsImageFrame::EnsureIntrinsicSizeAndRatio() {
 | 
			
		||||
  if (StyleDisplay()->IsContainSize()) {
 | 
			
		||||
    // If we have 'contain:size', then our intrinsic size and ratio are 0,0
 | 
			
		||||
| 
						 | 
				
			
			@ -965,8 +1125,9 @@ void nsImageFrame::EnsureIntrinsicSizeAndRatio() {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  // If mIntrinsicSize.width and height are 0, then we need to update from the
 | 
			
		||||
  // image container.
 | 
			
		||||
  if (mIntrinsicSize != IntrinsicSize(0, 0)) {
 | 
			
		||||
  // image container.  Note that we handle ::marker intrinsic size/ratio in
 | 
			
		||||
  // DidSetComputedStyle.
 | 
			
		||||
  if (mIntrinsicSize != IntrinsicSize(0, 0) && !IsForMarkerPseudo()) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2188,7 +2349,9 @@ void nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
 | 
			
		|||
    // XXX(seth): The SizeIsAvailable check here should not be necessary - the
 | 
			
		||||
    // intention is that a non-null mImage means we have a size, but there is
 | 
			
		||||
    // currently some code that violates this invariant.
 | 
			
		||||
    if (!imageOK || !mImage || !SizeIsAvailable(currentRequest)) {
 | 
			
		||||
    if ((mKind == Kind::ImageElement ||
 | 
			
		||||
         GetImageFromStyle()->IsImageRequestType()) &&
 | 
			
		||||
        (!imageOK || !mImage || !SizeIsAvailable(currentRequest))) {
 | 
			
		||||
      // No image yet, or image load failed. Draw the alt-text and an icon
 | 
			
		||||
      // indicating the status
 | 
			
		||||
      aLists.Content()->AppendNewToTop<nsDisplayAltFeedback>(aBuilder, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -2208,8 +2371,12 @@ void nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      aLists.Content()->AppendNewToTop<nsDisplayImage>(aBuilder, this, mImage,
 | 
			
		||||
                                                       mPrevImage);
 | 
			
		||||
      if (mImage) {
 | 
			
		||||
        aLists.Content()->AppendNewToTop<nsDisplayImage>(aBuilder, this, mImage,
 | 
			
		||||
                                                         mPrevImage);
 | 
			
		||||
      } else if (mKind != Kind::ImageElement) {
 | 
			
		||||
        aLists.Content()->AppendNewToTop<nsDisplayGradient>(aBuilder, this);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // If we were previously displaying an icon, we're not anymore
 | 
			
		||||
      if (mDisplayingIcon) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -187,6 +187,8 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
 | 
			
		|||
    // For a child of a ::before / ::after pseudo-element that had an url() item
 | 
			
		||||
    // for the content property.
 | 
			
		||||
    ContentPropertyAtIndex,
 | 
			
		||||
    // For a list-style-image ::marker.
 | 
			
		||||
    ListStyleImage,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Creates a suitable continuing frame for this frame.
 | 
			
		||||
| 
						 | 
				
			
			@ -199,6 +201,8 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
 | 
			
		|||
                                                      ComputedStyle*);
 | 
			
		||||
  friend nsIFrame* NS_NewImageFrameForGeneratedContentIndex(mozilla::PresShell*,
 | 
			
		||||
                                                            ComputedStyle*);
 | 
			
		||||
  friend nsIFrame* NS_NewImageFrameForListStyleImage(mozilla::PresShell*,
 | 
			
		||||
                                                     ComputedStyle*);
 | 
			
		||||
 | 
			
		||||
  nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, Kind aKind)
 | 
			
		||||
      : nsImageFrame(aStyle, aPresContext, kClassID, aKind) {}
 | 
			
		||||
| 
						 | 
				
			
			@ -260,6 +264,11 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
 | 
			
		|||
   */
 | 
			
		||||
  void MaybeDecodeForPredictedSize();
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Is this frame part of a ::marker pseudo?
 | 
			
		||||
   */
 | 
			
		||||
  bool IsForMarkerPseudo() const;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  friend class nsImageListener;
 | 
			
		||||
  friend class nsImageLoadingContent;
 | 
			
		||||
| 
						 | 
				
			
			@ -353,7 +362,7 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
 | 
			
		|||
 | 
			
		||||
  RefPtr<nsImageListener> mListener;
 | 
			
		||||
 | 
			
		||||
  // An image request created for content: url(..).
 | 
			
		||||
  // An image request created for content: url(..) or list-style-image.
 | 
			
		||||
  RefPtr<imgRequestProxy> mContentURLRequest;
 | 
			
		||||
 | 
			
		||||
  nsCOMPtr<imgIContainer> mImage;
 | 
			
		||||
| 
						 | 
				
			
			@ -426,6 +435,7 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
 | 
			
		|||
  static mozilla::StaticRefPtr<IconLoad> gIconLoad;
 | 
			
		||||
 | 
			
		||||
  friend class nsDisplayImage;
 | 
			
		||||
  friend class nsDisplayGradient;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5027,6 +5027,15 @@ void nsTextFrame::GetTextDecorations(
 | 
			
		|||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (context->GetPseudoType() == PseudoStyleType::marker &&
 | 
			
		||||
        (context->StyleList()->mListStylePosition ==
 | 
			
		||||
             NS_STYLE_LIST_STYLE_POSITION_OUTSIDE ||
 | 
			
		||||
         !context->StyleDisplay()->IsInlineOutsideStyle())) {
 | 
			
		||||
      // Outside ::marker pseudos, and inside markers that aren't inlines, don't
 | 
			
		||||
      // have text decorations.
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const nsStyleTextReset* const styleTextReset = context->StyleTextReset();
 | 
			
		||||
    const StyleTextDecorationLine textDecorations =
 | 
			
		||||
        styleTextReset->mTextDecorationLine;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,6 +48,7 @@ DECLARE_DISPLAY_ITEM_TYPE(FOREIGN_OBJECT,
 | 
			
		|||
DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BLANK, TYPE_RENDERS_NO_IMAGES)
 | 
			
		||||
DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BORDER, TYPE_RENDERS_NO_IMAGES)
 | 
			
		||||
DECLARE_DISPLAY_ITEM_TYPE(GENERIC, TYPE_RENDERS_NO_IMAGES)
 | 
			
		||||
DECLARE_DISPLAY_ITEM_TYPE(GRADIENT, TYPE_IS_CONTENTFUL)
 | 
			
		||||
DECLARE_DISPLAY_ITEM_TYPE(HEADER_FOOTER, TYPE_RENDERS_NO_IMAGES)
 | 
			
		||||
DECLARE_DISPLAY_ITEM_TYPE(IMAGE, TYPE_IS_CONTENTFUL)
 | 
			
		||||
DECLARE_DISPLAY_ITEM_TYPE(LINK, TYPE_RENDERS_NO_IMAGES)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -585,7 +585,7 @@ void BuiltinCounterStyle::GetSuffix(nsAString& aResult) {
 | 
			
		|||
 | 
			
		||||
static const char16_t kDiscCharacter = 0x2022;
 | 
			
		||||
static const char16_t kCircleCharacter = 0x25e6;
 | 
			
		||||
static const char16_t kSquareCharacter = 0x25fe;
 | 
			
		||||
static const char16_t kSquareCharacter = 0x25aa;
 | 
			
		||||
static const char16_t kRightPointingCharacter = 0x25b8;
 | 
			
		||||
static const char16_t kLeftPointingCharacter = 0x25c2;
 | 
			
		||||
static const char16_t kDownPointingCharacter = 0x25be;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -677,6 +677,13 @@ bool ServoStyleSet::GeneratedContentPseudoExists(
 | 
			
		|||
    if (!aParentStyle.StyleDisplay()->IsListItem()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    // ::marker only exist if we have 'content' or at least one of
 | 
			
		||||
    // 'list-style-type' or 'list-style-image'.
 | 
			
		||||
    if (aPseudoStyle.StyleList()->mCounterStyle.IsNone() &&
 | 
			
		||||
        aPseudoStyle.StyleList()->mListStyleImage.IsNone() &&
 | 
			
		||||
        aPseudoStyle.StyleContent()->ContentCount() == 0) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    // display:none is equivalent to not having the pseudo-element at all.
 | 
			
		||||
    if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) {
 | 
			
		||||
      return false;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -631,12 +631,11 @@ nsChangeHint nsStyleList::CalcDifference(
 | 
			
		|||
  // relies on that when the display value changes from something else
 | 
			
		||||
  // to list-item, that change itself would cause ReconstructFrame.
 | 
			
		||||
  if (aOldDisplay.IsListItem()) {
 | 
			
		||||
    if (mListStylePosition != aNewData.mListStylePosition) {
 | 
			
		||||
    if (mListStylePosition != aNewData.mListStylePosition ||
 | 
			
		||||
        mCounterStyle != aNewData.mCounterStyle ||
 | 
			
		||||
        mListStyleImage != aNewData.mListStyleImage) {
 | 
			
		||||
      return nsChangeHint_ReconstructFrame;
 | 
			
		||||
    }
 | 
			
		||||
    if (mCounterStyle != aNewData.mCounterStyle) {
 | 
			
		||||
      return NS_STYLE_HINT_REFLOW;
 | 
			
		||||
    }
 | 
			
		||||
  } else if (mListStylePosition != aNewData.mListStylePosition ||
 | 
			
		||||
             mCounterStyle != aNewData.mCounterStyle) {
 | 
			
		||||
    hint = nsChangeHint_NeutralChange;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue