diff --git a/content/tutorials/internals/howbrowserswork/fr/index.html b/content/tutorials/internals/howbrowserswork/fr/index.html new file mode 100644 index 000000000..1a35f9ba5 --- /dev/null +++ b/content/tutorials/internals/howbrowserswork/fr/index.html @@ -0,0 +1,2228 @@ +{% extends "tutorial.html" %} + +{% block iscompatible %} + +{% endblock %} +{% block head %} + + +{% endblock %} + + +{% block content %} +
+

Préface

+

+ Cette introduction détaillée sur les opérations internes de WebKit et Gecko est le résultat de beaucoup de + recherches menées par la développeuse israélienne Tali Garsiel. Durant quelques années, elle a examiné l'ensemble + des données publiées sur les composants internes des navigateurs + (voir les ressources) + et passé beaucoup de temps à lire le code source de navigateurs. Elle écrit : + +

+ À l'époque de la domination d'IE à 90% il n'y avait rien d'autre à faire que de considérer le navigateur comme une + "boîte noire", mais aujourd'hui, avec les navigateurs open représentant plus de la moitié des utilisateurs du marché, c'est + le bon moment pour jeter un œil sous le capot et regarder ce qui se trouve dans un navigateur. Eh bien, ce qu'on y + trouve sont des millions de lignes de C++... +
+ Tali a publié ses recherches sur son site, mais nous savions qu'elles méritaient + une plus large audience, et l'avons donc revu et republié ici. + +

+ En tant que développeur web, apprendre l'interne des opérations d'un navigateur vous aide à prendre de + meilleures décisions et à comprendre les justifications derrière l'apparition de bonnes pratiques. Bien + qu'il s'agisse d'un document plutôt conséquent, nous vous recommandons de passer un peu de temps à le creuser ; + soyez sûr(e) que vous ne le regretterez pas. + + Paul Irish, Relations Développeurs de Chrome +

+ + +
+

+ Cet article a été traduit en différentes langues : HTML5 Rocks héberge les versions en anglais, allemand, espagnol, japonais, portugais, russe et chinois simplifié. Vous pouvez + également lire des traductions stockées ailleurs en coréen et truc . +

+ Vous pouvez aussi regarder Tali Garsiel donnant une conférence sur ce + sujet sur Vimeo: + +

+
+ +
+ +
+ +

Introduction

+

+ Les navigateurs web sont les logiciels les plus utilisés. Dans cette introduction, j'expliquerai comment ils + fonctionnent en réalité. Nous verrons ce qui se passe lorsque vous tapez google.com dans la barre + d'adresse jusqu'à ce qu'apparaisse la page Google sur l'écran du navigateur. +

+ +

Table des matières

+ +
    +
  1. Introduction +
      +
    1. Les navigateurs dont nous allons parler
    2. +
    3. La principale fonctionnalité du navigateur
    4. +
    5. La structure haut niveau du navigateur
    6. +
    +
  2. +
  3. Le moteur de rendu +
      +
    1. Les moteurs de rendu
    2. +
    3. Le flux principal
    4. +
    5. Exemples de flux principaux
    6. +
    +
  4. +
  5. Analyse et construction et l'arbre DOM +
      +
    1. Analyse : généralités +
        +
      1. Grammaires
      2. +
      3. Combinaison analyseur syntatique–analyseur lexical
      4. +
      5. Traduction
      6. +
      7. Exemple d'analyse syntaxique
      8. +
      9. Définitions formelles pour vocabulaire et + syntaxe +
      10. +
      11. Types de analyseurs syntaxiques
      12. +
      13. Générer les parseurs automatiquement
      14. +
      +
    2. +
    3. Analyseur syntaxique HTML +
        +
      1. La définition de grammaire HTML
      2. +
      3. Pas une grammaire non contextuelle
      4. +
      5. DTD HTML
      6. +
      7. DOM
      8. +
      9. L'algorithme de parsing
      10. +
      11. L'algorithme de tokenisation
      12. +
      13. L'algorithme de construction d'arbre
      14. +
      15. Actions lorsque le parsing est terminé
      16. +
      17. Tolérance aux erreurs du navigateur
      18. +
      +
    4. +
    5. Parsing CSS +
        +
      1. Parseur CSS de WebKit
      2. +
      +
    6. +
    7. Ordre des scripts de traitement et des feuilles de + style +
        +
      1. Scripts
      2. +
      3. Parsing spéculatif
      4. +
      5. Feuilles de style
      6. +
      +
    8. +
    +
  6. +
  7. Construction de l'arbre de rendu +
      +
    1. Lien entre l'arbre de rendu et l'arbre DOM
    2. +
    3. Flux de construction de l'arbre
    4. +
    5. Calcul du style +
        +
      1. Partage des données de style
      2. +
      3. Arbre de règles de Firefox +
          +
        1. Division en structures
        2. +
        3. Calculer les contextes de style en + utilisant l'arbre de règles
        4. +
        +
      4. +
      5. Manipuler les règles pour une correspondance + facilitée
      6. +
      7. Appliquer les règles dans le bon ordre de + cascade +
          +
        1. Ordre de cascade de la feuille de style
        2. +
        3. Spécificité
        4. +
        5. Trier les règles
        6. +
        +
      8. +
      +
    6. +
    7. Processus progressif
    8. +
    +
  8. +
  9. Mise en page +
      +
    1. Système de marqueur de changement
    2. +
    3. Positionnement global et incrémental
    4. +
    5. Positionnements asynchrones et synchrones
    6. +
    7. Optimisations
    8. +
    9. Le processus de mise en page
    10. +
    11. Calcul de la largeur
    12. +
    13. Saut de ligne
    14. +
    +
  10. +
  11. Dessin +
      +
    1. Global et incrémental
    2. +
    3. L'ordre de dessin
    4. +
    5. Liste d'affichage de Firefox
    6. +
    7. Stockage de rectangles de WebKit
    8. +
    +
  12. +
  13. Changements dynamiques
  14. +
  15. Les threads du moteur de rendu +
      +
    1. Boucle d'événements
    2. +
    +
  16. +
  17. Modèle visuel de CSS2 +
      +
    1. Le canvas
    2. +
    3. Modèle de boîte CSS
    4. +
    5. Schéma de positionnement
    6. +
    7. Types de boîtes
    8. +
    9. Positionnement +
        +
      1. Relatif
      2. +
      3. Flottant
      4. +
      5. Absolu et fixé
      6. +
      +
    10. +
    11. Représentation en couches
    12. +
    +
  18. +
  19. Ressources
  20. +
+ + +
+ +

Les navigateurs dont nous allons parler

+

+ Cinq grands navigateurs sont utilisés sur les ordinateurs de bureau aujourd'hui : Chrome, Internet Explorer, + Firefox, Safari et Opera. Sur mobile, les principaux navigateurs sont Android Browser, iPhone, Opera Mini et Opera + Mobile, UC Browser, les navigateurs du Nokia S40/S60 browsers et Chrome–tous, à l'exception des navigateurs + Opéra, étant basés sur WebKit. Je donnerai des exemples des navigateurs open source Firefox et Chrome, ainsi que + Safari (qui est en partie open source). Selon StatCounter statistics (en Juin 2013) Chrome, Firefox et Safari représentent + près de 71% de l'utilisation globale des navigateurs sur ordinateur de bureau. Sur mobile, Android Browser, iPhone + et Chrome constituent près de 54% de cette utilisation. +

+ +

La fonctionnalité principale des navigateurs

+

+ La fonctionnalité principale d'un navigateur est de vous présenter la ressource web que vous avez choisie, en la + demandant au serveur et en l'affichant dans la fenêtre de navigation. La ressource en question est généralement un + document HTML, mais pourrait aussi être un PDF, une image, ou n'importe quel autre type de contenu. La localisation + de la ressource est spécifiée par l'utilisateur au travers d'un URI (Identificateur Uniforme de Ressource). +

+

+ La manière dont le navigateur interprète et affiche les fichiers HTML est décrite dans les spécifications HTML et + CSS. Ces spécifications sont maintenues par l'organisation W3C (Consortium World Wide Web), qui est + l'organisation régissant les standards du web. Durant des années les navigateurs ne se sont conformés qu'à une + partie des specifications et ont développé leurs propres extensions. Cela a causé de sérieux problèmes de + compatibilité pour les auteurs de pages web. Aujourd'hui la plupart des navigateurs se conforment plus ou moins à + ces specifications. +

+

+ Les interfaces utilisateur d'un navigateur se ressemblent beaucoup entre elles. Parmi les éléments les plus courants + d'interface utilisateur, on trouve : +

+ +

+ Étonnamment, l'interface utilisateur du navigateur n'est spécifiée dans aucune spécification formelle ; elle émane + just de bonnes pratiques forgées au cours d'années d'expérience et de navigateurs s'imitant les uns-les autres. La + spécification HTML5 ne définit pas les éléments d'IU que doit posséder un navigateur, mais liste certains éléments + courants. Parmi ceux-ci, la barre d'adresse, la barre de statut et la barre d'outils. Il existe, bien sûr, des + fonctionnalités spécifiques à un navigateur donné, comme le gestionnaire de téléchargements de Firefox par exemple. +

+

La structure haut-niveau du navigateur

+

+ Les composants principaux d'un navigateur sont (1.1): +

+ +
    + +
  1. L'interface utilisateur : cela inclut la barre d'adresse, les boutons retour/avant, le menu de + signets, etc. Tout ce qu'affiche le navigateur en dehors de la fenêtre où vous voyez la page demandée.
  2. +
  3. Le moteur de navigation : gère les actions entre l'IU et le moteur de rendu.
  4. +
  5. Le moteur de rendu : responsable de l'affichage du contenu demandé. Par exemple si le contenu + demandé est en HTML, le moteur de rendu analyse le HTML et le CSS, puis affiche le contenu analysé à l'écran.
  6. +
  7. Réseau : pour les appels réseaux comme les requête HTTP, en utilisant des implémentations + différentes pour différentes plates-formes derrière une interface indépendante de la plate-forme.
  8. +
  9. Backend IU : utilisé pour dessiner les composants de base comme des boîtes combo ou des + fenêtres. Ce backend propose une interface générique qui n'est pas spécifique à la plate-forme. Derrière il + utilise des méthodes d'interface utilisateur du système d'exploitation.
  10. +
  11. Interpréteur JavaScript. Utilisé pour analyser syntaxiquement et exécuter le code JavaScript . +
  12. +
  13. Stockage de données. Il s'agit d'une couche de persistance. Le navigateur peut avoir besoin de + sauver toutes sortes de données localement, comme des cookies. Les navigateurs supportent aussi des mécanismes de + stockage comme le localStorage, IndexedDB, WebSQL et le système de fichiers.
  14. + +
+ + +
+ Composants du navigateur +
Figure : Composants du navigateur
+
+ + +

+ Il est important de noter que les navigateurs comme Chrome lancent plusieurs instances du moteur de rendu : une pour + chaque onglet. Chaque onglet s'exécute dans un processus distinct. +

+ +

Le moteur de rendu

+

