Mozilla FireFox Gecko内核源代码解析(4.nsHTMLTokens)

本文深入解析Mozilla FireFox Gecko内核源代码中的nsHTMLTokens部分,探讨HTML Tokens的类型、状态、结构定义,以及如何解析不同Token。内容涵盖nsHTMLTokens.h头文件中的声明和定义,枚举类型用于标签类型,以及Token的基本方法和数据成员。同时,文章指出nsHTMLTags.h/cpp文件用于查看HTML标签定义,而nsHTMLToken.cpp则包含更多实现细节。
摘要由CSDN通过智能技术生成

Mozilla FireFox Gecko内核源代码解析

(4.nsHTMLTokens)

中科院计算技术研究所网络数据科学与工程研究中心

信息抽取小组

耿耘

gengyun@sohu.com

之前我们分析了nsHTMLTokenizer(详见其解析篇),其中我们了解到了,其中设计了如何配合 nsScanner对输入流循环地解析流程,如怎么进行回溯等流式操作。实际上其中并没有包含具体的字符比对,以及正则表达式匹配等工作。同时也没有具体地声明“哪些HTML标签才是合法的标签”等具体信息。

 

而这些信息实际上都包含在了nsHTMLTokens这个文件中。在这个文件中除了对HTML中常见的各种Tag和他们最后生成的Token进行了一一的对应,并且对Tokens的类型,名称,状态,结构等进行了定义。并且对于一些类型的Token,都提供了相应的Consume方法,该种方法就是提供给在nsHTMLTokenizer中所调用的,真正对相应的Token所对应的HTML文本进行解析的方法。

 

通过学习这个nsHTMLTokens,还可以对Mozilla所推出的HTML标准进行了解,可以知道它都包含什么样的Tokens,哪些Tokens是合法的,以及他们的属性都是如何在浏览器中存储的。

 

首先,我们来看它的头文件nsHTMLTokens.h,其中包含了哪些声明和定义,这个头文件比较长,因此我们对其的内容逐个进行解析

 

首先来看他在文件头写下的一段注释:

 

这个文件中包含了我们的HTML Token的类型定义,这个定义能够被我们的DTD所理解。实际上,这一套Token定义也可以用于XML解析。目前我们拥有文本,注释,起始型标签,结束型标签,实体,属性,样式,脚本以及省略内容,这些个类型的Tokens。空格和换行符同样拥有他们所对应的Token,但是它们在未来的版本中可能会被消除掉。

 

如果你想查看HTML的标签定义,请查看叫做nsHTMLTags.h/cpp的文件。

 

大部分的Token类型都有相似的API。他们都有获取Token类型的方法(GetTokenType);那些代表HTML TagTokens还有一个获取tag类型的方法(GetTypeID)。另外,大部分的Token都有一个在解析流程中帮助它们自己进行解析的调用方法(Consume)。我们同样还提供了一些调试用的代码。

 

下面我们来看代码:

#ifndefHTMLTOKENS_H
#defineHTMLTOKENS_H
 
#include "nsToken.h"
#include "nsHTMLTags.h"
#include "nsString.h"
#include "nsScannerString.h"
 
classnsScanner;
 
  /*******************************************************************
   * This enum defines the set of token typesthat we currently support.
   *******************************************************************/
 
//下面这个枚举类型,定义了我们目前所支持的Token类型,这个很重要,相当于HTML的规范定义其中的一部分,我们可以看到Mozilla一共将所有的Token分为了如下的14种类型,其中的两种类型unknown和last是浏览器内部使用的,不属于HTML规范
enumeHTMLTokenTypes {
 eToken_unknown=0,
 eToken_start=1,     eToken_end,         eToken_comment,        eToken_entity,
 eToken_whitespace,  eToken_newline,     eToken_text,           eToken_attribute,
 eToken_instruction, eToken_cdatasection, eToken_doctypeDecl,     eToken_markupDecl,
 eToken_last //make sure this stays the lasttoken...
};
//这个从字面上就能看出,
nsresult      ConsumeQuotedString(PRUnicharaChar,nsString& aString,nsScanner& aScanner);
//这个从字面上就能看出是对属性文本进行解析的
nsresult      ConsumeAttributeText(PRUnicharaChar,nsString& aString,nsScanner& aScanner);
这个是通过一个整形的标示位来获取TagName的
constPRUnichar* GetTagName(PRInt32 aTag);
//PRInt32     FindEntityIndex(nsString&aString,PRInt32 aCount=-1);
下面我们来看一个HTMLToken的基类,他是用于为其他类进行继承而服务的,其中定义了一些基本的属性和方法,后面的几个Token类都是基于这个类建立的。
 
