2012년 3월 28일 수요일

ContentMain - ContentMainRunner (1)

Content Shell main()의 두번째 라인이자 마지막 라인인 ContentMain() 호출이다.

int ContentMain(int argc,
                const char** argv,
                ContentMainDelegate* delegate);

ShellMainDelegate 객체를 생성한 뒤, ContentMain()를 호출하면서 Content Shell을 실행하고 있다.

이제 ContentMain()에 전달한 ShellMainDelegate 객체가 어디서 어떻게 쓰이는지 살펴보고,
클라이언트들(ShellContentBrowserClient, RendererClient, UtilityClient 등) 가
언제 어디서 참조되는지 알아보자.

ContentMain()... 긴 여정이 될 것 같은 느낌이다.

ContentMain()의 구현은 다음과 같다.



ContentMain()은 ContentMainRunner 클래스를 통해 content module의 초기화, 실행, 종료를
처리하고 있다.

사실 ContentMainRunner 는 추상클래스이고, ContentMainRunner::Create()를 통해 추상클래스를 구현한 ContentMainRunnerImpl 객체가 생성된다.

Chromium 코드를 보다보면 많은 패턴들을 만나게 되는데, 여기서는 factory method 패턴을 만난것 같다. :)


ContentMainDelegate  포인터는 Content State 를 초기화하는 Initialize()의 파라미터로 전달된다.

class ContentMainRunner {
virtual int Initialize(int argc,
                           const char** argv,
                           ContentMainDelegate* delegate) = 0;
};

Initialize()의 실제 구현부분으로 가보자.
Initialize()는 src/content/app/content_main_runner.cc 에 구현되어있다.

Initialize()에서 delegate를 참조하여 ShellMainDelegate 의 멤버함수를 호출하는 첫번째 부분이다.


BasicStartupComplete()를 호출하는 부분이다. ContentMainRunner의 아주 초기 시점에 호출이 되는 것을 알 수 있다. (ShellMainDelegate 클래스의 위 함수는 빈 함수임)

몇몇 함수들이 수행된 후 PreSandboxStartup()이 호출된다.


ShellMainDeleage 의 PreSandboxStartup()에서는 ShellContentClient 객체를 content module의 content client 등록하고 (content::SetContentClient()), process_type 에 맞는 sub client(browser client, renderer client 등)를 초기화한다.

다음으로 SandboxInitialized() 가 호출된다.



ShellMainDelegate의 SandboxInitialized()는 아무일도 하지 않는다.

ContentMainRunner의 Initialize() 에서 ShellMainDelegate 의 역할을 간단히 정리해보면,
content module에 content client 등록(ShellContentClient)과 sub client 등록인것 같다.

2012년 3월 27일 화요일

Content Shell 의 구조 - ShellMainDelegate 클래스(3)

Content Shell의 ShellMainDelegate 클래스의 구현에 대해 살펴보자.

shell_main_delegate.cc 파일을 보면 ContentMainDelegate의 많은 추상함수들이
빈 함수로 구현되어 있음을 알 수 있다.

아래는 ShellMainDelegate 클래스에서 실제로 구현한 함수들이다.
PreSandboxStartup()
RunProcess()
ZygoteForked()
InitializeShellContentClient()
InitializeResourceBundle()

PreSandboxStartup() 함수를 살펴보자.


content::SetContentClient() 함수가 이 Content Shell에서 중요한 역할을 하고 있는것 같다.
이전에 언급한 적이 있는것 같은데, Content Module이 Server가 되고, Content Module을 이용하여
구현한 브라우저가 Client가 되는형태라고 말이다.
ShellMainDelegate 클래스를 가볍게 보고나서, ContentMain() 함수를 알아볼 때
이 client 가 언제 어떻게 사용되는지 알 수 있을 것이다.

다음으로 InitializeShellContentClient() 함수를 호출하고 있다.
process_type을 파라미터로 전달해 주는데, 이 type이 무엇일까?
아래의 InitializeShellContentClient() 함수를 보면 process_type을 비교하여 type에 맞는 client 를
설정하고 있다. Content Client 도 세부적으로 browser client, renderer client, plugin client, utility client들이 필요한 것 같다.


