소스 코드 다운
- https://chromium.googlesource.com/chromium/src.git
빌드 및 디버그 도구 준비
- https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/get_the_code.md
- 비주얼 스튜디오 2022
- sdk 10.0.22621.0
fetch chromium 시 유의사항
- --no-history 플래그 줄 것
- 과거 히스토리 필요없으므로..
- git 다운 시 3시간 걸릴 걸 1시간으로 줄여줌
빌드 시 유의사항
- 환경 변수 관련
- depot_tools를 python, git보다 상위에 둘 것
- 환경 변수에 vs 설치 경로 추가 필요
- vs2022_install = C:\Program Files\Microsoft Visual Studio\2022\Professional
- 없으면 빌드 시도 시 vs 설치가 안되어 있다며 빌드 실패함
- 불필요한 옵션은 끌 것
- 예) js 디버깅할 것 아니면 v8 디버그 기능은 끈다
- v8_symbol_level = 0
- 첫 빌드에 48시간 정도 걸리므로 미리 계획을 잘 세울 것
- 재빌드는 코드 수정 범위에 따라 10분 ~ 1시간 정도 걸림
- 소스 및 빌드 결과물 용량 : 약 140GB
코드 수정 시 유의사항
- 크로미움 전체 코드를 한꺼번에 열었다간 VS 또는 PC가 다운됨
- 가급적이면 전체 코드는 다음 경로에서 확인
- https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/third_party/blink/public
- 검색하고 싶으면,
- https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/blink/renderer/core/layout/layout_object.h;drc=7c39b16ecfc42db65732d1a011621edd79e2df8f;l=4205
- 수정하려면 모듈별로 열어서 수정할 것
- ex) 블링크만 열어서 수정
| 폴더 | 내용 |
|---|---|
| android_webview | Android 소프트웨어의 web view를 나타내는 부분을 간략화해 interface로 제공해주는 소스들을 모아둔 곳 |
| apps | Chrome 관련된 packaged app들이 존재 |
| base | Chromium 내 모든 프로젝트에서 공유되는 부분 base 디렉토리에는 일반적인 string이나 일반적인 utility들 |
| build | Build 와 연관된 설정들이 존재 |
| cc | Chromium 내 compositor를 담당하는 부분 |
| chrome | 디렉토리 이름과 같이, chrome 브라우저 내 필요한 것들이 존재 |
| component | Content module이 가지고 있는 모듈들이 저장된 곳 가장 최상위에서 사용되는 부분들이 여기에 저장되며, 공용으로 사용되는 것들이 많음 |
| content | sandbox로 구성된 browser process에서 multiprocessing 동작을 수행할 수 있는 핵심 코드 |
| device | Cross-platform |
| net | network 라이브러리 |
| skia + third_party/skia | Google에서 개발한 skia graphic library가 존재하는 부분 |
| sql | 파일기반 데이터 베이스인 SQLite의 wrapper함수들이 존재하는 부분 |
| third_party | 크고 작은 외부 라이브러리들이 존재하는데, 여기에는 압축, 디코딩, web engine 부분들이 존재(당시, web engine은 webkit에서 fork한 후 third_party directory에 두고 수정한 방식으로 진행해왔다. 특히 blink에 주목, web engine은 blink 부분에 존재) …/blink/renderer - web engine의 핵심. - HTML을 화면에 뿌려주는 역할 |
| ui/gfx | 공유 graphic class 들이 존재한다. Chromium의 UI를 기반의 형태를 갖추고 있음 |
| ui/views | UI 관련된 모든 것들이 존재 event 처리, UI 개발, rendering을 위한 부분 |
| url | Google의 open source인 url parsing 동작을 하는 소스코드 |
| v8 | Javascript 파싱 및 동작을 위한 부분들을 담당한다. v8엔진도 구글에서 오픈소스로 제공되고 있음 |
| 폴더 | 설명 |
|---|---|
| third_party/blink/ | Chromium 소스 코드 내 Blink 렌더링 엔진의 기본 디렉터리 |
| renderer/ | 코어 레이아웃, 렌더링 및 페인팅 등 대부분의 렌더링 코드가 여기 있음 core/: DOM, CSS 및 레이아웃 개체 등 렌더링 엔진 전체에서 사용되는 클래스들 포함 platform/: 그래픽, 네트워크 및 입력 등 modules/: WebRTC, WebUSB 및 WebBluetooth 등의 모듈들 |
| public/ | Blink 렌더링 엔진용 공개 API. mojom 등 |
| common/ | 렌더러와 브라우저 프로세스 간의 공유 코드.(주로 웹 플랫폼 기능 및 렌더러와 브라우저 간의 통신과 관련된 코드가 있다고 하는데 readme가 충분하지 않아보임..) |
| controller/ | 입력 처리, 탐색, 스레드 등 컨트롤러에 대한 코드 |
| bindings/ | 웹 API를 V8 JavaScript 엔진 및 웹 IDL(인터페이스 정의 언어)과 같은 기본 C++ 구현에 바인딩하기 위한 코드 |
| gpu/ | GPU 가속 및 WebGL 렌더링과 관련된 코드 |
| web_tests/ | 레이아웃 테스트 코드 |
| 폴더 | 설명 |
|---|---|
| ui/view/layout/ | 레이아웃 매니저와 렌더트리를 거치지 않는 노드들의 레이아웃 |
| ui/view/layout/layout_manager.h | ui를 그리기 위해 레이아웃을 관리하는 클래스 |
| ui/view/layout/table_layout.h | ui 요소를 테이블 형식으로 그리기 위해 사용됨 |
| ui/view/layout/fill_layout.h | ui 요소를 사용 가능한 공간에 맞게 크기를 조절하여 중앙ㅇ에 배치하는데 사용됨 |
| ui/view/layout/box_layout.h | 특정 행이나 열 위치에 ui요소를 배치하는데 사용됨 |
| ui/view/layout/animating_layout_manager.h | 특정 레이아웃의 애니메이션에 사용됨 |
각 OS 별 시작 함수들
- src/chrome/app/chrome_exe_main_win.cc
- src/chrome/app/chrome_exe_main_mac.cc
- ...등
윈도우 시작함수
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE prev, wchar _t*, int);
함수 정의
- APIENTRY : 매크로. 윈도우용으로 빌드된 크로미움이라면 "WINAPI"가 들어감
- hInstance : 현재 인스턴스 핸들러
- prev : 이전 인스턴스 핸들러. 일반적인 호출 시엔 nullptr로써, 사용되지 않는 변수
- _t\* : 커맨드 라인으로 받는 인수. 일반적인 호출 시엔 nullptr로써, 사용되지 않는 변수
- int : 항상 0이고, 사용되지 않음. (변수명이 없음)
- 단, remote용 진입점 등 다른 곳에 구현된 wWinMain에서는 사용하고 있었음..
함수 동작
브라우저(outer browser process)
- 사용자 입력, 브라우저 UI, 다른 프로세스들 총괄
GPU
- 렌더러가 생성한 skia 속성(그래픽 API)들을 받아서 픽셀을 칠함
- GPU 프로세스가 렌더러와 분리된 이유
- skia 또는 OpenGL 오류를 렌더러와 분리하여 렌더러를 보호
- 렌더러 프로세스는 CPU에 집중, GPU 프로세스는 GPU에 집중해 병렬로 동작하여 성능 향상
유틸리티
탭 프로세스(렌더러 프로세스, tab-specific renderer process)
- 해당 페이지 이름을 가진 프로세스
- 일반적으로 탭 한 개당 프로세스 1개
- 탭 별로 프로세스를 독립시켜 보안 강화(sandbox Model) => 보안, 안정성 강화
- Blink 엔진
- 페이지 렌더링 담당
예비 렌더러
서브 프레임
크로미움의 렌더링 파이프라인(상세)