/**
 *  Thisdeclares the basic token type used in the HTML DTD's.
 * @update  gess 3/25/98
 */
classCHTMLToken : public CToken {
public:
  virtual ~CHTMLToken();
 CHTMLToken(eHTMLTags aTag);
//全部都是虚函数,用于重载
  virtual eContainerInfo GetContainerInfo(void)const {return eFormUnknown;}
  virtual voidSetContainerInfo(eContainerInfo aInfo) { }
 
protected:
};
 
 
//下面我们来看非常重要的一个类CStartToken,顾名思义他是定义了起始型标签的数据结构,包括它所有的方法,属性等等。
 
/**
 *  Thisdeclares start tokens, which always take the form <xxxx>.
 *  Thisclass also knows how to consume related attributes.
 *
 * @update  gess 3/25/98
 */
//下面的这段代码声明了起始型的Tokens,它们都是采用<xxxx>的格式。这个类同样还知道如何对相关属性进行解析。
classCStartToken: public CHTMLToken {
 CTOKEN_IMPL_SIZEOF
 
public:
 CStartToken(eHTMLTags aTag=eHTMLTag_unknown);    //构造方法,参数为eHTMLTags,其值默认为未知类型
 CStartToken(const nsAString&aString);  //第二种构造方法,用字符串作为参数
 CStartToken(const nsAString&aName,eHTMLTags aTag);   //第三种构造方法,用字符串外带一个aTag作为参数。
     //下面的全部都是虚方法
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode); //解析扫描器中当前这段代码。
  virtual PRInt32 GetTypeID(void);   //获取类型ID
  virtual PRInt32 GetTokenType(void);     //获取Token的类型
 
  virtual PRBool IsEmpty(void);  //判断是否是空
  virtual voidSetEmpty(PRBool aValue);   //设置为空
 
  virtual constnsSubstring& GetStringValue(); //获取字符串形式的值
  virtual voidGetSource(nsString& anOutputString); //获取源代码,并输入到anOutputString中
  virtual voidAppendSourceTo(nsAString& anOutputString);    //添加源代码到anOutputString中
 
  // the following info is used to set well-formedness stateon start tags...
 //下面这段信息是用来设置起始型Tags上的良构状态的
  virtual eContainerInfo GetContainerInfo(void)const {return mContainerInfo;}
//获取当前的容器信息
  virtual voidSetContainerInfo(eContainerInfo aContainerInfo) {
     //设置当前的容器信息,如果当前容器信息为未知类型的花,那么就将其进行设置,意思是说只有在类型未知的情况下才能对其进行设置
   if (eFormUnknown==mContainerInfo) {
     mContainerInfo=aContainerInfo;
   }
 }
//判断是否是良构的
  virtual PRBool IsWellFormed(void)const {
   return eWellFormed == mContainerInfo;
 }
     //注意这个数据成员是public的
 nsString mTextValue;
protected:
 eContainerInfo mContainerInfo; //存放当前Token的容器信息
 PRPackedBool mEmpty; //存放当前Token是否是空
#ifdefDEBUG
  PRPackedBool mAttributed;
#endif
};
 
//下面我们来看和上面这个起始型Token相对应的结束型Token。
 
/**
 *  Thisdeclares end tokens, which always take the
 *  form</xxxx>. This class also knows how to consume
 * related attributes.
 *
 * @update  gess 3/25/98
 */
//下面这段代码声明了结束型的Token,它们都是采用</xxxx>的形式。这个类同时还知道如何去解析相关的属性。
classCEndToken: public CHTMLToken {
 CTOKEN_IMPL_SIZEOF
 
public:
 CEndToken(eHTMLTags aTag);     //构造方法
 CEndToken(const nsAString& aString);    //构造方法,用字符串做参数
 CEndToken(const nsAString&aName,eHTMLTags aTag);     //和前面的起始型Token的构造方法结构一样
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode); //对当前扫描器中的字符进行解析
  virtual PRInt32 GetTypeID(void);   //获取类型ID
  virtual PRInt32 GetTokenType(void);     //获取Token的类型
 
  virtual constnsSubstring& GetStringValue();     //获取字符值
  virtual voidGetSource(nsString& anOutputString); //获取源代码
  virtual voidAppendSourceTo(nsAString& anOutputString);    //输出源代码
 
protected:
 nsString mTextValue; //注意这个数据成员变成受保护类型的了,起始型标签的是public,可以思考一下为什么
};
 
//下面这个声明的是注释型标签
 
