Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: Source/WebCore/rendering/RenderQuote.cpp

Issue 10911104: Merge 124969 (Closed) Base URL: http://svn.webkit.org/repository/webkit/branches/chromium/1229/
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/WebCore/rendering/RenderQuote.h ('k') | Source/WebCore/rendering/RenderView.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /** 1 /**
2 * Copyright (C) 2011 Nokia Inc. All rights reserved. 2 * Copyright (C) 2011 Nokia Inc. All rights reserved.
3 * 3 *
4 * This library is free software; you can redistribute it and/or 4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public 5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either 6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version. 7 * version 2 of the License, or (at your option) any later version.
8 * 8 *
9 * This library is distributed in the hope that it will be useful, 9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details. 12 * Library General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU Library General Public License 14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to 15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA. 17 * Boston, MA 02110-1301, USA.
18 * 18 *
19 */ 19 */
20 20
21 #include "config.h" 21 #include "config.h"
22 #include "RenderQuote.h" 22 #include "RenderQuote.h"
23 23
24 #include "Document.h"
25 #include "QuotesData.h"
26 #include "RenderStyle.h"
27 #include <wtf/text/AtomicString.h> 24 #include <wtf/text/AtomicString.h>
28 25
29 #define UNKNOWN_DEPTH -1 26 #define U(x) ((const UChar*)L##x)
30 27
31 namespace WebCore { 28 namespace WebCore {
32 static inline void adjustDepth(int &depth, QuoteType type)
33 {
34 switch (type) {
35 case OPEN_QUOTE:
36 case NO_OPEN_QUOTE:
37 ++depth;
38 break;
39 case CLOSE_QUOTE:
40 case NO_CLOSE_QUOTE:
41 if (depth)
42 --depth;
43 break;
44 default:
45 ASSERT_NOT_REACHED();
46 }
47 }
48 29
49 RenderQuote::RenderQuote(Document* node, QuoteType quote) 30 RenderQuote::RenderQuote(Document* node, QuoteType quote)
50 : RenderText(node, StringImpl::empty()) 31 : RenderText(node, StringImpl::empty())
51 , m_type(quote) 32 , m_type(quote)
52 , m_depth(UNKNOWN_DEPTH) 33 , m_depth(0)
53 , m_next(0) 34 , m_next(0)
54 , m_previous(0) 35 , m_previous(0)
36 , m_attached(false)
55 { 37 {
56 view()->addRenderQuote();
57 } 38 }
58 39
59 RenderQuote::~RenderQuote() 40 RenderQuote::~RenderQuote()
60 { 41 {
42 ASSERT(!m_attached);
43 ASSERT(!m_next && !m_previous);
61 } 44 }
62 45
63 void RenderQuote::willBeDestroyed() 46 void RenderQuote::willBeDestroyed()
64 { 47 {
65 if (view()) 48 detachQuote();
66 view()->removeRenderQuote();
67 RenderText::willBeDestroyed(); 49 RenderText::willBeDestroyed();
68 } 50 }
69 51
70 const char* RenderQuote::renderName() const
71 {
72 return "RenderQuote";
73 }
74
75 // This function places a list of quote renderers starting at "this" in the list of quote renderers already
76 // in the document's renderer tree.
77 // The assumptions are made (for performance):
78 // 1. The list of quotes already in the renderers tree of the document is alread y in a consistent state
79 // (All quote renderers are linked and have the correct depth set)
80 // 2. The quote renderers of the inserted list are in a tree of renderers of the ir own which has been just
81 // inserted in the main renderer tree with its root as child of some renderer.
82 // 3. The quote renderers in the inserted list have depths consistent with their position in the list relative
83 // to "this", thus if "this" does not need to change its depth upon insertion, t he other renderers in the list don't
84 // need to either.
85 void RenderQuote::placeQuote()
86 {
87 RenderQuote* head = this;
88 ASSERT(!head->m_previous);
89 RenderQuote* tail = 0;
90 for (RenderObject* predecessor = head->previousInPreOrder(); predecessor; pr edecessor = predecessor->previousInPreOrder()) {
91 if (!predecessor->isQuote())
92 continue;
93 head->m_previous = toRenderQuote(predecessor);
94 if (head->m_previous->m_next) {
95 // We need to splice the list of quotes headed by head into the docu ment's list of quotes.
96 tail = head;
97 while (tail->m_next)
98 tail = tail->m_next;
99 tail->m_next = head->m_previous->m_next;
100 ASSERT(tail->m_next->m_previous == head->m_previous);
101 tail->m_next->m_previous = tail;
102 tail = tail->m_next; // This marks the splicing point here there may be a depth discontinuity
103 }
104 head->m_previous->m_next = head;
105 ASSERT(head->m_previous->m_depth != UNKNOWN_DEPTH);
106 break;
107 }
108 int newDepth;
109 if (!head->m_previous) {
110 newDepth = 0;
111 goto skipNewDepthCalc;
112 }
113 newDepth = head->m_previous->m_depth;
114 do {
115 adjustDepth(newDepth, head->m_previous->m_type);
116 skipNewDepthCalc:
117 if (head->m_depth == newDepth) { // All remaining depth should be correc t except if splicing was done.
118 if (!tail) // We've done the post splicing section already or there was no splicing.
119 break;
120 head = tail; // Continue after the splicing point
121 tail = 0; // Mark the possible splicing point discontinuity fixed.
122 newDepth = head->m_previous->m_depth;
123 continue;
124 }
125 head->m_depth = newDepth;
126 // FIXME: If the width and height of the quotation characters does not c hange we may only need to
127 // Invalidate the renderer's area not a relayout.
128 head->setNeedsLayoutAndPrefWidthsRecalc();
129 head = head->m_next;
130 if (head == tail) // We are at the splicing point
131 tail = 0; // Mark the possible depth discontinuity fixed.
132 } while (head);
133 }
134
135 #define U(x) ((const UChar*)L##x)
136
137 typedef HashMap<AtomicString, const QuotesData*, CaseFoldingHash> QuotesMap; 52 typedef HashMap<AtomicString, const QuotesData*, CaseFoldingHash> QuotesMap;
138 53
139 static const QuotesMap& quotesDataLanguageMap() 54 static const QuotesMap& quotesDataLanguageMap()
140 { 55 {
141 DEFINE_STATIC_LOCAL(QuotesMap, staticQuotesMap, ()); 56 DEFINE_STATIC_LOCAL(QuotesMap, staticQuotesMap, ());
142 if (staticQuotesMap.size()) 57 if (staticQuotesMap.size())
143 return staticQuotesMap; 58 return staticQuotesMap;
144 // FIXME: Expand this table to include all the languages in https://bug-3234 -attachments.webkit.org/attachment.cgi?id=2135 59 // FIXME: Expand this table to include all the languages in https://bug-3234 -attachments.webkit.org/attachment.cgi?id=2135
145 staticQuotesMap.set("en", QuotesData::create(U("\x201C"), U("\x201D"), U("\x 2018"), U("\x2019")).leakRef()); 60 staticQuotesMap.set("en", QuotesData::create(U("\x201C"), U("\x201D"), U("\x 2018"), U("\x2019")).leakRef());
146 staticQuotesMap.set("no", QuotesData::create(U("\x00AB"), U("\x00BB"), U("\x 2039"), U("\x203A")).leakRef()); 61 staticQuotesMap.set("no", QuotesData::create(U("\x00AB"), U("\x00BB"), U("\x 2039"), U("\x203A")).leakRef());
147 staticQuotesMap.set("ro", QuotesData::create(U("\x201E"), U("\x201D")).leakR ef()); 62 staticQuotesMap.set("ro", QuotesData::create(U("\x201E"), U("\x201D")).leakR ef());
148 staticQuotesMap.set("ru", QuotesData::create(U("\x00AB"), U("\x00BB"), U("\x 201E"), U("\x201C")).leakRef()); 63 staticQuotesMap.set("ru", QuotesData::create(U("\x00AB"), U("\x00BB"), U("\x 201E"), U("\x201C")).leakRef());
149 return staticQuotesMap; 64 return staticQuotesMap;
150 } 65 }
151 66
152 static const QuotesData* basicQuotesData() 67 static const QuotesData* basicQuotesData()
153 { 68 {
154 static const QuotesData* staticBasicQuotes = QuotesData::create(U("\""), U(" \""), U("'"), U("'")).leakRef(); 69 static const QuotesData* staticBasicQuotes = QuotesData::create(U("\""), U(" \""), U("'"), U("'")).leakRef();
155 return staticBasicQuotes; 70 return staticBasicQuotes;
156 } 71 }
157 72
158 PassRefPtr<StringImpl> RenderQuote::originalText() const 73 PassRefPtr<StringImpl> RenderQuote::originalText() const
159 { 74 {
160 if (!parent())
161 return 0;
162 ASSERT(m_depth != UNKNOWN_DEPTH);
163 const QuotesData* quotes = quotesData();
164 switch (m_type) { 75 switch (m_type) {
165 case NO_OPEN_QUOTE: 76 case NO_OPEN_QUOTE:
166 case NO_CLOSE_QUOTE: 77 case NO_CLOSE_QUOTE:
167 return StringImpl::empty(); 78 return StringImpl::empty();
168 case CLOSE_QUOTE: 79 case CLOSE_QUOTE:
169 // FIXME: When m_depth is 0 we should return empty string. 80 // FIXME: When m_depth is 0 we should return empty string.
170 return quotes->getCloseQuote(std::max(m_depth - 1, 0)).impl(); 81 return quotesData()->getCloseQuote(std::max(m_depth - 1, 0)).impl();
171 case OPEN_QUOTE: 82 case OPEN_QUOTE:
172 return quotes->getOpenQuote(m_depth).impl(); 83 return quotesData()->getOpenQuote(m_depth).impl();
173 default:
174 ASSERT_NOT_REACHED();
175 return StringImpl::empty();
176 } 84 }
85 ASSERT_NOT_REACHED();
86 return StringImpl::empty();
177 } 87 }
178 88
179 void RenderQuote::computePreferredLogicalWidths(float lead) 89 void RenderQuote::computePreferredLogicalWidths(float lead)
180 { 90 {
91 if (!m_attached)
92 attachQuote();
181 setTextInternal(originalText()); 93 setTextInternal(originalText());
182 RenderText::computePreferredLogicalWidths(lead); 94 RenderText::computePreferredLogicalWidths(lead);
183 } 95 }
184 96
185 const QuotesData* RenderQuote::quotesData() const 97 const QuotesData* RenderQuote::quotesData() const
186 { 98 {
187 if (QuotesData* customQuotes = style()->quotes()) 99 if (QuotesData* customQuotes = style()->quotes())
188 return customQuotes; 100 return customQuotes;
189 101
190 AtomicString language = style()->locale(); 102 AtomicString language = style()->locale();
191 if (language.isNull()) 103 if (language.isNull())
192 return basicQuotesData(); 104 return basicQuotesData();
193 const QuotesData* quotes = quotesDataLanguageMap().get(language); 105 const QuotesData* quotes = quotesDataLanguageMap().get(language);
194 if (!quotes) 106 if (!quotes)
195 return basicQuotesData(); 107 return basicQuotesData();
196 return quotes; 108 return quotes;
197 } 109 }
198 110
199 void RenderQuote::rendererSubtreeAttached(RenderObject* renderer) 111 void RenderQuote::attachQuote()
200 { 112 {
201 ASSERT(renderer->view()); 113 ASSERT(view());
202 if (!renderer->view()->hasRenderQuotes()) 114 ASSERT(!m_attached);
115 ASSERT(!m_next && !m_previous);
116
117 // FIXME: Don't set pref widths dirty during layout. See updateDepth() for
118 // more detail.
119 if (!isRooted()) {
120 setNeedsLayoutAndPrefWidthsRecalc();
203 return; 121 return;
204 for (RenderObject* descendant = renderer; descendant; descendant = descendan t->nextInPreOrder(renderer)) 122 }
205 if (descendant->isQuote()) { 123
206 toRenderQuote(descendant)->placeQuote(); 124 if (!view()->renderQuoteHead()) {
125 view()->setRenderQuoteHead(this);
126 m_attached = true;
127 return;
128 }
129
130 for (RenderObject* predecessor = previousInPreOrder(); predecessor; predeces sor = predecessor->previousInPreOrder()) {
131 if (!predecessor->isQuote())
132 continue;
133 m_previous = toRenderQuote(predecessor);
134 m_next = m_previous->m_next;
135 m_previous->m_next = this;
136 if (m_next)
137 m_next->m_previous = this;
138 break;
139 }
140
141 if (!m_previous) {
142 m_next = view()->renderQuoteHead();
143 view()->setRenderQuoteHead(this);
144 }
145 m_attached = true;
146 for (RenderQuote* quote = this; quote; quote = quote->m_next)
147 quote->updateDepth();
148
149 ASSERT(!m_next || m_next->m_attached);
150 ASSERT(!m_previous || m_previous->m_attached);
151 }
152
153 void RenderQuote::detachQuote()
154 {
155 ASSERT(!m_next || m_next->m_attached);
156 ASSERT(!m_previous || m_previous->m_attached);
157 if (!m_attached)
158 return;
159 if (m_previous)
160 m_previous->m_next = m_next;
161 else if (view())
162 view()->setRenderQuoteHead(m_next);
163 if (m_next)
164 m_next->m_previous = m_previous;
165 if (!documentBeingDestroyed()) {
166 for (RenderQuote* quote = m_next; quote; quote = quote->m_next)
167 quote->updateDepth();
168 }
169 m_attached = false;
170 m_next = 0;
171 m_previous = 0;
172 m_depth = 0;
173 }
174
175 void RenderQuote::updateDepth()
176 {
177 ASSERT(m_attached);
178 int oldDepth = m_depth;
179 m_depth = 0;
180 if (m_previous) {
181 m_depth = m_previous->m_depth;
182 switch (m_previous->m_type) {
183 case OPEN_QUOTE:
184 case NO_OPEN_QUOTE:
185 m_depth++;
186 break;
187 case CLOSE_QUOTE:
188 case NO_CLOSE_QUOTE:
189 if (m_depth)
190 m_depth--;
207 break; 191 break;
208 } 192 }
209 } 193 }
210 194 // FIXME: Don't call setNeedsLayout or dirty our preferred widths during lay out.
211 void RenderQuote::rendererRemovedFromTree(RenderObject* renderer) 195 // This is likely to fail anyway as one of our ancestor will call setNeedsLa yout(false),
212 { 196 // preventing the future layout to occur on |this|. The solution is to move that to a
213 ASSERT(renderer->view()); 197 // pre-layout phase.
214 if (!renderer->view()->hasRenderQuotes()) 198 if (oldDepth != m_depth)
215 return;
216 for (RenderObject* descendant = renderer; descendant; descendant = descendan t->nextInPreOrder(renderer))
217 if (descendant->isQuote()) {
218 RenderQuote* removedQuote = toRenderQuote(descendant);
219 RenderQuote* lastQuoteBefore = removedQuote->m_previous;
220 removedQuote->m_previous = 0;
221 int depth = removedQuote->m_depth;
222 for (descendant = descendant->nextInPreOrder(renderer); descendant; descendant = descendant->nextInPreOrder(renderer))
223 if (descendant->isQuote())
224 removedQuote = toRenderQuote(descendant);
225 RenderQuote* quoteAfter = removedQuote->m_next;
226 removedQuote->m_next = 0;
227 if (lastQuoteBefore)
228 lastQuoteBefore->m_next = quoteAfter;
229 if (quoteAfter) {
230 quoteAfter->m_previous = lastQuoteBefore;
231 do {
232 if (depth == quoteAfter->m_depth)
233 break;
234 quoteAfter->m_depth = depth;
235 quoteAfter->setNeedsLayoutAndPrefWidthsRecalc();
236 adjustDepth(depth, quoteAfter->m_type);
237 quoteAfter = quoteAfter->m_next;
238 } while (quoteAfter);
239 }
240 break;
241 }
242 }
243
244 void RenderQuote::styleDidChange(StyleDifference diff, const RenderStyle* oldSty le)
245 {
246 const QuotesData* newQuotes = style()->quotes();
247 const QuotesData* oldQuotes = oldStyle ? oldStyle->quotes() : 0;
248 if (!QuotesData::equals(newQuotes, oldQuotes))
249 setNeedsLayoutAndPrefWidthsRecalc(); 199 setNeedsLayoutAndPrefWidthsRecalc();
250 RenderText::styleDidChange(diff, oldStyle);
251 } 200 }
252 201
253 } // namespace WebCore 202 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/WebCore/rendering/RenderQuote.h ('k') | Source/WebCore/rendering/RenderView.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698