Back to index

lightning-sunbird  0.9+nobinonly
nsBRFrame.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  * 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  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 #include "nsCOMPtr.h"
00038 #include "nsFrame.h"
00039 #include "nsHTMLParts.h"
00040 #include "nsPresContext.h"
00041 #include "nsLineLayout.h"
00042 #include "nsStyleConsts.h"
00043 #include "nsHTMLAtoms.h"
00044 #include "nsIFontMetrics.h"
00045 #include "nsIRenderingContext.h"
00046 #include "nsLayoutAtoms.h"
00047 #include "nsTextTransformer.h"
00048 
00049 //FOR SELECTION
00050 #include "nsIContent.h"
00051 #include "nsIFrameSelection.h"
00052 //END INCLUDES FOR SELECTION
00053 
00054 class BRFrame : public nsFrame {
00055 public:
00056   // nsIFrame
00057 #ifdef NS_DEBUG
00058   NS_IMETHOD Paint(nsPresContext*      aPresContext,
00059                    nsIRenderingContext& aRenderingContext,
00060                    const nsRect&        aDirtyRect,
00061                    nsFramePaintLayer    aWhichLayer,
00062                    PRUint32             aFlags = 0);
00063 #endif
00064   NS_IMETHOD GetContentAndOffsetsFromPoint(nsPresContext* aCX,
00065                          const nsPoint& aPoint,
00066                          nsIContent** aNewContent,
00067                          PRInt32& aContentOffset,
00068                          PRInt32& aContentOffsetEnd,
00069                          PRBool&  aBeginFrameContent);
00070   NS_IMETHOD PeekOffset(nsPresContext* aPresContext, 
00071                          nsPeekOffsetStruct *aPos);
00072 
00073   // nsIHTMLReflow
00074   NS_IMETHOD Reflow(nsPresContext* aPresContext,
00075                     nsHTMLReflowMetrics& aDesiredSize,
00076                     const nsHTMLReflowState& aReflowState,
00077                     nsReflowStatus& aStatus);
00078   virtual nsIAtom* GetType() const;
00079 protected:
00080   virtual ~BRFrame();
00081 };
00082 
00083 nsresult
00084 NS_NewBRFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00085 {
00086   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00087   if (nsnull == aNewFrame) {
00088     return NS_ERROR_NULL_POINTER;
00089   }
00090   nsIFrame* frame = new (aPresShell) BRFrame;
00091   if (nsnull == frame) {
00092     return NS_ERROR_OUT_OF_MEMORY;
00093   }
00094   *aNewFrame = frame;
00095   return NS_OK;
00096 }
00097 
00098 BRFrame::~BRFrame()
00099 {
00100 }
00101 
00102 #ifdef NS_DEBUG
00103 NS_IMETHODIMP
00104 BRFrame::Paint(nsPresContext*      aPresContext,
00105                nsIRenderingContext& aRenderingContext,
00106                const nsRect&        aDirtyRect,
00107                nsFramePaintLayer    aWhichLayer,
00108                PRUint32             aFlags)
00109 {
00110   if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) {
00111     float p2t;
00112     p2t = aPresContext->PixelsToTwips();
00113     nscoord five = NSIntPixelsToTwips(5, p2t);
00114     aRenderingContext.SetColor(NS_RGB(0, 255, 255));
00115     aRenderingContext.FillRect(0, 0, five, five*2);
00116   }
00117   return NS_OK;
00118 }
00119 #endif
00120 
00121 NS_IMETHODIMP
00122 BRFrame::Reflow(nsPresContext* aPresContext,
00123                 nsHTMLReflowMetrics& aMetrics,
00124                 const nsHTMLReflowState& aReflowState,
00125                 nsReflowStatus& aStatus)
00126 {
00127   DO_GLOBAL_REFLOW_COUNT("BRFrame", aReflowState.reason);
00128   DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
00129   if (aMetrics.mComputeMEW) {
00130     aMetrics.mMaxElementWidth = 0;
00131   }
00132   aMetrics.height = 0; // BR frames with height 0 are ignored in quirks
00133                        // mode by nsLineLayout::VerticalAlignFrames .
00134                        // However, it's not always 0.  See below.
00135   aMetrics.width = 0;
00136   aMetrics.ascent = 0;
00137   aMetrics.descent = 0;
00138 
00139   // Only when the BR is operating in a line-layout situation will it
00140   // behave like a BR.
00141   nsLineLayout* ll = aReflowState.mLineLayout;
00142   if (ll) {
00143     // Note that the compatibility mode check excludes AlmostStandards
00144     // mode, since this is the inline box model.  See bug 161691.
00145     if ( ll->CanPlaceFloatNow() ||
00146          ll->GetCompatMode() == eCompatibility_FullStandards ) {
00147       // If we can place a float on the line now it means that the
00148       // line is effectively empty (there may be zero sized compressed
00149       // white-space frames on the line, but they are to be ignored).
00150       //
00151       // If this frame is going to terminate the line we know
00152       // that nothing else will go on the line. Therefore, in this
00153       // case, we provide some height for the BR frame so that it
00154       // creates some vertical whitespace.  It's necessary to use the
00155       // line-height rather than the font size because the
00156       // quirks-mode fix that doesn't apply the block's min
00157       // line-height makes this necessary to make BR cause a line
00158       // of the full line-height
00159 
00160       // We also do this in strict mode because BR should act like a
00161       // normal inline frame.  That line-height is used is important
00162       // here for cases where the line-height is less that 1.
00163       SetFontFromStyle(aReflowState.rendContext, mStyleContext);
00164       nsCOMPtr<nsIFontMetrics> fm;
00165       aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm));
00166       if (fm) {
00167         nscoord ascent, descent;
00168         fm->GetMaxAscent(ascent);
00169         fm->GetMaxDescent(descent);
00170         nscoord logicalHeight =
00171           aReflowState.CalcLineHeight(aPresContext,
00172                                        aReflowState.rendContext,
00173                                        this);
00174         nscoord leading = logicalHeight - ascent - descent;
00175         aMetrics.height = logicalHeight;
00176         aMetrics.ascent = ascent + (leading/2);
00177         aMetrics.descent = logicalHeight - aMetrics.ascent;
00178                       // = descent + (leading/2), but without rounding error
00179       }
00180       else {
00181         aMetrics.ascent = aMetrics.height = 0;
00182       }
00183 
00184       // XXX temporary until I figure out a better solution; see the
00185       // code in nsLineLayout::VerticalAlignFrames that zaps minY/maxY
00186       // if the width is zero.
00187       // XXX This also fixes bug 10036!
00188       // Warning: nsTextControlFrame::CalculateSizeStandard depends on
00189       // the following line, see bug 228752.
00190       aMetrics.width = 1;
00191 
00192       // Update max-element-width to keep us honest
00193       if (aMetrics.mComputeMEW && aMetrics.width > aMetrics.mMaxElementWidth) {
00194         aMetrics.mMaxElementWidth = aMetrics.width;
00195       }
00196     }
00197 
00198     // Return our reflow status
00199     PRUint32 breakType = aReflowState.mStyleDisplay->mBreakType;
00200     if (NS_STYLE_CLEAR_NONE == breakType) {
00201       breakType = NS_STYLE_CLEAR_LINE;
00202     }
00203 
00204     aStatus = NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
00205       NS_INLINE_MAKE_BREAK_TYPE(breakType);
00206     ll->SetLineEndsInBR(PR_TRUE);
00207   }
00208   else {
00209     aStatus = NS_FRAME_COMPLETE;
00210   }
00211 
00212   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
00213   return NS_OK;
00214 }
00215 
00216 nsIAtom*
00217 BRFrame::GetType() const
00218 {
00219   return nsLayoutAtoms::brFrame;
00220 }
00221 
00222 NS_IMETHODIMP BRFrame::GetContentAndOffsetsFromPoint(nsPresContext* aCX,
00223                                                      const nsPoint&  aPoint,
00224                                                      nsIContent **   aContent,
00225                                                      PRInt32&        aOffsetBegin,
00226                                                      PRInt32&        aOffsetEnd,
00227                                                      PRBool&         aBeginFrameContent)
00228 {
00229   if (!mContent)
00230     return NS_ERROR_NULL_POINTER;
00231   NS_IF_ADDREF(*aContent = mContent->GetParent());
00232 
00233   if (*aContent)
00234     aOffsetBegin = (*aContent)->IndexOf(mContent);
00235   aOffsetEnd = aOffsetBegin;
00236   aBeginFrameContent = PR_TRUE;
00237   return NS_OK;
00238 }
00239 
00240 NS_IMETHODIMP BRFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
00241 {
00242   if (!aPos)
00243     return NS_ERROR_NULL_POINTER;
00244 
00245   //BR is also a whitespace, but sometimes GetNextWord() can't handle this
00246   //See bug 304891
00247   nsTextTransformer::Initialize();
00248   if (nsTextTransformer::GetWordSelectEatSpaceAfter() &&
00249       aPos->mDirection == eDirNext)
00250     aPos->mEatingWS = PR_TRUE;
00251 
00252  //offset of this content in its parents child list. base 0
00253   PRInt32 offsetBegin = mContent->GetParent()->IndexOf(mContent);
00254 
00255   if (aPos->mAmount != eSelectLine && aPos->mAmount != eSelectBeginLine 
00256       && aPos->mAmount != eSelectEndLine) //then we must do the adjustment to make sure we leave this frame
00257   {
00258     if (aPos->mDirection == eDirNext)
00259       aPos->mStartOffset = offsetBegin +1;//go to end to make sure we jump to next node.
00260     else
00261       aPos->mStartOffset = offsetBegin; //we start at beginning to make sure we leave this frame.
00262   }
00263   return nsFrame::PeekOffset(aPresContext, aPos);//now we let the default take over.
00264 }