렌더 프로세스
- Main Thread
- Parse, DOM&Style, Layout, Prepaint, Paint, Layerize
- Main Thread Helper
- Compositor Thread
- Commit, Tiling, Raster, Quad, Activate
- + 스크롤, 애니메이션 등 병렬로 처리할 기능들
- Compositor Thread Helper
- 기타
- web Worker
- Media, Audio etc..
Parse
- 파싱 과정을 거쳐 최종적으로 "DOM" 트리 생성
- parse 동작 도중 중단이 되는 이유 => https://sia.codes/posts/render-blocking-resources/
DOM&Style
- DOM : Document Object Model, 트리구조 형태의 HTML Tag 노드 리스트
Layout
- DOM 노드들의 위치와 크기 정보를 조회해 렌더트리를 만든다
- LayoutObject* LayoutObject::CreateObject(Element* element, const ComputedStyle* style, LegacyLayout legacy)
- element : Dom node
- style : ComputedStyle
- Dom node + Css = LayoutObject
Prepaint
- paint 준비, 레이어를 위한 과정
- 각 레이어에 적용할 효과들인 Property Tree 생성
- Property Tree : 레이어마다 적용할 효과를 나타내는 트리
- 참고 : https://developer.chrome.com/articles/renderingng-data-structures/
- 레이어 : 화면에 보이는 요소들을 그룹 별로 묶은 것. 최종적으로 하나의 레이어로 합쳐짐
Paint
- 앞서 계산된 위치, 크기 정보(render tree)와 스타일 정보(property tree)로 렌더링 함수 draw를 호출
- 각 레이어 별로 있던 property tree는 레이어가 묶이며 displayItems로 병합됨
- 참고 : https://debugger.skia.org/
- 위 사이트에서 displayItems의 항목으로 결과를 확인해볼 수도 있음
Layerize
- 앞서 묶인 묶여진 레이어들의 목록 **Composited Layer List** 생성
- 렌더링은 각 레이어 단위로 이뤄짐
합성
- 웹페이지의 각 요소를 레이어 별로 분리하여 각 레이어 별로 픽셀을 그리는 기능
- 레이어 단위로 다시 그릴 수 있는 등 성능 상 이점이 있음
- 레이어들이 최종적으로 하나의 웹페이지로 합쳐지기 때문에 합성이라 부르는 것으로 보임
- translate처럼 합성만 일어나는 애니메이션 css는 성능이 뛰어남
commit
- composited Layer List가 Property Tree와 함께 합성 스레드로 복사됨
- 여기서 blink 엔진의 역할이 끝남
- 멀티 버퍼링 패턴
- Recyle Tree : 캐싱용 트리
- Pending Tree : 작업 중인 트리(현재 프레임)
- Active Tree : 작업 완료된 트리(이전 프레임)
- 메인스레드에서 HTML Tag를 파싱하고, JS 처리하는 등 바쁘더라도, commit은 메인스레드로부터 렌더링에 필요한 tree를 복사해 별도로 사용하기 때문에 화면에 끊임없이 렌더링을 할 수 있음
Tiling
- Tile(타일)은 Raster의 작업단위
- 레이어를 작은 타일로 쪼개는 과정
- 이로써 스크롤 밖에 있는 Tile의 Raster는 생략 가능
Raster
- Tile별로 draw 명령을 호출 -> GPU 메모리에 비트맵 저장
- GPU 하드웨어 가속기능을 사용한다면, Raster 과정에서 GPU가 연산을 대신해주기도 함
Quad
- Raster된 타일의 위치에 대한 정보를 가짐
- Draw Rect, Draw Text -> Draw Quad 변경
Activate
- Layer list -> (commit) -> pending tree -> (Raster) -> (Quad) -> Active Tree
Aggregate
- Compositor Frame, 브라우저 프로세스(UI), 렌더러 프로세스(다른 탭, iframe) 등 화면에 그려야할 모든 프로세스가 집합
Draw
- GPU 메인 thread에 올려진 skia 라이브러리에서 draw quad 명령이 수행되며 화면에 픽셀이 그려짐
- 렌더링 파이프 라인 종료
src/third_party/blink/renderer/core/html/: 문단이나 개체 등을 비롯한 핵심적인 HTML 요소들이 여기 있음
src/third_party/blink/renderer/core/layout/: 레이아웃 개체에 대한 코드
- layout_text.cc
- layout_inline.cc
- layout_box.cc
...등
"레이아웃 객체"를 skia로 전달하여 렌더링하게 된다
- 예전에는 블링크 엔진에 다음 파일들이 있었는데, webkit으로부터 탈피하면서 변경됨
- HTMLTableElement.cpp -> html_table_element.cc
- LayoutTable.cpp -> ng/table/layout_ng_table.cc