+ La responsabilité du moteur de rendu est, eh bien... de faire le rendu, c'est-à-dire d'afficher le contenu demandé + dans la fenêtre du navigateur. +

+

+ Par défaut le moteur de rendu peut afficher des documents HTML et XML, ainsi que des images. Il peut afficher + d'autres types de données à l'aide de plug-ins ou d'extensions ; par exemple, afficher des documents PDF en + utilisant un plug-in de visualisation PDF. Cependant, dans ce chapitre nous nous concentrerons sur le cas + d'utilisation principal : afficher du HTML et des images, formatés en utilisant CSS.

+ +

Moteurs de rendu

+

+ Différents navigateurs utilisent des moteurs de rendu différents : Internet Explorer utilise Trident, Firefox + utilise Gecko, Safari utilise WebKit. Chrome et Opera (depuis la version 15) utilisent Blink, un dérivé de WebKit. +

+

+ WebKit est un moteur de rendu open source qui a commencé comme moteur pour la plate-forme Linux puis a été modifié + par Apple pour supporter Mac et Windows. Voir webkit.org pour plus de détails. +

+ +

Le flux principal

+

+ Le moteur de rendu commencera à récupérer le contenu du document demandé en le demandant à la couche réseau. Cela + sera généralement fait par portions de 8 Ko. +

+

+ Après cela, il s'agit du flux de base du moteur de rendu : +

+ +
+ Flux de base du moteur de rendu +
Figure : Flux de base du moteur de rendu
+
+ + +

+ Le moteur de rendu commencera à analyser syntaxiquement le document HTML et à convertir les éléments en nœuds DOM dans un arbre appelé "arbre de contenu". Le moteur analysera syntaxiquement les données de + style, qu'elles viennent de fichiers CSS externes ou d'éléments de style dans le contenu. Les informations de style, + couplées aux instructions visuelles du HTML, seront utilisés pour créer un autre arbre : l'arbre de rendu. +

+

+ L'arbre de rendu contient des rectangles avec des attributs visuels comme la couleur et les dimensions. Les + rectangles sont dans le bon ordre pour être affichés à l'écran. +

+

+ Après sa construction, l'arbre de rendu passe par un processus de "layout". Cela veut dire + donner à chaque nœud les coordonnées exactes de là où il devrait apparaître à l'écran. L'étape suivante est de peindre–l'arbre de rendu va être traversé et chaque nœud sera dessiné en utilisant la + couche de backend IU. +

+

+ Il est important de comprendre qu'il s'agit d'un processus progressif. Pour une meilleure expérience utilisateur, le + moteur de rendu essaiera d'afficher du contenu à l'écran aussi tôt que possible. Il n'attendra pas que tout le HTML + soit analysé avant de construire les arbres de layout et de rendu. Des parties du contenu seront analysées et + affichées, tandis que le processus continuera avec le reste du contenu qui continue à arriver du réseau. +

+ +

Exemples de flux principaux

+ +
+ Flux principal de WebKit +
Figure : Flux principal de WebKit
+
+ + +
+ +
Figure : Flux principal du moteur de rendu Gecko de Mozilla (3.6) +
+
+ + +

+ Les figures 3 et 4 vous montrent que bien que WebKit et Gecko utilisent une terminologie légèrement différente, le + flux reste globalement le même. +

+ Gecko appelle "arbre d'image" l'arbre des éléments visuellement formaté. Chaque élément est une image à afficher. + WebKit utilise le terme de "arbre de rendu", constitué d'"objets de rendu". WebKit utilise le terme de "layout" pour + placer les éléments, tandis que Gecko parle de "Reflux". "Attachement" est le terme utilisé de WebKit pour faire le + lien entre nœuds DOM et information visuelle afin de créer l'arbre de rendu. Une différence non sémantique mineure + est que Gecko dispose d'une couche supplémentaire entre le HTML et l'arbre DOM tree. Il s'agit de "l'entonnoir à + contenu" qui est une fabrique d'éléments DOM. Nous allons parler de chacune des parties du flux : +

+

Analyse–généralités

+

+ L'analyse syntaxique étant un processus particulièrement significatif au sein du moteur de rendu, nous allons + l'examiner un peu plus en détails. Commençons par une petite introduction sur ce type d'analyse. +

+

+ L'analyse syntaxique d'un document implique de le traduire en une structure que le code peut utiliser. Le résultat + d'une analyse est généralement un arbre de nœuds représentant la structure du document. On l'appelle arbre d'analyse + ou arbre syntaxique. +

+ +

+ Par exemple, analyser l'expression 2 + 3 - 1 pourrait retourner cet arbre : + +

+ + +
+ nœud d'arbre d'une expression mathématique +
Figure : nœud d'arbre d'une expression mathématique
+
+ +

Grammaires

+

+ L'analyse syntaxique est basée sur les règles syntaxiques auxquelles obéit le document : le langage ou le format + dans lequel il a été rédigé. Chaque format que vous analysez doit avoir une grammaire déterministe constituée d'un + vocabulaire et de règles de syntaxe. On parle de grammaire non contextuelle. Les langues humaines ne sont pas de tels langages et + ne peuvent donc pas être analysées avec des techniques d'analyse syntaxique conventionnelles. +

+

Combinaison analyse syntaxique–analyse lexicale

+

+ L'analyse peut être séparée en deux sous-processus : l'analyse lexicale et l'analyse syntaxique. +

+

+ L'analyse lexicale est le processus de décomposition de l'entrée en tokens. Les tokens représentent le vocabulaire + du langage : la collection des blocs de construction valides. Pour une langue humaine il s'agira de tous les mots + que l'on peut trouver dans un dictionnaire de cette langue. +

+

+ L'analyse syntaxique est le fait d'appliquer les règles de syntaxe du langage. +

+

+ Les parsers divisent généralement le travail en deux composants : le lexer (parfois appelé tokenizer) qui est + responsable de décomposer l'entrée en tokens valides, et le parseur qui est responsable de la construction de + l'arbre d'analyse en analysant la structure du document en fonction des règles de syntaxe du langage. + + Le lexeur sait comment éliminer les caractères à ne pas prendre en compte comme les espaces et les sauts de ligne. +

+ +
+ du document source aux arbres d'analyse +
Figure : du document source aux arbres d'analyse
+
+ +

+ Le processus d'analyse est itératif. Le parseur demandera généralement au lexeur un nouveau token et essaiera de + faire correspondre le token à une des règles syntaxiques. Si une règle correspond, un nœud correspondant au token + sera ajouté à l'arbre d'analyse et le parseur demandera un autre token. +

+ Si aucune règle ne correspond, le parseur stockera le token en interne, et continuera à demander d'autres tokens + jusqu'à ce qu'une règle correspondant à l'ensemble des tokens stockés en interne soit trouvée. Si aucune règle n'est + trouvée alors le parseur lèvera une exception. Cela signifie que le document n'était pas valide et contenait des + erreurs de syntaxe. +

+

Traduction

+

+ Dans de nombreux cas l'arbre d'analyse n'est pas le produit final. L'analyse est souvent utilisée pour une + traduction : transformer le document d'entrée en un autre format. Un exemple est la compilation. La compilateur qui + compile le code source en code machine commence par l'analyser sous forme d'un arbre d'analyse, puis traduit l'arbre + en un document de code machine. +

+ + +
+ flux de compilation +
Figure : flux de compilation
+
+ + +

Exemple d'analyse

+

+ Dans la figure 5 nous avons construit un arbre d'analyse à partir d'une expression mathématique. Essayons de définir + un langage mathématique simple et voyons le processus d'analyse. +

+

+ Vocabulaire : Notre langage peut inclure des entiers, des signes plus et des signes moins. +

+

+ Syntaxe : +

    +
  1. Les blocs de construction de la syntaxe du langage sont des expressions, des termes et des operations. +
  2. Notre langage peut inclure n'importe quel nombre d'expressions.
  3. +
  4. Une expression est définie comme un "terme" suivi d'une "opération", suivie d'un autre terme
  5. +
  6. Une opération est un token plus ou un token moins
  7. +
  8. Un terme est un token d'entier ou une expression
  9. +
+

+ Analysons l'entrée 2 + 3 - 1.
La première sous-chaîne qui correspond à une règle est 2 + : selon la règle #5 il s'agit d'un terme. La second correspondance est 2 + 3 : cela correspond à la + troisième règle : un terme suivi d'une opération, suivie d'un autre terme. La correspondance suivante n'interviendra + que lorsque la fin de l'entrée sera atteinte. 2 + 3 - 1 est une expression parce que nous savons déjà que + 2 + 3 est un terme, et nous avons donc un terme suivi d'une opération, suivie d'un autre terme. 2 + + + ne correspondra à aucune règle et est donc une entrée invalide. +

+

Définitions formelles pour le vocabulaire et la syntaxe

+

+ Le vocabulaire est généralement exprimée au travers expressions + régulières. +

+

+ Par exemple notre langage sera défini comme : +

+ENTIER: 0|[1-9][0-9]*
+PLUS: +
+MOINS: -
+
+ Comme vous pouvez le voir, les entiers sont définis par une expression régulière.

+ La syntaxe est généralement définie dans un format appelé BNF . Our language will be defined as: +

+expression :=  terme  opération  terme
+opération :=  PLUS | MOINS
+terme := ENTIER | expression
+
+

+ Nous avons dit qu'un langage peut être analysé par des analyseurs syntaxiques réguliers si sa grammaire est une grammaire non contextuelle. Une définition intuitive d'une grammaire non contextuelle + est une grammaire qui peut être entièrement exprimée en BNF. Pour une définition formelle, voir l'article de Wikipedia sur les grammaires non + contextuelles +

Types d'analyseurs

+

+ Il existe deux types d'analyseurs : les analyseurs descendants et les analyseurs ascendants. Une explication + intuitive est que les analyseurs descendants examinent la structure de haut niveau de la syntaxe et tentent de + trouver une règle qui corresponde. Les analyseurs ascendants commençent par l'entrée et la transforment + progressivement dans les règles de syntaxe, en commeçant par les règles de bas niveau, jusqu'à trouver des + correspondance avec les règles de haut niveau. +

+

+ Voyons comme les deux types d'analyseurs syntaxiques vont traiter notre exemple. +

+

+ L'analyseur descendant va commencer par la règle de plus haut niveau : il va identifier 2 + 3 comme une + expression. Il va alors identifier 2 + 3 - 1 comme une expression (le processus d'identifier + l'expression évolue, en faisant correspondre les autres règles, mais le point de départ est la règle de plus haut + niveau). +

+

+ L'analyseur ascendant va scruter l'entrée jusqu'à ce qu'une règle corresponde. Il va alors remplacer l'entrée + correspondante par la règle. Cela va continuer ainsi jusqu'à la fin de l'entrée. L'expression correspondant + partiellement est placée sur la pile de l'analyseur. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PileEntrée
 2 + 3 - 1
