Back to index

lightning-sunbird  0.9+nobinonly
mozXMLTermStream.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is XMLterm.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Ramalingam Saravanan.
00018  * Portions created by the Initial Developer are Copyright (C) 1999
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 // mozXMLTermStream.cpp: implementation of mozIXMLTermStream
00038 // to display HTML/XML streams as documents
00039 
00040 #include "nscore.h"
00041 #include "prlog.h"
00042 
00043 #include "nsCOMPtr.h"
00044 #include "nsString.h"
00045 #include "nsReadableUtils.h"
00046 #include "plstr.h"
00047 
00048 #include "nsMemory.h"
00049 
00050 #include "nsIServiceManager.h"
00051 #include "nsIContentViewer.h"
00052 #include "nsIDocumentViewer.h"
00053 #include "nsPresContext.h"
00054 #include "nsIPresShell.h"
00055 #include "nsIContentViewerContainer.h"
00056 
00057 #include "nsIViewManager.h"
00058 #include "nsIScrollableView.h"
00059 #include "nsIDeviceContext.h"
00060 #include "nsIFrame.h"
00061 
00062 #include "nsIScriptContextOwner.h"
00063 #include "nsIScriptGlobalObject.h"
00064 
00065 #include "nsICategoryManager.h"
00066 #include "nsXPCOMCID.h"
00067 
00068 #include "mozXMLT.h"
00069 #include "mozXMLTermUtils.h"
00070 #include "mozXMLTermStream.h"
00071 
00072 static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
00073 
00075 // mozXMLTermStream implementation
00077 
00078 NS_IMPL_THREADSAFE_ISUPPORTS2(mozXMLTermStream, 
00079                               mozIXMLTermStream,
00080                               nsIInputStream)
00081 
00082 mozXMLTermStream::mozXMLTermStream() :
00083   mUTF8Buffer(""),
00084   mUTF8Offset(0),
00085   mMaxResizeHeight(0),
00086   mDOMWindow( nsnull ),
00087 #ifdef NO_WORKAROUND
00088   mDOMIFrameElement( nsnull ),
00089   mContext( nsnull ),
00090   mLoadGroup( nsnull ),
00091   mChannel( nsnull ),
00092   mStreamListener( nsnull )
00093 #else // !NO_WORKAROUND
00094   mDOMHTMLDocument( nsnull )
00095 #endif // !NO_WORKAROUND
00096 {
00097 }
00098 
00099 
00100 mozXMLTermStream::~mozXMLTermStream()
00101 {
00102 }
00103 
00104 // mozIXMLTermStream interface
00105 
00115 NS_IMETHODIMP mozXMLTermStream::Open(nsIDOMWindowInternal* aDOMWindow,
00116                                      const char* frameName,
00117                                      const char* contentURL,
00118                                      const char* contentType,
00119                                      PRInt32 maxResizeHeight)
00120 {
00121   nsresult result;
00122 
00123   XMLT_LOG(mozXMLTermStream::Open,20,("contentURL=%s, contentType=%s\n",
00124                                       contentURL, contentType));
00125 
00126   mMaxResizeHeight = maxResizeHeight;
00127 
00128   if (frameName && *frameName) {
00129     // Open stream in named subframe of current frame
00130     XMLT_LOG(mozXMLTermStream::Open,22,("frameName=%s\n", frameName));
00131 
00132     nsAutoString innerFrameName; innerFrameName.AssignASCII(frameName);
00133 
00134     // Get DOM IFRAME element
00135     nsCOMPtr<nsIDOMDocument> domDoc;
00136     result = aDOMWindow->GetDocument(getter_AddRefs(domDoc));
00137     if (NS_FAILED(result) || !domDoc)
00138       return NS_ERROR_FAILURE;
00139 
00140     nsCOMPtr<nsIDOMHTMLDocument> domHTMLDoc = do_QueryInterface(domDoc);
00141     if (!domHTMLDoc)
00142       return NS_ERROR_FAILURE;
00143 
00144     nsCOMPtr<nsIDOMNodeList> nodeList;
00145     result = domHTMLDoc->GetElementsByName(innerFrameName,
00146                                            getter_AddRefs(nodeList));
00147     if (NS_FAILED(result) || !nodeList)
00148       return NS_ERROR_FAILURE;
00149 
00150     PRUint32 count;
00151     nodeList->GetLength(&count);
00152     PR_ASSERT(count==1);
00153 
00154     nsCOMPtr<nsIDOMNode> domNode;
00155     result = nodeList->Item(0, getter_AddRefs(domNode));
00156     if (NS_FAILED(result) || !domNode)
00157       return NS_ERROR_FAILURE;
00158 
00159     mDOMIFrameElement = do_QueryInterface(domNode);
00160     if (!mDOMIFrameElement)
00161       return NS_ERROR_FAILURE;
00162 
00163     // Ensure that it is indeed an IFRAME element
00164     nsAutoString tagName;
00165     result = mDOMIFrameElement->GetTagName(tagName);
00166     if (NS_FAILED(result))
00167       return NS_ERROR_FAILURE;
00168 
00169     if (!tagName.LowerCaseEqualsLiteral("iframe"))
00170       return NS_ERROR_FAILURE;
00171 
00172     if (mMaxResizeHeight > 0) {
00173       // Set initial IFRAME size to be as wide as the window, but very short
00174       nsAutoString attWidth(NS_LITERAL_STRING("width"));
00175       nsAutoString valWidth(NS_LITERAL_STRING("100%"));
00176       mDOMIFrameElement->SetAttribute(attWidth,valWidth);
00177 
00178       nsAutoString attHeight(NS_LITERAL_STRING("height"));
00179       nsAutoString valHeight(NS_LITERAL_STRING("10"));
00180       mDOMIFrameElement->SetAttribute(attHeight,valHeight);
00181     }
00182 
00183     // Get inner DOM window by looking up the frames list
00184     nsCOMPtr<nsIDOMWindowInternal> innerDOMWindow;
00185     result = mozXMLTermUtils::GetInnerDOMWindow(aDOMWindow, innerFrameName,
00186                                 getter_AddRefs(innerDOMWindow));
00187     if (NS_FAILED(result) || !innerDOMWindow)
00188       return NS_ERROR_FAILURE;
00189 
00190     mDOMWindow = innerDOMWindow;
00191 
00192   } else {
00193     // Open stream in current frame
00194     mDOMIFrameElement = nsnull;
00195     mDOMWindow = aDOMWindow;
00196   }
00197 
00198   // Get docshell for DOM window
00199   nsCOMPtr<nsIDocShell> docShell;
00200   result = mozXMLTermUtils::ConvertDOMWindowToDocShell(mDOMWindow,
00201                                                     getter_AddRefs(docShell));
00202   if (NS_FAILED(result) || !docShell)
00203     return NS_ERROR_FAILURE;
00204 
00205 #ifdef NO_WORKAROUND
00206   XMLT_WARNING("mozXMLTermStream::Open, NO_WORKAROUND, url=%s\n", contentURL);
00207 
00208   nsCOMPtr<nsIInputStream> inputStream = this;
00209 
00210   // Create a simple URI
00211   nsCOMPtr<nsIURI> uri = do_CreateInstance(kSimpleURICID, &result);
00212   if (NS_FAILED(result))
00213     return result;
00214 
00215   result = uri->SetSpec(nsDependentCString(contentURL));
00216   if (NS_FAILED(result))
00217     return result;
00218 
00219 
00220   // Create a new load group
00221   result = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), nsnull);
00222   if (NS_FAILED(result))
00223     return result;
00224 
00225   // Create an input stream channel
00226   result = NS_NewInputStreamChannel(getter_AddRefs(mChannel),
00227                                     uri,
00228                                     inputStream,
00229                                     nsDependentCString(contentType),
00230                                     EmptyCString());
00231   if (NS_FAILED(result))
00232     return result;
00233 
00234   // Set channel's load group
00235   result = mChannel->SetLoadGroup(mLoadGroup);
00236   if (NS_FAILED(result))
00237     return result;
00238 
00239   // Create document loader for specified command and content type
00240   nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &result));
00241   if (NS_FAILED(result))
00242     return result;
00243 
00244   nsXPIDLCString contractID;
00245   result = catMan->GetCategoryEntry("Gecko-Content-Viewers", contentType,
00246                                     getter_Copies(contractID));
00247   if (NS_FAILED(result))
00248     return result;
00249 
00250   nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory;
00251   docLoaderFactory = do_GetService(contractID.get(), &result);
00252   if (NS_FAILED(result))
00253     return result;
00254 
00255   nsCOMPtr<nsIContentViewerContainer> contViewContainer =
00256                                              do_QueryInterface(docShell);
00257   nsCOMPtr<nsIContentViewer> contentViewer;
00258   result = docLoaderFactory->CreateInstance("view",
00259                                             mChannel,
00260                                             mLoadGroup,
00261                                             contentType,
00262                                             contViewContainer,
00263                                             nsnull,
00264                                             getter_AddRefs(mStreamListener),
00265                                             getter_AddRefs(contentViewer) );
00266   if (NS_FAILED(result))
00267     return result;
00268 
00269   // Set container for content view
00270   result = contentViewer->SetContainer(contViewContainer);
00271   if (NS_FAILED(result))
00272     return result;
00273 
00274   // Embed contentViewer in containing docShell
00275   result = contViewContainer->Embed(contentViewer, "view", nsnull);
00276   if (NS_FAILED(result))
00277     return result;
00278 
00279   // Start request
00280   result = mStreamListener->OnStartRequest(mChannel, mContext);
00281   if (NS_FAILED(result))
00282     return result;
00283 
00284 #else // !NO_WORKAROUND
00285   XMLT_WARNING("mozXMLTermStream::Open, WORKAROUND\n");
00286 
00287   nsCOMPtr<nsIDOMDocument> innerDOMDoc;
00288   result = mDOMWindow->GetDocument(getter_AddRefs(innerDOMDoc));
00289   XMLT_WARNING("mozXMLTermStream::Open,check1, 0x%x, 0x%x\n",
00290          result, (int) innerDOMDoc.get());
00291   if (NS_FAILED(result) || !innerDOMDoc)
00292     return NS_ERROR_FAILURE;
00293 
00294   mDOMHTMLDocument = do_QueryInterface(innerDOMDoc);
00295   XMLT_WARNING("mozXMLTermStream::Open,check2, 0x%x\n", result);
00296   if (!mDOMHTMLDocument)
00297     return NS_ERROR_FAILURE;
00298 
00299   result = mDOMHTMLDocument->Open();
00300   XMLT_WARNING("mozXMLTermStream::Open,check3, 0x%x\n", result);
00301   if (NS_FAILED(result))
00302     return result;
00303 #endif // !NO_WORKAROUND
00304 
00305   XMLT_LOG(mozXMLTermStream::Open,21,("returning\n"));
00306 
00307   return NS_OK;
00308 }
00309 
00310 
00311 // nsIInputStream interface
00312 NS_IMETHODIMP mozXMLTermStream::Close(void)
00313 {
00314   nsresult result;
00315 
00316   XMLT_LOG(mozXMLTermStream::Close,20,("\n"));
00317 
00318   mUTF8Buffer = "";
00319   mUTF8Offset = 0;
00320 
00321 #ifdef NO_WORKAROUND
00322   PRUint32 sourceOffset = 0;
00323   PRUint32 count = 0;
00324   result = mStreamListener->OnDataAvailable(mChannel, mContext,
00325                                             this, sourceOffset, count);
00326   if (NS_FAILED(result))
00327     return result;
00328 
00329   nsresult status = NS_OK;
00330   nsAutoString errorMsg;
00331   result = mStreamListener->OnStopRequest(mChannel, mContext, status);
00332   if (NS_FAILED(result))
00333     return result;
00334 
00335   mContext = nsnull;
00336   mLoadGroup = nsnull;
00337   mChannel = nsnull;
00338   mStreamListener = nsnull;
00339 
00340 #else // !NO_WORKAROUND
00341   result = mDOMHTMLDocument->Close();
00342   if (NS_FAILED(result))
00343     return result;
00344 #endif // !NO_WORKAROUND
00345 
00346   if (mMaxResizeHeight && mDOMIFrameElement) {
00347     // Size frame to content
00348     result = SizeToContentHeight(mMaxResizeHeight);
00349   }
00350   mMaxResizeHeight = 0;
00351 
00352   // Release interfaces etc
00353   mDOMWindow = nsnull;
00354   mDOMIFrameElement = nsnull;
00355 
00356   return NS_OK;
00357 }
00358 
00359 
00364 NS_IMETHODIMP mozXMLTermStream::SizeToContentHeight(PRInt32 maxHeight)
00365 {
00366   nsresult result;
00367 
00368   // Get docshell
00369   nsCOMPtr<nsIDocShell> docShell;
00370   result = mozXMLTermUtils::ConvertDOMWindowToDocShell(mDOMWindow,
00371                                                    getter_AddRefs(docShell));
00372   if (NS_FAILED(result) || !docShell)
00373     return NS_ERROR_FAILURE;
00374 
00375   // Get pres context
00376   nsCOMPtr<nsPresContext> presContext;
00377   result = docShell->GetPresContext(getter_AddRefs(presContext));
00378   if (NS_FAILED(result) || !presContext)
00379     return NS_ERROR_FAILURE;
00380 
00381   // Get scrollable view
00382   nsIScrollableView* scrollableView;
00383   result = mozXMLTermUtils::GetPresContextScrollableView(presContext,
00384                                                          &scrollableView);
00385   if (NS_FAILED(result) || !scrollableView)
00386     return NS_ERROR_FAILURE;
00387 
00388   // Get device context
00389   nsCOMPtr<nsIDeviceContext> deviceContext;
00390   result = mozXMLTermUtils::GetPresContextDeviceContext(presContext,
00391                                               getter_AddRefs(deviceContext));
00392   if (NS_FAILED(result) || !deviceContext)
00393     return NS_ERROR_FAILURE;
00394 
00395   // Determine twips to pixels conversion factor
00396   float pixelScale;
00397   pixelScale = presContext->TwipsToPixels();
00398 
00399   // Get scrollbar dimensions in pixels
00400   float sbWidth, sbHeight;
00401   deviceContext->GetScrollBarDimensions(sbWidth, sbHeight);
00402   PRInt32 scrollBarWidth = PRInt32(sbWidth*pixelScale);
00403   PRInt32 scrollBarHeight = PRInt32(sbHeight*pixelScale);
00404 
00405   // Determine docshell size in pixels
00406   nsRect shellArea = presContext->GetVisibleArea();
00407 
00408   PRInt32 shellWidth = PRInt32((float)shellArea.width * pixelScale);
00409   PRInt32 shellHeight = PRInt32((float)shellArea.height * pixelScale);
00410 
00411   // Determine page size in pixels
00412   nscoord contX, contY;
00413   scrollableView->GetContainerSize(&contX, &contY);
00414 
00415   PRInt32 pageWidth, pageHeight;
00416   pageWidth = PRInt32((float)contX*pixelScale);
00417   pageHeight = PRInt32((float)contY*pixelScale);
00418 
00419   XMLT_WARNING("mozXMLTermStream::SizeToContentHeight: scrollbar %d, %d\n",
00420          scrollBarWidth, scrollBarHeight);
00421 
00422   XMLT_WARNING("mozXMLTermStream::SizeToContentHeight: presShell %d, %d\n",
00423          shellWidth, shellHeight);
00424 
00425   XMLT_WARNING("mozXMLTermStream::SizeToContentHeight: page %d, %d, %e\n",
00426          pageWidth, pageHeight, pixelScale);
00427 
00428   if ((pageHeight > shellHeight) || (pageWidth > shellWidth)) {
00429     // Page larger than docshell
00430     nsAutoString attHeight(NS_LITERAL_STRING("height"));
00431     nsAutoString attWidth(NS_LITERAL_STRING("width"));
00432     nsAutoString attValue; attValue.SetLength(0);
00433 
00434     PRInt32 newPageHeight = pageHeight;
00435     PRInt32 excessWidth = (pageWidth+scrollBarWidth - shellWidth);
00436 
00437     XMLT_WARNING("mozXMLTermStream::SizeToContentHeight: excessWidth %d\n",
00438            excessWidth);
00439 
00440     if (excessWidth > 0) {
00441       // Widen IFRAME beyond page width by scrollbar width
00442       attValue.SetLength(0);
00443       attValue.AppendInt(shellWidth+scrollBarWidth);
00444       mDOMIFrameElement->SetAttribute(attWidth,attValue);
00445 
00446       // Recompute page dimensions
00447       scrollableView->GetContainerSize(&contX, &contY);
00448       pageWidth = PRInt32((float)contX*pixelScale);
00449       pageHeight = PRInt32((float)contY*pixelScale);
00450 
00451       newPageHeight = pageHeight;
00452       if (excessWidth > scrollBarWidth)
00453         newPageHeight += scrollBarHeight;
00454 
00455       XMLT_WARNING("mozXMLTermStream::SizeToContentHeight: page2 %d, %d, %d\n",
00456              pageWidth, pageHeight, newPageHeight);
00457 
00458       // Reset IFRAME width
00459       attValue.SetLength(0);
00460       attValue.AppendInt(shellWidth);
00461       mDOMIFrameElement->SetAttribute(attWidth,attValue);
00462     }
00463 
00464     // Resize IFRAME height to match page height (subject to a maximum)
00465     if (newPageHeight > maxHeight) newPageHeight = maxHeight;
00466     attValue.SetLength(0);
00467     attValue.AppendInt(newPageHeight);
00468     mDOMIFrameElement->SetAttribute(attHeight,attValue);
00469   }
00470 
00471   return NS_OK;
00472 }
00473 
00474 
00475 // nsIInputStream interface
00476 NS_IMETHODIMP mozXMLTermStream::Available(PRUint32 *_retval)
00477 {
00478   if (!_retval)
00479     return NS_ERROR_NULL_POINTER;
00480 
00481   *_retval = mUTF8Buffer.Length() - mUTF8Offset;
00482 
00483   XMLT_LOG(mozXMLTermStream::Available,60,("retval=%d\n", *_retval));
00484 
00485   return NS_OK;
00486 }
00487 
00488 
00489 NS_IMETHODIMP mozXMLTermStream::Read(char* buf, PRUint32 count,
00490                                      PRUint32* _retval)
00491 {
00492   XMLT_LOG(mozXMLTermStream::Read,60,("count=%d\n", count));
00493 
00494   if (!_retval)
00495     return NS_ERROR_NULL_POINTER;
00496 
00497   PR_ASSERT(mUTF8Buffer.Length() >= mUTF8Offset);
00498 
00499   PRUint32 remCount = mUTF8Buffer.Length() - mUTF8Offset;
00500 
00501   if (remCount == 0) {
00502     // Empty buffer
00503     *_retval = 0;
00504     return NS_OK;
00505   }
00506 
00507   if (count >= remCount) {
00508     // Return entire remaining buffer
00509     *_retval = remCount;
00510 
00511   } else {
00512     // Return only portion of buffer
00513     *_retval = count;
00514   }
00515 
00516   // Copy portion of string
00517   PL_strncpyz(buf, mUTF8Buffer.get() + mUTF8Offset, *_retval);
00518 
00519   mUTF8Offset += *_retval;
00520 
00521   XMLT_LOG(mozXMLTermStream::Read,61,("*retval=%d\n", *_retval));
00522 
00523   return NS_OK;
00524 }
00525 
00526 
00531 NS_IMETHODIMP mozXMLTermStream::Write(const PRUnichar* buf)
00532 {
00533   nsresult result;
00534 
00535   XMLT_LOG(mozXMLTermStream::Write,50,("\n"));
00536 
00537   if (!buf)
00538     return NS_ERROR_FAILURE;
00539 
00540   nsAutoString strBuf ( buf );
00541 
00542   // Convert Unicode string to UTF8 and store in buffer
00543   char* utf8Str = ToNewUTF8String(strBuf);
00544   mUTF8Buffer = utf8Str;
00545   nsMemory::Free(utf8Str);
00546 
00547   mUTF8Offset = 0;
00548 
00549 #ifdef NO_WORKAROUND
00550   PRUint32 sourceOffset = 0;
00551 
00552   while (mUTF8Offset < mUTF8Buffer.Length()) {
00553     PRUint32 remCount = mUTF8Buffer.Length() - mUTF8Offset;
00554     result = mStreamListener->OnDataAvailable(mChannel, mContext,
00555                                               this, sourceOffset, remCount);
00556     if (NS_FAILED(result))
00557       return result;
00558   }
00559 
00560 #else // !NO_WORKAROUND
00561   result = mDOMHTMLDocument->Write(strBuf);
00562   if (NS_FAILED(result))
00563     return result;
00564 #endif // !NO_WORKAROUND
00565 
00566   XMLT_WARNING("mozXMLTermStream::Write: str=%s\n", mUTF8Buffer.get());
00567 
00568   XMLT_LOG(mozXMLTermStream::Write,51,
00569            ("returning mUTF8Offset=%u\n", mUTF8Offset));
00570 
00571   return NS_OK;
00572 }
00573 
00574 NS_IMETHODIMP
00575 mozXMLTermStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval)
00576 {
00577     NS_NOTREACHED("ReadSegments");
00578     return NS_ERROR_NOT_IMPLEMENTED;
00579 }
00580 
00581 NS_IMETHODIMP
00582 mozXMLTermStream::IsNonBlocking(PRBool *aNonBlocking)
00583 {
00584     *aNonBlocking = PR_TRUE;
00585     return NS_OK;
00586 }