파싱된 요소가 skia에서 렌더링할 수 있는 모델이 된 것
렌더링 트리를 표현할 수 있는 노드 구조에 필요한 멤버들
- Node* node_: 레아아웃 객체의 DOM 노드 포인터
- LayoutObject* parent_: 렌더링 트리의 부모 레이아웃 객체에 대한 포인터
- LayoutObject* previous_sibling_ 및 LayoutObject* next_sibling_: 렌더링 트리에서 형제를 가리키는 포인터
- LayoutObject* first_child_ 및 LayoutObject* last_child_
- 렌더링 트리에서 레이아웃 객체의 첫 번째 및 마지막 자식을 가리키는 포인터
- scoped_refptr<const ComputedStyle> style_: 참조 횟수가 계산되는 스마트 포인터
레이아웃 위치 관련 멤버들
- LayoutBoxModelObject* container_: 레이아웃 개체의 위치와 크기를 계산하는데 사용되는 기준이 됨
- LayoutUnit x_, y_, width_, height_: 레이아웃 개체의 위치(x 및 y 좌표)와 사이즈(너비 및 높이)
- LayoutRect visual_overflow_rect_ 및 LayoutRect layout_overflow_rect_
- 레이아웃 객체가 자시느이 영역을 넘어가는 경우를 표현
- 비주얼 오버플로는 그림자나 윤곽선 등, 레이아웃 오버플로는 텍스트나 이미지가 경계를 넘어가는 것을 표현
- LayoutObject* previous_in_flow_ 및 LayoutObject* next_in_flow_: inline 요소를 표현하는 것처럼 보임
- bool is_self_needs_layout_ 및 bool is_child_needs_layout_
- 자신 또는 자식 객체에 레이아웃을 업데이트 필요한지 여부
<span>의 처리 과정참고 위치 : third_party/blink/renderer/core/html/parser/html_document_parser.cc
동작 과정
참고 위치 : third_party/blink/renderer/core/dom/node.cc
동작 과정
참고 위치 : third_party/blink/renderer/core/layout/layout_object_factory.cc
LayoutObjectFactory 클래스 참고
CreateLayoutObject()
LayoutObject* LayoutObject::CreateObject(Element* element,
const ComputedStyle& style,
LegacyLayout legacy) {
DCHECK(IsAllowedToModifyLayoutTreeStructure(element->GetDocument()));
// Minimal support for content properties replacing an entire element.
// Works only if we have exactly one piece of content and it's a URL, with
// some optional alternative text. Otherwise acts as if we didn't support this
// feature.
const ContentData* content_data = style.GetContentData();
if (!element->IsPseudoElement() &&
ShouldUseContentDataForElement(content_data)) {
LayoutImage* image = MakeGarbageCollected<LayoutImage>(element);
// LayoutImageResourceStyleImage requires a style being present on the
// image but we don't want to trigger a style change now as the node is
// not fully attached. Moving this code to style change doesn't make sense
// as it should be run once at layoutObject creation.
image->SetStyleInternal(const_cast<ComputedStyle*>(&style));
if (const StyleImage* style_image =
To<ImageContentData>(content_data)->GetImage()) {
image->SetImageResource(
MakeGarbageCollected<LayoutImageResourceStyleImage>(
const_cast<StyleImage*>(style_image)));
image->SetIsGeneratedContent();
} else {
image->SetImageResource(MakeGarbageCollected<LayoutImageResource>());
}
image->SetStyleInternal(nullptr);
return image;
} else if (element->GetPseudoId() == kPseudoIdMarker) {
return LayoutObjectFactory::CreateListMarker(*element, style, legacy);
}
switch (style.Display()) {
case EDisplay::kNone:
case EDisplay::kContents:
return nullptr;
case EDisplay::kInline:
return MakeGarbageCollected<LayoutInline>(element);
case EDisplay::kBlock:
case EDisplay::kFlowRoot:
case EDisplay::kInlineBlock:
case EDisplay::kListItem:
return LayoutObjectFactory::CreateBlockFlow(*element, style, legacy);
case EDisplay::kTable:
case EDisplay::kInlineTable:
return MakeGarbageCollected<LayoutNGTable>(element);
case EDisplay::kTableRowGroup:
case EDisplay::kTableHeaderGroup:
case EDisplay::kTableFooterGroup:
return MakeGarbageCollected<LayoutNGTableSection>(element);
case EDisplay::kTableRow:
return MakeGarbageCollected<LayoutNGTableRow>(element);
case EDisplay::kTableColumnGroup:
case EDisplay::kTableColumn:
return MakeGarbageCollected<LayoutNGTableColumn>(element);
case EDisplay::kTableCell:
return MakeGarbageCollected<LayoutNGTableCell>(element);
case EDisplay::kTableCaption:
return MakeGarbageCollected<LayoutNGTableCaption>(element);
case EDisplay::kWebkitBox:
case EDisplay::kWebkitInlineBox:
if (style.IsDeprecatedWebkitBoxWithVerticalLineClamp()) {
return MakeGarbageCollected<LayoutNGBlockFlow>(element);
}
UseCounter::Count(element->GetDocument(),
WebFeature::kWebkitBoxWithoutWebkitLineClamp);
return MakeGarbageCollected<LayoutNGFlexibleBox>(element);
case EDisplay::kFlex:
case EDisplay::kInlineFlex:
UseCounter::Count(element->GetDocument(), WebFeature::kCSSFlexibleBox);
return MakeGarbageCollected<LayoutNGFlexibleBox>(element);
case EDisplay::kGrid:
case EDisplay::kInlineGrid:
UseCounter::Count(element->GetDocument(), WebFeature::kCSSGridLayout);
return MakeGarbageCollected<LayoutNGGrid>(element);
case EDisplay::kMath:
case EDisplay::kBlockMath:
return MakeGarbageCollected<LayoutNGMathMLBlock>(element);
case EDisplay::kLayoutCustom:
case EDisplay::kInlineLayoutCustom:
return MakeGarbageCollected<LayoutNGCustom>(element);
}
NOTREACHED();
return nullptr;
}
- 디스플레이 속성에 따라서 처리됨 (span은 보통 EDisplay::kInline)
- 스위치 문에서 "kInline"일 경우, MakeGarbageCollected(element) 가 수행
MakeGarbageCollected(element)
LayoutInline 개체 생성 과정
- 생성자 함수
LayoutInline::LayoutInline(Element* element)
: LayoutBoxModelObject(element), line_boxes_() {
SetChildrenInline(true);
}
LayoutInline::Layout()
- LayoutInline 개체 및 자식에 대한 레이아웃 프로세스 시작
LayoutBlockFlow::LayoutInlineChildren()
- LayoutBlock의 하위 클래스. LayoutInline 개체를 포함하여 인라인 하위 요소의 레이아웃 처리
- LayoutBlockFlow::Layout()
- LayoutBlockFlow 개체 및 자식의 레이아웃 프로세스 시작
- LayoutBlockFlow::LayoutBlock()
- 하위 블록 수준에 있는 요소의 레이아웃 처리
- LayoutBlockFlow::LayoutInlineChildren()
- LayoutBlockFlow 내에서 줄 바꿈, 플로팅 및 고정된 위치를 고려하여 인라인 요소인 자식들을 배치
LineLayoutAlgorithm 클래스
- 줄에서 현재 가용한 너비 및 스타일 조건에 맞춰서 line에 inline element를 배치하거나 line break 수행
- LineLayoutAlgorithm::LayoutLine()
- 인라인 콘텐츠의 한 줄을 배치
- 라인 내에서 인라인 요소의 위치를 결정하고 필요에 따라 line break
- LineLayoutAlgorithm::ComputeInlinePositions()
- 텍스트 정렬, 맞춤 및 기타 스타일 규칙을 가지고 라인 내 인라인 요소의 수평 위치를 계산
- LineLayoutAlgorithm::BreakLine()
- 가용한 너비 및 스타일에 따라 line break 결정
참고 위치 : third_party/blink/renderer/core/style/computed_style.h
동작 과정
- ComputedStyle::Create() : 스타일 객체의 시작과 끝
- StyleResolver : 스타일이 결정되는 객체. 일단 이 객체가 초기화되며 스타일 계산이 시작됨
- MatchAuthorRules() : 스타일 시트를 읽고 지정된 요소에 일치하는 css 규칙을 찾아 매칭
- CascadeAndApply()
- 스타일들의 우선순위 적용
- !important가 여기서 처리됨
- SetComputedStyle() : 계산된 스타일을 dom트리에 저장
- 저장 위치는 Element::InlineStyle() 메서드 참조
void Node::AttachLayoutTree(AttachContext& context) {
DCHECK(GetDocument().InStyleRecalc() || IsDocumentNode());
DCHECK(!GetDocument().Lifecycle().InDetach());
DCHECK(!context.performing_reattach ||
GetDocument().GetStyleEngine().InRebuildLayoutTree());
LayoutObject* layout_object = GetLayoutObject(); // 현재 노드와 관련된 레이아웃 객체를 가져옴
DCHECK(!layout_object ||
(layout_object->Style() &&
(layout_object->Parent() || IsA<LayoutView>(layout_object)))); // 레이아웃 객체가 있으면 스타일이 있는지, 레이아웃의 부모 자식 관계를 확인
ClearNeedsReattachLayoutTree(); //
if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
cache->UpdateCacheAfterNodeIsAttached(this);
if (context.performing_reattach)
ReattachHookScope::NotifyAttach(*this);
}third_party/blink/renderer/core/html/html_table_element.cc
third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h