Thursday, August 7, 2008

WebKit : вид изнутри - I

WebKit - двигатель Safari. Движок с открытым исходным кодом, и много чего еще. Он же оживляет виджеты Dashboard, Web-приложения iPhone, используется в Apple Help, и в сотнях (если не тысячах) прикладных программ для Mac OS X.

Для маковского разработчика это один из привычных и легкодоступных элементов родной операционной системы. Сначала я его просто покажу...

А теперь можно поговорить и про сам WebKit.

1. Несерьезное введение в WebKit

Если вдуматься, название у него... вызывающее. "Набор для работы с web". Будто других не было и нет. Звучит почти также нагло и самоуверенно, как System 7. Нет, не та, о которой вы наверняка подумали, а операционная система 1991 года для Маков. Какая еще в те времена существовала "Система"? Уж не Windows ли 3.0?

И как "новое имя Mac OS X", которая отныне, якобы, просто System Ten. Но с этим пока не стоит торопиться, и в официальных документах она все еще Mac OS X, то есть, одна из многих. А вот у WebKit есть шанс, и очень неплохой, действительно превратиться во "все, что вам надо знать про web".

И отчасти это - восстановление исторической справедливости. Точь-в-точь в 36-й день рождения Стива Джобса в 1991 году Тим Бернес-Ли опубликовал WorldWideWeb, первый web-браузер в истории человечества, разработал формат HTML, и сделал он это на компьютере NeXT, с операционной системой NeXTstep 2.0.

Да, другие системы в то время уже были, и не только NeXTstep, но главное не в этом. 26 февраля 1991 года произошло событие исторического значения.

С NeXT, и формат HTML, и идеи, легшие в основу первого браузера, отправились в большой мир, где за 17 с лишним лет "нагуляли" приличный вес, обросли новыми интересными технологиями, и вот, наконец, как блудный сын в известной притче, все это возвращается в родной дом...

Шутки в сторону: WebKit одинаково подходит и любителям предельно легких решений, и обожателям глубокой непроходимой зауми - это очень глубокий и непростой предмет, в котором все это есть.

WebKit можно изучать по разному: можно "зацепиться" за простое, и постепенно продвигаться вглубь. Можно сразу взяться за него основательно и глубоко. В любом случае, масса удовольствия гарантируется. Кто и когда решил, что серьезные технологии должны быть скучными и непонятными?

2. Общее устройство

WebKit - это очень странный предмет. Он немного разный с точки зрения web-программиста и программиста прикладных программ. Кроме API на Objective-C, есть еще несколько. API на C, Qt C++, "мостик" с JavaScript API, и т.п.

Мы ограничимся Objective-C API, как самым естественным и легким в применении, даже если вы никогда не программировали не только на Objective-C, но даже на C.

Блок-схема WebKit.

Для программиста, WebKit - один из сотни стандартных фреймворков, входящих в состав Mac OS X. Значение термина "фреймворк" в Mac OS X несколько другое, чем в общей информатике. Это директории с расширением ".framework", играющие в системе примерно ту же роль, что и печально знаменитые DLL. Для Xcode они так и остались тем, чем были до Mac OS 10.4 - "цельными" файлами.

В фреймворках - исполняемый код, часто нескольких версий (нужная выбирается автоматически, в зависимости от контекста), различные ресурсы, в том числе локализованные, "публичные" заголовки, иногда документация. Фреймворк обязан включать в себя определенный набор поддиректорий.

И любое число необязательных. Помимо публичных заголовков, есть и другие. По разным причинам, разработчик фреймворка может решить, что некоторые из заголовков пользователю "не нужны". Поскольку WebKit - фреймворк с открытым исходным кодом, нет никаких проблем подсмотреть, что же от нас скрыли. По этому адресу всегда лежат 2-3 свеженьких варианта: "http://nightly.webkit.org/", для Мака и для Windows, и - исходный код.