terme + 3 - 1
terme opération 3 - 1
expression- 1
expression opération1
expression -
+ Ce type d'analyseur ascendant est appelé analyseur lecture-réduction, parce que l'entrée est lue et décalée vers la + droite (imaginez un pointeur commençant au début de l'entrée puis se déplaçant vers la droite) puis est + progressivement réduite à des règles de syntaxe.

+

Générer automatiquement des analyseurs

+

+ Des outils existent pour générer un analyseur syntaxiques. Vous leur donner la grammaire de votre langage–son + vocabulaire et ses règles de syntaxe–et ils génèrent un analyseur opérationnel. Créer un parseur demande une + compréhension approfondie de l'analyse syntaxique et il n'est pas aisé de créer un analyseur syntaxique soi-même ; + les générateurs de tels analyseurs sont donc très utiles. +

+

+ WebKit utilise deux générateurs d'analyseurs syntaxique bien connus : Flex pour créer un analyseur lexical, et Bison pour créer un analyseur syntaxique (il est possible que vous + les trouviez sous les noms de Lex et Yacc). L'entrée de Flex est un fichier contenu les définitions d'expressions + régulières des tokens. L'entrée de Bison est l'ensemble des règles de syntax du langage, au format BNF. +

+

Analyseur syntaxique HTML

+

+ Le rôle de l'analyseur syntaxique HTML est d'analyser les balises HTML sous forme d'arbre d'analyse. +

+

Définition de la grammaire HTML

+

+ Le vocabulaire et la syntaxe du HTML sont définis dans les specifications créées par + l'organisation W3C. +

+

Pas une grammaire non contextuelle

+

+ Comme nous l'avons vu dans l'introduction sur l'analyse syntaxique, la syntaxe de la grammaire peut être définie + formellement en utilisant des formats comme la BNF. +

+

+ Malheureusement tous les sujets d'un analyseur conventionnel ne s'appliquent pas au HTML (je ne les ai pas mentionné + juste pour le plaisir–ils seront utilisés dans l'analyse syntaxique du CSS et du JavaScript). HTML ne peut pas + être facilement défini avec la grammaire non contextuelle dont les analyseurs syntaxiques ont besoin. +

+

+ Il existe un format formel pour définit l'HTML–la DTD (Définition de Typ de Document)–mais il ne s'agit + pas d'une grammaire non contextuelle. +

+

+ Cela semble étrange au premier abord ; le HTML est plutôt proche du XML. Il existe beaucoup d'analyseurs syntaxique + pour XML. Il existe une variation XML du HTML–XHTML–alors quelle est la grosse différence ? +

+

+ La différence est que l'approche du HTML est plus "permissive" : elle vous laisse omettre certains tags (qui sont + alors ajoutés implicitement), ou parfois omettre des tags ouvrants ou fermants, etc. Dans l'ensemble c'est une + syntaxe "gentille", contrairement à la syntaxe rigide et exigeante du XML. +

+

+ Ce détail en apparence anodin change en fait tout. D'un côté c'est la principale raison à la popularité de HTML : il + vous pardonne vos erreurs et facilite la vie du créateur de contenu web. D'un autre côté, il rend difficile d'écrire + une grammaire formelle. Donc pour résumer, HTML ne peut être facilement analysé syntaxiquement en utilisant des + analyseurs syntaxiques conventionnels, parce que sa grammaire n'est pas non contextuelle. HTML ne peut être analysé + syntaxiquement par des analyseurs syntaxiques XML. +

+

DTD HTML

+

+ La définition de HTML est au format DTD. Ce format est utilisé pour définir des langages de la famille SGML. Le format contient les + définitions de tous les éléments autorisés, leurs attributs et leur hiérarchie. Comme nous l'avons vu auparavant, la + DTD HTML ne forme pas une grammaire non contextuelle. +

+

+ Il existe quelques variations de la DTD. Le mode strict se conforme uniquement aux spécifications mais d'autres + modes contiennent un support de balises utilisées par des navigateurs dans le passé. Le but est la compatibilité + ascendante avec des contenus plus anciens. La DTD stricte actuelle est ici : www.w3.org/TR/html4/strict.dtd +

+

DOM

+

+ L'arbre de sortie (l'"arbre d'analyse") est un arbre d'attributs et éléments DOM. DOM est l'abbréviation de Modèle Objet de Document. C'est la représentation + objet du document HTML et l'interface des éléments HTML avec le monde extérieur comme JavaScript.
La racine de + l'arbre est l'objet "Document". +

+

+ Le DOM a presque une relation un-pour-un avec les balises. Par exemple : +

+<html>
+  <body>
+    <p>
+      Hello World
+    </p>
+    <div> <img src="example.png"/></div>
+  </body>
+</html>
+
+ Ces balises seraient traduites en l'arbre DOM suivant :

+ +
+ Arbre DOM des balises d'exemple +
Figure : Arbre DOM des balises d'exemple
+
+ +

+ Comme HTML, le DOM est spécifié par l'organisation W3C. Voir www.w3.org/DOM/DOMTR. + Il s'agit d'une spécification générique pour manipuler les documents. Un module spécifique décrit les éléments HTML + en particulier. Les définitions HTML peuvent être trouvées ici : www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/idl-definitions.html. +

+

+ Quand je dis que l'arbre contient des nœuds DOM, je veux dire que l'arbre est construit avec des éléments qui + implémentent une des interfaces du DOM. Les navigateurs utilisent des implémentations concrètes qui ont d'autres + attributs utilisés par le navigateur en interne. +

+

L'algorithme d'analyse syntaxique

+

+ Comme nous l'avons vu dans les sections précédentes, HTML ne peut être analysé syntaxiquement en utilisant les + analyseurs syntaxiques normaux descendants ou ascendants. +

+

+ Les raisons sont : +

    +
  1. La nature permissive du langage.
  2. +
  3. Le fait que les navigateurs ont une tolérance aux erreurs traditionnelle pour supporter des cas de HTML invalide + bien connus.
  4. +
  5. Le processus d'analyse syntaxique est réentrant. Pour d'autres langages, la source ne change pas durant + l'analyse, mais en HTML, du code dynamique (tel que des éléments de script contenant des appels à document.write()) + peut ajouter de nouveaux tokens, et le processus d'analyse syntaxique modifie donc en fait l'entrée.
  6. +
+

+ Ne pouvant utiliser les techniques d'analyse syntaxique normales, les navigateurs créent des analyseurs syntaxiques + spécifiques pour l'analyse du HTML. +

+

+ L'algorithme d'analyse syntaxique + est décrit en détail par la spécification HTML5. L'algorithme consiste en deux étapes : la tokenisation et la + construction d'arbre. +

+ La tokenisation est l'analyse lexicale, qui analyse l'entrée sous forme de tokens. Parmi les tokens HTML se trouvent + des balises ouvrantes, fermantes, des noms et valeurs d'attributs. +

+

+ Le tokeniser reconnait le token, le donne au constructeur d'arbre, et consomme le prochain caractère pour + reconnaître le prochain token, et ainsi de suite jusqu'à la fin de l'entrée. +

+ +
+ flux d'analyse HTML (tiré de la spéc HTML5) +
Figure : flux d'analyse HTML (tiré de la spéc HTML5)
+
+ +

L'algorithme de tokenisation

+

+ La sortie de l'algorithme est un token HTML. L'algorithme est exprimé comme une machine à état. Chaque état consomme + un ou plusieurs caractères du flux d'entrée et met à jour l'état suivant en fonction de ces caractères. La décision + est influencée par l'état courant de tokenisation et par l'état de construction de l'arbre. Cela signifie que le + même caractère consommé donnera des résultats différents pour le prochain état correct, en fonction de l'état en + cours. L'algorithme est trop complexe pour être complètement décrit, donc voyons un exemple simple qui nous aidera à + comprendre le principe. + +

+

+ + Exemple de base–tokeniser le HTML suivant : + +

+ +
+<html>
+  <body>
+    Hello world
+  </body>
+</html>
+
+ +

+ + L'état initial est l'"état donnée". Lorsque le caractère < est rencontré, l'état est changé en "état + balise ouverte". Consommer un caractère a-z provoque la création d'un "Token de début de balise", + et l'état est changé en "état nom de tag". Nous restons dans cet état jusqu'à ce que le caractère + > soit consommé. Chaque caractère est ajouté au nouveau nom de token. Dans notre cas le token créé + est un token html. + +

+

+ + Lorsque la balise > est atteinte, le token en cours est émis et l'état revient à l'"état + donnée". La balise <body> sera traitée au travers des mêmes étapes. Jusqu'ici les balises + html et body ont été émises. Nous sommes maintenant de retour dans l'"état donnée". + Consommer le caractère H de Hello world provoquera la création et l'émission d'un token de + caractère, ceci jusqu'à ce que le < de </body> soit atteint. Nous émettrons un + token caractère pour chaque caractère de Hello world. + +

+

+ + Nous sommes maintenant revenus dans l'"état balise ouverte". Consommer la prochain entrée / + provoquera la création d'un token de balise fermante et un déplacement vers l'"état nom de + balise". À nouveau nous restons dans cet état jusqu'à atteindre >. Puis le nouveau token de + balise sera émis et nous retournerons à l'"état donnée". L'entrée </html> sera traitée + comme le cas précédent. + +

+ +
+ Tokeniser l'entrée d'exemple +
Figure : Tokeniser l'entrée d'exemple
+
+ +

Algorithme de construction d'arbre

+

+ Lorsque l'analyseur syntaxique est créé l'objet Document est créé. Lors de la phase de construction d'arbre l'arbre + DOM avec le Document à sa racine sera modifié et des éléments y seront ajoutés. Chaque nœud émis par le tokeniser + sera traité par le constructeur d'arbre. Pour chaque token la spécification définit quel élément du DOM est adapté + et sera créé pour ce token. L'élément est ajouté à l'arbre DOM, ainsi qu'à la pile des éléments ouverts. Cette pile + est utilisée pour corriger les incohérences d'imbrication et les balises non fermées. L'algorithme est également + décrit comme une machine à état. Les états sont appelés "nœuds d'insertion". +

+ +

+ Voyons le processus de construction d'arbre pour l'entrée d'exemple : +

+ + +
+<html>
+  <body>
+    Hello world
+  </body>
+</html>
+
+ +

+ L'entrée de la construction d'arbre est une séquence de tokens issue d'étape de tokenisation. Le premier mode est le + "mode initial". Recevoir le token "html" provoquera un passage dans le mode "avant html" et un + retraitement du token dans ce mode. Cela provoquera la création de l'élément HTMLHtmlElement, qui sera ajouté à + l'objet racine Document. + +

+

+ + L'état sera changé en "avant en-tête". Le token "body" est alors reçu. Un HTMLHeadElement sera créé + implicitement bien que nous n'ayons pas de token "head" et sera ajouté à l'arbre. + +

+

+ + Nous passons maintenant en mode "dans l'en-tête" puis dans "après en-tête". Le token body est + retraité, un HTMLBodyElement est créé et inséré et le mode est changé à to "dans corps de document". + +

+

+ + Les tokens caractères de la chaîne "Hello world" sont maintenant reçus. Le premier provoquera la création et + l'insertion d'un nœud "Texte" et les autres caractères seront ajoutés à ce nœud. + +

+

+ + La réception du token de fin de body provoquera un passage dans le mode "après corps de document". Nous + recevrons maintenant la balise de fin de html qui nous placera dans le mode "après après corps de document". + Recevoir le token de fin de fichier terminera l'analyse syntaxique. +

+ +
+ Construction d'arbre du html d'exemple +
Figure : construction d'arbre du html d'exemple
+
+ + +

Actions lorsque l'analyse syntaxique est terminée

+

+ À cette étape le navigateur marquera le document comme interactif et commencera à analyser les scripts qui sont en + mode "deferred" : ceux qui doivent être exécutés après l'analyse du document. L'état du document sera alors fixé à + "complet" et un événement "load" va être émis. +

+ +

+ Vous pouvez voir les algorithmes complets de + tokenisation et construction d'arbre dans la spécification HTML5 +

+ +

Tolérance aux erreurs des navigateurs

+

+ Vous n'aurez jamais d'erreur "Syntaxe invalide" dans une page HTML. Les navigateurs corrigent tout contenu invalide + et poursuivent leur analyse. + +

+

+ Prenez ce HTML par exemple : + +

+ +
+<html>
+  <mytag>
+  </mytag>
+  <div>
+  <p>
+  </div>
+    Really lousy HTML
+  </p>
+</html>
+
+ +

+ + Je dois avoir violé près d'un million de règles ("mytag" n'est pas une balise standard, mauvaise imbrication des + éléments "p" et "div", etc.) mais le navigateur l'affiche toujours correctement et ne se plaint de rien. Donc une + bonne partie du code de l'analyseur syntaxique consiste à corriger les erreurs de l'auteur du code HTML. + +