/**
 *  Thisdeclares comment tokens. Comments are usually
 * thought of as tokens, but we treat them that way
 *  hereso that the parser can have a consistent view
 *  ofall tokens.
 *
 * @update  gess 3/25/98
 */
//下面这段代码声明了注释型标签的数据结构。注释通常被当做Token来对待,但是我们在这里这样对他们进行处理,以便Parser能够对所有的Tokens都有一致的认识。
classCCommentToken: public CHTMLToken {
 CTOKEN_IMPL_SIZEOF   //参见nsToken.h文件,预先#define的一个语句
 
public:
 CCommentToken();     //构造方法
 CCommentToken(const nsAString&aString);     //构造方法,采用字符串作为参数
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode); //标准的解析方法,对扫描器当前的字符串进行解析
  virtual PRInt32 GetTokenType(void);     //获取Token的类型
  virtual constnsSubstring& GetStringValue(void); //获取字符串类型的值
  virtual voidAppendSourceTo(nsAString& anOutputString);    //输出源代码到字符串
 nsresult ConsumeStrictComment(nsScanner& aScanner);   //解析strict类型的注释
 nsresult ConsumeQuirksComment(nsScanner& aScanner);   //解析quirks类型的注释
     //上面的strict和quirks是根据DTD不同而不同的两种解析模式。
protected:
 nsScannerSubstring mComment; // does notinclude MDO & MDC
 nsScannerSubstring mCommentDecl; // includesMDO & MDC
};
 
//下面是用来存放实体类型的Token的类的声明。
/**
 *  Thisclass declares entity tokens, which always take
 *  theform &xxxx;. This class also offers a few utility
 * methods that allow you to easily reduce entities.
 *
 * @update  gess 3/25/98
 */
classCEntityToken : public CHTMLToken {
 CTOKEN_IMPL_SIZEOF   //预先的#define语句,请参见nsToken.h
 
public:
 CEntityToken();  //构造方法
 CEntityToken(const nsAString&aString); //构造方法,用字符串做为参数
  virtual PRInt32 GetTokenType(void);     //获取Token的类型
 PRInt32 TranslateToUnicodeStr(nsString& aString);     //将字符串编码转换为Unicode的方法
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode); //主要解析方法,从当前扫描器的当前位置开始解析
  static nsresult ConsumeEntity(PRUnichar aChar,nsString& aString,
                                nsScanner&aScanner);   //解析实体用的方法,注意参数的区别
  static PRInt32 TranslateToUnicodeStr(PRInt32aValue,nsString& aString);
     //转换字符串为Unicode编码,注意参数和前面方法的不同
  virtual constnsSubstring& GetStringValue(void); //获取字符串的值
  virtual voidGetSource(nsString& anOutputString); //获取源代码
  virtual voidAppendSourceTo(nsAString& anOutputString);    //输出源代码到目标字符串
 
protected:
 nsString mTextValue; //注意这里也是受保护的数据类型
};
 
 
//下面是存放空格字符类型Token的类。
/**
 * Whitespace tokens are used where whitespace can be
 * detected as distinct from text. This allows us to
 * easily skip leading/trailing whitespace when desired.
 *
 * @update  gess 3/25/98
 */
//空格类型字符的Token是在当空格能够被和文本区分地监测出来的时候所使用。这使得我们可以在需要的时候轻易地跳过那些开头/结尾的空格。
classCWhitespaceToken: public CHTMLToken {
 CTOKEN_IMPL_SIZEOF   //预先#define的语句,请参考nsToken.h
 
public:
 CWhitespaceToken();  //构造方法
 CWhitespaceToken(const nsAString&aString);  //构造方法,用字符串作为参数
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode); //主要解析方法
  virtual PRInt32 GetTokenType(void);     //获取Token的类型
  virtual constnsSubstring& GetStringValue(void); //获取字符串的值
 
protected:
 nsScannerSharedSubstring mTextValue;    //受保护类型的数据成员,存放文本值
};
 
 
//下面是用来存放普通文本的Token的类的声明
/**
 *  Texttokens contain the normalized form of html text.
 *  Thesetokens are guaranteed not to contain entities,
 *  startor end tags, or newlines.
 *
 * @update  gess 3/25/98
 */