Помимо предлагаемого нам в заголовках фреймворка доступа к Objective-C API, внутри еще много всякой всячины. Два внутренних фреймворка (WebCore и JavaScriptCore), которые, при необходимости, можно использовать отдельно от WebKit, написаны на C++. Внутри настолько активно используется один из двух основных фреймворков Cocoa, Foundation, что я даже закрасил его квадратик тем же цветом, что и WebKit.

В Foundation - богатейший набор классов для работы с URL (NSURL, NSURLRequest, NSURLResponse, NSURLDownload и т.п., всего их 15), с помощью которых можно решать огромное число самых разных коммуникационных задач без WebKit, они же используются и в нем.

В Snow Safari мы использовали NSURL и NSURLRequest.

У "фундамента" Foundation на чистом C, Core Foundation, есть облегченный аналог для Windows - Core Foundation Lite. CFURLRef, CFURLRequestRef...

Второй главный фреймворк Cocoa, Application Kit (AppKit), и набор графических фреймворков Core Graphics используются почти исключительно на Mac OS X. При использовании на других платформах, применяются местные средства.

С этого места и до конца статьи, мы "знаем" только публичный интерфейс программирования приложений в WebKit. Это примерно полторы сотни классов и протоколов, множество правил и тонкостей - если забраться на приличную глубину, жизнь станет нелегкой, но интересной.

Поверьте: большинству вполне хватит даже очень небольшой его части.

3. Фасад

В стародавние времена, когда выехать за рубежи нашей Родины и слетать за пару десятков световых лет от Солнечной системы было примерно также легко, а то, что привозилось из так называемых кап-стран было настолько поразительно, для успокоения проникшихся любопытством лиц, нам рассказывали, что за приятным для глаза "глянцевым фасадом", на самом-то деле, скрывается такое...

У WebKit, как и у мифического Запада советской эпохи, тоже есть фасад. Это класс WebView. Перетаскивает ли программист его экземпляр из библиотеки готовых объектов в Interface Builder, или создает его искусственно, в исходном коде, фасад немедленно готов ответить на запрос о загрузке web-страницы из глобальной паутины или с диска компьютера... ударным трудом.

Фасад этот не менее глянцевый. И именно WebView считается в WebKit основным и главным классом. А за фасадом и в самом деле творится такое... Невидимые нам труженники, в поте лица, рождаются, выполняют свой долг, и умирают, передав свое дело другим невидимым труженникам...

Запрос на загрузку контента получает главный фрейм WebView, экземпляр класса WebForm. Поскольку WebKit, а следовательно и любой экземпляр WebView в окне нашей программы, умеет работать с документами нескольких типов (по-умолчанию, с HTML, XML, простым текстом, фильмами QuickTime и PDF-документами, но с помощью плагинов этот список может быть расширен), дальнейшее может проходить по нескольким сценариям.

Если это HTML-документ, WebFrame, как только приходит ответ от запрошенного сервера, немедленно начинает создавать иерархию из объектов класса WebFrame, моделируя структуру получаемого HTML-документа. Для каждого из этих объектов, создается WebFrameView c временным (provisional - этот термин важен) источником данных (объект класса WebDataSource).

Первая фаза загрузки HTML. Фреймы WebView тоже поддерживает, и делает это хорошо: пробовал.

Когда иерархия элементов загружаемой страницы (десятки, сотни, даже тысячи элементов разных MIME-типов) построена, начинается загрузка содержания этих элементов. Как только временный (provisional) источник данных получает от сервера первый байт, элемент превращается в "committed", то есть, в достоверный и подтвержденный, и вместо временного источника данных создается новый, "постоянный".

Элементы разных типов обрабатываются по разному. Список поддерживаемых MIME-типов контента тоже можно расширить, написав и зарегистрировав свои классы-отработчики надлежащим образом. Как только полученного содержания в конкретном элементе HTML становится достаточным для отображения его в связанном с отвечающим за него экземпляром WebFrame экземпляре WebFrameView, элемент рисуется на экране.

Иерархия объектов, возникающая в процессе загрузки HTML-страницы.

Как конкретно все это происходит, документация WebKit оставляет за кадром. Но отнюдь не по злой воле. "Последовательность действий может измениться в любой момент". По понятным причинам, этот процесс непрерывно оптимизируется.