+

+ + La gestion d'erreurs est relativement uniforme dans les navigateurs, mais assez incroyablement elle n'a pas été + incluse dans les spécifications HTML. Tout comme les signets et les boutons retour/avant, c'est juste quelque chose + qui s'est développé dans les navigateurs au fil des années. Il y a des constructions HTML invalides qui sont + répétées dans de nombreux sites, et les navigateurs tentent de les corriger d'une manière similaire à ce que font + d'autres navigateurs. + +

+ +

+ La spécification HTML5 définit certaines de ces attentes (WebKit résume bien cela dans le commentaire au début de la + classe de l'analyseur syntaxique HTML). +

+ +
+

L'analyseur syntaxique analyse l'entrée tokenisée dans le document, construisant l'arbre du document. Si le + document est bien formé, son analyse est rapide.

+ +

Malheureusement, nous devons supporter de nombreux documents HTML qui ne sont pas bien formés, et l'analyseur + syntaxique doit donc être tolérant aux erreurs.

+ +

Nous devons prêter attention au moins aux conditions d'erreur suivantes :

+ +
    +
  1. L'élément que l'on tente d'ajouter est explicitement interdit à l'intérieur d'une balise parente. Dans ce cas + nous devrions fermer toutes les balises jusqu'à celle qui interdit l'élément, et l'ajouter à la suite.
  2. +
  3. Nous n'avons pas le droit d'ajouter l'élément directement. Il se pourrait que la personnes rédigeant le + document a oublié une balise au milieu (ou que la balise au milieu est optionnelle). Ce pourrait être le cas + avec les balises suivantes : HTML HEAD BODY TBODY TR TD LI (en ai-je oublié ?).
  4. +
  5. Nous voulons ajouter un élément de type bloc dans un élément inline. Ferme tous les éléments inline jusqu'au + prochain élément bloc de plus haut niveau.
  6. +
  7. Si ça n'aide pas, fermer les éléments jusqu'à ce qu'il soit autorisé d'ajouter l'élément–ou ignorer la + balise.
  8. +
+ +
+ +

+ Voyons quelques exemples de tolérance aux erreurs de WebKit : +

+

</br> au lieu de <br>

+

+ Certains sites utilisent </br> au lieu de <br>. Afin d'être compatible avec IE et Firefox, WebKit traite + cela comme <br>.
Le code : +

+if (t->isCloseTag(brTag) && m_document->inCompatMode()) {
+     reportError(MalformedBRError);
+     t->beginTag = true;
+}
+
+ Notez que la gestion d'erreur est interne : elle ne sera pas présentée à l'utilisateur.

Un tableau égaré

+

+ Un tableau égaré est un tableau dans un autre tableau, mais pas à l'intérieur d'une cellule de tableau. +

+

Par exemple :

+
+<table>
+    <table>
+        <tr><td>tableau interne</td></tr>
+    </table>
+    <tr><td>tableau externe</td></tr>
+</table>
+
+ WebKit changera cette hiérarchie en deux tableaux voisins : +
+<table>
+    <tr><td>tableau externe</td></tr>
+</table>
+<table>
+    <tr><td>tableau interne</td></tr>
+</table>
+
+ Le code : +
+if (m_inStrayTableContent && localName == tableTag)
+        popBlock(tableTag);
+
+ WebKit utilise une pile pour le contenu de l'élément courant : il dépilera le tableau interne hors de la pile du + tableau externe. Les tableaux seront alors frères.

Éléments formulaires imbriqués

+

+ Au cas où l'utilisateur place un formulaire dans un autre formulaire, le second formulaire est ignoré.
Le code + : +

+if (!m_currentFormElement) {
+        m_currentFormElement = new HTMLFormElement(formTag,    m_document);
+}
+
+

Une hiérarchie de balises trop profonde

+

+ Le commentaire parle de lui-même.
+

+
+ www.liceo.edu.mx est un exemple de site arrivant à imbriquer près de 1500 balises, tous à partir d'un tas de + <b>s. Nous n'autoriserons tout au plus que 20 balises imbriquées du même type avant de simplement toutes les + ignorer. +
+
+
+bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName)
+{
+
+unsigned i = 0;
+for (HTMLStackElem* curr = m_blockStack;
+         i < cMaxRedundantTagDepth && curr && curr->tagName == tagName;
+     curr = curr->next, i++) { }
+return i != cMaxRedundantTagDepth;
+}
+
+

Balises fermantes html ou body mal placées

+

+ Encore une fois–le commentaire parle de lui-même. + +

+ Support de HTML vraiment cassé. Nous ne fermons jamais la balise body, car certaines pages web stupides la ferment + avant la réelle fin du doc. Fions-nous à l'appel à end() pour fermer les choses. +
+ +
+if (t->tagName == htmlTag || t->tagName == bodyTag )
+        return;
+
+
+ Donc attentions auteurs du web–à moins que vous ne vouliez apparaître comme exemple dans un extrait de code de + tolérance aux erreurs de WebKit–rédigez du HTML bien formé.

+

Analyse syntaxique de CSS

+

+ Vous vous souvenez des concepts d'analyse syntaxique dans l'introduction ? Eh bien, contrairement à HTML, CSS est + une grammaire non contextuelle et peut être analysé en utilisant les types d'analyseurs décrits dans l'introduction. + En fait les spécification CSS définissent la grammaire lexicale et + syntaxique de CSS. +

+

+ Voyons quelques exemples :
La grammaire lexicale (le vocabulaire) est définie par les expressions régulières de + chaque token : +