type에 맞는 세부 클라이언트들은 content::GetContentClient()->set_XXX 함수를 이용하여 셋팅하고 있다. PreSandboxStartup() 에서 content::SetContentClient()를 이용하여 ShellContentClient 객체를 셋팅하고, content::GetContentClient()는 이 때 설정한 ShellContentClient를 리턴한다.
Content Module은 SetContentClient()를 통해 셋팅된 각각의 포인터를 통해 Embedder의 Client 객체들을 참조하게 될것이다. 여기서 Embedder가 무엇인가? 이제는 바로 답을 할 수 있어야 할 것이다!
다음으로 InitializeResourceBundle() 함수를 호출하고 있다.
이 함수는 content_shell.pak 이라는 pak 파일을 이용하여 ui::ResourceBundle에 초기화를 요청하는것 같다. 이 pak 파일은 content_shell 빌드시 생성된다.

PreSandboxStartup() 함수에 대해 알아보았다. PreSandboxStartup()은 Content Module 이 Embedder에게 Sandbox 초기화전에 할일하라고 알려줄 때 사용되는 추상함수이다. Content Module은 이 추상함수를 호출하고 Sandbox 관련 내용(?)을 초기화 할 것이다. 아마 이 부분은 content::ContentMain() 함수에서 수행될 것이다.

SandboxInitialized() 함수는 빈 함수로 보아 Content Shell 에서는 Sandbox 에 대한부분은 없는것 같다.

RunProcess() 함수를 살펴보자.
이 함수는 process type과 MainFunctionParams 라는 구조체를 파라미터로 전달받고 있고 파라미터 타입이 빈 문자열일 경우에 ShellBrowserMain() 함수를 호출하고 있다.
ShellBrowserMain() 함수는 src/content/shell/shell_browser_main.cc 에 정의되어 있고, 주석을 보면 이 함수가 Content Shell의 Main routine 임을 알 수있다. 이번 포스트는 ShellMainDelegate 클래스에 대한 이야기이므로 ShellBrowserMain은 다음에 알아보자.

마지막으로 ZygoteForked() 함수를 살펴보자. 프로세스가 fork() 된 후,  process type(switchs::kProcessType)을 보고 이 타입에 맞는 Content Client 를 InitializeShellContentClient() 함수에서 초기화하고 있다. 여기서 초기화되는 각각의 클라이언트들은 Content Module 내 프로세스들이 embedder에게 무언가 요청할 때 사용될 것이다.

지금까지 ShellMainDelegate 클래스에 대해 알아보았다. 이 클래스가 하는일은 크게 두가지로 볼 수 있겠다. 첫번째는 Content Module에서 사용되는 프로세스 타입에 맞는 Content Client 들을 초기화하는 일이고 두번째는 ShellBrowserMain을 통해 브라우저 메인 루틴을 실행하는 일이다. 이 두가지 모두 ContentMain() 이 호출되면서 그 안에서 참조되는 것들이다. 이것들의 자세한 내용은 ContentMain()에서 사용될 때 알아보자.

2012년 3월 22일 목요일

Content Shell 의 구조 - ShellMainDelegate 클래스(2)

이전 포스트에서는 ContentMainDelegate 인터페이스 클래스에 대해 알아보았다.
이제 ShellMainDelegate 클래스에 대해 살펴볼 시간이다.

ShellMainDelegate 클래스는 생성자, 소멸자, ContentMainDelegate 인터페이스 클래스의
멤버함수들, 그리고 두개의 private 멤버함수, 다섯개의 private 멤버함수로 구성되어 있다.

private 멤버함수는 다음과 같다.

InitializeShellContentClient()
InitializeResourceBundle()

private 멤버 변수는 다음과 같다.

content::ShellContentBrowserClient          browser_client_
content::ShellContentRendererClient         renderer_client_
content::ShellContentPluginClient             plugin_client_
content::ShellContentUtilityClient             utility_client_
content::ShellContentClient                     content_client_

위 변수들의 이름을 보면 ShellContentXXXClient 인 것을 알 수 있다.
여기서 잠깐,,, Client 이긴 한데 무엇의 Client 일까? Client가 있으면 Server도 있어야 하는데
여기서 Server는 무엇일까?

잠시 Content Module로 돌아가서 여기에서 말하는 Client - Server 가 무엇인지 알아보자.

Content Shell에 대한 포스트 에서 Content Shell은 Content Module을 이용한 레퍼런스
브라우저라고 잠깐 이야기를 했었다.

Chrome 이나 Content Shell 은 각각의 ContentMainDelegate 인터페이스 클래스를 구현하고
그 객체를 ContentMain() 함수에 매개변수로 전달하는것으로 브라우저가 시작이된다.

이 구조로 본다면, Content Module이 Server 가 되고, Delegate 가 Client 가 되겠다.
Content Shell 이라는 Client 가 Content Module 이라는 Server 를  이용해서 브라우저를 구성하고 있는것이다.