//文本Tokens包含普通格式的html文本,这些Token保证不会包含任何的实体数据,起始或结束标签,或者新行。
classCTextToken: public CHTMLToken {
 CTOKEN_IMPL_SIZEOF   //预先#define的方法,请参见nsToken.h
 
public:
 CTextToken();    //构造方法
 CTextToken(const nsAString&aString);   //使用字符串作为参数的构造方法
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode);
//主要解析方法,从当前扫描器的当前位置开始进行解析
  virtual PRInt32 GetTokenType(void);     //获取Token的类型
  virtual PRInt32 GetTextLength(void);    //获取文本的长度
  virtual voidCopyTo(nsAString& aStr);   //拷贝文本到字符串
  virtual constnsSubstring& GetStringValue(void); //获取字符串值
     //绑定文本到扫描器的起始和结束位置
  virtual voidBind(nsScanner* aScanner, nsScannerIterator& aStart,  
                    nsScannerIterator&aEnd);
     //绑定到字符串
  virtual void Bind(const nsAString& aStr);
     //解析字符类型的数据,注意参数的作用
 nsresult ConsumeCharacterData(PRBool aIgnoreComments,
                                nsScanner&aScanner,
                                const nsAString& aEndTagName,
                                PRInt32 aFlag,
                                PRBool&aFlushTokens);
     //解析经过预解析字符类型的数据,注意参数的作用,我们到具体实现的代码时再进行说明
 nsresult ConsumeParsedCharacterData(PRBool aDiscardFirstNewline,
                                      PRBoolaConservativeConsume,
                                     nsScanner& aScanner,
                                      constnsAString& aEndTagName,
                                      PRInt32aFlag,
                                     PRBool& aFound);
 
protected:
 nsScannerSubstring mTextValue; //注意这个数据类型也是受保护的
};
 
//下面是用来存放[!CDATA],即连续型段文本的数据的类。
/**
 * CDATASection tokens contain raw unescaped text content delimited by
 *  a![CDATA[ and ]].
 *  XXXNot really a HTML construct - maybe we need a separation
 *
 * @update  vidur 11/12/98
 */
//CDATA类型的Token包含连续的段文本,它们由![CDATA[ 和 ]]符号进行划分,其实这并不能说是严格意义上的HTML结构—也许我们需要对他们进行一下区分
classCCDATASectionToken : public CHTMLToken {
 CTOKEN_IMPL_SIZEOF
 
public:
 CCDATASectionToken(eHTMLTags aTag = eHTMLTag_unknown);     //构造方法
 CCDATASectionToken(const nsAString&aString);    //构造方法
 
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode); //主要解析方法,从当前解析器的当前位置开始进行解析
  virtual PRInt32 GetTokenType(void);     //获取当前Token的类型
  virtual constnsSubstring& GetStringValue(void); //获取字符串的值
 
protected:
 nsString mTextValue; //受保护类型的数据成员,存放当前文本值
};
 
//下面的类用来存放一些声明型的标签,他们也是被认为是连续型的段文本。
 
/**
 * Declaration tokens contain raw unescaped text content (not really, but
 *  rightnow we use this only for view source).
 *  XXXNot really a HTML construct - maybe we need a separation
 *
 */
//声明类型的Tokens包含连续的纯文本内容(其实并不一定,但是我们目前只有在阅览源代码方式时来使用它)
//并不是一个HTML结构—也许我们需要对其进行一下区分
classCMarkupDeclToken : public CHTMLToken {
 CTOKEN_IMPL_SIZEOF   //预先#define的方法,详情请见nsToken.h
 
public:
 CMarkupDeclToken();  //构造方法
 CMarkupDeclToken(const nsAString&aString);  //构造方法
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode); //解析方法,从当前解析器的当前位置开始进行解析
  virtual PRInt32 GetTokenType(void);     //获取Token类型
  virtual constnsSubstring& GetStringValue(void); //获取字符串的值
 
protected:
 nsScannerSubstring  mTextValue;    //用来存放当前文本的值
};
 
 
//下面是用来存放属性的类。
/**
 * Attribute tokens are used to contain attribute key/value
 *  pairswhereever they may occur. Typically, they should
 *  occuronly in start tokens. However, we may expand that
 * ability when XML tokens become commonplace.
 *
 * @update  gess 3/25/98
 */