Важно знать только несколько простых и банальных истин. Браузеры, в которых применяется WebKit, отлично справляются с отрисовкой самых замысловатых web-страниц. Давно пройден "на отлично" кислотный тест номер 2 (Acid-2), официальная версия WebKit почти справляется с кислотным тестом номер три (Acid-3), а свежие его вариации (и, видимо, версия, используемая в бета-версии Safari 4, которую тоже уже можно сгрузить) проходят "на отлично" и его.

И кроме того, Safari был заявлен как "самый быстрый браузер в мире", а его быстрота берется здесь. Если вам интересны более глубокие технические подробности - пожалуйста. Исходный код открыт. Можете сравнить несколько сотен опубликованных вариантов исходного кода, чтобы узнать ход сражения за четкость и скорость загрузки web-страниц. Идеи, ошибки, догадки...

Фасад и правда немного слишком глянцевый получился... Но увы, нет в мире идеалов, и загрузка web-страниц - процесс слишком сложный и многоаспектный.

4. Чего НЕ делает WebView

В процессе загрузки страницы может случиться миллион различных неприятностей. Данные любого из элементов могут оказаться недоступны. Источник данных может успешно приступить к приему данных, но их поток может прерваться в любую микросекунду. WebView более-менее справляется с такими ситуациями, но не самым лучшим образом.

Молча.

WebFrameView, чей источник данных не смог загрузиться, просто вообще не будет нарисован. Возможно, не отрисуется вся страница.

Никоим образом WebView не станет сообщать пользователю о том, что произошло. Ни выбросив на экран сообщение, ни записав что-то умное и подробное в лог, ни нарисовав на месте неподдерживаемого или некорректного типа данных картинку.

Поскольку загрузка страницы (и все маневры, вовлекающие в себя рождение и смерть сотен экземпляров нескольких классов, их непростое взаимодействие друг с другом, и т.п. - вот о чем надо сериалы снимать) происходит асинхронно, то есть, получив запрос и начав его выполнять, WebView возвращает управление пользователю, и параллельно с этим начинает отрабатывать запрос, иногда вообще трудно понять: а начинался ли процесс?

Окно как было девственно белым, таким оно и остается.

Получение и расшифровка данных, особенно от удаленных источников, или в условиях ненадежной связи, дело не мгновенное. Но WebView не знает, каким образом мы хотели бы сообщать пользователю информацию о состоянии его запроса, о процессе в целом, о том, сколько уже всего загружено, и сколько еще предстоит...

Окно как было девственно белым, таким оно и остается, и остается только гадать: грузится ли это страница, просто немного застряла, или все уже давно кончилось, и победили не мы?

Кстати, эти самые белые окна помогли придумать проекту Snow Safari его название. Не только они, но и они - тоже. Варианты названия были Fox Hunter, Fox Firer, Internet Exploder (по порядку: "охотник на лис", "тот, кто увольняет/уволит лису/Fox", "Взрыватель Интернета"). Но самым этичным мне показалось небольшое издевательство над тем, что мне дорого.

Кроме сбоев в процессе загрузки страницы, есть еще немало аспектов, в которых поведение WebKit "по умолчанию" едва ли удовлетворит пользователя. Например, как поступать с ссылками, требующими открытия для себя нового окна?

В принципе, можно было бы что-то придумать и на этот случай, но гораздо проще открывать новое окно (и новый документ) общепринятыми в Cocoa способами. Тем более, что такое решение могло "встать на пути" у разработчика приложения.

Задачи из реальной жизни лишь частично укладываются в схемы, которые можно продумать заранее. Почти всегда в них масса тонкостей и едва уловимых, но очень важных, деталей и подробностей. Автомат, который берет на себя многое из того, что так или иначе придется делать - это хорошо. Но только в том случае, если он управляем, гибок, его поведением можно управлять...

Продолжение следует...
WebKit : вид изнутри - I
Источник/Source: Олег Свиргстин

No comments: