Back to index

lightning-sunbird  0.9+nobinonly
nsMediaDocument.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Jungshik Shin <jshin@mailaps.org>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsMediaDocument.h"
00040 #include "nsHTMLAtoms.h"
00041 #include "nsRect.h"
00042 #include "nsPresContext.h"
00043 #include "nsIPresShell.h"
00044 #include "nsIScrollable.h"
00045 #include "nsIViewManager.h"
00046 #include "nsITextToSubURI.h"
00047 #include "nsIURL.h"
00048 #include "nsPrintfCString.h"
00049 #include "nsIContentViewer.h"
00050 #include "nsIMarkupDocumentViewer.h"
00051 #include "nsIDocShell.h"
00052 #include "nsIParser.h" // kCharsetFrom* macro definition
00053 #include "nsIDocumentCharsetInfo.h" 
00054 #include "nsNodeInfoManager.h"
00055 
00056 nsMediaDocumentStreamListener::nsMediaDocumentStreamListener(nsMediaDocument *aDocument)
00057 {
00058   mDocument = aDocument;
00059 }
00060 
00061 nsMediaDocumentStreamListener::~nsMediaDocumentStreamListener()
00062 {
00063 }
00064 
00065 
00066 NS_IMPL_THREADSAFE_ISUPPORTS2(nsMediaDocumentStreamListener,
00067                               nsIRequestObserver,
00068                               nsIStreamListener)
00069 
00070 
00071 void
00072 nsMediaDocumentStreamListener::SetStreamListener(nsIStreamListener *aListener)
00073 {
00074   mNextStream = aListener;
00075 }
00076 
00077 NS_IMETHODIMP
00078 nsMediaDocumentStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
00079 {
00080   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
00081 
00082   mDocument->StartLayout();
00083 
00084   if (mNextStream) {
00085     return mNextStream->OnStartRequest(request, ctxt);
00086   }
00087 
00088   return NS_OK;
00089 }
00090 
00091 NS_IMETHODIMP
00092 nsMediaDocumentStreamListener::OnStopRequest(nsIRequest* request,
00093                                              nsISupports *ctxt,
00094                                              nsresult status)
00095 {
00096   nsresult rv = NS_OK;
00097   if (mNextStream) {
00098     rv = mNextStream->OnStopRequest(request, ctxt, status);
00099   }
00100 
00101   // No more need for our document so clear our reference and prevent leaks
00102   mDocument = nsnull;
00103 
00104   return rv;
00105 }
00106 
00107 NS_IMETHODIMP
00108 nsMediaDocumentStreamListener::OnDataAvailable(nsIRequest* request,
00109                                                nsISupports *ctxt,
00110                                                nsIInputStream *inStr,
00111                                                PRUint32 sourceOffset,
00112                                                PRUint32 count)
00113 {
00114   if (mNextStream) {
00115     return mNextStream->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
00116   }
00117 
00118   return NS_OK;
00119 }
00120 
00121 // default format names for nsMediaDocument. 
00122 const char* const nsMediaDocument::sFormatNames[4] = 
00123 {
00124   "MediaTitleWithNoInfo",    // eWithNoInfo
00125   "MediaTitleWithFile",      // eWithFile
00126   "",                        // eWithDim
00127   ""                         // eWithDimAndFile
00128 };
00129 
00130 nsMediaDocument::nsMediaDocument()
00131 {
00132 }
00133 nsMediaDocument::~nsMediaDocument()
00134 {
00135 }
00136 
00137 nsresult
00138 nsMediaDocument::Init()
00139 {
00140   nsresult rv = nsHTMLDocument::Init();
00141   NS_ENSURE_SUCCESS(rv, rv);
00142 
00143   // Create a bundle for the localization
00144   nsCOMPtr<nsIStringBundleService> stringService(
00145     do_GetService(NS_STRINGBUNDLE_CONTRACTID));
00146   if (stringService) {
00147     stringService->CreateBundle(NSMEDIADOCUMENT_PROPERTIES_URI,
00148                                 getter_AddRefs(mStringBundle));
00149   }
00150 
00151   return NS_OK;
00152 }
00153 
00154 nsresult
00155 nsMediaDocument::StartDocumentLoad(const char*         aCommand,
00156                                    nsIChannel*         aChannel,
00157                                    nsILoadGroup*       aLoadGroup,
00158                                    nsISupports*        aContainer,
00159                                    nsIStreamListener** aDocListener,
00160                                    PRBool              aReset,
00161                                    nsIContentSink*     aSink)
00162 {
00163   nsresult rv = nsDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup,
00164                                               aContainer, aDocListener, aReset,
00165                                               aSink);
00166   if (NS_FAILED(rv)) {
00167     return rv;
00168   }
00169 
00170   // We try to set the charset of the current document to that of the 
00171   // 'genuine' (as opposed to an intervening 'chrome') parent document 
00172   // that may be in a different window/tab. Even if we fail here,
00173   // we just return NS_OK because another attempt is made in 
00174   // |UpdateTitleAndCharset| and the worst thing possible is a mangled 
00175   // filename in the titlebar and the file picker.
00176 
00177   // When this document is opened in the window/tab of the referring 
00178   // document (by a simple link-clicking), |prevDocCharacterSet| contains 
00179   // the charset of the referring document. On the other hand, if the
00180   // document is opened in a new window, it is |defaultCharacterSet| of |muCV| 
00181   // where the charset of our interest is stored. In case of openining 
00182   // in a new tab, we get the charset from |documentCharsetInfo|. Note that we 
00183   // exclude UTF-8 as 'invalid' because UTF-8 is likely to be the charset 
00184   // of a chrome document that has nothing to do with the actual content 
00185   // whose charset we want to know. Even if "the actual content" is indeed 
00186   // in UTF-8, we don't lose anything because the default empty value is 
00187   // considered synonymous with UTF-8. 
00188     
00189   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aContainer));
00190 
00191   // not being able to set the charset is not critical.
00192   NS_ENSURE_TRUE(docShell, NS_OK); 
00193 
00194   nsCOMPtr<nsIDocumentCharsetInfo> dcInfo;
00195   nsCAutoString charset;
00196 
00197   docShell->GetDocumentCharsetInfo(getter_AddRefs(dcInfo));
00198   if (dcInfo) {
00199     nsCOMPtr<nsIAtom> csAtom;
00200     dcInfo->GetParentCharset(getter_AddRefs(csAtom));
00201     if (csAtom) {   // opening in a new tab
00202       csAtom->ToUTF8String(charset);
00203     }
00204   }
00205 
00206   if (charset.IsEmpty() || charset.Equals("UTF-8")) {
00207     nsCOMPtr<nsIContentViewer> cv;
00208     docShell->GetContentViewer(getter_AddRefs(cv));
00209 
00210     // not being able to set the charset is not critical.
00211     NS_ENSURE_TRUE(cv, NS_OK); 
00212     nsCOMPtr<nsIMarkupDocumentViewer> muCV = do_QueryInterface(cv);
00213     if (muCV) {
00214       muCV->GetPrevDocCharacterSet(charset);   // opening in the same window/tab
00215       if (charset.Equals("UTF-8") || charset.IsEmpty()) {
00216         muCV->GetDefaultCharacterSet(charset); // opening in a new window
00217       }
00218     } 
00219   }
00220 
00221   if (!charset.IsEmpty() && !charset.Equals("UTF-8")) {
00222     SetDocumentCharacterSet(charset);
00223     mCharacterSetSource = kCharsetFromUserDefault;
00224   }
00225 
00226   return NS_OK;
00227 }
00228 
00229 nsresult
00230 nsMediaDocument::CreateSyntheticDocument()
00231 {
00232   // Synthesize an empty html document
00233   nsresult rv;
00234 
00235   nsCOMPtr<nsINodeInfo> nodeInfo;
00236   rv = mNodeInfoManager->GetNodeInfo(nsHTMLAtoms::html, nsnull,
00237                                      kNameSpaceID_None,
00238                                      getter_AddRefs(nodeInfo));
00239   NS_ENSURE_SUCCESS(rv, rv);
00240 
00241   nsRefPtr<nsGenericHTMLElement> root = NS_NewHTMLHtmlElement(nodeInfo);
00242   if (!root) {
00243     return NS_ERROR_OUT_OF_MEMORY;
00244   }
00245 
00246   rv = SetRootContent(root);
00247   NS_ENSURE_SUCCESS(rv, rv);
00248 
00249   rv = mNodeInfoManager->GetNodeInfo(nsHTMLAtoms::body, nsnull,
00250                                      kNameSpaceID_None,
00251                                      getter_AddRefs(nodeInfo));
00252   NS_ENSURE_SUCCESS(rv, rv);
00253 
00254   nsRefPtr<nsGenericHTMLElement> body = NS_NewHTMLBodyElement(nodeInfo);
00255   if (!body) {
00256     return NS_ERROR_OUT_OF_MEMORY;
00257   }
00258   mBodyContent = do_QueryInterface(body);
00259 
00260   root->AppendChildTo(body, PR_FALSE);
00261 
00262   return NS_OK;
00263 }
00264 
00265 nsresult
00266 nsMediaDocument::StartLayout()
00267 {
00268   PRUint32 numberOfShells = GetNumberOfShells();
00269   for (PRUint32 i = 0; i < numberOfShells; i++) {
00270     nsIPresShell *shell = GetShellAt(i);
00271 
00272     // Make shell an observer for next time.
00273     shell->BeginObservingDocument();
00274 
00275     // Initial-reflow this time.
00276     nsRect visibleArea = shell->GetPresContext()->GetVisibleArea();
00277     shell->InitialReflow(visibleArea.width, visibleArea.height);
00278 
00279     // Now trigger a refresh.
00280     nsIViewManager* vm = shell->GetViewManager();
00281     if (vm) {
00282       vm->EnableRefresh(NS_VMREFRESH_IMMEDIATE);
00283     }
00284   }
00285 
00286   return NS_OK;
00287 }
00288 
00289 void 
00290 nsMediaDocument::UpdateTitleAndCharset(const nsACString& aTypeStr,
00291                                        const char* const* aFormatNames,
00292                                        PRInt32 aWidth, PRInt32 aHeight,
00293                                        const nsAString& aStatus)
00294 {
00295   nsXPIDLString fileStr;
00296   if (mDocumentURI) {
00297     nsCAutoString fileName;
00298     nsCOMPtr<nsIURL> url = do_QueryInterface(mDocumentURI);
00299     if (url)
00300       url->GetFileName(fileName);
00301 
00302     nsCAutoString docCharset;
00303 
00304     // Now that the charset is set in |StartDocumentLoad| to the charset of
00305     // the document viewer instead of a bogus value ("ISO-8859-1" set in
00306     // |nsDocument|'s ctor), the priority is given to the current charset. 
00307     // This is necessary to deal with a media document being opened in a new 
00308     // window or a new tab, in which case |originCharset| of |nsIURI| is not 
00309     // reliable.
00310     if (mCharacterSetSource != kCharsetUninitialized) {  
00311       docCharset = mCharacterSet;
00312     }
00313     else {  
00314       // resort to |originCharset|
00315       mDocumentURI->GetOriginCharset(docCharset);
00316       SetDocumentCharacterSet(docCharset);
00317     }
00318     if (!fileName.IsEmpty()) {
00319       nsresult rv;
00320       nsCOMPtr<nsITextToSubURI> textToSubURI = 
00321         do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
00322       if (NS_SUCCEEDED(rv))
00323         // UnEscapeURIForUI always succeeds
00324         textToSubURI->UnEscapeURIForUI(docCharset, fileName, fileStr);
00325       else 
00326         CopyUTF8toUTF16(fileName, fileStr);
00327     }
00328   }
00329 
00330 
00331   NS_ConvertASCIItoUCS2 typeStr(aTypeStr);
00332   nsXPIDLString title;
00333 
00334   if (mStringBundle) {
00335     // if we got a valid size (not all media have a size)
00336     if (aWidth != 0 && aHeight != 0) {
00337       nsAutoString widthStr;
00338       nsAutoString heightStr;
00339       widthStr.AppendInt(aWidth);
00340       heightStr.AppendInt(aHeight);
00341       // If we got a filename, display it
00342       if (!fileStr.IsEmpty()) {
00343         const PRUnichar *formatStrings[4]  = {fileStr.get(), typeStr.get(), 
00344           widthStr.get(), heightStr.get()};
00345         NS_ConvertASCIItoUCS2 fmtName(aFormatNames[eWithDimAndFile]);
00346         mStringBundle->FormatStringFromName(fmtName.get(), formatStrings, 4,
00347                                             getter_Copies(title));
00348       } 
00349       else {
00350         const PRUnichar *formatStrings[3]  = {typeStr.get(), widthStr.get(), 
00351           heightStr.get()};
00352         NS_ConvertASCIItoUCS2 fmtName(aFormatNames[eWithDim]);
00353         mStringBundle->FormatStringFromName(fmtName.get(), formatStrings, 3,
00354                                             getter_Copies(title));
00355       }
00356     } 
00357     else {
00358     // If we got a filename, display it
00359       if (!fileStr.IsEmpty()) {
00360         const PRUnichar *formatStrings[2] = {fileStr.get(), typeStr.get()};
00361         NS_ConvertASCIItoUCS2 fmtName(aFormatNames[eWithFile]);
00362         mStringBundle->FormatStringFromName(fmtName.get(), formatStrings, 2,
00363                                             getter_Copies(title));
00364       }
00365       else {
00366         const PRUnichar *formatStrings[1] = {typeStr.get()};
00367         NS_ConvertASCIItoUCS2 fmtName(aFormatNames[eWithNoInfo]);
00368         mStringBundle->FormatStringFromName(fmtName.get(), formatStrings, 1,
00369                                             getter_Copies(title));
00370       }
00371     }
00372   } 
00373 
00374   // set it on the document
00375   if (aStatus.IsEmpty()) {
00376     SetTitle(title);
00377   }
00378   else {
00379     nsXPIDLString titleWithStatus;
00380     const nsPromiseFlatString& status = PromiseFlatString(aStatus);
00381     const PRUnichar *formatStrings[2] = {title.get(), status.get()};
00382     NS_NAMED_LITERAL_STRING(fmtName, "TitleWithStatus");
00383     mStringBundle->FormatStringFromName(fmtName.get(), formatStrings, 2,
00384                                         getter_Copies(titleWithStatus));
00385     SetTitle(titleWithStatus);
00386   }
00387 }