PageRenderTime 36ms CodeModel.GetById 23ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/parser/htmlparser/src/CNavDTD.h

http://github.com/zpao/v8monkey
C Header | 406 lines | 115 code | 41 blank | 250 comment | 0 complexity | 1792c351b18ed59efad1cff4adb51459 MD5 | raw file
  1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2/* vim: set sw=2 ts=2 et tw=78: */
  3/* ***** BEGIN LICENSE BLOCK *****
  4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  5 *
  6 * The contents of this file are subject to the Mozilla Public License Version
  7 * 1.1 (the "License"); you may not use this file except in compliance with
  8 * the License. You may obtain a copy of the License at
  9 * http://www.mozilla.org/MPL/
 10 *
 11 * Software distributed under the License is distributed on an "AS IS" basis,
 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 13 * for the specific language governing rights and limitations under the
 14 * License.
 15 *
 16 * The Original Code is mozilla.org code.
 17 *
 18 * The Initial Developer of the Original Code is
 19 * Netscape Communications Corporation.
 20 * Portions created by the Initial Developer are Copyright (C) 1998
 21 * the Initial Developer. All Rights Reserved.
 22 *
 23 * Contributor(s):
 24 *
 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.
 36 *
 37 * ***** END LICENSE BLOCK ***** */
 38
 39/**
 40 * MODULE NOTES:
 41 *
 42 * NavDTD is an implementation of the nsIDTD interface.
 43 * In particular, this class captures the behaviors of the original 
 44 * Navigator parser productions.
 45 *
 46 * This DTD, like any other in NGLayout, provides a few basic services:
 47 *  - First, the DTD collaborates with the Parser class to convert plain 
 48 *    text into a sequence of HTMLTokens. 
 49 *  - Second, the DTD describes containment rules for known elements. 
 50 *  - Third the DTD controls and coordinates the interaction between the
 51 *    parsing system and content sink. (The content sink is the interface
 52 *    that serves as a proxy for content model).
 53 *  - Fourth the DTD maintains an internal style-stack to handle residual (leaky)
 54 *    style tags.
 55 *
 56 * You're most likely working in this class file because
 57 * you want to add or change a behavior inherent in this DTD. The remainder
 58 * of this section will describe what you need to do to affect the kind of
 59 * change you want in this DTD.
 60 *
 61 * RESIDUAL-STYLE HANDLNG:
 62 *   There are a number of ways to represent style in an HTML document.
 63 *    1) explicit style tags (<B>, <I> etc)
 64 *    2) implicit styles (like those implicit in <Hn>)
 65 *    3) CSS based styles
 66 *
 67 *   Residual style handling results from explicit style tags that are
 68 *   not closed. Consider this example: <p>text <b>bold </p>
 69 *   When the <p> tag closes, the <b> tag is NOT automatically closed.
 70 *   Unclosed style tags are handled by the process we call residual-style 
 71 *   tag handling. 
 72 *
 73 *   There are two aspects to residual style tag handling. The first is the 
 74 *   construction and managing of a stack of residual style tags. The 
 75 *   second is the automatic emission of residual style tags onto leaf content
 76 *   in subsequent portions of the document.This step is necessary to propagate
 77 *   the expected style behavior to subsequent portions of the document.
 78 *
 79 *   Construction and managing the residual style stack is an inline process that
 80 *   occurs during the model building phase of the parse process. During the model-
 81 *   building phase of the parse process, a content stack is maintained which tracks
 82 *   the open container hierarchy. If a style tag(s) fails to be closed when a normal
 83 *   container is closed, that style tag is placed onto the residual style stack. If
 84 *   that style tag is subsequently closed (in most contexts), it is popped off the
 85 *   residual style stack -- and are of no further concern.
 86 *
 87 *   Residual style tag emission occurs when the style stack is not empty, and leaf
 88 *   content occurs. In our earlier example, the <b> tag "leaked" out of the <p> 
 89 *   container. Just before the next leaf is emitted (in this or another container) the 
 90 *   style tags that are on the stack are emitted in succession. These same residual
 91 *   style tags get closed automatically when the leaf's container closes, or if a
 92 *   child container is opened.
 93 * 
 94 *         
 95 */
 96#ifndef NS_NAVHTMLDTD__
 97#define NS_NAVHTMLDTD__
 98
 99#include "nsIDTD.h"
