Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / rdf / base / src / nsRDFContainer.cpp
blobd2f89af315cb9526ed95acfe98ed7f58d48e7860
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
41 Implementation for the RDF container.
43 Notes
44 -----
46 1. RDF containers are one-indexed. This means that a lot of the loops
47 that you'd normally think you'd write like this:
49 for (i = 0; i < count; ++i) {}
51 You've gotta write like this:
53 for (i = 1; i <= count; ++i) {}
55 "Sure, right, yeah, of course.", you say. Well maybe I'm just
56 thick, but it's easy to slip up.
58 2. The RDF:nextVal property on the container is an
59 implementation-level hack that is used to quickly compute the
60 next value for appending to the container. It will no doubt
61 become royally screwed up in the case of aggregation.
63 3. The RDF:nextVal property is also used to retrieve the count of
64 elements in the container.
69 #include "nsCOMPtr.h"
70 #include "nsIRDFContainer.h"
71 #include "nsIRDFContainerUtils.h"
72 #include "nsIRDFInMemoryDataSource.h"
73 #include "nsIRDFPropagatableDataSource.h"
74 #include "nsIRDFService.h"
75 #include "nsIServiceManager.h"
76 #include "nsRDFCID.h"
77 #include "nsString.h"
78 #include "nsXPIDLString.h"
79 #include "rdf.h"
81 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
82 static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
83 static const char kRDFNameSpaceURI[] = RDF_NAMESPACE_URI;
85 #define RDF_SEQ_LIST_LIMIT 8
87 class RDFContainerImpl : public nsIRDFContainer
89 public:
91 // nsISupports interface
92 NS_DECL_ISUPPORTS
94 // nsIRDFContainer interface
95 NS_DECL_NSIRDFCONTAINER
97 private:
98 friend nsresult NS_NewRDFContainer(nsIRDFContainer** aResult);
100 RDFContainerImpl();
101 virtual ~RDFContainerImpl();
103 nsresult Init();
105 nsresult Renumber(PRInt32 aStartIndex, PRInt32 aIncrement);
106 nsresult SetNextValue(PRInt32 aIndex);
107 nsresult GetNextValue(nsIRDFResource** aResult);
109 nsIRDFDataSource* mDataSource;
110 nsIRDFResource* mContainer;
112 // pseudo constants
113 static PRInt32 gRefCnt;
114 static nsIRDFService* gRDFService;
115 static nsIRDFContainerUtils* gRDFContainerUtils;
116 static nsIRDFResource* kRDF_nextVal;
120 PRInt32 RDFContainerImpl::gRefCnt = 0;
121 nsIRDFService* RDFContainerImpl::gRDFService;
122 nsIRDFContainerUtils* RDFContainerImpl::gRDFContainerUtils;
123 nsIRDFResource* RDFContainerImpl::kRDF_nextVal;
125 ////////////////////////////////////////////////////////////////////////
126 // nsISupports interface
128 NS_IMPL_ISUPPORTS1(RDFContainerImpl, nsIRDFContainer)
132 ////////////////////////////////////////////////////////////////////////
133 // nsIRDFContainer interface
135 NS_IMETHODIMP
136 RDFContainerImpl::GetDataSource(nsIRDFDataSource** _retval)
138 *_retval = mDataSource;
139 NS_IF_ADDREF(*_retval);
140 return NS_OK;
144 NS_IMETHODIMP
145 RDFContainerImpl::GetResource(nsIRDFResource** _retval)
147 *_retval = mContainer;
148 NS_IF_ADDREF(*_retval);
149 return NS_OK;
153 NS_IMETHODIMP
154 RDFContainerImpl::Init(nsIRDFDataSource *aDataSource, nsIRDFResource *aContainer)
156 NS_PRECONDITION(aDataSource != nsnull, "null ptr");
157 if (! aDataSource)
158 return NS_ERROR_NULL_POINTER;
160 NS_PRECONDITION(aContainer != nsnull, "null ptr");
161 if (! aContainer)
162 return NS_ERROR_NULL_POINTER;
164 nsresult rv;
165 PRBool isContainer;
166 rv = gRDFContainerUtils->IsContainer(aDataSource, aContainer, &isContainer);
167 if (NS_FAILED(rv)) return rv;
169 // ``throw'' if we can't create a container on the specified
170 // datasource/resource combination.
171 if (! isContainer)
172 return NS_ERROR_FAILURE;
174 NS_IF_RELEASE(mDataSource);
175 mDataSource = aDataSource;
176 NS_ADDREF(mDataSource);
178 NS_IF_RELEASE(mContainer);
179 mContainer = aContainer;
180 NS_ADDREF(mContainer);
182 return NS_OK;
186 NS_IMETHODIMP
187 RDFContainerImpl::GetCount(PRInt32 *aCount)
189 if (!mDataSource || !mContainer)
190 return NS_ERROR_NOT_INITIALIZED;
192 nsresult rv;
194 // Get the next value, which hangs off of the bag via the
195 // RDF:nextVal property. This is the _next value_ that will get
196 // assigned in a one-indexed array. So, it's actually _one more_
197 // than the actual count of elements in the container.
199 // XXX To handle aggregation, this should probably be a
200 // GetTargets() that enumerates all of the values and picks the
201 // largest one.
202 nsCOMPtr<nsIRDFNode> nextValNode;
203 rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, PR_TRUE, getter_AddRefs(nextValNode));
204 if (NS_FAILED(rv)) return rv;
206 if (rv == NS_RDF_NO_VALUE)
207 return NS_ERROR_UNEXPECTED;
209 nsCOMPtr<nsIRDFLiteral> nextValLiteral;
210 rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
211 if (NS_FAILED(rv)) return rv;
213 const PRUnichar *s;
214 rv = nextValLiteral->GetValueConst( &s );
215 if (NS_FAILED(rv)) return rv;
217 nsAutoString nextValStr(s);
219 PRInt32 nextVal;
220 PRInt32 err;
221 nextVal = nextValStr.ToInteger(&err);
222 if (NS_FAILED(err))
223 return NS_ERROR_UNEXPECTED;
225 *aCount = nextVal - 1;
226 return NS_OK;
230 NS_IMETHODIMP
231 RDFContainerImpl::GetElements(nsISimpleEnumerator **_retval)
233 if (!mDataSource || !mContainer)
234 return NS_ERROR_NOT_INITIALIZED;
236 return NS_NewContainerEnumerator(mDataSource, mContainer, _retval);
240 NS_IMETHODIMP
241 RDFContainerImpl::AppendElement(nsIRDFNode *aElement)
243 if (!mDataSource || !mContainer)
244 return NS_ERROR_NOT_INITIALIZED;
246 NS_PRECONDITION(aElement != nsnull, "null ptr");
247 if (! aElement)
248 return NS_ERROR_NULL_POINTER;
250 nsresult rv;
252 nsCOMPtr<nsIRDFResource> nextVal;
253 rv = GetNextValue(getter_AddRefs(nextVal));
254 if (NS_FAILED(rv)) return rv;
256 rv = mDataSource->Assert(mContainer, nextVal, aElement, PR_TRUE);
257 if (NS_FAILED(rv)) return rv;
259 return NS_OK;
263 NS_IMETHODIMP
264 RDFContainerImpl::RemoveElement(nsIRDFNode *aElement, PRBool aRenumber)
266 if (!mDataSource || !mContainer)
267 return NS_ERROR_NOT_INITIALIZED;
269 NS_PRECONDITION(aElement != nsnull, "null ptr");
270 if (! aElement)
271 return NS_ERROR_NULL_POINTER;
273 nsresult rv;
275 PRInt32 idx;
276 rv = IndexOf(aElement, &idx);
277 if (NS_FAILED(rv)) return rv;
279 if (idx < 0)
280 return NS_OK;
282 // Remove the element.
283 nsCOMPtr<nsIRDFResource> ordinal;
284 rv = gRDFContainerUtils->IndexToOrdinalResource(idx,
285 getter_AddRefs(ordinal));
286 if (NS_FAILED(rv)) return rv;
288 rv = mDataSource->Unassert(mContainer, ordinal, aElement);
289 if (NS_FAILED(rv)) return rv;
291 if (aRenumber) {
292 // Now slide the rest of the collection backwards to fill in
293 // the gap. This will have the side effect of completely
294 // renumber the container from index to the end.
295 rv = Renumber(idx + 1, -1);
296 if (NS_FAILED(rv)) return rv;
299 return NS_OK;
303 NS_IMETHODIMP
304 RDFContainerImpl::InsertElementAt(nsIRDFNode *aElement, PRInt32 aIndex, PRBool aRenumber)
306 if (!mDataSource || !mContainer)
307 return NS_ERROR_NOT_INITIALIZED;
309 NS_PRECONDITION(aElement != nsnull, "null ptr");
310 if (! aElement)
311 return NS_ERROR_NULL_POINTER;
313 NS_PRECONDITION(aIndex >= 1, "illegal value");
314 if (aIndex < 1)
315 return NS_ERROR_ILLEGAL_VALUE;
317 nsresult rv;
319 PRInt32 count;
320 rv = GetCount(&count);
321 if (NS_FAILED(rv)) return rv;
323 NS_ASSERTION(aIndex <= count + 1, "illegal value");
324 if (aIndex > count + 1)
325 return NS_ERROR_ILLEGAL_VALUE;
327 if (aRenumber) {
328 // Make a hole for the element. This will have the side effect of
329 // completely renumbering the container from 'aIndex' to 'count',
330 // and will spew assertions.
331 rv = Renumber(aIndex, +1);
332 if (NS_FAILED(rv)) return rv;
335 nsCOMPtr<nsIRDFResource> ordinal;
336 rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal));
337 if (NS_FAILED(rv)) return rv;
339 rv = mDataSource->Assert(mContainer, ordinal, aElement, PR_TRUE);
340 if (NS_FAILED(rv)) return rv;
342 return NS_OK;
345 NS_IMETHODIMP
346 RDFContainerImpl::RemoveElementAt(PRInt32 aIndex, PRBool aRenumber, nsIRDFNode** _retval)
348 if (!mDataSource || !mContainer)
349 return NS_ERROR_NOT_INITIALIZED;
351 *_retval = nsnull;
353 if (aIndex< 1)
354 return NS_ERROR_ILLEGAL_VALUE;
356 nsresult rv;
358 PRInt32 count;
359 rv = GetCount(&count);
360 if (NS_FAILED(rv)) return rv;
362 if (aIndex > count)
363 return NS_ERROR_ILLEGAL_VALUE;
365 nsCOMPtr<nsIRDFResource> ordinal;
366 rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal));
367 if (NS_FAILED(rv)) return rv;
369 nsCOMPtr<nsIRDFNode> old;
370 rv = mDataSource->GetTarget(mContainer, ordinal, PR_TRUE, getter_AddRefs(old));
371 if (NS_FAILED(rv)) return rv;
373 if (rv == NS_OK) {
374 rv = mDataSource->Unassert(mContainer, ordinal, old);
375 if (NS_FAILED(rv)) return rv;
377 if (aRenumber) {
378 // Now slide the rest of the collection backwards to fill in
379 // the gap. This will have the side effect of completely
380 // renumber the container from index to the end.
381 rv = Renumber(aIndex + 1, -1);
382 if (NS_FAILED(rv)) return rv;
386 old.swap(*_retval);
388 return NS_OK;
391 NS_IMETHODIMP
392 RDFContainerImpl::IndexOf(nsIRDFNode *aElement, PRInt32 *aIndex)
394 if (!mDataSource || !mContainer)
395 return NS_ERROR_NOT_INITIALIZED;
397 return gRDFContainerUtils->IndexOf(mDataSource, mContainer,
398 aElement, aIndex);
402 ////////////////////////////////////////////////////////////////////////
405 RDFContainerImpl::RDFContainerImpl()
406 : mDataSource(nsnull), mContainer(nsnull)
411 nsresult
412 RDFContainerImpl::Init()
414 if (gRefCnt++ == 0) {
415 nsresult rv;
417 rv = CallGetService(kRDFServiceCID, &gRDFService);
418 if (NS_FAILED(rv)) {
419 NS_ERROR("unable to get RDF service");
420 return rv;
423 rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
424 &kRDF_nextVal);
425 if (NS_FAILED(rv)) return rv;
427 rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils);
428 if (NS_FAILED(rv)) {
429 NS_ERROR("unable to get RDF container utils service");
430 return rv;
434 return NS_OK;
438 RDFContainerImpl::~RDFContainerImpl()
440 #ifdef DEBUG_REFS
441 --gInstanceCount;
442 fprintf(stdout, "%d - RDF: RDFContainerImpl\n", gInstanceCount);
443 #endif
445 NS_IF_RELEASE(mContainer);
446 NS_IF_RELEASE(mDataSource);
448 if (--gRefCnt == 0) {
449 NS_IF_RELEASE(gRDFContainerUtils);
450 NS_IF_RELEASE(gRDFService);
451 NS_IF_RELEASE(kRDF_nextVal);
456 nsresult
457 NS_NewRDFContainer(nsIRDFContainer** aResult)
459 RDFContainerImpl* result = new RDFContainerImpl();
460 if (! result)
461 return NS_ERROR_OUT_OF_MEMORY;
463 nsresult rv;
464 rv = result->Init();
465 if (NS_FAILED(rv)) {
466 delete result;
467 return rv;
470 NS_ADDREF(result);
471 *aResult = result;
472 return NS_OK;
476 nsresult
477 NS_NewRDFContainer(nsIRDFDataSource* aDataSource,
478 nsIRDFResource* aResource,
479 nsIRDFContainer** aResult)
481 nsresult rv;
482 rv = NS_NewRDFContainer(aResult);
483 if (NS_FAILED(rv)) return rv;
485 rv = (*aResult)->Init(aDataSource, aResource);
486 if (NS_FAILED(rv)) {
487 NS_RELEASE(*aResult);
489 return rv;
493 nsresult
494 RDFContainerImpl::Renumber(PRInt32 aStartIndex, PRInt32 aIncrement)
496 if (!mDataSource || !mContainer)
497 return NS_ERROR_NOT_INITIALIZED;
499 // Renumber the elements in the container starting with
500 // aStartIndex, updating each element's index by aIncrement. For
501 // example,
503 // (1:a 2:b 3:c)
504 // Renumber(2, +1);
505 // (1:a 3:b 4:c)
506 // Renumber(3, -1);
507 // (1:a 2:b 3:c)
509 nsresult rv;
511 if (! aIncrement)
512 return NS_OK;
514 PRInt32 count;
515 rv = GetCount(&count);
516 if (NS_FAILED(rv)) return rv;
518 if (aIncrement > 0) {
519 // Update the container's nextVal to reflect the
520 // renumbering. We do this now if aIncrement > 0 because we'll
521 // want to be able to acknowledge that new elements are in the
522 // container.
523 rv = SetNextValue(count + aIncrement + 1);
524 if (NS_FAILED(rv)) return rv;
527 PRInt32 i;
528 if (aIncrement < 0) {
529 i = aStartIndex;
531 else {
532 i = count; // we're one-indexed.
535 // Note: once we disable notifications, don't exit this method until
536 // enabling notifications
537 nsCOMPtr<nsIRDFPropagatableDataSource> propagatable =
538 do_QueryInterface(mDataSource);
539 if (propagatable) {
540 propagatable->SetPropagateChanges(PR_FALSE);
543 PRBool err = PR_FALSE;
544 while ((err == PR_FALSE) && ((aIncrement < 0) ? (i <= count) : (i >= aStartIndex)))
546 nsCOMPtr<nsIRDFResource> oldOrdinal;
547 rv = gRDFContainerUtils->IndexToOrdinalResource(i, getter_AddRefs(oldOrdinal));
548 if (NS_FAILED(rv))
550 err = PR_TRUE;
551 continue;
554 nsCOMPtr<nsIRDFResource> newOrdinal;
555 rv = gRDFContainerUtils->IndexToOrdinalResource(i + aIncrement, getter_AddRefs(newOrdinal));
556 if (NS_FAILED(rv))
558 err = PR_TRUE;
559 continue;
562 // Because of aggregation, we need to be paranoid about the
563 // possibility that >1 element may be present per ordinal. If
564 // there _is_ in fact more than one element, they'll all get
565 // assigned to the same new ordinal; i.e., we don't make any
566 // attempt to "clean up" the duplicate numbering. (Doing so
567 // would require two passes.)
568 nsCOMPtr<nsISimpleEnumerator> targets;
569 rv = mDataSource->GetTargets(mContainer, oldOrdinal, PR_TRUE, getter_AddRefs(targets));
570 if (NS_FAILED(rv))
572 err = PR_TRUE;
573 continue;
576 while (1) {
577 PRBool hasMore;
578 rv = targets->HasMoreElements(&hasMore);
579 if (NS_FAILED(rv))
581 err = PR_TRUE;
582 break;
585 if (! hasMore)
586 break;
588 nsCOMPtr<nsISupports> isupports;
589 rv = targets->GetNext(getter_AddRefs(isupports));
590 if (NS_FAILED(rv))
592 err = PR_TRUE;
593 break;
596 nsCOMPtr<nsIRDFNode> element( do_QueryInterface(isupports) );
597 NS_ASSERTION(element != nsnull, "something funky in the enumerator");
598 if (! element)
600 err = PR_TRUE;
601 rv = NS_ERROR_UNEXPECTED;
602 break;
605 rv = mDataSource->Unassert(mContainer, oldOrdinal, element);
606 if (NS_FAILED(rv))
608 err = PR_TRUE;
609 break;
612 rv = mDataSource->Assert(mContainer, newOrdinal, element, PR_TRUE);
613 if (NS_FAILED(rv))
615 err = PR_TRUE;
616 break;
620 i -= aIncrement;
623 if ((err == PR_FALSE) && (aIncrement < 0))
625 // Update the container's nextVal to reflect the
626 // renumbering. We do this now if aIncrement < 0 because, up
627 // until this point, we'll want people to be able to find
628 // things that are still "at the end".
629 rv = SetNextValue(count + aIncrement + 1);
630 if (NS_FAILED(rv))
632 err = PR_TRUE;
636 // Note: MUST enable notifications before exiting this method
637 if (propagatable) {
638 propagatable->SetPropagateChanges(PR_TRUE);
641 if (err == PR_TRUE) return(rv);
643 return NS_OK;
648 nsresult
649 RDFContainerImpl::SetNextValue(PRInt32 aIndex)
651 if (!mDataSource || !mContainer)
652 return NS_ERROR_NOT_INITIALIZED;
654 nsresult rv;
656 // Remove the current value of nextVal, if there is one.
657 nsCOMPtr<nsIRDFNode> nextValNode;
658 if (NS_SUCCEEDED(rv = mDataSource->GetTarget(mContainer,
659 kRDF_nextVal,
660 PR_TRUE,
661 getter_AddRefs(nextValNode)))) {
662 if (NS_FAILED(rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValNode))) {
663 NS_ERROR("unable to update nextVal");
664 return rv;
668 nsAutoString s;
669 s.AppendInt(aIndex, 10);
671 nsCOMPtr<nsIRDFLiteral> nextVal;
672 if (NS_FAILED(rv = gRDFService->GetLiteral(s.get(), getter_AddRefs(nextVal)))) {
673 NS_ERROR("unable to get nextVal literal");
674 return rv;
677 rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextVal, PR_TRUE);
678 if (rv != NS_RDF_ASSERTION_ACCEPTED) {
679 NS_ERROR("unable to update nextVal");
680 return NS_ERROR_FAILURE;
683 return NS_OK;
687 nsresult
688 RDFContainerImpl::GetNextValue(nsIRDFResource** aResult)
690 if (!mDataSource || !mContainer)
691 return NS_ERROR_NOT_INITIALIZED;
693 nsresult rv;
695 // Get the next value, which hangs off of the bag via the
696 // RDF:nextVal property.
697 nsCOMPtr<nsIRDFNode> nextValNode;
698 rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, PR_TRUE, getter_AddRefs(nextValNode));
699 if (NS_FAILED(rv)) return rv;
701 if (rv == NS_RDF_NO_VALUE)
702 return NS_ERROR_UNEXPECTED;
704 nsCOMPtr<nsIRDFLiteral> nextValLiteral;
705 rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
706 if (NS_FAILED(rv)) return rv;
708 const PRUnichar* s;
709 rv = nextValLiteral->GetValueConst(&s);
710 if (NS_FAILED(rv)) return rv;
712 PRInt32 nextVal = 0;
714 for (const PRUnichar* p = s; *p != 0; ++p) {
715 NS_ASSERTION(*p >= '0' && *p <= '9', "not a digit");
716 if (*p < '0' || *p > '9')
717 break;
719 nextVal *= 10;
720 nextVal += *p - '0';
724 char buf[sizeof(kRDFNameSpaceURI) + 16];
725 nsFixedCString nextValStr(buf, sizeof(buf), 0);
726 nextValStr = kRDFNameSpaceURI;
727 nextValStr.Append("_");
728 nextValStr.AppendInt(nextVal, 10);
730 rv = gRDFService->GetResource(nextValStr, aResult);
731 if (NS_FAILED(rv)) return rv;
733 // Now increment the RDF:nextVal property.
734 rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValLiteral);
735 if (NS_FAILED(rv)) return rv;
737 ++nextVal;
738 nextValStr.Truncate();
739 nextValStr.AppendInt(nextVal, 10);
741 rv = gRDFService->GetLiteral(NS_ConvertASCIItoUTF16(nextValStr).get(), getter_AddRefs(nextValLiteral));
742 if (NS_FAILED(rv)) return rv;
744 rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextValLiteral, PR_TRUE);
745 if (NS_FAILED(rv)) return rv;
747 if (RDF_SEQ_LIST_LIMIT == nextVal)
749 // focal point for RDF container mutation;
750 // basically, provide a hint to allow for fast access
751 nsCOMPtr<nsIRDFInMemoryDataSource> inMem = do_QueryInterface(mDataSource);
752 if (inMem)
754 // ignore error; failure just means slower access
755 (void)inMem->EnsureFastContainment(mContainer);
759 return NS_OK;