Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "inCSSValueSearch.h"
7 #include "mozilla/dom/StyleSheetList.h"
8 #include "nsCSSStyleSheet.h"
9 #include "nsIComponentManager.h"
10 #include "nsIServiceManager.h"
11 #include "nsReadableUtils.h"
12 #include "nsIDOMDocument.h"
13 #include "nsIDOMStyleSheetList.h"
14 #include "nsIDOMCSSStyleSheet.h"
15 #include "nsIDOMCSSRuleList.h"
16 #include "nsIDOMCSSStyleRule.h"
17 #include "nsIDOMCSSStyleDeclaration.h"
18 #include "nsIDOMCSSImportRule.h"
19 #include "nsIDOMCSSMediaRule.h"
20 #include "nsIDOMCSSSupportsRule.h"
21 #include "nsIURI.h"
22 #include "nsIDocument.h"
23 #include "nsNetUtil.h"
25 using namespace mozilla;
27 ///////////////////////////////////////////////////////////////////////////////
28 inCSSValueSearch::inCSSValueSearch()
29 : mResults(nullptr),
30 mProperties(nullptr),
31 mResultCount(0),
32 mPropertyCount(0),
33 mIsActive(false),
34 mHoldResults(true),
35 mReturnRelativeURLs(true),
36 mNormalizeChromeURLs(false)
37 {
38 nsCSSProps::AddRefTable();
39 mProperties = new nsCSSProperty[100];
40 }
42 inCSSValueSearch::~inCSSValueSearch()
43 {
44 delete[] mProperties;
45 delete mResults;
46 nsCSSProps::ReleaseTable();
47 }
49 NS_IMPL_ISUPPORTS(inCSSValueSearch, inISearchProcess, inICSSValueSearch)
51 ///////////////////////////////////////////////////////////////////////////////
52 // inISearchProcess
54 NS_IMETHODIMP
55 inCSSValueSearch::GetIsActive(bool *aIsActive)
56 {
57 *aIsActive = mIsActive;
58 return NS_OK;
59 }
61 NS_IMETHODIMP
62 inCSSValueSearch::GetResultCount(int32_t *aResultCount)
63 {
64 *aResultCount = mResultCount;
65 return NS_OK;
66 }
68 NS_IMETHODIMP
69 inCSSValueSearch::GetHoldResults(bool *aHoldResults)
70 {
71 *aHoldResults = mHoldResults;
72 return NS_OK;
73 }
75 NS_IMETHODIMP
76 inCSSValueSearch::SetHoldResults(bool aHoldResults)
77 {
78 mHoldResults = aHoldResults;
79 return NS_OK;
80 }
82 NS_IMETHODIMP
83 inCSSValueSearch::SearchSync()
84 {
85 InitSearch();
87 if (!mDocument) {
88 return NS_OK;
89 }
91 nsCOMPtr<nsIDocument> document = do_QueryInterface(mDocument);
92 MOZ_ASSERT(document);
94 nsCOMPtr<nsIURI> baseURI = document->GetBaseURI();
96 nsRefPtr<dom::StyleSheetList> sheets = document->StyleSheets();
97 MOZ_ASSERT(sheets);
99 uint32_t length = sheets->Length();
100 for (uint32_t i = 0; i < length; ++i) {
101 nsRefPtr<nsCSSStyleSheet> sheet = sheets->Item(i);
102 SearchStyleSheet(sheet, baseURI);
103 }
105 // XXX would be nice to search inline style as well.
107 return NS_OK;
108 }
110 NS_IMETHODIMP
111 inCSSValueSearch::SearchAsync(inISearchObserver *aObserver)
112 {
113 InitSearch();
114 mObserver = aObserver;
116 return NS_OK;
117 }
120 NS_IMETHODIMP
121 inCSSValueSearch::SearchStop()
122 {
123 KillSearch(inISearchObserver::IN_INTERRUPTED);
124 return NS_OK;
125 }
127 NS_IMETHODIMP
128 inCSSValueSearch::SearchStep(bool* _retval)
129 {
131 return NS_OK;
132 }
135 NS_IMETHODIMP
136 inCSSValueSearch::GetStringResultAt(int32_t aIndex, nsAString& _retval)
137 {
138 if (mHoldResults) {
139 nsAutoString* result = mResults->ElementAt(aIndex);
140 _retval = *result;
141 } else if (aIndex == mResultCount-1) {
142 _retval = mLastResult;
143 } else {
144 return NS_ERROR_FAILURE;
145 }
146 return NS_OK;
147 }
149 NS_IMETHODIMP
150 inCSSValueSearch::GetIntResultAt(int32_t aIndex, int32_t *_retval)
151 {
152 return NS_ERROR_NOT_IMPLEMENTED;
153 }
155 NS_IMETHODIMP
156 inCSSValueSearch::GetUIntResultAt(int32_t aIndex, uint32_t *_retval)
157 {
158 return NS_ERROR_NOT_IMPLEMENTED;
159 }
161 ///////////////////////////////////////////////////////////////////////////////
162 // inICSSValueSearch
164 NS_IMETHODIMP
165 inCSSValueSearch::GetDocument(nsIDOMDocument** aDocument)
166 {
167 *aDocument = mDocument;
168 NS_IF_ADDREF(*aDocument);
169 return NS_OK;
170 }
172 NS_IMETHODIMP
173 inCSSValueSearch::SetDocument(nsIDOMDocument* aDocument)
174 {
175 mDocument = aDocument;
176 return NS_OK;
177 }
179 NS_IMETHODIMP
180 inCSSValueSearch::GetBaseURL(char16_t** aBaseURL)
181 {
182 if (!(*aBaseURL = ToNewUnicode(mBaseURL)))
183 return NS_ERROR_OUT_OF_MEMORY;
184 return NS_OK;
185 }
187 NS_IMETHODIMP
188 inCSSValueSearch::SetBaseURL(const char16_t* aBaseURL)
189 {
190 mBaseURL.Assign(aBaseURL);
191 return NS_OK;
192 }
194 NS_IMETHODIMP
195 inCSSValueSearch::GetReturnRelativeURLs(bool* aReturnRelativeURLs)
196 {
197 *aReturnRelativeURLs = mReturnRelativeURLs;
198 return NS_OK;
199 }
201 NS_IMETHODIMP
202 inCSSValueSearch::SetReturnRelativeURLs(bool aReturnRelativeURLs)
203 {
204 mReturnRelativeURLs = aReturnRelativeURLs;
205 return NS_OK;
206 }
208 NS_IMETHODIMP
209 inCSSValueSearch::GetNormalizeChromeURLs(bool *aNormalizeChromeURLs)
210 {
211 *aNormalizeChromeURLs = mNormalizeChromeURLs;
212 return NS_OK;
213 }
215 NS_IMETHODIMP
216 inCSSValueSearch::SetNormalizeChromeURLs(bool aNormalizeChromeURLs)
217 {
218 mNormalizeChromeURLs = aNormalizeChromeURLs;
219 return NS_OK;
220 }
222 NS_IMETHODIMP
223 inCSSValueSearch::AddPropertyCriteria(const char16_t *aPropName)
224 {
225 nsCSSProperty prop =
226 nsCSSProps::LookupProperty(nsDependentString(aPropName),
227 nsCSSProps::eIgnoreEnabledState);
228 mProperties[mPropertyCount] = prop;
229 mPropertyCount++;
230 return NS_OK;
231 }
233 NS_IMETHODIMP
234 inCSSValueSearch::GetTextCriteria(char16_t** aTextCriteria)
235 {
236 if (!(*aTextCriteria = ToNewUnicode(mTextCriteria)))
237 return NS_ERROR_OUT_OF_MEMORY;
238 return NS_OK;
239 }
241 NS_IMETHODIMP
242 inCSSValueSearch::SetTextCriteria(const char16_t* aTextCriteria)
243 {
244 mTextCriteria.Assign(aTextCriteria);
245 return NS_OK;
246 }
248 ///////////////////////////////////////////////////////////////////////////////
249 // inCSSValueSearch
251 nsresult
252 inCSSValueSearch::InitSearch()
253 {
254 if (mHoldResults) {
255 mResults = new nsTArray<nsAutoString *>();
256 }
258 mResultCount = 0;
260 return NS_OK;
261 }
263 nsresult
264 inCSSValueSearch::KillSearch(int16_t aResult)
265 {
266 mIsActive = true;
267 mObserver->OnSearchEnd(this, aResult);
269 return NS_OK;
270 }
272 nsresult
273 inCSSValueSearch::SearchStyleSheet(nsIDOMCSSStyleSheet* aStyleSheet, nsIURI* aBaseURL)
274 {
275 nsCOMPtr<nsIURI> baseURL;
276 nsAutoString href;
277 aStyleSheet->GetHref(href);
278 if (href.IsEmpty())
279 baseURL = aBaseURL;
280 else
281 NS_NewURI(getter_AddRefs(baseURL), href, nullptr, aBaseURL);
283 nsCOMPtr<nsIDOMCSSRuleList> rules;
284 nsresult rv = aStyleSheet->GetCssRules(getter_AddRefs(rules));
285 NS_ENSURE_SUCCESS(rv, rv);
287 return SearchRuleList(rules, baseURL);
288 }
290 nsresult
291 inCSSValueSearch::SearchRuleList(nsIDOMCSSRuleList* aRuleList, nsIURI* aBaseURL)
292 {
293 uint32_t length;
294 aRuleList->GetLength(&length);
295 for (uint32_t i = 0; i < length; ++i) {
296 nsCOMPtr<nsIDOMCSSRule> rule;
297 aRuleList->Item(i, getter_AddRefs(rule));
298 uint16_t type;
299 rule->GetType(&type);
300 switch (type) {
301 case nsIDOMCSSRule::STYLE_RULE: {
302 nsCOMPtr<nsIDOMCSSStyleRule> styleRule = do_QueryInterface(rule);
303 SearchStyleRule(styleRule, aBaseURL);
304 } break;
305 case nsIDOMCSSRule::IMPORT_RULE: {
306 nsCOMPtr<nsIDOMCSSImportRule> importRule = do_QueryInterface(rule);
307 nsCOMPtr<nsIDOMCSSStyleSheet> childSheet;
308 importRule->GetStyleSheet(getter_AddRefs(childSheet));
309 if (childSheet)
310 SearchStyleSheet(childSheet, aBaseURL);
311 } break;
312 case nsIDOMCSSRule::MEDIA_RULE: {
313 nsCOMPtr<nsIDOMCSSMediaRule> mediaRule = do_QueryInterface(rule);
314 nsCOMPtr<nsIDOMCSSRuleList> childRules;
315 mediaRule->GetCssRules(getter_AddRefs(childRules));
316 SearchRuleList(childRules, aBaseURL);
317 } break;
318 case nsIDOMCSSRule::SUPPORTS_RULE: {
319 nsCOMPtr<nsIDOMCSSSupportsRule> supportsRule = do_QueryInterface(rule);
320 nsCOMPtr<nsIDOMCSSRuleList> childRules;
321 supportsRule->GetCssRules(getter_AddRefs(childRules));
322 SearchRuleList(childRules, aBaseURL);
323 } break;
324 default:
325 // XXX handle nsIDOMCSSRule::PAGE_RULE if we ever support it
326 break;
327 }
328 }
329 return NS_OK;
330 }
332 nsresult
333 inCSSValueSearch::SearchStyleRule(nsIDOMCSSStyleRule* aStyleRule, nsIURI* aBaseURL)
334 {
335 nsCOMPtr<nsIDOMCSSStyleDeclaration> decl;
336 nsresult rv = aStyleRule->GetStyle(getter_AddRefs(decl));
337 NS_ENSURE_SUCCESS(rv, rv);
339 uint32_t length;
340 decl->GetLength(&length);
341 nsAutoString property, value;
342 for (uint32_t i = 0; i < length; ++i) {
343 decl->Item(i, property);
344 // XXX This probably ought to use GetPropertyCSSValue if it were
345 // implemented.
346 decl->GetPropertyValue(property, value);
347 SearchStyleValue(value, aBaseURL);
348 }
349 return NS_OK;
350 }
352 nsresult
353 inCSSValueSearch::SearchStyleValue(const nsAFlatString& aValue, nsIURI* aBaseURL)
354 {
355 if (StringBeginsWith(aValue, NS_LITERAL_STRING("url(")) &&
356 StringEndsWith(aValue, NS_LITERAL_STRING(")"))) {
357 const nsASingleFragmentString &url =
358 Substring(aValue, 4, aValue.Length() - 5);
359 // XXXldb Need to do more with |mReturnRelativeURLs|, perhaps?
360 nsCOMPtr<nsIURI> uri;
361 nsresult rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, aBaseURL);
362 NS_ENSURE_SUCCESS(rv, rv);
363 nsAutoCString spec;
364 uri->GetSpec(spec);
365 nsAutoString *result = new NS_ConvertUTF8toUTF16(spec);
366 if (mReturnRelativeURLs)
367 EqualizeURL(result);
368 mResults->AppendElement(result);
369 ++mResultCount;
370 }
372 return NS_OK;
373 }
375 nsresult
376 inCSSValueSearch::EqualizeURL(nsAutoString* aURL)
377 {
378 if (mNormalizeChromeURLs) {
379 if (aURL->Find("chrome://", false, 0, 1) >= 0) {
380 uint32_t len = aURL->Length();
381 char16_t* result = new char16_t[len-8];
382 const char16_t* src = aURL->get();
383 uint32_t i = 9;
384 uint32_t milestone = 0;
385 uint32_t s = 0;
386 while (i < len) {
387 if (src[i] == '/') {
388 milestone += 1;
389 }
390 if (milestone != 1) {
391 result[i-9-s] = src[i];
392 } else {
393 s++;
394 }
395 i++;
396 }
397 result[i-9-s] = 0;
399 aURL->Assign(result);
400 delete [] result;
401 }
402 } else {
403 }
405 return NS_OK;
406 }