100#include "nsISupports.h"
101#include "nsIParser.h"
102#include "nsHTMLTags.h"
103#include "nsDeque.h"
104#include "nsParserCIID.h"
105#include "nsDTDUtils.h"
106#include "nsParser.h"
107#include "nsCycleCollectionParticipant.h"
108
109class nsIHTMLContentSink;
110class nsIParserNode;
111class nsDTDContext;
112class nsEntryStack;
113class nsITokenizer;
114class nsCParserNode;
115class nsTokenAllocator;
116
117/***************************************************************
118  Now the main event: CNavDTD.
119
120  This not so simple class performs all the duties of token 
121  construction and model building. It works in conjunction with
122  an nsParser.
123 ***************************************************************/
124
125#ifdef _MSC_VER
126#pragma warning( disable : 4275 )
127#endif
128
129class CNavDTD : public nsIDTD
130{
131#ifdef _MSC_VER
132#pragma warning( default : 4275 )
133#endif
134
135public:
136    /**
137     *  Common constructor for navdtd. You probably want to call
138     *  NS_NewNavHTMLDTD().
139     */
140    CNavDTD();
141    virtual ~CNavDTD();
142
143    /**
144     * This method is offered publically for the sole use from
145     * nsParser::ParseFragment. In general, you should prefer to use methods
146     * that are directly on nsIDTD, since those will be guaranteed to do the
147     * right thing.
148     *
149     * @param aNode The parser node that contains the token information for
150     *              this tag.
151     * @param aTag The actual tag that is being opened (should correspond to
152     *             aNode.
153     * @param aStyleStack The style stack that aNode might be a member of
154     *                    (usually null).
155     */
156    nsresult OpenContainer(const nsCParserNode *aNode,
157                           eHTMLTags aTag,
158                           nsEntryStack* aStyleStack = nsnull);
159
160    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
161    NS_DECL_NSIDTD
162    NS_DECL_CYCLE_COLLECTION_CLASS(CNavDTD)
163
164private:
165    /**
166     *  This method is called to determine whether or not a tag
167     *  of one type can contain a tag of another type.
168     *  
169     *  @param   aParent Tag of parent container
170     *  @param   aChild Tag of child container
171     *  @return  true if parent can contain child
172     */
173    bool CanPropagate(eHTMLTags aParent,
174                        eHTMLTags aChild,
175                        PRInt32 aParentContains);
176
177    /**
178     *  This method gets called to determine whether a given 
179     *  child tag can be omitted by the given parent.
180     *  
181     *  @param   aParent Parent tag being asked about omitting given child
182     *  @param   aChild Child tag being tested for omittability by parent
183     *  @param   aParentContains Can be 0,1,-1 (false,true, unknown)
184     *                           XXX should be PRInt32, not bool
185     *  @return  true if given tag can be omitted
186     */
187    bool CanOmit(eHTMLTags aParent, 
188                   eHTMLTags aChild,
189                   PRInt32& aParentContains);
190
191    /**
192     * Looking at aParent, try to see if we can propagate from aChild to
193     * aParent. If aParent is a TR tag, then see if we can start at TD instead
194     * of at aChild.
195     *
196     * @param   aParent Tag type of parent
197     * @param   aChild Tag type of child
198     * @return  true if closure was achieved -- otherwise false
199     */
200    bool ForwardPropagate(nsString& aSequence,
201                            eHTMLTags aParent,
202                            eHTMLTags aChild);
203
204    /**
205     * Given aParent that does not contain aChild, starting with aChild's
206     * first root tag, try to find aParent. If we can reach aParent simply by
207     * going up each first root tag, then return true. Otherwise, we could not
208     * propagate from aChild up to aParent, so return false.
209     *
210     * @param   aParent Tag type of parent
211     * @param   aChild Tag type of child
212     * @return  true if closure was achieved -- other false
213     */
214    bool BackwardPropagate(nsString& aSequence,
215                             eHTMLTags aParent,
216                             eHTMLTags aChild) const;
217
218    /**
219     * Attempt forward and/or backward propagation for the given child within
220     * the current context vector stack. And actually open the required tags.
221     *
222     * @param   aParent The tag we're trying to open this element inside of.
223     * @param   aChild Type of child to be propagated.
224     */
225    void CreateContextStackFor(eHTMLTags aParent, eHTMLTags aChild);
226
227    /**
228     * Ask if a given container is open anywhere on its stack
229     *
230     * @param   id of container you want to test for
231     * @return  TRUE if the given container type is open -- otherwise FALSE
232     */
233    bool HasOpenContainer(eHTMLTags aContainer) const;
234
235    /**
236     * This method allows the caller to determine if a any member
237     * in a set of tags is currently open.
238     *
239     * @param   aTagSet A set of tags you care about.
240     * @return  true if any of the members of aTagSet are currently open.
241     */
242    bool HasOpenContainer(const eHTMLTags aTagSet[], PRInt32 aCount) const;
243
244    /**
245     * Accessor that retrieves the tag type of the topmost item on the DTD's
246     * tag stack.
247     *
248     * @return The tag type (may be unknown)
249     */
250    eHTMLTags GetTopNode() const;
251
252    /**
253     * Finds the topmost occurrence of given tag within context vector stack.
254     *
255     * @param   tag to be found
256     * @return  index of topmost tag occurrence -- may be -1 (kNotFound).
257     */
258    PRInt32 LastOf(eHTMLTags aTagSet[], PRInt32 aCount) const;
259
260    nsresult HandleToken(CToken* aToken);
261
262    /**
263     *  This method gets called when a start token has been
264     *  encountered in the parse process. If the current container
265     *  can contain this tag, then add it. Otherwise, you have
266     *  two choices: 1) create an implicit container for this tag
267     *                  to be stored in
268     *               2) close the top container, and add this to
269     *                  whatever container ends up on top.
270     *
271     *  @param   aToken -- next (start) token to be handled
272     *  @return  Whether or not we should block the parser.
273     */
274    nsresult    HandleStartToken(CToken* aToken);
275
276    /** 
277     *  This method gets called when a start token has been 
278     *  encountered in the parse process. If the current container
279     *  can contain this tag, then add it. Otherwise, you have
280     *  two choices: 1) create an implicit container for this tag
281     *                  to be stored in
282     *               2) close the top container, and add this to
283     *                  whatever container ends up on top.
284     *   
285     *  @param   aToken Next (start) token to be handled.
286     *  @param   aChildTag The tag corresponding to aToken.
287     *  @param   aNode CParserNode representing this start token
288     *  @return  A potential request to block the parser.
289     */
290    nsresult    HandleDefaultStartToken(CToken* aToken, eHTMLTags aChildTag,
291                                        nsCParserNode *aNode);
292    nsresult    HandleEndToken(CToken* aToken);
293    nsresult    HandleEntityToken(CToken* aToken);
294    nsresult    HandleCommentToken(CToken* aToken);
295    nsresult    HandleAttributeToken(CToken* aToken);
296    nsresult    HandleProcessingInstructionToken(CToken* aToken);
297    nsresult    HandleDocTypeDeclToken(CToken* aToken);
298    nsresult    BuildNeglectedTarget(eHTMLTags aTarget, eHTMLTokenTypes aType);
299
300    nsresult OpenHTML(const nsCParserNode *aNode);
301    nsresult OpenBody(const nsCParserNode *aNode);
302
303    /**
304     * The special purpose methods automatically close
305     * one or more open containers.
306     * @return  error code - 0 if all went well.
307     */
308    nsresult CloseContainer(const eHTMLTags aTag, bool aMalformed);
309    nsresult CloseContainersTo(eHTMLTags aTag, bool aClosedByStartTag);
310    nsresult CloseContainersTo(PRInt32 anIndex, eHTMLTags aTag,
311                               bool aClosedByStartTag);
312    nsresult CloseResidualStyleTags(const eHTMLTags aTag,
313                                    bool aClosedByStartTag);
314
315    /**
316     * Causes leaf to be added to sink at current vector pos.
317     * @param   aNode is leaf node to be added.
318     * @return  error code - 0 if all went well.
319     */
320    nsresult AddLeaf(const nsIParserNode *aNode);
321    nsresult AddHeadContent(nsIParserNode *aNode);
322
323    /**
324     * This set of methods is used to create and manage the set of
325     * transient styles that occur as a result of poorly formed HTML
326     * or bugs in the original navigator.
327     *
328     * @param   aTag -- represents the transient style tag to be handled.
329     * @return  error code -- usually 0
330     */
331    nsresult  OpenTransientStyles(eHTMLTags aChildTag,
332                                  bool aCloseInvalid = true);
333    void      PopStyle(eHTMLTags aTag);
334
335    nsresult  PushIntoMisplacedStack(CToken* aToken)
336    {
337      NS_ENSURE_ARG_POINTER(aToken);
338      aToken->SetNewlineCount(0); // Note: We have already counted the newlines for these tokens
339
340      mMisplacedContent.Push(aToken);
341      return NS_OK;
342    }
343
344protected:
345
346    nsresult        CollectAttributes(nsIParserNode* aNode,eHTMLTags aTag,PRInt32 aCount);
347
348    /**
349     * This gets called before we've handled a given start tag.
350     * It's a generic hook to let us do pre processing.
351     *
352     * @param   aToken contains the tag in question
353     * @param   aTag is the tag itself.
354     * @param   aNode is the node (tag) with associated attributes.
355     * @return  NS_OK if we should continue, a failure code otherwise.
356     */
357    nsresult        WillHandleStartTag(CToken* aToken,eHTMLTags aChildTag,nsIParserNode& aNode);
358    nsresult        DidHandleStartTag(nsIParserNode& aNode,eHTMLTags aChildTag);
359
360    /**
361     *  This method gets called when a start token has been encountered that
362     *  the parent wants to omit. It stashes it in the current element if that
363     *  element accepts such misplaced tokens.
364     *
365     *  @param   aToken Next (start) token to be handled
366     *  @param   aChildTag id of the child in question
367     *  @param   aParent id of the parent in question
368     *  @param   aNode CParserNode representing this start token
369     */
370    void            HandleOmittedTag(CToken* aToken, eHTMLTags aChildTag,
371                                     eHTMLTags aParent, nsIParserNode *aNode);
372    nsresult        HandleSavedTokens(PRInt32 anIndex);
373    nsresult        HandleKeyGen(nsIParserNode *aNode);
374    bool            IsAlternateTag(eHTMLTags aTag);
375    bool            IsBlockElement(PRInt32 aTagID, PRInt32 aParentID) const;
376    bool            IsInlineElement(PRInt32 aTagID, PRInt32 aParentID) const;
377
378    nsDeque             mMisplacedContent;
379    
380    nsCOMPtr<nsIHTMLContentSink> mSink;
381    nsTokenAllocator*   mTokenAllocator;
382    nsDTDContext*       mBodyContext;
383    nsDTDContext*       mTempContext;
384    bool                mCountLines;
385    nsITokenizer*       mTokenizer; // weak
386   
387    nsString            mFilename; 
388    nsString            mScratch;  //used for various purposes; non-persistent
389    nsCString           mMimeType;
390
391    nsNodeAllocator     mNodeAllocator;
392    nsDTDMode           mDTDMode;
393    eParserDocType      mDocType;
394    eParserCommands     mParserCommand;   //tells us to viewcontent/viewsource/viewerrors...
395
396    PRInt32             mLineNumber;
397    PRInt32             mOpenMapCount;
398    PRInt32             mHeadContainerPosition;
399
400    PRUint16            mFlags;
401};
402
403#endif 
404
405
406