L'élément HTML <label> est un composant essentiel de l'accessibilité web, permettant de lier une description textuelle à un contrôle de formulaire. Dans Chromium, son comportement et son interface sont définis à travers plusieurs couches du moteur de rendu Blink, allant de la configuration JSON aux liaisons V8 pour JavaScript.
1. Déclaration du tag dans la configuration Blink
Le moteur Blink répertorie l'élément label dans ses fichiers de définition de tags. Cela permet de générer automatiquement une partie de la logique de parsing et de spécifier l'emplacement des fichiers d'interface.
// Chemin : third_party/blink/renderer/core/html/html_tag_names.json5
{
name: "label",
interfaceHeaderDir: "third_party/blink/renderer/core/html/forms",
},
2. Définition de l'interface Web IDL
Le contrat antre le moteur de rendu et l'API JavaScript est défini via un fichier IDL (Interface Definition Language). Cette interface expose les propriétés standard du label, telles que le formulaire associé et le contrôle ciblé.
// Chemin : html_label_element.idl
[
Exposed=Window,
HTMLConstructor
] interface HTMLLabelElement : HTMLElement {
readonly attribute HTMLFormElement? form;
[CEReactions, Reflect=for] attribute DOMString htmlFor;
readonly attribute HTMLElement? control;
};
3. Implémentation de la classe C++ (Blink Core)
La logique interne est implémentée dans la classe HTMLLabelElement. Elle hérite de HTMLElement et gère des aspects spécifiques comme les événements de clic simulés sur le contrôle associé.
// Chemin : third_party/blink/renderer/core/html/forms/html_label_element.h
namespace blink {
class CORE_EXPORT HTMLLabelElement final : public HTMLElement {
DEFINE_WRAPPERTYPEINFO();
public:
explicit HTMLLabelElement(Document& doc);
HTMLElement* control() const;
HTMLFormElement* form() const;
bool WillRespondToMouseClickEvents() override;
private:
bool IsInteractiveContent() const override;
void AccessKeyAction(SimulatedClickCreationScope scope) override;
// Gestion des états de survol et d'activation pour le contrôle lié
void SetActive(bool is_active) override;
void SetHovered(bool is_hovered) override;
void DefaultEventHandler(Event& evt) override;
bool HasActivationBehavior() const override;
void Focus(const FocusParams& params) override;
bool is_handling_click_;
};
} // namespace blink
4. Liaison avec le moteur JavaScript V8
Pour que JavaScript puisse interagir avec l'objet C++, Chromium génère des fichiers de liaison (bindings). Ces fichiers contiennent les callbacks qui font le pont entre les appels JS et les méthodes C++ de Blink.
// Exemple simplifié de callback de liaison V8
namespace blink {
namespace {
// Récupération de l'attribut 'control' depuis JavaScript
void ControlPropertyGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
// Extraction de l'instance C++ associée à l'objet V8
v8::Local<v8::Object> holder = info.This();
HTMLLabelElement* element_impl = V8HTMLLabelElement::ToWrappableUnsafe(isolate, holder);
// Appel de la méthode C++ et retour de la valeur vers V8
auto* target_control = element_impl->control();
bindings::V8SetReturnValue(info, target_control, element_impl);
}
// Gestion de l'attribut 'htmlFor' (réflecteur de l'attribut 'for')
void HtmlForAttributeSetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
const char* interface_name = "HTMLLabelElement";
const char* property_name = "htmlFor";
// Utilisation des mécanismes de réflexion pour mettre à jour l'attribut DOM
bindings::PerformAttributeSetCEReactionsReflectTypeString(
info, html_names::kForAttr, interface_name, property_name);
}
} // namespace
// Enregistrement des propriétés dans le template de l'interface
void V8HTMLLabelElement::InstallUnconditionalProperties(
v8::Isolate* isolate,
const DOMWrapperWorld& world,
v8::Local<v8::Template> instance_tmpl,
v8::Local<v8::Template> proto_tmpl,
v8::Local<v8::Template> interface_tmpl) {
using bindings::IDLMemberInstaller;
static const IDLMemberInstaller::AttributeConfig kLabelAttributes[] = {
{"form", FormPropertyGetterCallback, nullptr, unsigned(v8::None), ...},
{"htmlFor", HtmlForAttributeGetterCallback, HtmlForAttributeSetterCallback, ...},
{"control", ControlPropertyGetterCallback, nullptr, ...},
};
v8::Local<v8::Signature> sig = v8::Signature::New(isolate, interface_tmpl.As<v8::FunctionTemplate>());
IDLMemberInstaller::InstallAttributes(isolate, world, instance_tmpl, proto_tmpl, interface_tmpl, sig, kLabelAttributes);
}
} // namespace blink