1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* implementation of quotes for the CSS 'content' property */
9 #include "nsQuoteList.h"
10 #include "nsReadableUtils.h"
11 #include "nsIContent.h"
13 #include "nsIFrameInlines.h"
14 #include "nsContainerFrame.h"
15 #include "mozilla/ContainStyleScopeManager.h"
16 #include "mozilla/ErrorResult.h"
17 #include "mozilla/dom/Text.h"
18 #include "mozilla/intl/Quotes.h"
20 using namespace mozilla
;
22 bool nsQuoteNode::InitTextFrame(nsGenConList
* aList
, nsIFrame
* aPseudoFrame
,
23 nsIFrame
* aTextFrame
) {
24 nsGenConNode::InitTextFrame(aList
, aPseudoFrame
, aTextFrame
);
26 nsQuoteList
* quoteList
= static_cast<nsQuoteList
*>(aList
);
28 quoteList
->Insert(this);
29 if (quoteList
->IsLast(this))
30 quoteList
->Calc(this);
34 // Don't set up text for 'no-open-quote' and 'no-close-quote'.
36 aTextFrame
->GetContent()->AsText()->SetText(Text(), false);
41 nsString
nsQuoteNode::Text() {
42 NS_ASSERTION(mType
== StyleContentType::OpenQuote
||
43 mType
== StyleContentType::CloseQuote
,
44 "should only be called when mText should be non-null");
46 int32_t depth
= Depth();
47 MOZ_ASSERT(depth
>= -1);
53 const auto& quotesProp
= mPseudoFrame
->StyleList()->mQuotes
;
55 if (quotesProp
.IsAuto()) {
56 // Look up CLDR-derived quotation marks for the language of the context.
57 const nsIFrame
* frame
= mPseudoFrame
->GetInFlowParent();
58 // Parent of the pseudo is the element around which the quotes are applied;
59 // we want lang from *its* parent, unless it is the root.
60 // XXX Are there other cases where we shouldn't look up to the parent?
61 if (!frame
->Style()->IsRootElementStyle()) {
62 if (const nsIFrame
* parent
= frame
->GetInFlowParent()) {
66 const intl::Quotes
* quotes
=
67 intl::QuotesForLang(frame
->StyleFont()->mLanguage
);
68 // If we don't have quote-mark data for the language, use built-in
71 static const intl::Quotes sDefaultQuotes
= {
72 {0x201c, 0x201d, 0x2018, 0x2019}};
73 quotes
= &sDefaultQuotes
;
75 size_t index
= (depth
== 0 ? 0 : 2); // select first or second pair
76 index
+= (mType
== StyleContentType::OpenQuote
? 0 : 1); // open or close
77 result
.Append(quotes
->mChars
[index
]);
81 MOZ_ASSERT(quotesProp
.IsQuoteList());
82 const Span
<const StyleQuotePair
> quotes
= quotesProp
.AsQuoteList().AsSpan();
84 // Reuse the last pair when the depth is greater than the number of
85 // pairs of quotes. (Also make 'quotes: none' and close-quote from
86 // a depth of 0 equivalent for the next test.)
87 if (depth
>= static_cast<int32_t>(quotes
.Length())) {
88 depth
= static_cast<int32_t>(quotes
.Length()) - 1;
92 // close-quote from a depth of 0 or 'quotes: none'
96 const StyleQuotePair
& pair
= quotes
[depth
];
97 const StyleOwnedStr
& quote
=
98 mType
== StyleContentType::OpenQuote
? pair
.opening
: pair
.closing
;
99 result
.Assign(NS_ConvertUTF8toUTF16(quote
.AsString()));
103 static int32_t GetDepthBeforeFirstQuoteNode(ContainStyleScope
* aScope
) {
104 for (auto* ancestor
= aScope
->GetParent(); ancestor
;
105 ancestor
= ancestor
->GetParent()) {
106 auto& quoteList
= ancestor
->GetQuoteList();
107 if (auto* node
= static_cast<nsQuoteNode
*>(
108 aScope
->GetPrecedingElementInGenConList("eList
))) {
109 return node
->DepthAfter();
115 void nsQuoteList::Calc(nsQuoteNode
* aNode
) {
116 if (aNode
== FirstNode()) {
117 aNode
->mDepthBefore
= GetDepthBeforeFirstQuoteNode(mScope
);
119 aNode
->mDepthBefore
= Prev(aNode
)->DepthAfter();
123 void nsQuoteList::RecalcAll() {
124 for (nsQuoteNode
* node
= FirstNode(); node
; node
= Next(node
)) {
125 int32_t oldDepth
= node
->mDepthBefore
;
128 if (node
->mDepthBefore
!= oldDepth
&& node
->mText
&& node
->IsRealQuote())
129 node
->mText
->SetData(node
->Text(), IgnoreErrors());
134 void nsQuoteList::PrintChain() {
135 using StyleContentType
= nsQuoteNode::StyleContentType
;
138 for (nsQuoteNode
* node
= FirstNode(); node
; node
= Next(node
)) {
139 printf(" %p %d - ", static_cast<void*>(node
), node
->mDepthBefore
);
140 switch (node
->mType
) {
141 case StyleContentType::OpenQuote
:
144 case StyleContentType::NoOpenQuote
:
147 case StyleContentType::CloseQuote
:
150 case StyleContentType::NoCloseQuote
:
154 printf("unknown!!!");
156 printf(" %d - %d,", node
->Depth(), node
->DepthAfter());
159 node
->mText
->GetData(data
);
160 printf(" \"%s\",", NS_ConvertUTF16toUTF8(data
).get());