Veja as principais estruturas de dados, que são entradas e saídas para o pipeline de renderização.
Essas estruturas de dados são:
- As árvores de frames são compostas por nós locais e remotos que representam quais documentos da Web estão em que o processo de renderização e qual renderizador Blink estão em execução.
- A árvore de fragmentos imutável representa a saída e a entrada do algoritmo de restrição de layout.
- As árvores de propriedades representam as hierarquias de transformação, recorte, efeito e rolagem de um documento da Web. Elas são usadas em todo o pipeline.
- Listas de exibição e blocos de pintura são as entradas dos algoritmos de varredura e de camadas.
- Os frames do compositor encapsulam superfícies, superfícies de renderização e blocos de textura de GPU que são usados para desenhar usando a GPU.
Antes de analisar essas estruturas de dados, o exemplo a seguir se baseia na análise da arquitetura. Esse exemplo é usado ao longo deste documento com demonstrações de como as estruturas de dados se aplicam a ele.
<!-- Example code -->
<html>
<div style="overflow: hidden; width: 100px; height: 100px;">
<iframe style="filter: blur(3px);
transform: rotateZ(1deg);
width: 100px; height: 300px"
id="one" src="foo.com/etc"></iframe>
</div>
<iframe style="top:200px;
transform: scale(1.1) translateX(200px)"
id="two" src="bar.com"></iframe>
</html>
Árvores emolduradas
Às vezes, o Chrome pode optar por renderizar um frame de origem cruzada em um processo de renderização diferente do frame pai.
No código de exemplo, há três frames no total:
Com o isolamento de sites, o Chromium usa dois processos de renderização para mostrar a página da Web. Cada processo de renderização tem sua própria representação da árvore de frames dessa página da Web:
Um frame renderizado em um processo diferente é representado como um frame remoto. Um frame remoto contém as informações mínimas necessárias para atuar como um marcador na renderização, como as dimensões dele, por exemplo. Caso contrário, o frame remoto não terá as informações necessárias para renderizar o conteúdo real.
Por outro lado, um frame local representa um frame que passa pelo pipeline de renderização padrão. O frame local contém todas as informações necessárias para transformar os dados dele, como a árvore DOM e os dados de estilo, em algo que pode ser renderizado e exibido.
O pipeline de renderização opera na granularidade de um
fragmento de árvore de frames local.
Considere um exemplo mais complicado com foo.com
como frame principal:
<iframe src="bar.com"></iframe>
E o seguinte subframe bar.com
:
<iframe src="foo.com/etc"></iframe>
Embora ainda haja apenas dois renderizadores, agora há três fragmentos da árvore
de frames locais, com dois no processo de renderização para foo.com
e um no
processo de renderização para bar.com
:
Para produzir um frame do compositor para a página da Web, o Viz solicita simultaneamente um frame do compositor no frame raiz de cada uma das três árvores de frames locais e, em seguida, os agrega. Consulte também a seção de frames do compositor.
O frame principal foo.com
e o subframe foo.com/other-page
fazem parte da mesma árvore de frames e renderizados no mesmo processo.
No entanto, os dois frames ainda têm
ciclos de vida de documentos
independentes, já que fazem parte de diferentes fragmentos da árvore de frames local.
Por esse motivo, é impossível gerar um frame do compositor para ambos em uma atualização.
O processo de renderização não tem informações suficientes
para compor o frame do compositor gerado para foo.com/other-page
diretamente no frame principal do foo.com
.
Por exemplo, o frame pai bar.com
fora do processo pode afetar a exibição do iframe foo.com/other-url
, transformando o iframe com CSS ou ocultando partes do iframe com outros elementos no DOM.
A cascata de atualização da propriedade visual
Propriedades visuais, como o fator de escala do dispositivo e o tamanho da janela de visualização, afetam a saída renderizada e precisam ser sincronizadas entre os fragmentos da árvore de frames local. A raiz de cada fragmento de árvore de frames local tem um objeto de widget associado. As atualizações de propriedades visuais vão para o widget do frame principal antes de se propagar para os widgets restantes de cima para baixo.
Por exemplo, quando o tamanho da janela de visualização muda:
Esse processo não é instantâneo. Portanto, as propriedades visuais replicadas também incluem um token de sincronização. O compositor do Viz usa esse token de sincronização para aguardar que todos os fragmentos da árvore de frames locais enviem um frame do compositor com o token de sincronização atual. Esse processo evita misturar frames do compositor com diferentes propriedades visuais.
A árvore de fragmentos imutável
A árvore de fragmentos imutável é a saída do estágio de layout do pipeline de renderização. Ela representa a posição e o tamanho de todos os elementos na página (sem transformações aplicadas).
Cada fragmento representa uma parte de um elemento DOM. Normalmente, há apenas um fragmento por elemento, mas pode haver mais se ele for dividido em diferentes páginas durante a impressão ou em colunas em um contexto de várias colunas.
Após o layout, cada fragmento se torna imutável e nunca mais é alterado. É importante ressaltar que também colocamos algumas restrições adicionais. O que não fazemos:
- Permitir qualquer referência "para cima" na árvore. Um filho não pode ter um ponteiro para o pai.
- "bolha" de dados pela árvore (um filho só lê informações dos filhos, não do pai).
Essas restrições nos permitem reutilizar um fragmento para um layout subsequente. Sem essas restrições, precisaríamos gerar novamente toda a árvore com frequência, o que é caro.
Normalmente, a maioria dos layouts são atualizações incrementais, por exemplo, um app da Web atualizando uma pequena parte da interface em resposta ao clique do usuário em um elemento. O ideal é que o layout funcione apenas de forma proporcional ao que realmente mudou na tela. Podemos fazer isso reutilizando o máximo possível de partes da árvore anterior. Isso significa (normalmente) que só precisamos reconstruir a coluna da árvore.
No futuro, esse design imutável pode nos permitir fazer coisas interessantes, como transmitir a árvore de fragmentos imutável pelos limites da linha de execução, se necessário (para executar fases subsequentes em uma linha de execução diferente), gerar várias árvores para uma animação de layout suave ou realizar layouts especulativos paralelos. Isso também nos oferece o potencial do layout com várias linhas de execução.
Itens de fragmento inline
O conteúdo inline (principalmente texto estilizado) usa uma representação um pouco diferente. Em vez de uma estrutura de árvore com caixas e ponteiros, representamos o conteúdo in-line em uma lista simples que representa a árvore. O principal benefício é que uma representação de lista simples para inline é rápida, útil para inspecionar ou consultar estruturas de dados inline e eficiente em termos de memória. Isso é extremamente importante para o desempenho da renderização da Web, já que a renderização de texto é muito complexa e pode se tornar facilmente a parte mais lenta do pipeline, a menos que seja altamente otimizada.
A lista simples é criada para cada contexto de formatação inline na ordem de uma pesquisa de profundidade na subárvore de layout inline. Cada entrada na lista é uma tupla de (objeto, número de descendentes). Por exemplo, considere este DOM:
<div style="width: 0;">
<span style="color: blue; position: relative;">Hi</span> <b>there</b>.
</div>
A propriedade width
é definida como 0 para que a linha fique entre "Hi" e "there".
Quando o contexto de formatação inline dessa situação é representado como uma árvore, ele se parece com o seguinte:
{
"Line box": {
"Box <span>": {
"Text": "Hi"
}
},
"Line box": {
"Box <b>": {
"Text": "There"
}
},
{
"Text": "."
}
}
A lista simples tem esta aparência:
- (Caixa de linha, 2)
- (Caixa <span>, 1)
- (Texto "Oi", 0)
- (Caixa de linha, 3)
- (Caixa <b>, 1)
- (Texto "there", 0)
- (Texto ".", 0)
Existem muitos consumidores dessa estrutura de dados: APIs de acessibilidade
e APIs de geometria, como
getClientRects
e contenteditable
.
Cada um tem requisitos diferentes.
Esses componentes acessam a estrutura de dados simples com um cursor de conveniência.
O cursor
tem APIs, como MoveToNext
, MoveToNextLine
e CursorForChildren
.
Essa representação de cursor é muito eficiente para conteúdo de texto por vários motivos:
- A iteração na ordem de pesquisa que prioriza a profundidade é muito rápida. Isso é usado com muita frequência porque é semelhante aos movimentos do acento circunflexo. Como é uma lista simples, a pesquisa em profundidade apenas incrementa o deslocamento da matriz, fornecendo iterações rápidas e localidade da memória.
- Ele oferece uma pesquisa em primeiro lugar, que é necessária ao, por exemplo, pintar o plano de fundo de caixas de linha e inline.
- Saber o número de descendentes agiliza a mudança para o próximo irmão. Basta incrementar o deslocamento da matriz por esse número.
Árvores de propriedade
O DOM é uma árvore de elementos (além dos nós de texto), e o CSS pode aplicar vários estilos a eles.
Ela aparece de quatro maneiras:
- Layout:entradas para o algoritmo de restrição de layout.
- Paint:como pintar e fazer a varredura do elemento, mas não dos descendentes.
- Visual:efeitos de varredura/desenho aplicados à subárvore do DOM, como transformações, filtros e recortes.
- Rolagem:recorte e rolagem dos cantos arredondados e alinhados ao eixo da subárvore contida.
As árvores de propriedades são estruturas de dados que explicam como os efeitos visuais e de rolagem se aplicam aos elementos DOM. Eles oferecem um meio de responder a perguntas como: onde, em relação à tela, é um determinado elemento DOM, considerando o tamanho e a posição do layout? Qual sequência de operações da GPU deve ser usada para aplicar efeitos visuais e de rolagem?
Os efeitos visuais e de rolagem na Web são muito complicados em sua glória. Portanto, o mais importante que as árvores de propriedades fazem é traduzir essa complexidade em uma única estrutura de dados que represente com precisão sua estrutura e significado, removendo ao mesmo tempo o restante da complexidade do DOM e do CSS. Isso nos permite implementar algoritmos para composição e rolagem com muito mais confiança. Especificamente, faça o seguinte:
- Geometria potencialmente propensa a erros e outros cálculos podem ser centralizados em um só lugar.
- A complexidade de criar e atualizar árvores de propriedades é isolada em um estágio do pipeline de renderização.
- É muito mais fácil e rápido enviar árvores de propriedades para linhas de execução e processos diferentes do que o estado completo do DOM. Assim, é possível usá-las em muitos casos de uso.
- Quanto mais casos de uso houver, mais vantagens podemos ter com o armazenamento em cache de geometria criado sobre ele, porque eles podem reutilizar os caches uns dos outros.
O RenderingNG usa árvores de propriedades para muitas finalidades, incluindo:
- Separação da composição da pintura e da composição da linha de execução principal.
- Determinar uma estratégia ideal de composição / desenho.
- Medição da geometria do IntersectionObserver.
- Evitar o trabalho para elementos fora da tela e blocos de textura da GPU.
- Invalidar a pintura e a varredura de maneira eficiente e precisa.
- Medir a mudança de layout e a maior exibição de conteúdo nas Core Web Vitals.
Todo documento da Web tem quatro árvores de propriedades separadas: transformar, recortar, aplicar e rolar.(*) A árvore de transformação representa transformações e rolagem de CSS. (Uma transformação de rolagem é representada como uma matriz de transformação 2D.) A árvore de clipes representa clipes excedentes. A árvore de efeitos representa todos os outros efeitos visuais: opacidade, filtros, máscaras, modos de combinação e outros tipos de clipes, como clipes. A árvore de rolagem representa informações sobre rolagem, por exemplo, a forma como a cadeia de rolagem é unida. Ela é necessária para executar a rolagem na linha de execução do compositor. Cada nó em uma árvore de propriedades representa uma rolagem ou um efeito visual aplicado por um elemento DOM. Se isso tiver vários efeitos, pode haver mais de um nó da árvore de propriedades em cada árvore para o mesmo elemento.
A topologia de cada árvore é como uma representação esparsa do DOM. Por exemplo, se houver três elementos do DOM com clipes de estouro, haverá três nós da árvore de transferência, e a estrutura da árvore de transferência seguirá a relação de bloco que contém entre os clipes excedentes. Também há ligações entre as árvores. Esses links indicam a hierarquia relativa do DOM e, portanto, a ordem de aplicação dos nós. Por exemplo, se uma transformação em um elemento DOM estiver abaixo de outro elemento DOM com um filtro, a transformação será aplicada antes do filtro.
Cada elemento DOM tem um estado da árvore de propriedades, que é uma tupla de quatro tuplas (transformação, recorte, efeito, rolagem) que indica o recorte do ancestral mais próximo, transformação e efeito dos nós da árvore que entram em vigor nesse elemento. Isso é muito conveniente, porque, com essas informações, sabemos exatamente a lista de clipes, transformações e efeitos que se aplicam a esse elemento e em que ordem. Isso nos diz onde ele está na tela e como desenhá-lo.
Exemplo
(fonte)
<html>
<div style="overflow: scroll; width: 100px; height: 100px;">
<iframe style="filter: blur(3px);
transform: rotateZ(1deg);
width: 100px; height: 300px"
id="one" srcdoc="iframe one"></iframe>
</div>
<iframe style="top:200px;
transform: scale(1.1) translateX(200px)" id=two
srcdoc="iframe two"></iframe>
</html>
Para o exemplo anterior (que é um pouco diferente do que é mostrado na introdução), estes são os principais elementos das árvores de propriedades geradas:
Mostrar listas e blocos de pintura
Um item de exibição contém comandos de desenho de baixo nível (veja aqui) que podem ser rasterizados com o Skia. Os itens de exibição normalmente são simples, com apenas alguns comandos de desenho, como desenhar uma borda ou um plano de fundo. A caminhada pela árvore de exibição itera sobre a árvore de layout e os fragmentos associados seguindo a ordem de pintura do CSS para produzir uma lista de itens de exibição.
Exemplo:
<div id="green" style="background:green; width:80px;">
Hello world
</div>
<div id="blue" style="width:100px;
height:100px; background:blue;
position:absolute;
top:0; left:0; z-index:-1;">
</div>
Esse HTML e CSS produziriam a seguinte lista de exibição, em que cada célula é um item de exibição:
Plano de fundo da visualização | #blue em segundo plano |
#green em segundo plano |
Texto inline #green |
---|---|---|---|
drawRect com tamanho 800 x 600 e cor branca. |
drawRect com tamanho 100 x 100 na posição 0,0 e cor azul. |
drawRect com tamanho 80 x 18 na posição 8,8 e cor verde. |
drawTextBlob com as posições 8,8 e o texto "Hello world". |
A lista de itens de exibição é ordenada de frente para trás. No exemplo acima, o div verde está antes do div azul na ordem do DOM, mas a ordem de pintura do CSS exige que o div azul negativo do Z-index pinte antes (etapa 3) o div verde (etapa 4.1). Os itens de exibição correspondem aproximadamente às etapas atômicas da especificação da ordem de pintura do CSS. Um único elemento DOM pode resultar em vários itens de exibição, por exemplo, como #green tem um item de exibição para o plano de fundo e outro para o texto inline. Essa granularidade é importante para representar toda a complexidade da especificação da ordem de pintura do CSS, como a intercalação criada pela margem negativa:
<div id="green" style="background:green; width:80px;">
Hello world
</div>
<div id="gray" style="width:35px; height:20px;
background:gray;margin-top:-10px;"></div>
Isso produz a seguinte lista de exibição, em que cada célula é um item de exibição:
Plano de fundo da visualização | #green em segundo plano |
#gray em segundo plano |
Texto inline #green |
---|---|---|---|
drawRect com tamanho 800 x 600 e cor branca. |
drawRect com tamanho 80 x 18 na posição 8,8 e cor verde. |
drawRect com tamanho 35 x 20 na posição 8,16 e cor cinza. |
drawTextBlob com as posições 8,8 e o texto "Hello world". |
A lista de itens de exibição é armazenada e reutilizada em atualizações posteriores. Se um objeto de layout não tiver sido modificado durante a caminhada pela árvore de pintura, os itens de exibição dele serão copiados da lista anterior. Uma otimização adicional depende de uma propriedade da especificação da ordem de pintura do CSS: empilhar os contextos de maneira atômica. Se nenhum objeto de layout tiver sido modificado em um contexto de empilhamento, a caminhada pela árvore de pintura pulará o contexto de empilhamento e copiará toda a sequência de itens de exibição da lista anterior.
O estado atual da árvore de propriedades é mantido durante a caminhada pela árvore de exibição, e a lista de itens de exibição é agrupada em "blocos" de itens de exibição que compartilham o mesmo estado da árvore de propriedades. Isso é demonstrado neste exemplo:
<div id="scroll" style="background:pink; width:100px;
height:100px; overflow:scroll;
position:absolute; top:0; left:0;">
Hello world
<div id="orange" style="width:75px; height:200px;
background:orange; transform:rotateZ(25deg);">
I'm falling
</div>
</div>
Isso produz a seguinte lista de exibição, em que cada célula é um item de exibição:
Plano de fundo da visualização | #scroll em segundo plano |
Texto inline #scroll |
#orange em segundo plano |
Texto inline #orange |
---|---|---|---|---|
drawRect com tamanho 800 x 600 e cor branca. |
drawRect com tamanho 100 x 100 na posição 0,0 e cor rosa. |
drawTextBlob com a posição 0,0 e o texto "Hello world". |
drawRect com tamanho 75x200 na posição 0,0 e cor laranja. |
drawTextBlob com posição 0,0 e texto "I'm caindo". |
Então, a árvore de propriedades de transformação e os blocos de pintura seriam (simplificados para simplificar):
A lista ordenada de blocos de pintura, que são grupos de itens de exibição e um estado de árvore de propriedades, são as entradas para a etapa de criação de camadas do pipeline de renderização. A lista inteira de partes de tinta pode ser mesclada em uma única camada composta e rasterizada juntas, mas isso exigiria uma rasterização dispendiosa toda vez que o usuário rolasse. Uma camada composta pode ser criada para cada bloco de pintura e rasterizada individualmente para evitar toda a nova varredura, mas isso esgotaria rapidamente a memória da GPU. A etapa de criação de camadas precisa equilibrar a memória da GPU e reduzir os custos quando houver mudanças. Uma boa abordagem geral é mesclar blocos por padrão e não mesclar blocos de pintura que têm estados de árvore de propriedades que precisam mudar na linha de execução do compositor, como com a rolagem de compositor-thread ou com as animações de transformação de compositor-thread.
O ideal é que o exemplo anterior produza duas camadas compostas:
- Uma camada composta de 800 x 600 contendo os comandos de desenho:
drawRect
com tamanho 800 x 600 e em brancodrawRect
com tamanho 100 x 100 na posição 0,0 e cor rosa
- Uma camada composta de 144 x 224 contendo os comandos de desenho:
drawTextBlob
com a posição 0,0 e o texto "Hello world"- traduzir 0,18
rotateZ(25deg)
drawRect
com tamanho 75x200 na posição 0,0 e cor laranjadrawTextBlob
com a posição 0,0 e o texto "I'm caindo"
Se o usuário rolar a tela para #scroll
,
a segunda camada composta será movida, mas nenhuma rasterização será necessária.
Para o exemplo, na seção anterior sobre árvores de propriedades, há seis blocos de pintura. Junto com os estados da árvore de propriedades (transformar, cortar, efeito, rolagem), eles são:
- Plano de fundo do documento: rolagem do documento, clipe do documento, raiz, rolagem do documento.
- Horizontal, vertical e canto de rolagem para div (três partes de tinta separadas):
rolagem do documento, clipe de documento, desfoque
#one
, rolagem do documento. - Iframe
#one
: rotação de#one
, clipe de rolagem flutuante,#one
desfoque, rolagem do div. - Iframe
#two
: escala de#two
, recorte de documento, raiz, rolagem do documento.
Frames de composição: superfícies, superfícies de renderização e blocos de textura da GPU
O navegador e os processos de renderização gerenciam a varredura do conteúdo e enviam os frames do compositor ao processo do Viz para apresentação na tela. Os frames do compositor representam como agrupar conteúdo rasterizado e desenhá-lo de maneira eficiente usando a GPU.
Blocos
Em teoria, um processo de renderização ou compositor de processo de navegador pode fazer a varredura de pixels em uma única textura do tamanho total da janela de visualização do renderizador e enviar essa textura ao Viz. Para exibi-la, o compositor de exibição precisaria apenas copiar os pixels dessa textura para a posição adequada no buffer de frame (por exemplo, a tela). No entanto, se esse compositor quisesse atualizar mesmo um único pixel, seria necessário fazer uma nova varredura da janela de visualização completa e enviar uma nova textura para o Viz.
Em vez disso, a janela de visualização é dividida em blocos. Um bloco de textura de GPU separado respalda cada bloco com os pixels rasterizados para parte da janela de visualização. O renderizador pode atualizar blocos individuais ou apenas mudar a posição dos blocos existentes na tela. Por exemplo, ao rolar um site, a posição dos blocos atuais muda para cima e, apenas ocasionalmente, um novo bloco precisa ser rasterizado para conteúdo mais abaixo na página.
![Quatro blocos.](https://developer.chrome.com/static/docs/chromium/renderingng-data-structures/image/four-tiles-b115857a2f73.jpg?authuser=6&hl=pt)
Quadriciclos e superfícies
Os blocos de textura da GPU são um tipo especial de quad, que é apenas um nome sofisticado para uma ou outra categoria de textura. Um quadrângulo identifica a textura de entrada e indica como transformar e aplicar efeitos visuais a ela. Por exemplo, blocos de conteúdo regulares têm uma transformação que indica a posição x, y deles na grade de blocos.
Esses blocos rasterizados são agrupados em uma passe de renderização, que é uma lista de quads. A passagem de renderização não contém informações de pixels. Em vez disso, ela tem instruções sobre onde e como desenhar cada quad para produzir a saída de pixel desejada. Há um quadrado de desenho para cada bloco de textura da GPU. O compositor da tela precisa iterar a lista de quads, desenhando cada um com os efeitos visuais especificados para produzir a saída de pixel desejada para a passagem de renderização. A composição de quads de desenho para uma passagem de renderização pode ser feita de maneira eficiente na GPU, porque os efeitos visuais permitidos são cuidadosamente escolhidos para serem mapeados diretamente para os recursos da GPU.
Existem outros tipos de quadrângulos de desenho além dos blocos rasterizados. Por exemplo, há quadrados de desenho de cores sólidas que não são respaldados por uma textura, ou quadrados de desenho de textura para texturas que não sejam de blocos, como vídeo ou tela.
Também é possível que um frame do compositor incorpore outro. Por exemplo, o compositor do navegador produz um frame do compositor com a interface do navegador e um retângulo vazio em que o conteúdo do compositor de renderização será incorporado. Outro exemplo são iframes isolados de site. Esse embedding é realizado por meio de superfícies.
Quando um compositor envia um frame do compositor, ele é acompanhado por um identificador, chamado de ID de superfície, permitindo que outros frames do compositor o incorporem por referência. O frame do compositor mais recente enviado com um ID de superfície específico é armazenado pelo Viz. Outro frame do compositor pode se referir a ele posteriormente por um quadrado de desenho de superfície e, portanto, o Viz sabe o que desenhar. Os quadrângulos de desenho da superfície contêm apenas IDs de superfície, e não texturas.
Transmissões de renderização intermediárias
Alguns efeitos visuais, como muitos filtros ou modos de combinação avançados, exigem que dois ou mais quads sejam desenhados em uma textura intermediária. Em seguida, a textura intermediária é desenhada em um buffer de destino na GPU (ou possivelmente outra textura intermediária), aplicando o efeito visual ao mesmo tempo. Para permitir isso, um frame do compositor contém uma lista de passagens de renderização. Sempre há uma passagem de renderização raiz, que é desenhada por último e cujo destino corresponde ao buffer do frame, e pode haver mais.
A possibilidade de várias passagens de renderização explica o nome "passagem de renderização". Cada passagem precisa ser executada sequencialmente na GPU, em várias "passagens", enquanto uma única passagem pode ser concluída em uma única computação de GPU massivamente paralela.
Agregação
Vários frames do compositor são enviados ao Viz e precisam ser desenhados na tela juntos. Isso é feito por uma fase de agregação que os converte em um único frame de compositor agregado. A agregação substitui os quads de desenho da superfície pelos frames do compositor especificados. Também é uma oportunidade de otimizar o conteúdo que está fora da tela ou texturas intermediárias desnecessárias. Por exemplo, em muitos casos, o frame do compositor para um iframe isolado de um site não precisa da própria textura intermediária e pode ser desenhado diretamente no buffer de frame usando quatros de desenho adequados. A fase de agregação identifica essas otimizações e as aplica com base no conhecimento global não acessível a compositores de renderização individuais.
Exemplo
Confira os frames do compositor que representam o exemplo do início desta postagem.
- Plataforma
foo.com/index.html
: id=0- Passagem de renderização 0: desenha na saída.
- Quadrado de desenho da passagem de renderização: desenhe com desfoque de 3 px e corte na passagem de renderização 0.
- Passagem de renderização 1:
- Desenhe quadrângulos para o conteúdo do bloco do iframe
#one
, com as posições x e y para cada um.
- Desenhe quadrângulos para o conteúdo do bloco do iframe
- Passagem de renderização 1:
- Quadriciclo de desenho da superfície: com ID 2, desenhado com transformação de escala e translação.
- Quadrado de desenho da passagem de renderização: desenhe com desfoque de 3 px e corte na passagem de renderização 0.
- Passagem de renderização 0: desenha na saída.
- Plataforma da interface do navegador: ID=1
- Passagem de renderização 0: desenha na saída.
- Desenhe quadrângulos para a interface do navegador (lado a lado também)
- Passagem de renderização 0: desenha na saída.
- Plataforma
bar.com/index.html
: ID=2- Passagem de renderização 0: desenha na saída.
- Desenhe quadrângulos para o conteúdo do iframe
#two
, com as posições x e y para cada um.
- Desenhe quadrângulos para o conteúdo do iframe
- Passagem de renderização 0: desenha na saída.
Ilustrações de Una Kravets.