//属性tokens是用来包含属性的,其中需要存储属性名/属性值的序对。普通情况下,他们应当只在起始型Tokens中出现。然而,我们可能在今后遇到XML Token的时候扩展这一功能。
classCAttributeToken: public CHTMLToken {
 CTOKEN_IMPL_SIZEOF   //预先#define的代码,详情请参见nsToken.h
 
public:
 CAttributeToken();   //构造方法
 CAttributeToken(const nsAString&aString);   //构造方法
 CAttributeToken(const nsAString&aKey,const nsAString& aString);   //构造方法
 ~CAttributeToken() {}     //析构方法
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode); //主要解析方法,用来解析当前扫描器的当前位置的值
  virtual PRInt32 GetTokenType(void);     //获取Token的类型
  const nsSubstring&     GetKey(void){return mTextKey.AsString(); } //获取Key,即属性名的值
  virtual void SetKey(const nsAString& aKey);  //设置key,即属性名的值
     //绑定Key至扫描器
  virtual voidBindKey(nsScanner* aScanner, nsScannerIterator& aStart,
                       nsScannerIterator&aEnd);
     //获取值,获取当前的文本值
  const nsSubstring& GetValue(void) {returnmTextValue.str();}
     //获取字符串的值
  virtual constnsSubstring& GetStringValue(void);
     //输出源代码到字符串
  virtual voidGetSource(nsString& anOutputString);
     //输出源代码到字符串的尾端
  virtual voidAppendSourceTo(nsAString& anOutputString);
 
 PRPackedBool mHasEqualWithoutValue;     //一个BOOL判断位,从字面上来看应该是判断该属性是否是没有赋值的情况。
protected:
 nsScannerSharedSubstring mTextValue;    //当前的文本值
 nsScannerSubstring mTextKey;   //当前的属性名
};
 
//下面是一个用来存放换行符的类的声明。
/**
 * Newline tokens contain, you guessed it, newlines.
 *  Theyconsume newline (CR/LF) either alone or in pairs.
 *
 * @update  gess 3/25/98
 */
//换行符包含,你猜是什么,当然是换行符。
//他们包含成对或者单独的换行符(CR/LF)
classCNewlineToken: public CHTMLToken {
 CTOKEN_IMPL_SIZEOF   //预先#define的值,详情参见nsToken.h
 
public:
 CNewlineToken();     //构造方法   
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode); //主要的解析方法,从当前扫描器的当前位置进行扫描
  virtual PRInt32 GetTokenType(void);     //获取Token的类型
  virtual constnsSubstring& GetStringValue(void); //获取字符串的值
 
  static void AllocNewline();    //分配新行
  static voidFreeNewline();     //回收新行
};
 
//下面是用来存放指令类型的Token。
/**
 * Whitespace tokens are used where whitespace can be
 * detected as distinct from text. This allows us to
 * easily skip leading/trailing whitespace when desired.
 *
 * @update  gess 3/25/98
 */
//和空格字符Token的代码注释重复了
classCInstructionToken: public CHTMLToken {
 CTOKEN_IMPL_SIZEOF
 
public:
 CInstructionToken();
 CInstructionToken(const nsAString&aString);
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode);
  virtual PRInt32 GetTokenType(void);
  virtual constnsSubstring& GetStringValue(void);
 
protected:
 nsString mTextValue;
};
 
 
//最后一个,就是用来对DOCTYPE进行存放的:
 
/**
 * This token is generated by the HTML andExpat tokenizers
 * when they see the doctype declaration("<!DOCTYPE ... >")
 *
 */
//这个Token是当HTML和Expat分词器看到doctype声明(”<!DOCTYPE…>”)的时候自动生成的
classCDoctypeDeclToken: public CHTMLToken {
 CTOKEN_IMPL_SIZEOF   //预先#define的语句,详情请查看nsToken.h文件
 
public:
 CDoctypeDeclToken(eHTMLTags aTag=eHTMLTag_unknown);   //构造方法
 CDoctypeDeclToken(const nsAString&aString,eHTMLTags aTag=eHTMLTag_unknown); //构造方法
  virtual nsresult Consume(PRUnicharaChar,nsScanner& aScanner,PRInt32 aMode); //主要解析方法,用来从当前的扫描器的当前位置开始进行解析
  virtual PRInt32 GetTokenType(void);     //获取Token的类型
  virtual constnsSubstring& GetStringValue(void); //获取字符串的值
  virtual voidSetStringValue(const nsAString& aStr);   //设置字符串的值
 
protected:
 nsString mTextValue; //受保护的数据类型,用来存放字符值
};
#endif



以上就是所有
nsHTMLToken.h头文件的内容了,可以看到,它主要采用了一个枚举类型集合来声明了所有的HTML标签的类型,这个枚举类型主要用在Allocator中创建并为每个新Token分配内存的时候所使用,并且对每个标签类型定义了它们的基本方法和数据成员,下面,我们就来看看这些方法的具体实现和数据成员的使用。 

 

下面是nsHTMLToken.cpp文件的源代码解析:

#include <ctype.h>
#include <time.h>
#include <stdio.h>
#include "nsScanner.h"
#include "nsToken.h"
include "nsHTMLTokens.h"
#include "prtypes.h"
#include "nsDebug.h"
#include "nsHTMLTags.h"
#include "nsHTMLEntities.h"
#include "nsCRT.h"
#include "nsReadableUtils.h"
#include "
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值