Back to index

lightning-sunbird  0.9+nobinonly
nsHTMLCanvasFrame.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.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  *   Vladimir Vukicevic <vladimir@pobox.com>
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *    Vladimir Vukicevic <vladimir@pobox.com> (original author)
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 "nsHTMLParts.h"
00040 #include "nsCOMPtr.h"
00041 #include "nsIServiceManager.h"
00042 #include "nsLayoutAtoms.h"
00043 
00044 #include "nsHTMLCanvasFrame.h"
00045 #include "nsICanvasElement.h"
00046 
00047 #include "nsTransform2D.h"
00048 
00049 nsresult
00050 NS_NewHTMLCanvasFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00051 {
00052   nsHTMLCanvasFrame* it = new (aPresShell) nsHTMLCanvasFrame;
00053   if (nsnull == it) {
00054     return NS_ERROR_OUT_OF_MEMORY;
00055   }
00056   *aNewFrame = it;
00057   return NS_OK;
00058 }
00059 
00060 nsHTMLCanvasFrame::nsHTMLCanvasFrame()
00061 {
00062 }
00063 
00064 nsHTMLCanvasFrame::~nsHTMLCanvasFrame()
00065 {
00066 }
00067 
00068 // We really want a PR_MINMAX to go along with PR_MIN/PR_MAX
00069 #define MINMAX(_value,_min,_max) \
00070     ((_value) < (_min)           \
00071      ? (_min)                    \
00072      : ((_value) > (_max)        \
00073         ? (_max)                 \
00074         : (_value)))
00075 
00076 NS_IMETHODIMP
00077 nsHTMLCanvasFrame::Reflow(nsPresContext*           aPresContext,
00078                           nsHTMLReflowMetrics&     aMetrics,
00079                           const nsHTMLReflowState& aReflowState,
00080                           nsReflowStatus&          aStatus)
00081 {
00082   DO_GLOBAL_REFLOW_COUNT("nsHTMLCanvasFrame", aReflowState.reason);
00083   DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
00084   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
00085                   ("enter nsHTMLCanvasFrame::Reflow: availSize=%d,%d",
00086                   aReflowState.availableWidth, aReflowState.availableHeight));
00087 
00088   NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");
00089 
00090   aStatus = NS_FRAME_COMPLETE;
00091 
00092   nsCOMPtr<nsICanvasElement> canvas(do_QueryInterface(GetContent()));
00093   NS_ENSURE_TRUE(canvas, NS_ERROR_FAILURE);
00094 
00095   PRUint32 w, h;
00096   nsresult rv = canvas->GetSize (&w, &h);
00097   NS_ENSURE_SUCCESS(rv, rv);
00098 
00099   float p2t = GetPresContext()->PixelsToTwips();
00100 
00101   mCanvasSize.SizeTo(NSIntPixelsToTwips(w, p2t), NSIntPixelsToTwips(h, p2t));
00102 
00103   if (aReflowState.mComputedWidth == NS_INTRINSICSIZE)
00104     aMetrics.width = mCanvasSize.width;
00105   else
00106     aMetrics.width = aReflowState.mComputedWidth;
00107 
00108   if (aReflowState.mComputedHeight == NS_INTRINSICSIZE)
00109     aMetrics.height = mCanvasSize.height;
00110   else
00111     aMetrics.height = aReflowState.mComputedHeight;
00112 
00113   // clamp
00114   aMetrics.height = MINMAX(aMetrics.height, aReflowState.mComputedMinHeight, aReflowState.mComputedMaxHeight);
00115   aMetrics.width = MINMAX(aMetrics.width, aReflowState.mComputedMinWidth, aReflowState.mComputedMaxWidth);
00116 
00117   // stash this away so we can compute our inner area later
00118   mBorderPadding   = aReflowState.mComputedBorderPadding;
00119 
00120   aMetrics.width += mBorderPadding.left + mBorderPadding.right;
00121   aMetrics.height += mBorderPadding.top + mBorderPadding.bottom;
00122 
00123   if (mPrevInFlow) {
00124     nscoord y = GetContinuationOffset(&aMetrics.width);
00125     aMetrics.height -= y + mBorderPadding.top;
00126     aMetrics.height = PR_MAX(0, aMetrics.height);
00127   }
00128 
00129   aMetrics.ascent  = aMetrics.height;
00130   aMetrics.descent = 0;
00131 
00132   if (aMetrics.mComputeMEW) {
00133     aMetrics.SetMEWToActualWidth(aReflowState.mStylePosition->mWidth.GetUnit());
00134   }
00135   
00136   if (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH) {
00137     aMetrics.mMaximumWidth = aMetrics.width;
00138   }
00139   aMetrics.mOverflowArea.SetRect(0, 0, aMetrics.width, aMetrics.height);
00140   FinishAndStoreOverflow(&aMetrics);
00141 
00142   if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) {
00143     Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE);
00144   }
00145 
00146   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
00147                   ("exit nsHTMLCanvasFrame::Reflow: size=%d,%d",
00148                   aMetrics.width, aMetrics.height));
00149   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
00150   return NS_OK;
00151 }
00152 
00153 // FIXME taken from nsImageFrame, but then had splittable frame stuff
00154 // removed.  That needs to be fixed.
00155 nsRect 
00156 nsHTMLCanvasFrame::GetInnerArea() const
00157 {
00158   nsRect r;
00159   r.x = mBorderPadding.left;
00160   r.y = mBorderPadding.top;
00161   r.width = mRect.width - mBorderPadding.left - mBorderPadding.right;
00162   r.height = mRect.height - mBorderPadding.top - mBorderPadding.bottom;
00163   return r;
00164 }
00165 
00166 NS_IMETHODIMP
00167 nsHTMLCanvasFrame::Paint(nsPresContext*       aPresContext,
00168                          nsIRenderingContext& aRenderingContext,
00169                          const nsRect&        aDirtyRect,
00170                          nsFramePaintLayer    aWhichLayer,
00171                          PRUint32             aFlags)
00172 {
00173   PRBool isVisible;
00174   if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible)) && 
00175       isVisible && mRect.width && mRect.height)
00176   {
00177     // If painting is suppressed, we need to stop image painting.
00178     PRBool paintingSuppressed = PR_FALSE;
00179     aPresContext->PresShell()->IsPaintingSuppressed(&paintingSuppressed);
00180     if (paintingSuppressed) {
00181       return NS_OK;
00182     }
00183 
00184     // make sure that the rendering context has updated the
00185     // image frame
00186     nsCOMPtr<nsICanvasElement> canvas(do_QueryInterface(GetContent()));
00187     NS_ENSURE_TRUE(canvas, NS_ERROR_FAILURE);
00188 
00189     // from nsImageFrame
00190     // First paint background and borders, which should be in the
00191     // FOREGROUND or BACKGROUND paint layer if the element is
00192     // inline-level or block-level, respectively (bug 36710).  (See
00193     // CSS2 9.5, which is the rationale for paint layers.)
00194     const nsStyleDisplay* display = GetStyleDisplay();
00195     nsFramePaintLayer backgroundLayer = display->IsBlockLevel()
00196       ? NS_FRAME_PAINT_LAYER_BACKGROUND
00197       : NS_FRAME_PAINT_LAYER_FOREGROUND;
00198 
00199     if (aWhichLayer == backgroundLayer) {
00200       PaintSelf(aPresContext, aRenderingContext, aDirtyRect);
00201     }
00202 
00203     if (aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND) {
00204       nsRect inner = GetInnerArea();
00205 
00206       nsTransform2D *tx = nsnull;
00207       aRenderingContext.GetCurrentTransform(tx);
00208 
00209       float t2p = GetPresContext()->TwipsToPixels();
00210       float p2t = GetPresContext()->PixelsToTwips();
00211 
00212       if (inner.width != mCanvasSize.width ||
00213           inner.height != mCanvasSize.height)
00214       {
00215         float sx = inner.width / (float) mCanvasSize.width;
00216         float sy = inner.height / (float) mCanvasSize.height;
00217 
00218         aRenderingContext.PushState();
00219         aRenderingContext.Translate(inner.x, inner.y);
00220         aRenderingContext.Scale(sx, sy);
00221 
00222         canvas->RenderContexts(&aRenderingContext);
00223 
00224         aRenderingContext.PopState();
00225       } else {
00226         //nsIRenderingContext::AutoPushTranslation(&aRenderingContext, px, py);
00227 
00228         aRenderingContext.PushState();
00229         aRenderingContext.Translate(inner.x, inner.y);
00230 
00231         canvas->RenderContexts(&aRenderingContext);
00232 
00233         aRenderingContext.PopState();
00234       }
00235     }
00236   }
00237 
00238   return nsFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, nsISelectionDisplay::DISPLAY_IMAGES);
00239 }
00240 
00241 NS_IMETHODIMP
00242 nsHTMLCanvasFrame::CanContinueTextRun(PRBool& aContinueTextRun) const
00243 {
00244   // stolen from nsImageFrame.cpp
00245   // images really CAN continue text runs, but the textFrame needs to be 
00246   // educated before we can indicate that it can. For now, we handle the fixing up 
00247   // of max element widths in nsLineLayout::VerticalAlignFrames, but hopefully
00248   // this can be eliminated and the textFrame can be convinced to handle inlines
00249   // that take up space in text runs.
00250 
00251   aContinueTextRun = PR_FALSE;
00252   return NS_OK;
00253 }
00254 
00255 NS_IMETHODIMP  
00256 nsHTMLCanvasFrame::GetContentForEvent(nsPresContext* aPresContext,
00257                                       nsEvent* aEvent,
00258                                       nsIContent** aContent)
00259 {
00260   NS_ENSURE_ARG_POINTER(aContent);
00261   *aContent = GetContent();
00262   NS_IF_ADDREF(*aContent);
00263   return NS_OK;
00264 }
00265 
00266 nsIAtom*
00267 nsHTMLCanvasFrame::GetType() const
00268 {
00269   return nsLayoutAtoms::HTMLCanvasFrame;
00270 }
00271 
00272 // get the offset into the content area of the image where aImg starts if it is a continuation.
00273 // from nsImageFrame
00274 nscoord 
00275 nsHTMLCanvasFrame::GetContinuationOffset(nscoord* aWidth) const
00276 {
00277   nscoord offset = 0;
00278   if (aWidth) {
00279     *aWidth = 0;
00280   }
00281 
00282   if (mPrevInFlow) {
00283     for (nsIFrame* prevInFlow = mPrevInFlow ; prevInFlow; prevInFlow = prevInFlow->GetPrevInFlow()) {
00284       nsRect rect = prevInFlow->GetRect();
00285       if (aWidth) {
00286         *aWidth = rect.width;
00287       }
00288       offset += rect.height;
00289     }
00290     offset -= mBorderPadding.top;
00291     offset = PR_MAX(0, offset);
00292   }
00293   return offset;
00294 }
00295 
00296 #ifdef ACCESSIBILITY
00297 NS_IMETHODIMP
00298 nsHTMLCanvasFrame::GetAccessible(nsIAccessible** aAccessible)
00299 {
00300   return NS_ERROR_FAILURE;
00301 }
00302 #endif
00303 
00304 #ifdef DEBUG
00305 NS_IMETHODIMP
00306 nsHTMLCanvasFrame::GetFrameName(nsAString& aResult) const
00307 {
00308   return MakeFrameName(NS_LITERAL_STRING("HTMLCanvas"), aResult);
00309 }
00310 
00311 NS_IMETHODIMP
00312 nsHTMLCanvasFrame::List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
00313 {
00314   IndentBy(out, aIndent);
00315   ListTag(out);
00316   fputs("\n", out);
00317   return NS_OK;
00318 }
00319 #endif
00320