Content Module이 동작을 하면서 자신을 구동시킨 Client (Chrome or Content Shell)를
호출(?)하고 싶을때, 이 Delegate 내 Client 를 이용하여 함수들을 호출을 하는것이다.

Client 들이 무슨 일을 하는지, Content Module에서는 언제 Client 를 호출해서 이용하는지 궁금해진다.
차차 알아보자~^^;

다시 ShellMainDelegate 클래스로 돌아가서,,,

InitializeShellContentClient() 멤버 함수가 있다. 이름으로 미루어 이 함수를 이용해서
위에서 선언된 여러 Client 들을 초기화하지 않을까 싶다.

이것은 다음 포스트에서 실제 ShellMainDelegate 함수들의 구현을 살펴보면서 확인해보자.

2012년 3월 21일 수요일

Content Shell 의 구조 - ShellMainDelegate 클래스(1)

앞 포스트에서 Content Shell의 메인함수를 살펴보았다.
메인함수는 ShellMainDelegate 객체를 생성하고, ContentMain() 함수는 이 객체를 가지고
Content Shell을 실행하고 있다

계속 Content에 대한 이야기를 하고 있는데, 과연 Content가 무엇인가?
아래 그림은 Chromium Developer Site 에 있는 다이어그램이다.


위 다이어그램은 Chrome 에서 Content의 위치를 보여주고 있다.
(Content Shell이 아님, Chrome임)
Chrome은 Content Module이 제공하는 Content API를 이용하여 구현된 것처럼 보인다.

Developer 페이지에서 Content Module은 페이지 렌더링을 위한 Core Module이라고 기술하고 있다.
다이어그램을 보면 Content Module이 WebKit을 이용하고 있는 것을 알 수 있다.
아마도 Chrome은 페이지 렌더링은 Content API를 이용하여 페이지 렌더링을 하고
그외 다른 특징들(ex, Extension, NaCl)은 Chrome 계층에서 구현을 하고 있는 듯 하다.

Content Module은 크롬 브라우저를 구성하는 엔진(WebKit을 포함하는)이라고 보는게 맞는듯 하다.
그리고, Content Shell은 Content Module을 이용한 레퍼런스 브라우저 정도가 될 것 같다.

ShellMainDelegate 클래스 분석에 앞서 간단히 Content Module의 위치(?)가 어느쯤인지 알아보았다.

자 그럼 ShellMainDelegate 클래스를 알아보자.

src/content/shell/shell_main_delegate.h 파일을 보면, ShellMainDelegate 클래스는
content::ContentMainDelegate 인터페이스 클래스를 구현하고 있는 것을 알 수 있다.

Content Module이 정의해 놓은 ContentMainDelegate 인터페이스에 맞게 Delegate 클래스를
구현하면, Content Module을 이용한 브라우저를 구현할 수 있는 것 같다.

ContentMainDelegate 인터페이스가 정의하고 있는 함수들은 다음과 같다.

* BasicStartupComplete()
* PreSandboxStartup()
* SandboxInitialized()
* RunProcess()
* ProcessExiting()
* ZygoteStarting()
* ZygoteForked()

Mac 관련 함수를 제외하고 보니 위의 7개의 함수만 구현을 하면 나도 Content Module을 이용하여
브라우저를 만들수가 있을 것 같다~~ :)

함수 프로토타입위에 친절히 주석이 달려있긴하지만, 아직은 내용이 와닿지 않는다.
그래도 한번 살펴보자.
이해가 안가더라도 이후에 ShellMainDelegate 클래스를 구현한 부분을 보면 조금은 이해가 가지 않을까?

1. BasicStartupComplete()
주석에 따르면 이 함수를 통해 embedder에게 아주 기본적인 작업(absolute basic startup)이
끝났음을 말해준다고 한다.
embedder?? 아마 여기서 embedder는 Chrome 모듈 또는 Content Shell이 될 것 같다.
ContentMain() 함수가 호출 되면, Content Module이 초기화 작업을 진행하다 아주 기본 작업이 끝났음을 embedder(chrome, chromium or content shell)에게 알려주는 함수인 것이다.

2. PreSandboxStartup()
Content Module이 Embedder에게 Sandbox가 초기화되기 전에 필요한 일을 당장 해라라고 이 함수를 통해 알려준다.
embedder는 이 함수에서 관련 작업을 수행하면 될 것이다. 그런데 여기서 말하는 sandbox는 무엇일까?
흠... 차차 알게되겠지 ^^;

3. Sandboxinitialized()
이제 embedder는 이 함수를 통해 sandbox 초기화 이후에 수행할 수 있는 작업을 할 수 있게 있다.
sandbox 초기화 이후에 embedder가 할 일이 무엇일까? 궁금 궁금..

