summaryrefslogtreecommitdiffstats
path: root/layout/base/nsQuoteList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base/nsQuoteList.cpp')
-rw-r--r--layout/base/nsQuoteList.cpp165
1 files changed, 165 insertions, 0 deletions
diff --git a/layout/base/nsQuoteList.cpp b/layout/base/nsQuoteList.cpp
new file mode 100644
index 0000000000..19e4306ec8
--- /dev/null
+++ b/layout/base/nsQuoteList.cpp
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* implementation of quotes for the CSS 'content' property */
+
+#include "nsQuoteList.h"
+#include "nsReadableUtils.h"
+#include "nsIContent.h"
+#include "nsIFrame.h"
+#include "nsIFrameInlines.h"
+#include "nsContainerFrame.h"
+#include "mozilla/ContainStyleScopeManager.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/Text.h"
+#include "mozilla/intl/Quotes.h"
+
+using namespace mozilla;
+
+bool nsQuoteNode::InitTextFrame(nsGenConList* aList, nsIFrame* aPseudoFrame,
+ nsIFrame* aTextFrame) {
+ nsGenConNode::InitTextFrame(aList, aPseudoFrame, aTextFrame);
+
+ nsQuoteList* quoteList = static_cast<nsQuoteList*>(aList);
+ bool dirty = false;
+ quoteList->Insert(this);
+ if (quoteList->IsLast(this))
+ quoteList->Calc(this);
+ else
+ dirty = true;
+
+ // Don't set up text for 'no-open-quote' and 'no-close-quote'.
+ if (IsRealQuote()) {
+ aTextFrame->GetContent()->AsText()->SetText(Text(), false);
+ }
+ return dirty;
+}
+
+nsString nsQuoteNode::Text() {
+ NS_ASSERTION(mType == StyleContentType::OpenQuote ||
+ mType == StyleContentType::CloseQuote,
+ "should only be called when mText should be non-null");
+ nsString result;
+ int32_t depth = Depth();
+ MOZ_ASSERT(depth >= -1);
+
+ if (depth < 0) {
+ return result;
+ }
+
+ const auto& quotesProp = mPseudoFrame->StyleList()->mQuotes;
+
+ if (quotesProp.IsAuto()) {
+ // Look up CLDR-derived quotation marks for the language of the context.
+ const nsIFrame* frame = mPseudoFrame->GetInFlowParent();
+ // Parent of the pseudo is the element around which the quotes are applied;
+ // we want lang from *its* parent, unless it is the root.
+ // XXX Are there other cases where we shouldn't look up to the parent?
+ if (!frame->Style()->IsRootElementStyle()) {
+ if (const nsIFrame* parent = frame->GetInFlowParent()) {
+ frame = parent;
+ }
+ }
+ const intl::Quotes* quotes =
+ intl::QuotesForLang(frame->StyleFont()->mLanguage);
+ // If we don't have quote-mark data for the language, use built-in
+ // defaults.
+ if (!quotes) {
+ static const intl::Quotes sDefaultQuotes = {
+ {0x201c, 0x201d, 0x2018, 0x2019}};
+ quotes = &sDefaultQuotes;
+ }
+ size_t index = (depth == 0 ? 0 : 2); // select first or second pair
+ index += (mType == StyleContentType::OpenQuote ? 0 : 1); // open or close
+ result.Append(quotes->mChars[index]);
+ return result;
+ }
+
+ MOZ_ASSERT(quotesProp.IsQuoteList());
+ const Span<const StyleQuotePair> quotes = quotesProp.AsQuoteList().AsSpan();
+
+ // Reuse the last pair when the depth is greater than the number of
+ // pairs of quotes. (Also make 'quotes: none' and close-quote from
+ // a depth of 0 equivalent for the next test.)
+ if (depth >= static_cast<int32_t>(quotes.Length())) {
+ depth = static_cast<int32_t>(quotes.Length()) - 1;
+ }
+
+ if (depth == -1) {
+ // close-quote from a depth of 0 or 'quotes: none'
+ return result;
+ }
+
+ const StyleQuotePair& pair = quotes[depth];
+ const StyleOwnedStr& quote =
+ mType == StyleContentType::OpenQuote ? pair.opening : pair.closing;
+ result.Assign(NS_ConvertUTF8toUTF16(quote.AsString()));
+ return result;
+}
+
+static int32_t GetDepthBeforeFirstQuoteNode(ContainStyleScope* aScope) {
+ for (auto* ancestor = aScope->GetParent(); ancestor;
+ ancestor = ancestor->GetParent()) {
+ auto& quoteList = ancestor->GetQuoteList();
+ if (auto* node = static_cast<nsQuoteNode*>(
+ aScope->GetPrecedingElementInGenConList(&quoteList))) {
+ return node->DepthAfter();
+ }
+ }
+ return 0;
+}
+
+void nsQuoteList::Calc(nsQuoteNode* aNode) {
+ if (aNode == FirstNode()) {
+ aNode->mDepthBefore = GetDepthBeforeFirstQuoteNode(mScope);
+ } else {
+ aNode->mDepthBefore = Prev(aNode)->DepthAfter();
+ }
+}
+
+void nsQuoteList::RecalcAll() {
+ for (nsQuoteNode* node = FirstNode(); node; node = Next(node)) {
+ int32_t oldDepth = node->mDepthBefore;
+ Calc(node);
+
+ if (node->mDepthBefore != oldDepth && node->mText && node->IsRealQuote())
+ node->mText->SetData(node->Text(), IgnoreErrors());
+ }
+}
+
+#ifdef DEBUG
+void nsQuoteList::PrintChain() {
+ using StyleContentType = nsQuoteNode::StyleContentType;
+
+ printf("Chain: \n");
+ for (nsQuoteNode* node = FirstNode(); node; node = Next(node)) {
+ printf(" %p %d - ", static_cast<void*>(node), node->mDepthBefore);
+ switch (node->mType) {
+ case StyleContentType::OpenQuote:
+ printf("open");
+ break;
+ case StyleContentType::NoOpenQuote:
+ printf("noOpen");
+ break;
+ case StyleContentType::CloseQuote:
+ printf("close");
+ break;
+ case StyleContentType::NoCloseQuote:
+ printf("noClose");
+ break;
+ default:
+ printf("unknown!!!");
+ }
+ printf(" %d - %d,", node->Depth(), node->DepthAfter());
+ if (node->mText) {
+ nsAutoString data;
+ node->mText->GetData(data);
+ printf(" \"%s\",", NS_ConvertUTF16toUTF8(data).get());
+ }
+ printf("\n");
+ }
+}
+#endif