Follow-on fix for bug 457825. Use sheet principal for agent and user sheets. r=dbaron...
[wine-gecko.git] / content / html / document / src / nsMediaDocument.cpp
blobb61a46c3edf498e898c71cc9b027ff4178cd0493
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 * Jungshik Shin <jshin@mailaps.org>
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 ***** */
39 #include "nsMediaDocument.h"
40 #include "nsGkAtoms.h"
41 #include "nsRect.h"
42 #include "nsPresContext.h"
43 #include "nsIPresShell.h"
44 #include "nsIScrollable.h"
45 #include "nsIViewManager.h"
46 #include "nsITextToSubURI.h"
47 #include "nsIURL.h"
48 #include "nsPrintfCString.h"
49 #include "nsIContentViewer.h"
50 #include "nsIMarkupDocumentViewer.h"
51 #include "nsIDocShell.h"
52 #include "nsIParser.h" // kCharsetFrom* macro definition
53 #include "nsIDocumentCharsetInfo.h"
54 #include "nsNodeInfoManager.h"
56 nsMediaDocumentStreamListener::nsMediaDocumentStreamListener(nsMediaDocument *aDocument)
58 mDocument = aDocument;
61 nsMediaDocumentStreamListener::~nsMediaDocumentStreamListener()
66 NS_IMPL_THREADSAFE_ISUPPORTS2(nsMediaDocumentStreamListener,
67 nsIRequestObserver,
68 nsIStreamListener)
71 void
72 nsMediaDocumentStreamListener::SetStreamListener(nsIStreamListener *aListener)
74 mNextStream = aListener;
77 NS_IMETHODIMP
78 nsMediaDocumentStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
80 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
82 mDocument->StartLayout();
84 if (mNextStream) {
85 return mNextStream->OnStartRequest(request, ctxt);
88 return NS_OK;
91 NS_IMETHODIMP
92 nsMediaDocumentStreamListener::OnStopRequest(nsIRequest* request,
93 nsISupports *ctxt,
94 nsresult status)
96 nsresult rv = NS_OK;
97 if (mNextStream) {
98 rv = mNextStream->OnStopRequest(request, ctxt, status);
101 // No more need for our document so clear our reference and prevent leaks
102 mDocument = nsnull;
104 return rv;
107 NS_IMETHODIMP
108 nsMediaDocumentStreamListener::OnDataAvailable(nsIRequest* request,
109 nsISupports *ctxt,
110 nsIInputStream *inStr,
111 PRUint32 sourceOffset,
112 PRUint32 count)
114 if (mNextStream) {
115 return mNextStream->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
118 return NS_OK;
121 // default format names for nsMediaDocument.
122 const char* const nsMediaDocument::sFormatNames[4] =
124 "MediaTitleWithNoInfo", // eWithNoInfo
125 "MediaTitleWithFile", // eWithFile
126 "", // eWithDim
127 "" // eWithDimAndFile
130 nsMediaDocument::nsMediaDocument()
133 nsMediaDocument::~nsMediaDocument()
137 nsresult
138 nsMediaDocument::Init()
140 nsresult rv = nsHTMLDocument::Init();
141 NS_ENSURE_SUCCESS(rv, rv);
143 // Create a bundle for the localization
144 nsCOMPtr<nsIStringBundleService> stringService(
145 do_GetService(NS_STRINGBUNDLE_CONTRACTID));
146 if (stringService) {
147 stringService->CreateBundle(NSMEDIADOCUMENT_PROPERTIES_URI,
148 getter_AddRefs(mStringBundle));
151 return NS_OK;
154 nsresult
155 nsMediaDocument::StartDocumentLoad(const char* aCommand,
156 nsIChannel* aChannel,
157 nsILoadGroup* aLoadGroup,
158 nsISupports* aContainer,
159 nsIStreamListener** aDocListener,
160 PRBool aReset,
161 nsIContentSink* aSink)
163 nsresult rv = nsDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup,
164 aContainer, aDocListener, aReset,
165 aSink);
166 if (NS_FAILED(rv)) {
167 return rv;
170 // We try to set the charset of the current document to that of the
171 // 'genuine' (as opposed to an intervening 'chrome') parent document
172 // that may be in a different window/tab. Even if we fail here,
173 // we just return NS_OK because another attempt is made in
174 // |UpdateTitleAndCharset| and the worst thing possible is a mangled
175 // filename in the titlebar and the file picker.
177 // When this document is opened in the window/tab of the referring
178 // document (by a simple link-clicking), |prevDocCharacterSet| contains
179 // the charset of the referring document. On the other hand, if the
180 // document is opened in a new window, it is |defaultCharacterSet| of |muCV|
181 // where the charset of our interest is stored. In case of openining
182 // in a new tab, we get the charset from |documentCharsetInfo|. Note that we
183 // exclude UTF-8 as 'invalid' because UTF-8 is likely to be the charset
184 // of a chrome document that has nothing to do with the actual content
185 // whose charset we want to know. Even if "the actual content" is indeed
186 // in UTF-8, we don't lose anything because the default empty value is
187 // considered synonymous with UTF-8.
189 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aContainer));
191 // not being able to set the charset is not critical.
192 NS_ENSURE_TRUE(docShell, NS_OK);
194 nsCOMPtr<nsIDocumentCharsetInfo> dcInfo;
195 nsCAutoString charset;
197 docShell->GetDocumentCharsetInfo(getter_AddRefs(dcInfo));
198 if (dcInfo) {
199 nsCOMPtr<nsIAtom> csAtom;
200 dcInfo->GetParentCharset(getter_AddRefs(csAtom));
201 if (csAtom) { // opening in a new tab
202 csAtom->ToUTF8String(charset);
206 if (charset.IsEmpty() || charset.Equals("UTF-8")) {
207 nsCOMPtr<nsIContentViewer> cv;
208 docShell->GetContentViewer(getter_AddRefs(cv));
210 // not being able to set the charset is not critical.
211 NS_ENSURE_TRUE(cv, NS_OK);
212 nsCOMPtr<nsIMarkupDocumentViewer> muCV = do_QueryInterface(cv);
213 if (muCV) {
214 muCV->GetPrevDocCharacterSet(charset); // opening in the same window/tab
215 if (charset.Equals("UTF-8") || charset.IsEmpty()) {
216 muCV->GetDefaultCharacterSet(charset); // opening in a new window
221 if (!charset.IsEmpty() && !charset.Equals("UTF-8")) {
222 SetDocumentCharacterSet(charset);
223 mCharacterSetSource = kCharsetFromUserDefault;
226 return NS_OK;
229 nsresult
230 nsMediaDocument::CreateSyntheticDocument()
232 // Synthesize an empty html document
233 nsresult rv;
235 nsCOMPtr<nsINodeInfo> nodeInfo;
236 nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::html, nsnull,
237 kNameSpaceID_None);
238 NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
240 nsRefPtr<nsGenericHTMLElement> root = NS_NewHTMLHtmlElement(nodeInfo);
241 if (!root) {
242 return NS_ERROR_OUT_OF_MEMORY;
245 NS_ASSERTION(GetChildCount() == 0, "Shouldn't have any kids");
246 rv = AppendChildTo(root, PR_FALSE);
247 NS_ENSURE_SUCCESS(rv, rv);
249 nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::head, nsnull,
250 kNameSpaceID_None);
251 NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
253 // Create a <head> so our title has somewhere to live
254 nsRefPtr<nsGenericHTMLElement> head = NS_NewHTMLHeadElement(nodeInfo);
255 if (!head) {
256 return NS_ERROR_OUT_OF_MEMORY;
259 root->AppendChildTo(head, PR_FALSE);
261 nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::body, nsnull,
262 kNameSpaceID_None);
263 NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
265 nsRefPtr<nsGenericHTMLElement> body = NS_NewHTMLBodyElement(nodeInfo);
266 if (!body) {
267 return NS_ERROR_OUT_OF_MEMORY;
270 root->AppendChildTo(body, PR_FALSE);
272 return NS_OK;
275 nsresult
276 nsMediaDocument::StartLayout()
278 mMayStartLayout = PR_TRUE;
279 nsPresShellIterator iter(this);
280 nsCOMPtr<nsIPresShell> shell;
281 while ((shell = iter.GetNextShell())) {
282 PRBool didInitialReflow = PR_FALSE;
283 shell->GetDidInitialReflow(&didInitialReflow);
284 if (didInitialReflow) {
285 // Don't mess with this presshell: someone has already handled
286 // its initial reflow.
287 continue;
290 nsRect visibleArea = shell->GetPresContext()->GetVisibleArea();
291 nsresult rv = shell->InitialReflow(visibleArea.width, visibleArea.height);
292 NS_ENSURE_SUCCESS(rv, rv);
294 // Now trigger a refresh. vm might be null if the presshell got
295 // Destroy() called already.
296 nsIViewManager* vm = shell->GetViewManager();
297 if (vm) {
298 vm->EnableRefresh(NS_VMREFRESH_IMMEDIATE);
302 return NS_OK;
305 void
306 nsMediaDocument::UpdateTitleAndCharset(const nsACString& aTypeStr,
307 const char* const* aFormatNames,
308 PRInt32 aWidth, PRInt32 aHeight,
309 const nsAString& aStatus)
311 nsXPIDLString fileStr;
312 if (mDocumentURI) {
313 nsCAutoString fileName;
314 nsCOMPtr<nsIURL> url = do_QueryInterface(mDocumentURI);
315 if (url)
316 url->GetFileName(fileName);
318 nsCAutoString docCharset;
320 // Now that the charset is set in |StartDocumentLoad| to the charset of
321 // the document viewer instead of a bogus value ("ISO-8859-1" set in
322 // |nsDocument|'s ctor), the priority is given to the current charset.
323 // This is necessary to deal with a media document being opened in a new
324 // window or a new tab, in which case |originCharset| of |nsIURI| is not
325 // reliable.
326 if (mCharacterSetSource != kCharsetUninitialized) {
327 docCharset = mCharacterSet;
329 else {
330 // resort to |originCharset|
331 mDocumentURI->GetOriginCharset(docCharset);
332 SetDocumentCharacterSet(docCharset);
334 if (!fileName.IsEmpty()) {
335 nsresult rv;
336 nsCOMPtr<nsITextToSubURI> textToSubURI =
337 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
338 if (NS_SUCCEEDED(rv))
339 // UnEscapeURIForUI always succeeds
340 textToSubURI->UnEscapeURIForUI(docCharset, fileName, fileStr);
341 else
342 CopyUTF8toUTF16(fileName, fileStr);
347 NS_ConvertASCIItoUTF16 typeStr(aTypeStr);
348 nsXPIDLString title;
350 if (mStringBundle) {
351 // if we got a valid size (not all media have a size)
352 if (aWidth != 0 && aHeight != 0) {
353 nsAutoString widthStr;
354 nsAutoString heightStr;
355 widthStr.AppendInt(aWidth);
356 heightStr.AppendInt(aHeight);
357 // If we got a filename, display it
358 if (!fileStr.IsEmpty()) {
359 const PRUnichar *formatStrings[4] = {fileStr.get(), typeStr.get(),
360 widthStr.get(), heightStr.get()};
361 NS_ConvertASCIItoUTF16 fmtName(aFormatNames[eWithDimAndFile]);
362 mStringBundle->FormatStringFromName(fmtName.get(), formatStrings, 4,
363 getter_Copies(title));
365 else {
366 const PRUnichar *formatStrings[3] = {typeStr.get(), widthStr.get(),
367 heightStr.get()};
368 NS_ConvertASCIItoUTF16 fmtName(aFormatNames[eWithDim]);
369 mStringBundle->FormatStringFromName(fmtName.get(), formatStrings, 3,
370 getter_Copies(title));
373 else {
374 // If we got a filename, display it
375 if (!fileStr.IsEmpty()) {
376 const PRUnichar *formatStrings[2] = {fileStr.get(), typeStr.get()};
377 NS_ConvertASCIItoUTF16 fmtName(aFormatNames[eWithFile]);
378 mStringBundle->FormatStringFromName(fmtName.get(), formatStrings, 2,
379 getter_Copies(title));
381 else {
382 const PRUnichar *formatStrings[1] = {typeStr.get()};
383 NS_ConvertASCIItoUTF16 fmtName(aFormatNames[eWithNoInfo]);
384 mStringBundle->FormatStringFromName(fmtName.get(), formatStrings, 1,
385 getter_Copies(title));
390 // set it on the document
391 if (aStatus.IsEmpty()) {
392 SetTitle(title);
394 else {
395 nsXPIDLString titleWithStatus;
396 const nsPromiseFlatString& status = PromiseFlatString(aStatus);
397 const PRUnichar *formatStrings[2] = {title.get(), status.get()};
398 NS_NAMED_LITERAL_STRING(fmtName, "TitleWithStatus");
399 mStringBundle->FormatStringFromName(fmtName.get(), formatStrings, 2,
400 getter_Copies(titleWithStatus));
401 SetTitle(titleWithStatus);