4. RunProcess()
Embedder에게 프로세스를 시작하라고 말한다? 이것은 무슨 말일까?
Content Module은 멀티프로세스 렌더링 구조를 가지고 있다고 말하고 있는데,
프로세스는 embedder를 통해 생성된다는 말인가??? 이해가 잘 안된다...

5. ProcessExisting()
프로세스가 끝나기 전에 호출한다고 하는데, 여기서 말하는 프로세스는 RunProcess()를 통해 생성한
프로세스 인가? 점점 궁금해진다. 얼른 ShellMainDelegate 클래스의 구현이 보고 싶어진다.

6. ZygoteStarting()
Zygote 가 나왔다. 안드로이드에서 처음 들은 단어인 Zygote...
Zygote 개념이 Chromium 에서도 사용되나보다.
Embedder에게 Zygote 프로세스가 시작되었다고 알려준단다.
이 함수의 리턴값은 ZygoteForkDelegate* 란 Delegate 로 미루어 ContentModule에서
zygote 관련일을 이 포인터를 통해 embedder에게 요청하는 것을 짐작할 수 있다.

7. ZygoteForked()
Zygote 프로세스가 fork 될 때마다 호출된다고 한다. Zygote는 자신을 자가 복제 세포 처럼 fork() 하여
다른 프로세스로 변신을 하는데, 아마도 zygote가 fork 되었으니 새로운 프로세스로 변신할 준비가 되었다고 embedder 에게 알려주는 함수인것 같은 느낌이다.

앞서 Content Module 이 엔진이라고 비유를 했었는데, 이 엔진 자체로는 브라우저가 될 수 없고,
UI 등등 브라우저 Customizaiton 이 필요한 부분들은 Content Module이 이 Delegate 를 통해
embedder에게 위임(delegate)하고 있는 것을 알 수 있다.

오픈소스를 보며 항상 느끼는 것이지만, 코드가 정말 구조화가 잘 되어 있는 느낌이다.
학생 때 오픈소스를 알았더라면... 하는 생각을 요즘들어 자주 하지만 지금이라도 늦지 않았다!!

다음 포스트에서는 이 ContentMainDeleage 인터페이스 클래스를 ShellMainDelegate 클래스가 어떻게 구현을 하고 있는지
살펴보자.

2012년 3월 20일 화요일

Content Shell의 구조 - main 함수

이번 포스트에서는 Content Shell의 main 함수가 구현되어 있는 shell_main.cc 파일을 살펴보겠다.

파일을 보면 main 함수는 단 10줄로 구현되어있다... 정말 깔끔한 코드!!
그것도 리눅스와 관련이 없는 코드들을 제외하면 단 2줄의 코드가 호출될 뿐이다.. 아름답다...ㅠ


위 코드 이미지를 보면, ShellMainDelegate 객체 인스턴스를 생성하고, ContentMain 이란 함수에
이 인스턴스를 넘겨주는 것으로 브라우저를 실행시키고 있다.

Delegate 이름이 붙은것으로 미루어 delegate 패턴이 사용하고 있음을 짐작하게 한다.
아마 ContentMain() 함수에서 플랫폼관련 초기화 부분(ex, UI)은 이 ShellMainDelegate 인스턴스에 위임(delegate) 하고 있을 것 같다.

ShellMainDelegate 클래스는 content::ContentMainDelegate 를 구현(Implement) 한 클래스이다.
Content Module은 Content Module을 기반으로 브라우저를 구현할 때 필요한 요소들을
ContentMainDelegate 인터페이스 클래스를 구현하여 ContentMain() 함수에 전달하는 방식으로 사용하도록 하고있다.

Chromium(chrome) 브라우저도 마찬가지로 ContentMainDelegate 클래스를 구현하여 구성이되어있을 것이다.

다음 포스트에서는 ShellMainDelegate 클래스에 대해 알아보자.

Content Shell


Chromium은 Content Module을 토대로 페이지 렌더링을 수행하고 있다.
즉, Content Module의 API(Content API)를 이용하여 Chromium이 구현된 것이다.

Content Module은 멀티 프로세스 렌더링이 가능하게 구현되어 있고, GPU 가속 기능도 구현되어 있다고 한다.
그렇다고 하는데, 아직은 어느 부분에서 어떻게 구현이 되어 있는지는 차차 공부해서 알아볼 계획이다.

Content Module의 분석에 앞서 Content Module 테스트를 위한 브라우저인 Content Shell을 통해 브라우저 구현을 위해
Content API 가 어떻게 사용되는지 알아보자.

