1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/xul/templates/src/nsXULContentUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,472 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.9 + * 1.10 + * 1.11 + * This Original Code has been modified by IBM Corporation. 1.12 + * Modifications made by IBM described herein are 1.13 + * Copyright (c) International Business Machines 1.14 + * Corporation, 2000 1.15 + * 1.16 + * Modifications to Mozilla code or documentation 1.17 + * identified per MPL Section 3.3 1.18 + * 1.19 + * Date Modified by Description of modification 1.20 + * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink 1.21 + * use in OS2 1.22 + */ 1.23 + 1.24 + 1.25 +/* 1.26 + 1.27 + A package of routines shared by the XUL content code. 1.28 + 1.29 + */ 1.30 + 1.31 +#include "mozilla/ArrayUtils.h" 1.32 + 1.33 +#include "nsCOMPtr.h" 1.34 +#include "nsIContent.h" 1.35 +#include "nsIDocument.h" 1.36 +#include "nsIDOMElement.h" 1.37 +#include "nsIDOMXULCommandDispatcher.h" 1.38 +#include "nsIDOMXULDocument.h" 1.39 +#include "nsIRDFNode.h" 1.40 +#include "nsIRDFService.h" 1.41 +#include "nsIServiceManager.h" 1.42 +#include "nsIURL.h" 1.43 +#include "nsXULContentUtils.h" 1.44 +#include "nsLayoutCID.h" 1.45 +#include "nsNameSpaceManager.h" 1.46 +#include "nsNetUtil.h" 1.47 +#include "nsRDFCID.h" 1.48 +#include "nsString.h" 1.49 +#include "nsXPIDLString.h" 1.50 +#include "nsGkAtoms.h" 1.51 +#include "prlog.h" 1.52 +#include "prtime.h" 1.53 +#include "rdf.h" 1.54 +#include "nsContentUtils.h" 1.55 +#include "nsIDateTimeFormat.h" 1.56 +#include "nsDateTimeFormatCID.h" 1.57 +#include "nsIScriptableDateFormat.h" 1.58 +#include "nsICollation.h" 1.59 +#include "nsCollationCID.h" 1.60 +#include "nsILocale.h" 1.61 +#include "nsILocaleService.h" 1.62 +#include "nsIConsoleService.h" 1.63 +#include "nsEscape.h" 1.64 + 1.65 +using namespace mozilla; 1.66 + 1.67 +//------------------------------------------------------------------------ 1.68 + 1.69 +nsIRDFService* nsXULContentUtils::gRDF; 1.70 +nsIDateTimeFormat* nsXULContentUtils::gFormat; 1.71 +nsICollation *nsXULContentUtils::gCollation; 1.72 + 1.73 +#ifdef PR_LOGGING 1.74 +extern PRLogModuleInfo* gXULTemplateLog; 1.75 +#endif 1.76 + 1.77 +#define XUL_RESOURCE(ident, uri) nsIRDFResource* nsXULContentUtils::ident 1.78 +#define XUL_LITERAL(ident, val) nsIRDFLiteral* nsXULContentUtils::ident 1.79 +#include "nsXULResourceList.h" 1.80 +#undef XUL_RESOURCE 1.81 +#undef XUL_LITERAL 1.82 + 1.83 +//------------------------------------------------------------------------ 1.84 +// Constructors n' stuff 1.85 +// 1.86 + 1.87 +nsresult 1.88 +nsXULContentUtils::Init() 1.89 +{ 1.90 + static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); 1.91 + nsresult rv = CallGetService(kRDFServiceCID, &gRDF); 1.92 + if (NS_FAILED(rv)) { 1.93 + return rv; 1.94 + } 1.95 + 1.96 +#define XUL_RESOURCE(ident, uri) \ 1.97 + PR_BEGIN_MACRO \ 1.98 + rv = gRDF->GetResource(NS_LITERAL_CSTRING(uri), &(ident)); \ 1.99 + if (NS_FAILED(rv)) return rv; \ 1.100 + PR_END_MACRO 1.101 + 1.102 +#define XUL_LITERAL(ident, val) \ 1.103 + PR_BEGIN_MACRO \ 1.104 + rv = gRDF->GetLiteral(NS_LITERAL_STRING(val).get(), &(ident)); \ 1.105 + if (NS_FAILED(rv)) return rv; \ 1.106 + PR_END_MACRO 1.107 + 1.108 +#include "nsXULResourceList.h" 1.109 +#undef XUL_RESOURCE 1.110 +#undef XUL_LITERAL 1.111 + 1.112 + rv = CallCreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &gFormat); 1.113 + if (NS_FAILED(rv)) { 1.114 + return rv; 1.115 + } 1.116 + 1.117 + return NS_OK; 1.118 +} 1.119 + 1.120 + 1.121 +nsresult 1.122 +nsXULContentUtils::Finish() 1.123 +{ 1.124 + NS_IF_RELEASE(gRDF); 1.125 + 1.126 +#define XUL_RESOURCE(ident, uri) NS_IF_RELEASE(ident) 1.127 +#define XUL_LITERAL(ident, val) NS_IF_RELEASE(ident) 1.128 +#include "nsXULResourceList.h" 1.129 +#undef XUL_RESOURCE 1.130 +#undef XUL_LITERAL 1.131 + 1.132 + NS_IF_RELEASE(gFormat); 1.133 + NS_IF_RELEASE(gCollation); 1.134 + 1.135 + return NS_OK; 1.136 +} 1.137 + 1.138 +nsICollation* 1.139 +nsXULContentUtils::GetCollation() 1.140 +{ 1.141 + if (!gCollation) { 1.142 + nsresult rv; 1.143 + 1.144 + // get a locale service 1.145 + nsCOMPtr<nsILocaleService> localeService = 1.146 + do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); 1.147 + if (NS_SUCCEEDED(rv)) { 1.148 + nsCOMPtr<nsILocale> locale; 1.149 + rv = localeService->GetApplicationLocale(getter_AddRefs(locale)); 1.150 + if (NS_SUCCEEDED(rv) && locale) { 1.151 + nsCOMPtr<nsICollationFactory> colFactory = 1.152 + do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID); 1.153 + if (colFactory) { 1.154 + rv = colFactory->CreateCollation(locale, &gCollation); 1.155 + NS_ASSERTION(NS_SUCCEEDED(rv), 1.156 + "couldn't create collation instance"); 1.157 + } else 1.158 + NS_ERROR("couldn't create instance of collation factory"); 1.159 + } else 1.160 + NS_ERROR("unable to get application locale"); 1.161 + } else 1.162 + NS_ERROR("couldn't get locale factory"); 1.163 + } 1.164 + 1.165 + return gCollation; 1.166 +} 1.167 + 1.168 +//------------------------------------------------------------------------ 1.169 + 1.170 +nsresult 1.171 +nsXULContentUtils::FindChildByTag(nsIContent* aElement, 1.172 + int32_t aNameSpaceID, 1.173 + nsIAtom* aTag, 1.174 + nsIContent** aResult) 1.175 +{ 1.176 + for (nsIContent* child = aElement->GetFirstChild(); 1.177 + child; 1.178 + child = child->GetNextSibling()) { 1.179 + 1.180 + if (child->NodeInfo()->Equals(aTag, aNameSpaceID)) { 1.181 + NS_ADDREF(*aResult = child); 1.182 + 1.183 + return NS_OK; 1.184 + } 1.185 + } 1.186 + 1.187 + *aResult = nullptr; 1.188 + return NS_RDF_NO_VALUE; // not found 1.189 +} 1.190 + 1.191 + 1.192 +nsresult 1.193 +nsXULContentUtils::GetElementResource(nsIContent* aElement, nsIRDFResource** aResult) 1.194 +{ 1.195 + // Perform a reverse mapping from an element in the content model 1.196 + // to an RDF resource. 1.197 + nsresult rv; 1.198 + 1.199 + char16_t buf[128]; 1.200 + nsFixedString id(buf, ArrayLength(buf), 0); 1.201 + 1.202 + // Whoa. Why the "id" attribute? What if it's not even a XUL 1.203 + // element? This is totally bogus! 1.204 + aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id); 1.205 + if (id.IsEmpty()) 1.206 + return NS_ERROR_FAILURE; 1.207 + 1.208 + // Since the element will store its ID attribute as a document-relative value, 1.209 + // we may need to qualify it first... 1.210 + nsCOMPtr<nsIDocument> doc = aElement->GetDocument(); 1.211 + NS_ASSERTION(doc, "element is not in any document"); 1.212 + if (! doc) 1.213 + return NS_ERROR_FAILURE; 1.214 + 1.215 + rv = nsXULContentUtils::MakeElementResource(doc, id, aResult); 1.216 + if (NS_FAILED(rv)) return rv; 1.217 + 1.218 + return NS_OK; 1.219 +} 1.220 + 1.221 + 1.222 +/* 1.223 + Note: this routine is similar, yet distinctly different from, nsBookmarksService::GetTextForNode 1.224 +*/ 1.225 + 1.226 +nsresult 1.227 +nsXULContentUtils::GetTextForNode(nsIRDFNode* aNode, nsAString& aResult) 1.228 +{ 1.229 + if (! aNode) { 1.230 + aResult.Truncate(); 1.231 + return NS_OK; 1.232 + } 1.233 + 1.234 + nsresult rv; 1.235 + 1.236 + // Literals are the most common, so try these first. 1.237 + nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(aNode); 1.238 + if (literal) { 1.239 + const char16_t* p; 1.240 + rv = literal->GetValueConst(&p); 1.241 + if (NS_FAILED(rv)) return rv; 1.242 + 1.243 + aResult = p; 1.244 + return NS_OK; 1.245 + } 1.246 + 1.247 + nsCOMPtr<nsIRDFDate> dateLiteral = do_QueryInterface(aNode); 1.248 + if (dateLiteral) { 1.249 + PRTime value; 1.250 + rv = dateLiteral->GetValue(&value); 1.251 + if (NS_FAILED(rv)) return rv; 1.252 + 1.253 + nsAutoString str; 1.254 + rv = gFormat->FormatPRTime(nullptr /* nsILocale* locale */, 1.255 + kDateFormatShort, 1.256 + kTimeFormatSeconds, 1.257 + value, 1.258 + str); 1.259 + aResult.Assign(str); 1.260 + 1.261 + if (NS_FAILED(rv)) return rv; 1.262 + 1.263 + return NS_OK; 1.264 + } 1.265 + 1.266 + nsCOMPtr<nsIRDFInt> intLiteral = do_QueryInterface(aNode); 1.267 + if (intLiteral) { 1.268 + int32_t value; 1.269 + rv = intLiteral->GetValue(&value); 1.270 + if (NS_FAILED(rv)) return rv; 1.271 + 1.272 + aResult.Truncate(); 1.273 + nsAutoString intStr; 1.274 + intStr.AppendInt(value, 10); 1.275 + aResult.Append(intStr); 1.276 + return NS_OK; 1.277 + } 1.278 + 1.279 + 1.280 + nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(aNode); 1.281 + if (resource) { 1.282 + const char* p; 1.283 + rv = resource->GetValueConst(&p); 1.284 + if (NS_FAILED(rv)) return rv; 1.285 + CopyUTF8toUTF16(p, aResult); 1.286 + return NS_OK; 1.287 + } 1.288 + 1.289 + NS_ERROR("not a resource or a literal"); 1.290 + return NS_ERROR_UNEXPECTED; 1.291 +} 1.292 + 1.293 +nsresult 1.294 +nsXULContentUtils::MakeElementURI(nsIDocument* aDocument, 1.295 + const nsAString& aElementID, 1.296 + nsCString& aURI) 1.297 +{ 1.298 + // Convert an element's ID to a URI that can be used to refer to 1.299 + // the element in the XUL graph. 1.300 + 1.301 + nsIURI *docURI = aDocument->GetDocumentURI(); 1.302 + NS_ENSURE_TRUE(docURI, NS_ERROR_UNEXPECTED); 1.303 + 1.304 + nsRefPtr<nsIURI> docURIClone; 1.305 + nsresult rv = docURI->Clone(getter_AddRefs(docURIClone)); 1.306 + NS_ENSURE_SUCCESS(rv, rv); 1.307 + 1.308 + rv = docURIClone->SetRef(NS_ConvertUTF16toUTF8(aElementID)); 1.309 + if (NS_SUCCEEDED(rv)) { 1.310 + return docURIClone->GetSpec(aURI); 1.311 + } 1.312 + 1.313 + // docURIClone is apparently immutable. Fine - we can append ref manually. 1.314 + rv = docURI->GetSpec(aURI); 1.315 + NS_ENSURE_SUCCESS(rv, rv); 1.316 + 1.317 + nsAutoCString ref; 1.318 + NS_EscapeURL(NS_ConvertUTF16toUTF8(aElementID), esc_FilePath | esc_AlwaysCopy, ref); 1.319 + 1.320 + aURI.Append('#'); 1.321 + aURI.Append(ref); 1.322 + 1.323 + return NS_OK; 1.324 +} 1.325 + 1.326 + 1.327 +nsresult 1.328 +nsXULContentUtils::MakeElementResource(nsIDocument* aDocument, const nsAString& aID, nsIRDFResource** aResult) 1.329 +{ 1.330 + nsresult rv; 1.331 + 1.332 + char buf[256]; 1.333 + nsFixedCString uri(buf, sizeof(buf), 0); 1.334 + rv = MakeElementURI(aDocument, aID, uri); 1.335 + if (NS_FAILED(rv)) return rv; 1.336 + 1.337 + rv = gRDF->GetResource(uri, aResult); 1.338 + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create resource"); 1.339 + if (NS_FAILED(rv)) return rv; 1.340 + 1.341 + return NS_OK; 1.342 +} 1.343 + 1.344 + 1.345 + 1.346 +nsresult 1.347 +nsXULContentUtils::MakeElementID(nsIDocument* aDocument, 1.348 + const nsACString& aURI, 1.349 + nsAString& aElementID) 1.350 +{ 1.351 + // Convert a URI into an element ID that can be accessed from the 1.352 + // DOM APIs. 1.353 + nsCOMPtr<nsIURI> uri; 1.354 + nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI, 1.355 + aDocument->GetDocumentCharacterSet().get()); 1.356 + NS_ENSURE_SUCCESS(rv, rv); 1.357 + 1.358 + nsAutoCString ref; 1.359 + uri->GetRef(ref); 1.360 + CopyUTF8toUTF16(ref, aElementID); 1.361 + 1.362 + return NS_OK; 1.363 +} 1.364 + 1.365 +nsresult 1.366 +nsXULContentUtils::GetResource(int32_t aNameSpaceID, nsIAtom* aAttribute, nsIRDFResource** aResult) 1.367 +{ 1.368 + // construct a fully-qualified URI from the namespace/tag pair. 1.369 + NS_PRECONDITION(aAttribute != nullptr, "null ptr"); 1.370 + if (! aAttribute) 1.371 + return NS_ERROR_NULL_POINTER; 1.372 + 1.373 + return GetResource(aNameSpaceID, nsDependentAtomString(aAttribute), 1.374 + aResult); 1.375 +} 1.376 + 1.377 + 1.378 +nsresult 1.379 +nsXULContentUtils::GetResource(int32_t aNameSpaceID, const nsAString& aAttribute, nsIRDFResource** aResult) 1.380 +{ 1.381 + // construct a fully-qualified URI from the namespace/tag pair. 1.382 + 1.383 + // XXX should we allow nodes with no namespace??? 1.384 + //NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "no namespace"); 1.385 + //if (aNameSpaceID == kNameSpaceID_Unknown) 1.386 + // return NS_ERROR_UNEXPECTED; 1.387 + 1.388 + nsresult rv; 1.389 + 1.390 + char16_t buf[256]; 1.391 + nsFixedString uri(buf, ArrayLength(buf), 0); 1.392 + if (aNameSpaceID != kNameSpaceID_Unknown && aNameSpaceID != kNameSpaceID_None) { 1.393 + rv = nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, uri); 1.394 + // XXX ignore failure; treat as "no namespace" 1.395 + } 1.396 + 1.397 + // XXX check to see if we need to insert a '/' or a '#'. Oy. 1.398 + if (!uri.IsEmpty() && uri.Last() != '#' && uri.Last() != '/' && aAttribute.First() != '#') 1.399 + uri.Append(char16_t('#')); 1.400 + 1.401 + uri.Append(aAttribute); 1.402 + 1.403 + rv = gRDF->GetUnicodeResource(uri, aResult); 1.404 + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get resource"); 1.405 + if (NS_FAILED(rv)) return rv; 1.406 + 1.407 + return NS_OK; 1.408 +} 1.409 + 1.410 + 1.411 +nsresult 1.412 +nsXULContentUtils::SetCommandUpdater(nsIDocument* aDocument, nsIContent* aElement) 1.413 +{ 1.414 + // Deal with setting up a 'commandupdater'. Pulls the 'events' and 1.415 + // 'targets' attributes off of aElement, and adds it to the 1.416 + // document's command dispatcher. 1.417 + NS_PRECONDITION(aDocument != nullptr, "null ptr"); 1.418 + if (! aDocument) 1.419 + return NS_ERROR_NULL_POINTER; 1.420 + 1.421 + NS_PRECONDITION(aElement != nullptr, "null ptr"); 1.422 + if (! aElement) 1.423 + return NS_ERROR_NULL_POINTER; 1.424 + 1.425 + nsresult rv; 1.426 + 1.427 + nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(aDocument); 1.428 + NS_ASSERTION(xuldoc != nullptr, "not a xul document"); 1.429 + if (! xuldoc) 1.430 + return NS_ERROR_UNEXPECTED; 1.431 + 1.432 + nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher; 1.433 + rv = xuldoc->GetCommandDispatcher(getter_AddRefs(dispatcher)); 1.434 + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get dispatcher"); 1.435 + if (NS_FAILED(rv)) return rv; 1.436 + 1.437 + NS_ASSERTION(dispatcher != nullptr, "no dispatcher"); 1.438 + if (! dispatcher) 1.439 + return NS_ERROR_UNEXPECTED; 1.440 + 1.441 + nsAutoString events; 1.442 + aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::events, events); 1.443 + if (events.IsEmpty()) 1.444 + events.AssignLiteral("*"); 1.445 + 1.446 + nsAutoString targets; 1.447 + aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::targets, targets); 1.448 + 1.449 + if (targets.IsEmpty()) 1.450 + targets.AssignLiteral("*"); 1.451 + 1.452 + nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(aElement); 1.453 + NS_ASSERTION(domelement != nullptr, "not a DOM element"); 1.454 + if (! domelement) 1.455 + return NS_ERROR_UNEXPECTED; 1.456 + 1.457 + rv = dispatcher->AddCommandUpdater(domelement, events, targets); 1.458 + if (NS_FAILED(rv)) return rv; 1.459 + 1.460 + return NS_OK; 1.461 +} 1.462 + 1.463 +void 1.464 +nsXULContentUtils::LogTemplateError(const char* aStr) 1.465 +{ 1.466 + nsAutoString message; 1.467 + message.AssignLiteral("Error parsing template: "); 1.468 + message.Append(NS_ConvertUTF8toUTF16(aStr).get()); 1.469 + 1.470 + nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID); 1.471 + if (cs) { 1.472 + cs->LogStringMessage(message.get()); 1.473 + PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS, ("Error parsing template: %s", aStr)); 1.474 + } 1.475 +}