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