/* 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/. */ #include "inCSSValueSearch.h" #include "mozilla/StyleSheetInlines.h" #include "mozilla/dom/StyleSheetList.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsReadableUtils.h" #include "nsIDOMDocument.h" #include "nsIDOMStyleSheetList.h" #include "nsIDOMCSSStyleSheet.h" #include "nsIDOMCSSRuleList.h" #include "nsIDOMCSSStyleRule.h" #include "nsIDOMCSSStyleDeclaration.h" #include "nsIDOMCSSImportRule.h" #include "nsIDOMCSSMediaRule.h" #include "nsIDOMCSSSupportsRule.h" #include "nsIURI.h" #include "nsIDocument.h" #include "nsNetUtil.h" using namespace mozilla; /////////////////////////////////////////////////////////////////////////////// inCSSValueSearch::inCSSValueSearch() : mResults(nullptr), mProperties(nullptr), mResultCount(0), mPropertyCount(0), mIsActive(false), mHoldResults(true), mReturnRelativeURLs(true), mNormalizeChromeURLs(false) { nsCSSProps::AddRefTable(); mProperties = new nsCSSPropertyID[100]; } inCSSValueSearch::~inCSSValueSearch() { delete[] mProperties; delete mResults; nsCSSProps::ReleaseTable(); } NS_IMPL_ISUPPORTS(inCSSValueSearch, inISearchProcess, inICSSValueSearch) /////////////////////////////////////////////////////////////////////////////// // inISearchProcess NS_IMETHODIMP inCSSValueSearch::GetIsActive(bool *aIsActive) { *aIsActive = mIsActive; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::GetResultCount(int32_t *aResultCount) { *aResultCount = mResultCount; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::GetHoldResults(bool *aHoldResults) { *aHoldResults = mHoldResults; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::SetHoldResults(bool aHoldResults) { mHoldResults = aHoldResults; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::SearchSync() { InitSearch(); if (!mDocument) { return NS_OK; } nsCOMPtr document = do_QueryInterface(mDocument); MOZ_ASSERT(document); nsCOMPtr baseURI = document->GetBaseURI(); RefPtr sheets = document->StyleSheets(); MOZ_ASSERT(sheets); uint32_t length = sheets->Length(); for (uint32_t i = 0; i < length; ++i) { RefPtr sheet = sheets->Item(i); SearchStyleSheet(sheet, baseURI); } // XXX would be nice to search inline style as well. return NS_OK; } NS_IMETHODIMP inCSSValueSearch::SearchAsync(inISearchObserver *aObserver) { InitSearch(); mObserver = aObserver; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::SearchStop() { KillSearch(inISearchObserver::IN_INTERRUPTED); return NS_OK; } NS_IMETHODIMP inCSSValueSearch::SearchStep(bool* _retval) { return NS_OK; } NS_IMETHODIMP inCSSValueSearch::GetStringResultAt(int32_t aIndex, nsAString& _retval) { if (mHoldResults) { nsAutoString* result = mResults->ElementAt(aIndex); _retval = *result; } else if (aIndex == mResultCount-1) { _retval = mLastResult; } else { return NS_ERROR_FAILURE; } return NS_OK; } NS_IMETHODIMP inCSSValueSearch::GetIntResultAt(int32_t aIndex, int32_t *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP inCSSValueSearch::GetUIntResultAt(int32_t aIndex, uint32_t *_retval) { return NS_ERROR_NOT_IMPLEMENTED; } /////////////////////////////////////////////////////////////////////////////// // inICSSValueSearch NS_IMETHODIMP inCSSValueSearch::GetDocument(nsIDOMDocument** aDocument) { *aDocument = mDocument; NS_IF_ADDREF(*aDocument); return NS_OK; } NS_IMETHODIMP inCSSValueSearch::SetDocument(nsIDOMDocument* aDocument) { mDocument = aDocument; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::GetBaseURL(char16_t** aBaseURL) { if (!(*aBaseURL = ToNewUnicode(mBaseURL))) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::SetBaseURL(const char16_t* aBaseURL) { mBaseURL.Assign(aBaseURL); return NS_OK; } NS_IMETHODIMP inCSSValueSearch::GetReturnRelativeURLs(bool* aReturnRelativeURLs) { *aReturnRelativeURLs = mReturnRelativeURLs; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::SetReturnRelativeURLs(bool aReturnRelativeURLs) { mReturnRelativeURLs = aReturnRelativeURLs; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::GetNormalizeChromeURLs(bool *aNormalizeChromeURLs) { *aNormalizeChromeURLs = mNormalizeChromeURLs; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::SetNormalizeChromeURLs(bool aNormalizeChromeURLs) { mNormalizeChromeURLs = aNormalizeChromeURLs; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::AddPropertyCriteria(const char16_t *aPropName) { nsCSSPropertyID prop = nsCSSProps::LookupProperty(nsDependentString(aPropName), CSSEnabledState::eIgnoreEnabledState); mProperties[mPropertyCount] = prop; mPropertyCount++; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::GetTextCriteria(char16_t** aTextCriteria) { if (!(*aTextCriteria = ToNewUnicode(mTextCriteria))) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } NS_IMETHODIMP inCSSValueSearch::SetTextCriteria(const char16_t* aTextCriteria) { mTextCriteria.Assign(aTextCriteria); return NS_OK; } /////////////////////////////////////////////////////////////////////////////// // inCSSValueSearch nsresult inCSSValueSearch::InitSearch() { if (mHoldResults) { mResults = new nsTArray(); } mResultCount = 0; return NS_OK; } nsresult inCSSValueSearch::KillSearch(int16_t aResult) { mIsActive = true; mObserver->OnSearchEnd(this, aResult); return NS_OK; } nsresult inCSSValueSearch::SearchStyleSheet(nsIDOMCSSStyleSheet* aStyleSheet, nsIURI* aBaseURL) { nsCOMPtr baseURL; nsAutoString href; aStyleSheet->GetHref(href); if (href.IsEmpty()) baseURL = aBaseURL; else NS_NewURI(getter_AddRefs(baseURL), href, nullptr, aBaseURL); nsCOMPtr rules; nsresult rv = aStyleSheet->GetCssRules(getter_AddRefs(rules)); NS_ENSURE_SUCCESS(rv, rv); return SearchRuleList(rules, baseURL); } nsresult inCSSValueSearch::SearchRuleList(nsIDOMCSSRuleList* aRuleList, nsIURI* aBaseURL) { uint32_t length; aRuleList->GetLength(&length); for (uint32_t i = 0; i < length; ++i) { nsCOMPtr rule; aRuleList->Item(i, getter_AddRefs(rule)); uint16_t type; rule->GetType(&type); switch (type) { case nsIDOMCSSRule::STYLE_RULE: { nsCOMPtr styleRule = do_QueryInterface(rule); SearchStyleRule(styleRule, aBaseURL); } break; case nsIDOMCSSRule::IMPORT_RULE: { nsCOMPtr importRule = do_QueryInterface(rule); nsCOMPtr childSheet; importRule->GetStyleSheet(getter_AddRefs(childSheet)); if (childSheet) SearchStyleSheet(childSheet, aBaseURL); } break; case nsIDOMCSSRule::MEDIA_RULE: { nsCOMPtr mediaRule = do_QueryInterface(rule); nsCOMPtr childRules; mediaRule->GetCssRules(getter_AddRefs(childRules)); SearchRuleList(childRules, aBaseURL); } break; case nsIDOMCSSRule::SUPPORTS_RULE: { nsCOMPtr supportsRule = do_QueryInterface(rule); nsCOMPtr childRules; supportsRule->GetCssRules(getter_AddRefs(childRules)); SearchRuleList(childRules, aBaseURL); } break; default: // XXX handle nsIDOMCSSRule::PAGE_RULE if we ever support it break; } } return NS_OK; } nsresult inCSSValueSearch::SearchStyleRule(nsIDOMCSSStyleRule* aStyleRule, nsIURI* aBaseURL) { nsCOMPtr decl; nsresult rv = aStyleRule->GetStyle(getter_AddRefs(decl)); NS_ENSURE_SUCCESS(rv, rv); uint32_t length; decl->GetLength(&length); nsAutoString property, value; for (uint32_t i = 0; i < length; ++i) { decl->Item(i, property); // XXX This probably ought to use GetPropertyCSSValue if it were // implemented. decl->GetPropertyValue(property, value); SearchStyleValue(value, aBaseURL); } return NS_OK; } nsresult inCSSValueSearch::SearchStyleValue(const nsAFlatString& aValue, nsIURI* aBaseURL) { if (StringBeginsWith(aValue, NS_LITERAL_STRING("url(")) && StringEndsWith(aValue, NS_LITERAL_STRING(")"))) { const nsASingleFragmentString &url = Substring(aValue, 4, aValue.Length() - 5); // XXXldb Need to do more with |mReturnRelativeURLs|, perhaps? nsCOMPtr uri; nsresult rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, aBaseURL); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString spec; rv = uri->GetSpec(spec); NS_ENSURE_SUCCESS(rv, rv); nsAutoString *result = new NS_ConvertUTF8toUTF16(spec); if (mReturnRelativeURLs) EqualizeURL(result); mResults->AppendElement(result); ++mResultCount; } return NS_OK; } nsresult inCSSValueSearch::EqualizeURL(nsAutoString* aURL) { if (mNormalizeChromeURLs) { if (aURL->Find("chrome://", false, 0, 1) >= 0) { uint32_t len = aURL->Length(); char16_t* result = new char16_t[len-8]; const char16_t* src = aURL->get(); uint32_t i = 9; uint32_t milestone = 0; uint32_t s = 0; while (i < len) { if (src[i] == '/') { milestone += 1; } if (milestone != 1) { result[i-9-s] = src[i]; } else { s++; } i++; } result[i-9-s] = 0; aURL->Assign(result); delete [] result; } } else { } return NS_OK; }