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
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.
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"
42 #include "nsPresContext.h"
43 #include "nsIPresShell.h"
44 #include "nsIScrollable.h"
45 #include "nsIViewManager.h"
46 #include "nsITextToSubURI.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
,
72 nsMediaDocumentStreamListener::SetStreamListener(nsIStreamListener
*aListener
)
74 mNextStream
= aListener
;
78 nsMediaDocumentStreamListener::OnStartRequest(nsIRequest
* request
, nsISupports
*ctxt
)
80 NS_ENSURE_TRUE(mDocument
, NS_ERROR_FAILURE
);
82 mDocument
->StartLayout();
85 return mNextStream
->OnStartRequest(request
, ctxt
);
92 nsMediaDocumentStreamListener::OnStopRequest(nsIRequest
* request
,
98 rv
= mNextStream
->OnStopRequest(request
, ctxt
, status
);
101 // No more need for our document so clear our reference and prevent leaks
108 nsMediaDocumentStreamListener::OnDataAvailable(nsIRequest
* request
,
110 nsIInputStream
*inStr
,
111 PRUint32 sourceOffset
,
115 return mNextStream
->OnDataAvailable(request
, ctxt
, inStr
, sourceOffset
, count
);
121 // default format names for nsMediaDocument.
122 const char* const nsMediaDocument::sFormatNames
[4] =
124 "MediaTitleWithNoInfo", // eWithNoInfo
125 "MediaTitleWithFile", // eWithFile
127 "" // eWithDimAndFile
130 nsMediaDocument::nsMediaDocument()
133 nsMediaDocument::~nsMediaDocument()
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
));
147 stringService
->CreateBundle(NSMEDIADOCUMENT_PROPERTIES_URI
,
148 getter_AddRefs(mStringBundle
));
155 nsMediaDocument::StartDocumentLoad(const char* aCommand
,
156 nsIChannel
* aChannel
,
157 nsILoadGroup
* aLoadGroup
,
158 nsISupports
* aContainer
,
159 nsIStreamListener
** aDocListener
,
161 nsIContentSink
* aSink
)
163 nsresult rv
= nsDocument::StartDocumentLoad(aCommand
, aChannel
, aLoadGroup
,
164 aContainer
, aDocListener
, aReset
,
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
));
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
);
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
;
230 nsMediaDocument::CreateSyntheticDocument()
232 // Synthesize an empty html document
235 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
236 nodeInfo
= mNodeInfoManager
->GetNodeInfo(nsGkAtoms::html
, nsnull
,
238 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
240 nsRefPtr
<nsGenericHTMLElement
> root
= NS_NewHTMLHtmlElement(nodeInfo
);
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
,
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
);
256 return NS_ERROR_OUT_OF_MEMORY
;
259 root
->AppendChildTo(head
, PR_FALSE
);
261 nodeInfo
= mNodeInfoManager
->GetNodeInfo(nsGkAtoms::body
, nsnull
,
263 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
265 nsRefPtr
<nsGenericHTMLElement
> body
= NS_NewHTMLBodyElement(nodeInfo
);
267 return NS_ERROR_OUT_OF_MEMORY
;
270 root
->AppendChildTo(body
, PR_FALSE
);
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.
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();
298 vm
->EnableRefresh(NS_VMREFRESH_IMMEDIATE
);
306 nsMediaDocument::UpdateTitleAndCharset(const nsACString
& aTypeStr
,
307 const char* const* aFormatNames
,
308 PRInt32 aWidth
, PRInt32 aHeight
,
309 const nsAString
& aStatus
)
311 nsXPIDLString fileStr
;
313 nsCAutoString fileName
;
314 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(mDocumentURI
);
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
326 if (mCharacterSetSource
!= kCharsetUninitialized
) {
327 docCharset
= mCharacterSet
;
330 // resort to |originCharset|
331 mDocumentURI
->GetOriginCharset(docCharset
);
332 SetDocumentCharacterSet(docCharset
);
334 if (!fileName
.IsEmpty()) {
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
);
342 CopyUTF8toUTF16(fileName
, fileStr
);
347 NS_ConvertASCIItoUTF16
typeStr(aTypeStr
);
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
));
366 const PRUnichar
*formatStrings
[3] = {typeStr
.get(), widthStr
.get(),
368 NS_ConvertASCIItoUTF16
fmtName(aFormatNames
[eWithDim
]);
369 mStringBundle
->FormatStringFromName(fmtName
.get(), formatStrings
, 3,
370 getter_Copies(title
));
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
));
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()) {
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
);