+comment   \/\*[^*]*\*+([^/*][^*]*\*+)*\/
+num   [0-9]+|[0-9]*"."[0-9]+
+nonascii  [\200-\377]
+nmstart   [_a-z]|{nonascii}|{escape}
+nmchar    [_a-z0-9-]|{nonascii}|{escape}
+name    {nmchar}+
+ident   {nmstart}{nmchar}*
+
+

+ "ident" est l'abréviation de identificateur, comme un nom de classe par exemple. "name" est un identifiant d'élément + (référencé par "#" ) +

+

+ La grammaire syntaxique est décrite en BNF. +

+ruleset
+  : selector [ ',' S* selector ]*
+    '{' S* declaration [ ';' S* declaration ]* '}' S*
+  ;
+selector
+  : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]?
+  ;
+simple_selector
+  : element_name [ HASH | class | attrib | pseudo ]*
+  | [ HASH | class | attrib | pseudo ]+
+  ;
+class
+  : '.' IDENT
+  ;
+element_name
+  : IDENT | '*'
+  ;
+attrib
+  : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
+    [ IDENT | STRING ] S* ] ']'
+  ;
+pseudo
+  : ':' [ IDENT | FUNCTION S* [IDENT S*] ')' ]
+  ;
+
+ Explication : un ensemble de règles est cette structure : +
+div.error, a.error {
+  color:red;
+  font-weight:bold;
+}
+
+ div.error et a.error sont des sélecteurs. La partie à l'intérieur des accolades contient les règles qui sont + appliquées par cet ensemble. Cette structure est définie formellement dans cette définition : +
+ruleset
+  : selector [ ',' S* selector ]*
+    '{' S* declaration [ ';' S* declaration ]* '}' S*
+  ;
+
+ Cela signifie qu'un ensemble de règles est un sélecteur ou éventuellement un certain nombre de sélecteurs séparés par + une virgule et des espaces (S veut dire espace). Un ensemble de règles contient des accolades et à l'intérieur de + celles-ci une déclaration ou éventuellement une série de déclarations séparées par un point-virgule. "declaration" et + "selector" seront définis dans les définitions BNF suivantes.

+

Analyse syntaxique de CSS par WebKit

+

+ WebKit utilise les générateurs d'analyseurs syntaxiques Flex et Bison pour créer + des parseurs automatiquement à partir de fichiers de grammaire CSS. Comme vous vous en souvenez lors de + l'introduction à l'analyse syntaxique, Bison crée un analyseur syntaxique ascendant de type lecture-réduction. + Firefox utilise un analyseur syntaxique descendant écrit à la main. Dans les deux cas chaque fichier CSS est analysé + pour produire un objet StyleSheet. Chaque objet contient des règles CSS. Les objets de type règle CSS contiennent un + sélecteur et des objets de déclarations ainsi que d'autres objets correspondant à la grammaire CSS. +

+ +
+ Analyse syntaxique du CSS +
Figure : analyse syntaxique du CSS
+
+ + +

Ordre de traitement des scripts et des feuilles de style +

+

Scripts

+

+ Le modèle du web est synchrone. Les auteurs s'attendent à ce que les scripts soient analysés et exécutés + immédiatement lorsque l'analyseur syntaxique trouve une balise <script>. L'analyse syntaxique du document + s'interrompt jusqu'à ce que le script ait été exécuté. Si le script est externe alors la ressource doit d'abord être + téléchargée depuis le réseau–ce qui est aussi fait de manière synchrone, et l'analyse s'interrompt jusqu'à ce + que la ressource soit récupérée. Ce fut le modèle pendant de nombreuses années et c'est aussi indiqué dans les + spécifications HTML4 et 5. Les auteurs peuvent ajouter l'attribut "defer" à un script, auquel cas il n'interrompra + pas l'analyse du document et s'exécutera après que le document ait été analysé. HTML5 ajoute une option pour marquer + le script comme asynchrone afin qu'il soit analysé et exécuté par un thread différent. +

+

Analyse spéculative

+

+ WebKit come Firefox font cette optimisation. Lorsqu'ils exécutent des scripts, un autre thread analyse le reste du + document et cherche quelles autres ressources doivent être chargées du réseau et les charge. De cette manière, les + ressources peuvent être chargées sur des connexions parallèles et la vitesse globale améliorée. Note : l'analyseur + spéculatif n'analyse que les références à des ressources externes comme les feuilles de style, les images et les + scripts externes : il ne modifie pas l'arbre DOM–cela reste le travail de l'analyseur principal. +

+

Feuilles de style

+

+ Les feuilles de style d'un autre côté ont un modèle différent. Conceptuellement il semble que puisque les feuilles + de style ne changent pas l'arbre DOM, il n'y a aucune raison d'interrompre l'analyse du document pour les attendre. + Il y a la question, cependant, des scripts demandant des informations sur les styles pendant la phase d'analyse du + document. Si le style n'est pas encore chargé et analysé, le script récupèrera des réponses incorrectes et cela a + apparemment causé beaucoup de problèmes. Cela semble être un cas rare mais c'est en fait assez courant. Firefox + bloque tous les scripts lorsqu'une feuille de style est en cours de chargement et d'analyse. WebKit ne bloque les + scripts que lorsqu'ils tentent de lire certaines propriétés de style qui pourraient être affectées par des feuilles + de style non chargées. +

+

Construction de l'arbre de rendu

+

+ Pendant que l'arbre DOM est construit, la navigateur construit un autre arbre, l'arbre de rendu. Cet arbre est + constitué d'éléments visuels, dans l'ordre où ils seront affichés. C'est la représentation visuelle du document. Le + but de cet arbre est de permettre de dessiner les contenus dans leur ordre correct. +

+

+ Firefox appelle "frames" les éléments de l'arbre de rendu. WebKit utilise le terme de rendu ou objet de rendu.
+ Un rendu sait comment s'agencer et se dessiner lui et ses éléments fils.
La classe RenderObject de WebKit, la + base de tous les rendus, a la définition suivante : +

+class RenderObject{
+  virtual void layout();
+  virtual void paint(PaintInfo);
+  virtual void rect repaintRect();
+  Node* node;  //the DOM node
+  RenderStyle* style;  // le style calculé
+  RenderLayer* containgLayer; //the containing z-index layer
+}
+
+

+ Chaque rendu représente une zone rectangulaire correspondant généralement à la boîte CSS d'un nœud, comme c'est décrit + dans la spec CSS2. Cela inclut des informations géometriques comme la largeur, la hauteur et la position.
Le type + de boîte dépend de la valeur "display" de l'attribut de style associé au nœud (voir la section de calcul du style). Voici le code de WebKit pour décider quel type de rendu devrait être + créé pour un nœud DOM, en fonction de l'attribut display : +

+RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
+{
+    Document* doc = node->document();
+    RenderArena* arena = doc->renderArena();
+    ...
+    RenderObject* o = 0;
+
+    switch (style->display()) {
+        case NONE:
+            break;
+        case INLINE:
+            o = new (arena) RenderInline(node);
+            break;
+        case BLOCK:
+            o = new (arena) RenderBlock(node);
+            break;
+        case INLINE_BLOCK:
+            o = new (arena) RenderBlock(node);
+            break;
+        case LIST_ITEM:
+            o = new (arena) RenderListItem(node);
+            break;
+       ...
+    }
+
+    return o;
+}
+
+ Le type de l'élément est aussi pris en compte : par exemple, les éléments de formulaires et les tableaux ont des + images spécifiques.
Dans WebKit si un élément veut créer un rendu spécifique, il redéfinira la méthode + createRenderer(). Les rendus pointent vers des objets de style contenant des informations non géométriques.

+

Lien entre arbre de rendu et arbre DOM

+ Les rendus correspondent aux éléments du DOM, mais la relation n'est pas un pour un. Des éléments non-visuels du DOM + ne seront pas insérés dans l'arbre de rendu. Un exemple est l'élément "head". Également les éléments dont la valeur de + display ont été mis à "none" n'apparaîtrons pas dans l'arbre (alors que les éléments avec la visibilité "hidden" + apparaîtront dans l'arbre).

+ Il existe des éléments du DOM correspondant à plusieurs objets visuels. Ce sont généralement des éléments ayant une + structure complexe qui ne peut être décrite par un simple rectangle. Par exemple, l'élément "select" a 3 rendus : un + pour la zone d'affichage, un pour la boîte de la liste déroulante et un pour le bouton. Également lorsque le texte est + divisé en plusieurs lignes parce que la largeur n'est pas suffisante pour une ligne, les nouvelles lignes seront + ajoutées comme autant de rendus supplémentaires.
Un autre exemple de rendus multiples et le HTML cassé. Selon la + spéc CSS un élément inline doit contenir soit uniquement des éléments de type bloc, soit uniquement des éléments + inline. Dans le cas d'un contenu mixte, des rendus de bloc anonymes seront créés pour encapsuler les éléments inline. +

+

+ Des objets de rendu correspondent à un nœud DOM mais par au même endroit dans l'arbre. Les éléments flottants ou + positionnés de manière absolue sont hors du flux, placés dans un endroit différent de l'arbre, et associés à l'image + réelle. Une image factice est l'endroit où elles auraient dû être. +

+ + + +
+ L'arbre de rendu et l'arbre DOM associé +
Figure : L'arbre de rendu et l'arbre DOM associé (3.1). Le "viewport" est le bloc conteneur initial. Dans WebKit ce sera l'objet "RenderView" +
+
+ + +

Le flux de construction de l'arbre

+

+ Dans Firefox, la présentation est abonnée aux mises-à-jour du DOM. La présentation la création d'images au + FrameConstructor et le constructeur résoud le style (voir calcul du style) et crée une + image. +

+

+ Dans WebKit le processus de résolution du style et de création d'un rendu est appelé "attachement". Chaque nœud DOM + dispose d'une méthode "attach". L'attachement est synchrone, l'insertion de nœud dans l'arbre DOM appelle la méthode + "attach" du nouveau nœud. +

+ Traiter les balises html et body débouche sur la construction de la racine de l'arbre de rendu. L'objet de rendu + racine correspond à ce que la spéc CSS appelle le bloc conteneur : le bloc de plus haut niveau qui contient tous les + autres blocs. Ses dimensions sont celles du viewport : les dimensions de la fenêtre d'affichage du navigateur. + Firefox l'appelle ViewPortFrame et WebKit RenderView. Il s'agit de l'objet de rendu vers + lequel pointe le document. Le reste de l'arbre est construit au travers de l'insertion de nœuds DOM. +

+

+ Voir la spéc CSS2 sur le modèle de traitement. +

+ + +

Calcul de style

+

+ Construire l'arbre de rendu nécessite de calcul les propriétés visuelles de chaque objet de rendu. Cela est fait en + calculant les propriétés de style de chaque élément. +

+

+ Le style inclut les feuilles de style d'origines diverses, les éléments de style inclus et les propriétés visuelles + du HTML (comme la propriété "bgcolor"). Ces dernières sont traduites sous forme de propriétés de style CSS + correspondantes. +

+

+ Les origines des feuilles de style sont les feuilles de style par défaut du navigateur, les feuilles de style + fournies par l'auteur de la page et les feuilles de style de l'utilisateur–ce sont des feuilles de style + fournies par l'utilisateur du navigateur (les navigateurs vous permettent de définir vos styles favoris. Dans + Firefox, par exemple, cela est fait en plaçant une feuille de style dans le dossier "Firefox Profile"). +

+

+ Le calcul de style amène plusieurs difficultés : +

    +
  1. Les données de style sont une très grande structure, contenant de nombreuses propriétés de + style, ce qui peut provoquer des problèmes de mémoire.
  2. +
  3. +

    Trouver les règles correspondantes à chaque élément peut poser des problèmes de performance + si ce n'est pas optimisé. Traverser toute la liste de règles pour chaque élément afin de trouver des + correspondances est une tâche considérable. Les sélecteurs peuvent avoir une structure complexe pouvant amener + le processus de correspondance à emprunter un chemin prometteur qui se révèle finalement non pertinent et un + autre chemin doit alors être essayé. +

    +

    Par exemple–ce sélecteur composite :

    + +
    +div div div div{
    +  ...
    +}
    +
    + signifie que les règles s'appliquent à une <div> qui descend de 3 divs. Supposez que vous + vouliez vérifier si la règle s'applique pour un élément <div> donné. Vous choisissez un certain + chemin dans l'arbre à vérifier. Vous pourriez avoir besoin de remonter l'arbre de nœuds juste pour vous apercevoir + qu'il n'y a que deux divs et que la règle ne s'applique donc pas. Vous devez alors essayer d'autres chemins dans + l'arbre. +
  4. +
  5. Appliquer les règles implique des règles de cascade assez complexes qui définissent la + hiérarchie des règles.
  6. +
+ Voyons comment les navigateurs adressent ces problèmes : + +

Partage des données de style

+

+ Les nœuds WebKit référencent des objets de style (RenderStyle). Ces objets peuvent être partagés par les nœuds dans + certaines conditions. Les nœuds sont frères ou cousins et : +

    +
  1. Les éléments doivent être dans le même état de souris (e.g., un ne peut être en :hover tandis que l'autre ne + l'est pas)
  2. +
  3. Aucun élément ne peut avoir un id
  4. +
  5. Les noms de balises doivent correspondre
  6. +
  7. Les attributs de classe doivent correspondre
  8. +
  9. Les ensembles d'attributs associés doivent être identiques
  10. +
  11. Les états de lien doivent correspondre
  12. +
  13. les états de focalisation doivent correspondre
  14. +
  15. Aucun des éléments ne doit être affecté par des sélecteurs d'attribut, où "affecté" est défini comme le fait + d'avoir une correspondance de sélecteur qui utilise un sélecteur d'attribut à n'importe quelle position dans le + sélecteur
  16. +
  17. Il ne doit y avoir aucun attribut de style inclus dans les éléments
  18. +
  19. Aucun sélecteur frère ne doit être utilisé. WebCore active simplement un switch global quand un sélecteur de + frère est rencontré et désactive le partage de style pour l'ensemble du document quand ils sont présents. Cela + inclut le sélecteur + et des sélecteurs comme :first-child et :last-child.
  20. +
+ +

Arbre de règles de Firefox

+

+ Firefox dispose de deux arbres supplémentaires pour faciliter le calcul de style : l'arbre de règles et l'arbre de + contexte de style. WebKit a aussi des objets de style mais ils ne sont pas stockés dans un arbre comme l'arbre de + contexte de style, ce sont seulement les nœuds DOM qui pointent vers le style qui leur est associé. + +

+ +
+ Arbre de contexte de style de Firefox +
Figure : Arbre de contexte de style de Firefox (2.2) +
+
+ + +

+ Les contextes de style contiennent des valeurs finales. Les valeurs sont calculées en appliquant l'ensemble des + règles correspondantes dans le bon ordre et en effectuant des manipulations les transformant de valeurs logiques en + valeurs concretes. Par exemple, si la valeur logique est un pourcentage de l'écran, elle sera calculée et + transformée en unités absolues. L'idée de l'arbre de règles est vraiment maline. Elle permet de partager ces valeurs + entre nœuds pour éviter de les recalculer. Cela économise aussi de la mémoire. +

+ +

+ Toutes les règles que l'on a pu faire correspondre sont stockées dans un arbre. Les nœuds du bas dans un arbre ont + une plus grande priorité. L'arbre contient tous les chemins des règles pour lesquelles on a trouvé des + correspondances. Le stockage des règles est fait à la demande. L'arbre n'est pas calculé au début pour chaque nœud + mais, à chaque fois qu'un nœud à besoin d'être calculé, les chemins calculés sont ajoutés à l'arbre. +

+

+ L'idée est de voir les chemins de l'arbre comme les mots d'un lexique. Disons que nous avons déjà calculé cet arbre + de règles : + +

+ +
+ + Supposez que nous ayons besoin de faire correspondre des règles pour un autre élément de l'arbre de contenu, et que + nous trouvions que les règles correspondantes (dans le bon ordre) sont B-E-I. Nous avons déjà ce chemin dans l'arbre + car nous avons déjà calculé le chemin A-B-E-I-L. Nous avons maintenant moins de choses à faire.

+ Voyons comment l'arbre nous économise du travail. +

+

Division en structures

+

+ Les contextes de style sont divisés en structures. Ces structures contiennent des informations de style pour une + certaine catégorie comme border ou color. Toutes les propriétés dans une structure sont héritées ou non héritées. + Les propriétés héritées sont des qui, à moins d'être définies par l'élément, sont héritées du parent. Les propriétés + non héritées (appelées propriétés "reset") utilisent des valeurs par défaut si elles ne sont pas définies. +

+

+ L'arbre nous aide pour cacher des structures entières (contenant les valeurs calculées finales) dans l'arbre. L'idée + est que si le nœud du bas n'a pas fourni de définition pour une structure, une structure cachée dans un nœud plus + haut peut être utilisée. +

+

Calculer les contextes de style en utilisant l'arbre de + règles +

+

+ Lorsque l'on calcule le contexte de style pour un élément donné, on commence par calculer un chemin dans l'arbre de + règles ou en utiliser un existant. On commence alors à appliquer les règles trouvées dans le chemin pour remplir les + structures de notre nouveau context de style. On commence au nœud du bas du chemin–celui avec la priorité la + plus élevée (le sélecteur le plus spécifique généralement) et on traverse l'arbre jusqu'à ce que notre structure + soit complète. S'il n'y a aucune spécification pour la structure dans ce nœud de règle, alors on peut beaucoup + optimizer–on remonte l'arbre jusqu'à trouver un nœud qui le spécifie entièrement et on pointe simplement + dessus–c'est la meilleure optimisation–la structure entière est partagée. Cela évite le calcul de + valeurs finales et économise de la mémoire.
Si nous trouvons des définitions partielles nous remontons l'arbre + jusqu'à ce que la structure soit remplie. +

+

+ Si nous n'avons trouvé aucune définition pour notre structure alors, au cas où la structure est un type "hérité", + nous pointons vers la structure de notre parent dans l'arbre de contexte. Dans un tel cas nous avons encore + réussi à partager les structures. Si c'est une structure de reset alors les valeurs par défaut seront utilisées. +

+

+ Si le nœud le plus spécifique ajoute des valeurs alors il nous faut faire des calculs supplémentaires pour les + transformer en valeurs réelles. On cache alors le résultat dans le nœud de l'arbre afin qu'il puisse être réutilisé + par des nœuds enfants. +

+

+ Dans le cas où un élément a un voisin ou un frère qui pointe vers le même nœud d'arbre, alors l'ensemble du + contexte de style peut être partagé entre eux. +

+

+ Voyons un exemple : Supposez que nous ayons ce HTML + + +

+<html>
+  <body>
+    <div class="err" id="div1">
+      <p>
+        this is a <span class="big"> grosse erreur </span>
+        this is also a
+        <span class="big"> très grosse erreur</span> error
+      </p>
+    </div>
+    <div class="err" id="div2">une autre erreur</div>
+  </body>
+</html>
+
+ + et les règles suivantes : +
+div {margin:5px;color:black}
+.err {color:red}
+.big {margin-top:3px}
+div span {margin-bottom:4px}
+#div1 {color:blue}
+#div2 {color:green}
+
+

+ Pour simplifier les choses disons que nous avons besoin de ne remplir que deux structures : la structure de couleur + et la structure de marge. La structure de couleur ne contient qu'un membre : la couleur. La structure de marge + contient les quatre côtés.
L'arbre de règles résultant ressemblera à ceci (les nœuds sont marqués avec le nom + du nœud : le numéro de la règle vers laquelle ils pointent): + + +

+ L'arbre de règles +
Figure : L'arbre de règles
+
+ + +
L'arbre de contexte ressemblera à ceci (nom de nœud : le nœud de règle vers lequel ils pointent): + + +
+ L'arbre de contexte +
Figure : L'arbre de contexte
+
+ + +

+ Supposons que nous analysons syntaxiquement le HTML et arrivons à la seconde balise <div>. Nous avons besoin + de créer un contexte de style pour ce nœud et de remplir ses structures de style.
Nous allons chercher les + correspondances de règles et découvrir que les règles correspondant à la <div> sont 1, 2 et 6. Cela signifie + qu'il existe déjà un chemin dans l'arbre que notre élément peut utiliser et que nous avons juste besoin d'y ajouter + un nouveau nœud pour la règle 6 (nœud F dans l'arbre de règles).
Nous créerons un contexte de style et le + placerons dans l'arbre de contexte. Le nouveau contexte de style pointera vers le nœud F dans l'arbre de règles. +

+

+ Nous avons maintenant besoin de remplir les structures de style. Nous commencerons par remplir la structure de + marge. Puisque le dernier nœud de règle (F) n'ajoute rien à la structure de marge, nous pouvons remonter dans + l'arbre jusqu'à trouver une structure cachée, calculée lors d'une insertion précédente, et l'utiliser. Nous allons + la trouver sur le nœud B, qui est le nœud le plus élevé a avoir spécifié des règles sur les marges. +

+

+ Nous avons bien une définition pour la structure de couleur, et ne pouvons donc pas utiliser une structure déjà + cachée. La couleur ayant un attribut, nous n'avons pas besoin de remonter l'arbre pour remplir d'autres attributs. + Nous calculerons la valeur finale (convertir la chaîne en RVB etc) et cacherons la structure calculée sur ce nœud. +

+

+ Le travail sur le second élément <span> est encore plus simple. Nous chercherons les correspondances avec les + règles et en arriverons à la conclusion qu'il pointe vers la règle G, comme le span précédent. Comme nous avons des + noeuds frères qui pointent vers le même noeud, nous pouvons partager l'ensemble du contexte de style et simplement + pointer vers le contexte du span précédent. +

+

+ Pour les structures contenant des règles héritées du parent, le cache est fait sur l'arbre de context (la propriété + de couleur est en réalité héritée, mais Firefox la taite comme une propriété reset et la cache sur l'arbre de + règles).
Par exemple nous avons ajouté des règles pour les fontes dans un paragraphe : +

+p {font-family: Verdana; font size: 10px; font-weight: bold}
+
+ L'élément paragraphe, qui est un élément fils de la div dans l'arbre de context, pourrait alors partager la même + structure de fonte que son élément parent. C'est le cas si aucune règle de fonte n'a été spécifié pour le + paragraphe.

+ Dans WebKit, il n'y a pas d'arbre de règles. Les déclarations qui trouvent une correspondances sont traversées quatre + fois. En tout premier, les règles de haute priorité non-importantes sont appliquées (les propriétés qui devraient être + appliquées en premier parce que d'autres en dépendent, comme display), puis celles de haute priorité importantes, puis + celles de priorité normales non-importantes, et enfin celles de priorité normale importantes. Cela veut dire que les + propriétés qui apparaissent plusieurs fois seront résolues dans le bon ordre de cascade. Le dernier gagne.
+

+

+ Donc pour résumer : partager les objets de style (entièrement ou certaines des structures qu'ils contiennent) permet + d'adresser les problèmes 1 et 3. L'arbre de règles de Firefox aide + également à appliquer les propriétés dans le bon ordre. +

+

Manipuler les règles pour une correspondance facilitée

+

+ Il existe plusieurs sources de règles de style : +

+

+ Les deux dernières sont facilement associées à l'élément puisque les attributs de style et que les attributs HTML + peuvent être associés en utilisant l'élément comme clé. +

+

+ Comme indiqué précédemment pour le problème n°2, la correspondance de règle CSS peut être plus + complexe. Pour résoudre la difficulté, les règles sont manipulées pour un accès plus facile. +

+

+ Après avoir analysé syntaxiquement la feuille de style, les règles sont ajoutées à une des diverses tables de + hachage, en fonction du sélecteur. Il y a plusieurs maps par id, par nom de classe, par nom de balise et une map + générale pour tout ce qui ne rentre pas dans ces catégories. Si le sélecteur est un id, la règle sera ajoutée à la + map des ids, si c'est une classe elle sera ajoutée à la map des classes, etc.
Cette manipulation facilite + beaucoup la recherche de correspondance de règles. Il n'y a pas besoin de rechercher dans chaque déclaration : on + peut extraire de ces maps les règles à associer à un élément. Cette optimisation élimine 95+% des règles, de sorte + qu'il n'y a même plus besoin de les prendre en compte durant le process de recherche de correspondances (4.1). +

+

+ Voyons par exemple les règles de style suivantes : +

+p.error {color: red}
+#messageDiv {height: 50px}
+div {margin: 5px}
+
+ La première règle sera insérée dans la map de classes. La seconde dans la map des ids et la troisième dans la map des + balises.
Pour le fragment HTML suivant; +
+<p class="error">une erreur est intervenue </p>
+<div id=" messageDiv">ceci est un message</div>
+
+

+ Nous allons d'abord essayer de trouver des règles pour l'élément p. La map de classes contiendra une clé "error" avec + laquelle on pourra trouver la règle pour "p.error". L'élément div aura des règles associées dans la map des ids (la + clé est l'id) et la map de balises. Le seul travail restant est donc de trouver quelles règles parmi celles extraites + correspond vraiment.
Par exemple si la règle pour la div était +

+table div {margin: 5px}
+
+ elle sera quand même extraite de la map des balises, parce que la clé est le sélecteur le plus à droite, mais elle ne + sera pas associée à notre élément div, qui n'a pas d'ancêtre de type table.

+ WebKit comme Firefox effectuent cette manipulation. +

+

Appliquer les règles dans le bon ordre de cascade

+

+ L'objet de style a des propriétés correspondant à chaque attribut visuel (tous les attributs CSS, mais en plus + générique). Si la propriété n'est définie par aucune des règles trouvées, alors des propriétés peuvent être héritées + via l'objet de style de l'élément parent. Les autres propriétés ont des valeurs par défaut. +

+

+ Le problème survient lorsqu'il y a plus d'une définition–arrive alors l'ordre de la cascade pour résoudre le + problème. +

Ordre de cascade de la feuille de style

+ La déclaration d'une propriété de style peut apparaître dans plusieurs feuilles de style, et même plusieurs fois dans + une feuille de style donnée. Cela signifie que l'ordre d'application des règles est très important. On appelle ça + l'ordre en "cascade". Selon la spéc CSS2, l'ordre en cascade est (de faible à élevé): +
    +
  1. les déclarations du navigateur
  2. +
  3. les déclarations normales de l'utilisateur
  4. +
  5. les déclarations normales de l'auteur
  6. +
  7. les déclarations importantes de l'auteur
  8. +
  9. les déclarations importantes de l'utilisateur
  10. +
+

+ Les déclarations du navigateur sont moins importantes et l'utilisateur ne passe devant l'auteur que lorsque ses + déclarations sont marquées comme importantes. Les déclarations du même ordre seront triées par spécificité puis en fonction de l'ordre dans lequel elles sont spécifiées. Les attributs + visuels HTML sont traduits sous forme de déclarations CSS. Ils sont traités comme des règles de l'auteur avec une + faible priorité. +

+

Spécificité

+

+ La spécificité du sélecteur est définie par la spécification CSS2 comme suit : +

+ Concaténer les 4 nombres a-b-c-d (dans un système numérique avec une grande base) donne la spécificité.

+ La base numérique que vous devez utiliser est définie par le plus grand nombre que vous avez dans une des catégories. +
Par exemple, si a=14 vous devez utiliser une base hexadécimale. Dans le cas peu probable où a=17 vous devrez + utiliser une base numérique à 17 chiffres. Cette dernière situation peut arriver avec un sélecteur comme ceci : html + body div div p ... (17 balises dans votre sélecteur.. peu probable). +

+

+ Quelques exemples : +

+ *             {}  /* a=0 b=0 c=0 d=0 -> spécificité = 0,0,0,0 */
+ li            {}  /* a=0 b=0 c=0 d=1 -> spécificité = 0,0,0,1 */
+ li:first-line {}  /* a=0 b=0 c=0 d=2 -> spécificité = 0,0,0,2 */
+ ul li         {}  /* a=0 b=0 c=0 d=2 -> spécificité = 0,0,0,2 */
+ ul ol+li      {}  /* a=0 b=0 c=0 d=3 -> spécificité = 0,0,0,3 */
+ h1 + *[rel=up]{}  /* a=0 b=0 c=1 d=1 -> spécificité = 0,0,1,1 */
+ ul ol li.red  {}  /* a=0 b=0 c=1 d=3 -> spécificité = 0,0,1,3 */
+ li.red.level  {}  /* a=0 b=0 c=2 d=1 -> spécificité = 0,0,2,1 */
+ #x34y         {}  /* a=0 b=1 c=0 d=0 -> spécificité = 0,1,0,0 */
+ style=""          /* a=1 b=0 c=0 d=0 -> spécificité = 1,0,0,0 */
+
+

+

Trier les règles

+

+ Une fois les règles trouvées, elles sont triées selon les règles de la cascade. WebKit utilise un tri à bulles pour + les petites listes et un tri fusion pour les grandes. WebKit implémente le tri en redéfinissant l'opérateur ">" + pour les règles : +

+static bool operator >(CSSRuleData& r1, CSSRuleData& r2)
+{
+    int spec1 = r1.selector()->specificity();
+    int spec2 = r2.selector()->specificity();
+    return (spec1 == spec2) : r1.position() > r2.position() : spec1 > spec2;
+}
+
+

+

Processus progressif

+

+ WebKit utilise un flag pour marquer si toutes les feuilles de style de plus haut niveau (y compris les @imports) ont + été chargées. Si le style n'est pas complètement chargé lors de l'attachement, des espaces réservés sont utilisés et + cela est marqué dans le document, et ils seront recalculés lorsque les feuilles de style auront été chargées. +

+ + +

Mise en page

+

+ Lorsque le rendu est créé et ajouté à l'arbre, il n'a pas de position ni de taille. Calculer ces valeurs appelé + layout ou reflow. +

+

+ HTML utilise un modèle d'agencement basé sur un flux, ce qui veut dire que la plupart du temps il est possible de + calculer la géométrie en une seule fois. Les éléments arrivant plus tard ``dans le flux'' n'affecteront typiquement + pas la géométrie des éléments qui étaient auparavant ``dans le flux'', et donc le positionnement des éléments peut + se faire de gauche à droite, de haut en bas pour tout le document. Il y a des exceptions : par exemple, les tableaux + HTML peuvent demander plus d'une passe (3.5). +

+

+ Le système de coordonnées est relative à l'image racine. Les coordonnées haut et gauche sont utilisées. +

+

+ La mise en page est un processus récursif. Cela commence au rendu racine, qui correspond à l'élément + <html> du document HTML. La mise en page continue récursivement à travers une partie ou l'ensemble + de la hiérarchie des images, en calculant les informations géométriques pour chaque rendu qui le nécessite. +

+ La position du rendu racine est 0,0 et ses dimensions sont celles du viewport–la partie visible de la fenêtre du + navigateur. +

+ Tous les rendus ont une méthode "layout" ou "reflow", et chaque rendu appelle la méthode layout de ses enfants qui + nécessitent une mise en page. +

+

Système de marqueur de changement

+

+ Afin de ne pas procéder à une remise en page totale à chaque petit changement, les navigateurs utilisent un système + de "marqueur de changement". Un rendu qui est changé ou ajouté se marque lui et ses enfants comme "modifié" : + nécessitant une remise en page. +

+

+ Il existe deux marqueurs : "modifié", et "les enfants ont été modifiés", ce qui signifie que bien que le rendu + lui-même puisse être OK, au moins un de ses enfants nécessite une remise en page. +

+

Remise en page globale et incrémentale

+

+ La mise en page peut être déclenchée sur l'arbre de rendu en entier–il s'agit alors d'une mise en page + "globale". Cela peut arriver lorsque : +

    +
  1. un changement global de style qui affecte tous les rendus, comme le changement d'une taille de fonte.
  2. +
  3. un écran est redimensionné
  4. +
+

+ La mise en page peut être incrémentale, et seuls les rendus modifiés seront repositionnés (cela peut provoquer des + dégâts qui demanderont d'autres remise en page).
Une mise en page incrémentale est déclenchée (de manière + asynchrone) lorsque les rendus sont marqués comme modifiés. Par exemple lorsque de nouveaux rendus sont ajoutés à + l'arbre de rendu après que du nouveau contenu soit arrivé du réseau et ajouté à l'arbre DOM. +

+ + +
+ Mise en page incrémentale +
Figure : Mise en page incrémentale–seuls les rendus marqués modifiés et leurs + enfants sont repositionnés (3.6) +
+
+ +

Mise en page asynchrone et synchrone

+ La mise en page incrémentale est faite de manière asynchrone. Firefox empile des "commandes de reflux" pour des mises + en page incrémentales et un planificateur déclenche l'exécution groupée de ces commandes. WebKit dispose aussi d'un + système de rafraîchissement qui réalise une mise en page incrémentale à intervalles réguliers–l'arbre est + traversé et les rendus modifiés sont repositionnés.
Les scripts demandant des informations de style, comme + "offsetHeight", peuvent déclencher une mise en page incrémentale de manière synchrone.
Une remise en page globale + sera généralement déclenchée de manière synchrone.
Parfois une mise en page est déclenchée comme conséquence + d'une mise en page précédente, parce que des attributs, comme la position du défilement, a changé. +

Optimisations

+ Lorsqu'une mise en page est déclenchée par un "redimensionnement" ou un changement dans la position du rendu (mais pas + de taille), les tailles des rendus sont récupérées d'un cache et ne sont donc pas recalculées.
Dans certains cas, + une branche de l'arbre seulement est modifiée et la mise en page ne partira pas de la racine. Cela peut arriver dans + des cas où le changement est local et n'affecte pas les éléments autour–comme du texte saisi dans des champs + (autrement chaque saisie au clavier déclencherait une remise en page depuis la racine).

+

Le processus de mise en page

+

+ La mise en page se fait généralement selon le schéma suivant : +

    +
  1. Le rendu parent détermine sa propre largeur. +
  2. Le parent examine ses enfants et pour chacun d'entre eux : +
      +
    1. Positionne le rendu de l'enfant (fixe ses x et y).
    2. +
    3. Déclenche la mise en page de l'enfant si nécessaire–i.e. ils sont marqués comme modifiés ou nous + sommes en train de faire une mise en page globale, ou pour une autre raison–qui calcule la hauteur de + l'enfant.
    4. +
    +
  3. +
  4. Le parent utilise les hauteurs accumulées des enfants et les hauteurs des marges externes et internes pour fixer + sa propre hauteur–cela sera ensuite utilisé par le parent du rendu parent.
  5. +
  6. Il fixe son marqueur de changement à faux.
  7. +
+

+ Firefox utilise un objet "état" (nsHTMLReflowState) comme paramètre de la mise en page (appelée "reflow"). Entre + autres choses cet état inclut la largeur des parents.
Le résultat de la mise en page de Firefox est un objet + "métriques" (nsHTMLReflowMetrics). Il contiendra la hauteur calculée du rendu. +

+

Calcul de la largeur

+

+ La largeur du rendu est calculée en utilisant la largeur du bloc conteneur, la propriété "width" du style du rendu, + les marges et les bordures.
Par exemple la lageur de la div suivante : +

+<div style="width: 30%"/>
+
+ sera calculée par WebKit comme suit (classe RenderBox, méthode calcWidth): + + Jusqu'ici il s'agit du calcul de la "largeur préférée". Les largeurs minimum et maximum vont ensuite être calculés. +
Si la largeur préférée est plus grande que la margeur maximale, la valeur maximum est utilisée. Si elle est + inférieure à la largeur minimum (l'unité la plus petite qui ne puisse être coupée) alors la largeur minimale est + utilisée.

+ Les valeurs sont cachées au cas où une mise en page soit demandée, mais la largeur ne change pas. +

+

+

Retour à la ligne

+

+ Lorsqu'un rendu au milieu d'une mise en page décide qu'il doit revenir à la ligne, le rendu s'arrête et propage au + parent de la mise en page qu'il a besoin de revenir à la ligne. Le parent crée des rendus supplémentaires et appelle + layout dessus. +

+

Dessin

+

+ Dans l'étape de dessin, l'arbre de rendu est traversé et la méthode "paint()" du rendu est appelée pour afficher le + contenu à l'écran. Le dessin utilise le composant de l'infrastructure UI. +

Global et incrémental

+ Comme la mise en page, le dessin peut aussi être global–tout l'arbre est dessiné–ou incrémental. Lors du + dessin incrémental, certains des rendus changent d'une manière qui n'affecte pas tout l'arbre. Le rendu changé + invalide son rectangle à l'écran. Cela amène le SE à le voir comme une "région modifiée" et il génère un événement + "paint". Le SE le fait de manière très astucieuse et agrège plusieurs régions en une. Dans Chrome cela est plus + compliqué parce que le rendu se trouve dans un processus différent du processus principal. Chrome simule le + comportement du SE dans une certaine mesure. La présentation écoute ces événements et délègue le message à la racine + du rendu. L'arbre est traversé jusqu'à ce que le rendu pertinent soit trouvé. Il se redessine alors tout seul (ainsi + que ses enfants généralement). +

L'ordre de dessin

+ CSS2 définit l'ordre du processus de dessin. C'est en fait + l'ordre dans lequel les éléments sont empilés dans les contextes d'empilement. Cet + ordre affecte le dessin puisque les piles sont dessinées de l'arrière vers l'avant. L'ordre d'empilement d'un rendu de + bloc est : +
    +
  1. couleur de fond
  2. +
  3. image de fond
  4. +
  5. bordure
  6. +
  7. enfants
  8. +
  9. outline
  10. +
+

+

Liste d'affichage de Firefox

+ Firefox parcourt l'arbre de rendu et construit une liste d'affichage pour les rectangles à dessiner. Elle contient les + rendus associés aux rectangles, dans le bon ordre de dessin (fonds des rendus, puis leurs bordures, etc). + + De cette manière, l'arbre n'a besoin d'être traversé qu'une seule fois pour redessiner, au lieu de plusieurs fois–dessiner + tous les fonds, puis toutes les images, toutes les bordures, etc. + +

+ Firefox optimise le processus en évitant d'ajouter ce qui sera caché, comme des éléments entièrement masqués + derrière d'autres éléments opaques. +

+

Stockage de rectangles de WebKit

+ Avant de redessiner, WebKit sauve l'ancien rectangle sous forme de bitmap. Il ne dessine alors que la différence entre + les nouveaux et les anciens rectangles. + +
+ +

Changements dynamiques

+ Les navigateurs s'efforce de faire le moins de choses possibles suite à un changement. Donc les changements de la + couleur d'un élément ne provoqueront un dessin que de cet élément. Les changements de la position de l'élément + provoqueront une remise en page et un nouveau dessin de l'élément, de ses enfants et des éventuels éléments frères. + Ajouter un noeud dans le DOM provoquera une mise en page et un nouveau dessin du noeud. Ces changements majeurs, comme + l'augmentation de la aille de fonte de l'élément "html", provoqueront l'invalidation des caches, une remise en page et + un nouveau dessin de la totalité de l'arbre. + + +

Les threads du moteur de rendu

+ Le moteur de rendu est mono-thread. Presque tout, à l'exception des opérations réseau, se produit dans un seul thread. + Dans Firefox et Safari il s'agit d'un thread principal du navigateur. Dans Chrome il s'agit du thread principal de + l'onglet.
Les opérations réseau peuvent être prise en charge par plusieurs threads parallèles. Le nombre de + connexions en parallèle est limité (généralement 2 à 6 connexions). +

Boucle d'événements

+ Le thread principal du navigateur est une boucle d'événements. C'est une boucle infinie qui empêche le processus de se + terminer. Elle attend des événements (comme les événements de mise en page ou de dessin) et le traite. Voici le code + de la boucle d'événements principale de Firefox: +
+while (!mExiting)
+    NS_ProcessNextEvent(thread);
+
+ + +

Modèle visuel de CSS2

+

Le canvas

+

+ Selon la spécification CSS2, le terme de canvas + décrit "l'espace où est rendu la structure de formatage" : là où le navigateur dessine le contenu. + + Le canvas est infini pour chaque dimension de l'espace mais les navigateurs choisissent une largeur initiale basée + sur les dimensions du viewport. +

+

+ Selon www.w3.org/TR/CSS2/zindex.html, le canvas est transparent + s'il est contenu dans un autre, et reçoit une couleur définie par le navigateur s'il n'en a pas. +

+

Modèle de boîte CSS

+

+ Le modèle de boîte CSS décrit des boîtes rectangulaires qui sont + générées pour les éléments de l'arbre du document et affichées conformément au modèle de formatage visuel.
+ Chaque boîte dispose d'une zone de contenu (e.g. du texte, une image, etc.) ainsi que d'éventuelles bordure et + marges interne et externe. + + +

+ +
Figure : Le modèle de boîte CSS2
+
+ + +

+ Chaque noeud génère 0..n de ces boîtes.
Tous les éléments ont une propriété "display" qui détermine le type de + boîte qui sera générée. + + Exemples : + +

+block : génère une boîte de type bloc.
+inline : génère une ou plusieurs boîte en ligne.
+none : aucune boîte n'est générée.
+
+ Le défaut est inline mais la feuille de style du navigateur peut fixer d'autres valeurs par défaut. Par exemple : le + display par défaut pour un élément "div" est block.
Vous pouvez trouver un exemple de feuille de style par défaut + ici : www.w3.org/TR/CSS2/sample.html

+ +

Schéma de positionnement

+

+ Il y a trois schémas : +

    +
  1. Normal : l'objet est positionné en fonction de sa place dans le document. Cela veut dire que sa place dans + l'arbre de rendu est comme sa place dans l'arbre DOM et affichée selon le type et les dimensions de sa boîte
  2. +
  3. Flottant : l'objet est d'abord affiché comme du flux normal, puis déplacé aussi à gauche ou à droite que + possible
  4. +
  5. Absolu : l'objet est placé dans l'arbre de rendu à un endroit différent de sa place dans l'arbre DOM
  6. +
+

+ Le schéma de positionnement est fixé par la propriété "position" et l'attribut "float". +

+
En positionnement statique, aucune position n'est définie et le postionnement par défaut est utilisé. Dans les + autres schémas, l'auteur spécifie la position : top, bottom, left, right.

+ La manière dont la boîte est affichée est déterminée par : +

+

+

Types de boîte

+

+ Boîte bloc : forme un bloc–possède son propre rectangle dans la fenêtre du navigateur. +

+ + +
+ Boîte de type bloc +
Figure : Boîte de type bloc
+
+ +

+ Boîte en ligne : ne possède pas son propre bloc, mais se trouve à l'intérieur un bloc conteneur. +

+ + +
+ Boîtes en ligne +
Figure : Boîtes en ligne
+
+ + +

+ Les blocs sont formatés verticalement l'un après l'autre. Les boîtes en lignes sont formatées horizontalement. +

+ + +
+ Formatage bloc et en ligne +
Figure : Formatage bloc et en ligne
+
+ + +

+ Les boîtes en ligne sont placées dans des lignes ou "boîtes de ligne". Les lignes sont au moins aussi hautes que la + boîte la plus haute mais peuvent être plus hautes, lorsque les boîtes sont alignées "baseline"–ce qui veut + dire que la partie basse d'un élément est alignée en un point d'une autre boîte autre que sa base. Si la largeur du + conteneur n'est pas suffisante, les inlines seront plus sur plusieurs lignes. C'est généralement ce qui se passe + dans un paragraphe. + +

+ + +
+ Lignes +
Figure : Lignes
+
+ +

Positionnement

+

Relatif

+

+ Positionnement relatif–positionné comme d'habitude plus déplacé selon le delta demandé. +

+ +
+ Positionnement relatif +
Figure : Positionnement relatif
+
+ +

Flottants

+

+ Une boîte flottante est décalée vers la gauche ou la droite sur une ligne. La caractéristique intéressante est que + les autres boîtes la contournent. Le HTML: +

+<p>
+  <img style="float: right" src="images/image.gif" width="100" height="100">
+  Lorem ipsum dolor sit amet, consectetuer...
+</p>
+
+ Ressemblera à :

+ + +
+ Flottant +
Figure : Flottant
+
+ + +

Absolu et fixé

+

+ La mise en page est définie exactement, indépendamment du flux normal. L'élément ne participe pas au flux normal. + Les dimensions sont relatives au conteneur. Dans le cas fixé, le conteneur est le viewport. + +

+ Positionnement fixé +
Figure : Positionnement fixé
+
+ + +
Note : la boîte fixée ne se déplacera pas même lors que l'on fait défiler le document !

+

Représentation en couches

+

+ Ceci est spécifié par la propriété CSS z-index. Elle représente la 3ème dimension de la boîte : sa position le long + de l'"axe z". +

+

+ Les boîtes sont réparties en piles (appelées contextes d'empilement). Dans chaque pile + les éléments à l'arrière seront dessinés en premier et les éléments à l'avant par-dessus, plus près de + l'utilisateur. Dans le cas d'un recouvrement, l'élément le plus proche masquera l'élément précédent.
Les piles + sont ordonnées selon la propriété z-index. Les boîtes ayant une propriété "z-index" forment une pile locale. Le + viewport a la pile externe. + +

Exemple :

+ +
+<style type="text/css">
+      div {
+        position: absolute;
+        left: 2in;
+        top: 2in;
+      }
+</style>
+
+<p>
+    <div
+         style="z-index: 3;background-color:red; width: 1in; height: 1in; ">
+    </div>
+    <div
+         style="z-index: 1;background-color:green;width: 2in; height: 2in;">
+    </div>
+ </p>
+
+ Le résultat sera ainsi :

+ + +
+ Positionnement fixé +
Figure : Positionnement fixé
+
+ +

+ Bien que la div rouge précède la verte dans le balisage, et aurait donc dû être dessinée avant dans le flux normal, + sa propriété z-index est plus élevée, et elle est donc plus en avant dans la pile possédée par la boîte racine. +

+ +

Ressources

+
+
    +
  1. Architecture du navigateur +
      +
    1. Grosskurth, Alan. A Reference + Architecture for Web Browsers (pdf) +
    2. Gupta, Vineet. How Browsers Work–Part + 1–Architecture +
    + +
  2. Analyse syntaxique +
      +
    1. Aho, Sethi, Ullman, Compilers: Principles, Techniques, and Tools (aka the "Dragon book"), + Addison-Wesley, 1986 +
    2. Rick Jelliffe. The Bold and the + Beautiful: two new drafts for HTML 5. +
    + +
  3. Firefox +
      +
    1. L. David Baron, Faster + HTML and CSS: Layout Engine Internals for Web Developers. +
    2. L. David Baron, Faster HTML and CSS: Layout + Engine Internals for Web Developers (Google tech talk video) +
    3. L. David Baron, Mozilla's + Layout Engine +
    4. L. David Baron, Mozilla Style + System Documentation +
    5. Chris Waterson, Notes on HTML + Reflow +
    6. Chris Waterson, Gecko + Overview +
    7. Alexander Larsson, The + life of an HTML HTTP request +
    + +
  4. WebKit +
      +
    1. David Hyatt, Implementing + CSS(part 1) +
    2. David Hyatt, An Overview of + WebCore +
    3. David Hyatt, WebCore Rendering +
    4. David Hyatt, The FOUC Problem +
    + +
  5. Spécifications du W3C +
      +
    1. HTML 4.01 Specification +
    2. W3C HTML5 Specification +
    3. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) + Specification +
    + +
  6. Instruction de construction des navigateurs +
      +
    1. Firefox. https://developer.mozilla.org/en/Build_Documentation +
    2. WebKit. http://webkit.org/building/build.html +
    + +
+ + + +
+ + +
+ + + + +

Traductions

+

Cette page a été traduite en Japonais, deux fois ! How Browsers + Work–Behind the Scenes of Modern Web Browsers (ja) by @_kosei_ + and also ブラウザってどうやって動いてるの?(モダンWEBブラウザシーンの裏側 by @ikeike443 and @kiyoto01. + Thanks everyone!

+ + +{% endblock %}