Chromium은 아주 거대한 프로젝트여서 풀 빌드시 한시간은 훌쩍 넘긴다.
(물론 빌드서버 성능에 따라 다르지만... 내 노트북에서는 그렇다.)

따라서 Chromium feature 를 건드리지 않고 Content Module을 수정& 테스트하고 싶다면,
Content Shell을 통해 빠르게 빌드해서 테스트해볼 수 있다.

Chromium은 Content Shell 뿐만아니라 Test Shell도 제공하고 있다.
Test Shell은 Content Module이 아닌 WebKit을 이용하여 구현된 테스트 브라우저 처럼 보인다.
(src/webkit/tools/test_shell에 있음)
Content Shell 및 Test Shell은 Chromium을 공부하는데 좋은 시작점이 될 것 같다.

Content Shell의 코드는 Chromium의 src/content/shell에 있다.
디렉토리 내 파일들을 쭈욱 보면, 그리 많지 않은 수의 파일들로 구성이 되어 있고,
각각의 파일들의 사이즈도 그리 크지 않는 것으로 보아, Content Module을 이용하여 간단한 브라우저를 구현하는것이
그리 어려운 일은 아닌 것 처럼 보인다.

이번 포스트에서는 content shell을 빌드해서 테스트를 해보자.
Chromium을 빌드하는 방법은 이전 포스트들에서 설명을 해놓았으므로 자세한 설명은 생략하고,
다음의 명령으로 Content Shell을 빌드할 수 있다.

$> make -j4 BUILDTYPE=Release content_shell

BUILDTYPE 은 Release 와 Debug 두 타입의 선택이 가능하다.
아래는 빌드 후 실행한 화면이다. 첫 페이지로 google 홈페이지가 로딩이 되는데, Content Shell 코드 내에서
www.google.com 페이지를 로딩하고 있기 때문이다. 차차 분석해가며 초기페이지를 바꿔보기도 해보자!


다음 포스트에서는 content shell의 main 함수부터 분석을 해보자!!

2012년 3월 16일 금요일

HTML5 Canvas (한빛미디어)



"To Flash" 라는 문구로 시작되는 이 책은 HTML5 Canvas에 대한 내용을 담고 있다.

캔버스(canvas)에 수많은 기능들이 있겠지만 이 책은 그중에서 2D 에 대한 내용을 중점적으로 다루고 있다.
선그리기, 도형그리기, 이미지로딩, 색칠, 문자 출력, 회전변환, 확대 축소 등등의 기본적인 2D 에 대한 기능 설명과 함께,
캔버스에서 비디오와 오디오가 어떻게 사용되는지에 대한 내용도 포함하고 있다.
이러한 기능들을 이용하여 간단한 웹앱 게임을 만들어가면서 설명하고 있어서 지루하지 않게 배울수가 있었다.
책의 뒷부분에서는 맛보기로 WebGL, ElectroServer에 대한 설명을 언급하고 있는데,
독자들이 이 책을 읽고 스스로 더 공부를 하도록 가이드를 주는것 같아서 좋았다.

이 책을 선택한 이유 중 하나는 "어떻게 html과 javascript로 웹앱을 만들지?" 하는 궁금함 이었다.
그만큼 나는 html과 javascript에 대한 지식이 거의 없었다.
하지만 이 책은 캔버스를 사용하는데 필요한 기본 html, javascript에 대한 배경설명으로 시작되기 때문에,
책의 예제코드를 이해하는데 크게 어려움이 없었던 것 같다.
이 책은 예제 소스코드 한줄 한줄에 대해 자세히 설명하고 있고,
매 챕터마다 풀 소스코드를 수록하고있어서 책만 읽더라도
캔버스를 이용하여 html을 어떻게 구현을 하는지에 대한 감을 잡을 수 있었다.

하지만 예제로 사용되는 코드가 중복되는 부분이 많아서 불필요하게 책이 좀 두꺼워진 것 같다.
그렇지만 나와같은 초보자들에게는 더 도움이 되는 부분이다.

번역서는 보통 문맥이 매끄럽지않게 번역되는 부분때문에 개인적으로 원서를 고집하는 경향이 있었지만,
이 책은 깔끔한 번역으로 번역서라고 느껴지지 않을 정도로 글을 읽는데 문제가 없었다.

이 책을 꼼꼼히 읽는다면 웹앱을 만들 채비를 갖출 수 있을것이다.

나만의 멋진 웹앱으로 크롬의 웹앱스토어나 아이튠스 앱스토어에 등록해보자.

http://www.hanb.co.kr/trackback/978-89-7914-898-5