-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdiplomamunka.tex
3102 lines (2666 loc) · 153 KB
/
diplomamunka.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\documentclass[12pt]{report}
\def\magyarOptions{defaults=hu-min}
\usepackage[magyar,english]{babel}
\usepackage[utf8]{inputenc}
\usepackage{t1enc}
\usepackage{times}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsthm}
\usepackage{graphicx}
\graphicspath{{figures/}}
\usepackage[bottom,hang,flushmargin]{footmisc}
\usepackage[many]{tcolorbox}
\usepackage{enumitem}
\usepackage{fancyhdr}
\usepackage{float}
\usepackage{hyperref}
\usepackage{makecell}
\usepackage{verbatim}
\usepackage{xcolor}
\usepackage{listings}
\lstset{
basicstyle=\selectlanguage{english}\ttfamily\small,
rulecolor=\color{gray},
frame=b,
}
\usepackage{caption}
\DeclareCaptionFont{white}{\color{white}}
\DeclareCaptionFormat{listing}{\colorbox{gray}{\parbox{148mm}{\bfseries#3}}}
\captionsetup[lstlisting]{format=listing,labelfont=white,textfont=white}
% Margins
\hoffset -1in
\voffset -1in
\oddsidemargin 35mm
\textwidth 150mm
\topmargin 15mm
\headheight 10mm
\headsep 5mm
\textheight 237mm
% Justification
\tolerance=1
\emergencystretch=\maxdimen
\hyphenpenalty=10000
\hbadness=10000
\sloppy
% Colors
\definecolor{qtgreen}{HTML}{44A51C}
\definecolor{qtred}{HTML}{A5441C}
% URL style
\hypersetup{
colorlinks=false, % Disable colorlinks for not coloring table of contents
unicode=true,
}
\let\orighref\href
\renewcommand{\href}[2]{%
\orighref{#1}{\textcolor{blue}{\texttt{#2}}}
}
\let\origurl\url
\renewcommand{\url}[1]{%
\textcolor{blue}{\origurl{#1}}
}
\newcommand{\todo}[1]{%
\textcolor{red}{\textbf{TODO:} #1}
}
\newcommand{\fixme}[1]{%
\textcolor{red}{\textbf{FIXME:} #1}
}
\newcommand{\gerrit}[1]{%
\textcolor{qtgreen}{\origurl{https://codereview.qt-project.org/\#/c/#1}}
}
\newcommand{\qtbug}[1]{%
\textcolor{qtred}{\origurl{https://bugreports.qt.io/browse/QTBUG-#1}}
}
\setdescription{
style=standard,
align=right,
itemindent=1cm,
labelwidth=1cm,
leftmargin=1cm,
before={\renewcommand\makelabel[1]{\bfseries ########1:}},
%font=\sffamily\bfseries,
}
\newtcolorbox{reviewbox}[1][]
{title=Gerrit Code Review,
width=12.5cm,
left=0pt,
right=0pt,
fonttitle=\bfseries,
coltitle=white,
colframe=qtgreen,
colback=white,
#1
}
\newtcolorbox{issuebox}[1][]
{title=Jira Issue,
width=12.5cm,
left=0pt,
right=0pt,
fonttitle=\bfseries,
coltitle=white,
colframe=qtred,
colback=white,
#1
}
\hyphenation{QtWebEngine QtWebKit WebKit Chromium Content Apple Google Quick Widget WebSocket
QtWebSockets QtWebChannel Android WebEngine JavaScript JavaScriptCore WebCore thread}
\def\title{A QtWebEngine bővítése és bemutatása saját böngészőalkalmazás segítségével}
\begin{document}
\selectlanguage{magyar}
% EMPTY PAGE STYLE
\fancypagestyle{plain}{
\fancyhf{}
\fancyfoot[R]{\thepage}
\renewcommand{\headrulewidth}{0pt}
}
% FOOTER & HEADER
\pagestyle{fancy}
\fancyhf{}
\fancyhead[L]{\title}
\fancyfoot[R]{\thepage}
%\fancyfoot[C]{\thepage}
%%% TITLE PAGE %%%
\thispagestyle{empty}
\begin{center}
\vspace*{1cm}
{\Large\textbf{Szegedi Tudományegyetem}}
\vspace{0.5cm}
{\Large\textbf{Informatikai Tanszékcsoport}}
\vspace{3.8cm}
{\LARGE\textbf{\title}}
\vspace{3.6cm}
{\Large Diplomamunka}
\vspace{4cm}
\begin{large}
\begin{tabular}{c@{\hspace{4cm}}c}
\emph{Készítette:} & \emph{Témavezető:} \\
\textbf{Varga Péter} & \textbf{Dr. Kiss Ákos} \\
programtervező & egyetemi adjunktus \\
informatikus szakos & \\
hallgató &
\end{tabular}
\end{large}
\vspace*{2.3cm}
\begin{Large}
Szeged
\vspace{2mm}
2016
\end{Large}
\end{center}
%%% TABLE OF CONTENTS %%%
\tableofcontents
%%% PROLOGUE %%%
\chapter*{Feladatkiírás}
\addcontentsline{toc}{section}{Feladatkiírás}
\noindent
A QtWebEngine bővítése úgy, hogy a QtWebKitet használó fejlesztők könnyen portolhassák
a projektjüket QtWebEngine-re. Továbbá olyan új funkciók megvalósítása is fontos, amelyek
hozzásegítik a QtWebEngine-t, hogy lépést tartson a fejlődő web technológiákkal
(például HTML5). Az újonnan implementált funkciókat tesztelni kell.
\bigskip
\noindent
A tesztelésre lehetőséget nyújt a Qt \textit{auto test} keretrendszere. Azoknál funkcióknál,
melyek nem tesztelhetők megfelelően auto tesztekkel, ott manuális tesztelésre van szükség.
A manuális teszteléshez példa alkalmazás(ok) megvalósítására van szükség. A példa
alkalmazásnak felhasználhatónak kell lennie hibakeresésre is. A megvalósítás során szem
előtt kell tartani, hogy az alkalmazás forráskódját a jövőben a funkciók dokumentálására és
bemutatására is felhasználhatjuk.
\bigskip
\noindent
A fejlesztés során az alábbi szempontokat is kell figyelembe venni:
\begin{itemize}
\item Bináris kompatibilitás megtartása korábbi QtWebEngine verziókkal:
publikus API-ban a változtatások számát minimalizálni kell,
meglévő API-t (függvény, property, signal, stb.) módosítani vagy eltávolítani
nem lehet.
\item Törekvés kompatibilitásra a QtWebKittel.
A QtWebEngine-hez adott új API-k ne térjenek el (névben, paraméterezésben, stb.)
az eredeti QtWebKit API-tól, hacsak ezt az új funkcionalitás bővítése nem indokolja.
\item Törekedni kell arra, hogy a Quick és Widget API hasonlítson egymásra,
amennyire csak lehet.
\item Az új funkcionalitásokhoz auto tesztet kell készíteni,
ahol ez megoldható.
\item Qt 5.6-os verziójától minden új funkcionalitást dokumentálni kell.
\end{itemize}
\chapter*{Tartalmi összefoglaló}
\addcontentsline{toc}{section}{Tartalmi összefoglaló}
\begin{itemize}
\item \textbf{A téma megnevezése:} \\
\title
\item \textbf{A megadott feladat megfogalmazása:} \\
A QtWebEngine bővítése új funkciókkal és azok tesztelése a
Qt teszt keretrendszerének segítségével. Az új funkciók bemutatása
egy saját böngészőalkalmazás megvalósításával.
\item \textbf{A megoldási mód:} \\
Részvétel a QtWebEngine project fejlesztésében. Az új funkciók
megvalósítása C++ és QML nyelven. Egy példa böngészőalkalmazás implementálása
QtQuick keretrendszer használatával, C++ és QML nyelven.
\item \textbf{Alkalmazott eszközök, módszerek:} \\
A fejlesztés GNU/Linux rendszeren, QtCreator fejlesztői
környezetben (IDE) történt. A hibakereséshez GDB-t használtam.
Makefile-ok legenerálását a project fájlokból a qmake végzi.
A project fordítása Linuxon a GNU Toolchainnel (GCC 5.3),
OS X-en Xcode-al (Xcode 7.2.1), Windowson pedig
MSVC 2013 32-bites verziójával történt. A verzió-követéshez Gitet
használtam. A teszteléshez szükséges keretrendszert és a teszteket a Qt
repository tartalmazza.
\item \textbf{Elért eredmények:} \\
A QtWebEngine 8 új funkcióval lett kibővítve. Ebből 4 a QtWebKitből
átvett, 3 a tesztelést és hibakeresést segíti, 1 pedig HTML5 funkció.
\item \textbf{Kulcsszavak:} \\
\texttt{QtWebEngine}, \texttt{QtWebKit}, \texttt{QtQuick}, \texttt{Qt},
\texttt{Chromium}, \texttt{Chromium Content API}, \texttt{Web}, \texttt{HTML5},
\texttt{WebKit}, \texttt{Blink}, \texttt{C++}, \texttt{QML}, \texttt{Quick},
\texttt{Widget}, \texttt{WebEngineView}
\end{itemize}
%%% CONTENT %%%
\chapter*{Bevezetés}
\addcontentsline{toc}{section}{Bevezetés}
A QtWebEngine projekt fejlesztése 2013-ban kezdődött
\cite{bib:qt-blog-introducing-qtwebengine} a WebKit--Chromium szétválás bejelentését
követően. A projekt megkezdése előtt a Qt fejlesztői csapata volt a harmadik legaktívabb
contributora a WebKit projektnek az Apple és a Google után. A szétválást a Google távozása
jelentette projektből, amikor saját WebKit forkon (Blink) kezdtek el dolgozni. Ebben az időben
a Qt fejlesztői dönteni kényszerültek: folytassák-e a WebKitre épülő QtWebKit
projektjüket és maradjanak az Apple szárnysegédjei, vagy beálljanak az új lehetőséget
és irányt mutató Google mögé azáltal, hogy egy Blinket beágyazó web böngésző platform fölé
építenek egy új API-t. A döntés megkönnyítése érdekében kezdték el fejleszteni -- eleinte csak
kísérleti jelleggel -- a Chromiumra épülő QtWebEngine-t. Végül a QtWebEngine és a Google
mellett döntöttek.
2014 elején kapcsolódtam be a projektbe és azóta is részt veszek a fejlesztésekben.
Az azóta eltelt több mint 2 év alatt sokat tanultam a Qt-ról, Chromiumról és a web
technológiákról. Dolgozatomban az ez idő alatt gyűjtött tapasztalatokból és fejlesztésekből
szeretnék megörökíteni egy részletet.
A QtWebEngine projekt célja megegyezik az előd, QtWebKit projekt céljával: egy Qt modul
(függvénykönyvtár) nyújtása a fejlesztők számára, amelynek használatával könnyedén
integrálhatnak böngésző funkcionalitásokat saját Qt alkalmazásaikba vagy akár valósíthatnak
meg saját böngészőalkalmazást Qt platform felett, mindezt úgy, hogy nincs szükség mélyebb
ismeretekre arról, hogyan is működik egy böngésző.
Dolgozatomat 3 részre tagoltam. Az első részben adok áttekintést arról, hogy mi is az a
Chromium, mi a Qt, ezek hogyan kapcsolódnak egymáshoz és hogyan is épül fel ebből a
QtWebEngine. A második részben összegyűjtöttem 8 olyan funkcionalitást, amit magam
fejlesztettem és adtam hozzá a QtWebEngine-hez. Röviden leírom, hogyan valósítottam meg
őket, mi volt a célom velük és milyen nehézségekkel kellett szembe néznem a megvalósítás
során.
A legutolsó fejezetben szeretném bebizonyítani, hogy könnyű a QtWebEngine használatával
böngészőalkalmazást készíteni. Sajnos a Chromium erőforrás igénye és magas szintű API-ja
miatt, nem várható el a QtWebEngine-től, hogy sebességben és/vagy memória-fogyasztásban
jobb vagy hatékonyabb legyen más, hasonló keretrendszereknél.
A QtWebEngine igazi előnye kétség kívül az egyszerű használhatóságban és a cross-platform
támogatásban rejlik.
\chapter{Áttekintés: \mbox{Chromium + Qt = QtWebEngine}}
\section{Chromium}
A Chromium a Google által fejlesztett, nyílt forrású (open source) web böngésző projekt.
Túlnyomó része C++ nyelven van megvalósítva. Támogatja napjaink legnépszerűbb operációs
rendszereit (cross-platform), legyen az desktop (Windows, Linux, OS X) vagy mobil
(Android, iOS, QNX). A projekt fő célja, hogy egy tabokat használó ablakkazelőt, vagy
\textit{shellt} valósítson meg a webhez, ahelyett, hogy egy hagyományos böngészőalkalmazás
legyen \cite{bib:wiki-chromium}.
\subsection{Chrome}
A Google saját Chromiumra épülő böngészőalkalmazása a Google Chrome \cite{bib:wiki-chrome}.
Ez az alkalmazás a Chromiummal szemben nem nyílt forrású, viszont a böngésző megvalósításának
nagy része a Chromium projekt része. A Chrome nem nyílt részei például a beépített
Adobe Flash Player (Pepper Flash Player) és az automatikus frissítésekért felelős komponens
(GoogleUpdate). Egy másik, szintén népszerű, Chromiumra épülő böngészőalkalmazás az Opera.
\subsection{Blink}
A Chromium a 28-as verziójától kezdve a Blink böngészőmotort használja \cite{bib:wiki-blink}.
A motor elsődleges feladata a webes tartalom megjelenítése a képernyőn
\cite{bib:chromium-displays-web-pages}. Talán ebből is látszik, hogy a Blink az egyik
legfontosabb komponense a Chromiumnak. A Chromium a 28-es verzió előtt a WebKitet használta
erre célra. A Google a WebKit projektet forkolta és nevezte át Blinkre.
A Blink a WebKit projektnek csak egy részét vette át \cite{bib:chromium-blink}. Nem
tartalmazza a WebKit2-ben megvalósított multi-processz architektúrát, nincs benne a sandbox
támogatás és a JavaScriptCore JavaScript motor. Tulajdonképpen a WebKitből a Blinkben csak a
WebCore renderelő motor maradt, így jelentősen leegyszerűsítve és lecsökkentve annak
forráskódját. A WebKit által nyújtott, viszont elhagyott funkciókat a Chromium más szinteken,
saját megoldásokkal valósítja meg (például saját JavaScript motorja a V8). Az eltávolításoktól
eltekintve a Blink még mindig nagyon hasonlít a WebKitre (WebCore-ra). A legtöbb változó és
függvény elnevezés megmaradt, gyakori az elnevezésekben a ``WebKit'' kulcsszó. Maga a Blink
projekt is a Chromium forrás struktúrán belül a \texttt{third\_party/WebKit} könyvtárban
helyezkedik el.
A Blink felel a weboldal tartalmának feldolgozásért és a tartalom megjelenítésének
előkészítésért a képernyőn. Az oldal tartalmát először parse-olja és a HTML elemekből
\texttt{WebCore::Node} objektumokat gyárt. Ezeket a \texttt{Node}-okat egy fába rendezi,
amit DOM (Document Object Model) fának hívnak \cite{bib:w3c-dom}. A DOM fának a gyökér
\texttt{Node}-ja mindig az úgynevezett \textit{Document Node} \cite{bib:chromium-gpu}.
A fa építése során a motor minden megjeleníthető \texttt{Node}-hoz egy
\texttt{RenderObject}-et rendel. A \texttt{RenderObject} az az elem, ami ``tudja'', hogyan
kell a hozzátartozó \texttt{Node}-ot megjeleníteni. A DOM fa építésével párhuzamosan, a Blink
egy másik fát is épít a \texttt{RenderObject}-ekből, ez a \textit{Render Tree}. Egyes
\texttt{RenderObject}-ekhez \texttt{RenderLayer}-t is rendel, amiből egy újabb fát épít,
ami a \textit{RenderLayer Tree} lesz.
\begin{figure}[h]
\centering
\includegraphics[scale=0.46]{rendering-trees}
\caption{
\label{fig:rendering-trees}
Rendering Trees \cite{bib:chromium-oopifs}
}
\end{figure}
\noindent
Az \ref{fig:rendering-trees} ábra szemlélteti, hogyan is állnak össze ezek a struktúrák.
A DOM Tree és a Render Tree szinte azonos, annyi különbséggel, hogy a Render Tree csak a
megjeleníthető \texttt{Node}-okat tartalmazza. A RenderLayer Tree a Render Tree egy
lecsupaszított változata, amit a megjelenítő komponens (renderer) fog használni a rajzoláshoz.
A \texttt{RenderLayer}-ből elérhetőek a \texttt{RenderObject}-ek, a RenderLayer Tree
szerkezete pedig hordozza azt az információt, hogy milyen sorrendben kell kirajzolni
\texttt{RenderObject}-eket.
Az, hogy a rajzolás hogyan történik, az függ attól, hogy van e elérhető hardveres gyorsítás.
Ha nincs, akkor szoftveres renderelés történik. A szoftveres renderelés során a rajzoló
algoritmus bejárja a RenderLayer Tree-n keresztül a \texttt{RenderObject}-eket és azokat egy
közös bitmapre rajzoltatja ki. Ha kész, ez a bitmap lesz elküldve egy másik processz
(Browser Process) számára megjelenítésre. Szoftveres renderelés esetén a rajzolást a Skia
grafikus motor végzi.
Ha van elérhető hardveres gyorsítás, akkor az eljárás valamivel bonyolultabb. Ebben az
esetben, a \texttt{RenderObject} nem bitmapbe ``rajzolja bele magát'', hanem 3D API-n
keresztül (OpenGL vagy Windowson esetleg D3D) utasításokat küld közvetlenül a GPU
utasítás pufferébe (command buffer) végrehajtásra. Ezt az eljárást már a
Chrome Compositor (CC) végzi.
\subsection{Chrome Compositor (CC)}
A Chrome Compositor nem része a Blinknek (ahogy a Skia sem). Ennek az az oka,
hogy a Chromium a böngészőalkalmazás felhasználói felületének (GUI) összeállításához is
nyújt API-kat (például Aura). A Chromium a GUI megrajzolásához is a Chrome Compositort
használja.
Ahhoz, hogy a compositor ki tudja rajzolni a DOM-ban tárolt tartalmat, további layer
absztrakciókra van szükség \cite{bib:chromium-gpu}:
\begin{center}
\texttt{RenderLayers} $\rightarrow$ \texttt{GraphicsLayers} $\rightarrow$
\texttt{WebLayers} $\rightarrow$ \texttt{CC Layers}
\end{center}
A compositor a végeredményt nem bitmapbe, hanem textúrába rajzolja. Az elkészült
textúrák a GPU memóriájában vannak tárolva és úgynevezett \textit{texture mailbox}
\cite{bib:chromium-texture-mailbox} segítségével azonosítják őket.
A texture mailbox egy OpenGL kiterjesztés, ami egyedi és globális
string azonosítót rendel a textúrához és lehetővé teszi, hogy az más OpenGL contextben
is elérhető legyen.
A texture mailbox-nak hála az összeállított képet nem kell az IPC-n (Inter-Process
Communication) keresztül megosztani a processzek között (mint a szoftveres rendering
esetében), hanem a GPU memórián keresztül bármelyik processz hozzáférhet a textúrához.
Ezzel a megoldással elég csak a textúra azonosítót (mailbox) átküldeni IPC-n.
\subsection{Multi-processz Architektúra}
Chromium volt az egyik első olyan böngésző, ami úgy lett megtervezve, hogy több processzre
legyen felosztva. A WebKit multi-processz architektúrára épülő API-ja
-- a WebKit2\footnote{A QtWebKit Quick API-ja a WebKit2-re épül} --
is a Chromium megvalósításáról mintázta a multi-processz architektúráját
\cite{bib:webkit-webkit2}.
A multi-processz architektúrán alapuló böngésző alapgondolata az, hogy a böngészőalkalmazás
UI-ért felelős része saját processzben fut, míg a weboldalak megjelenítésért más
processzek felelnek. Ennek több előnye is van \cite{bib:chromium-blog-multi-process}:
\begin{description}
\item[Felhasználói élmény]
Előfordulhat, hogy egy weboldalon futó script (vagy ``webalkalmazás'')
nagyon leterheli a böngészőt. Ha ez a script és a UI egy processzben fut,
akkor ezek nagyobb valószínűséggel vonnak el egymástól erőforrást. Ha külön
processzben, egymástól függetlenül futnak, kisebb valószínűséggel alakul ki
köztük versenyhelyzet, így a UI nagyobb CPU használatnál is ``reszponzívabb''
lehet.
\item[Biztonság]
Egyes processzek sandboxban futhatnak. Ezáltal nem férhetnek hozzá a rendszer
olyan erőforrásaihoz, ami veszélyes lehet (például: merevlemez, hálózat,
videó memória, stb).
Továbbá a különböző weboldalakat megjelenítő processzek egymástól is el vannak
különítve, így egy ártalmas oldal, vagy plugin nem férhet hozzá más oldalon használt
``kényes'' információhoz (például jelszó).
\item[Hibatűrés, Robosztusság]
Ha egy oldal betöltésekor vagy egy bővítmény futtatásakor hiba történik és
összeomlik, az nem rántja magával a teljes böngészőt. Hiba esetén a UI és más
megnyitott oldalak, tabok megmaradnak.
\end{description}
A multi-processz architektúrának hátrányai is vannak: ez a megoldás sokkal
erőforrás-igényesebb, és a megvalósítás is bonyolultabb (több hibalehetőség).
A processzek használata memória többletköltséggel jár. A futtatható processzek
számát limitálni kell, mert túl sok processz jelentős lassulást okozhat (például az ütemező
többletköltsége miatt).
A processzek IPC-n (Chromium's IPC System) keresztül kommunikálnak egymással.
A Chromiumban 4 fő processz típust különböztetünk meg:
\subsubsection{Browser Process}
Ez az a processz, ahol maga böngésző alkalmazás (UI) fut. Ez felelős megjelenítésért,
a felhasználói események és a tabok kezeléséért. Ez a fő processz, ami a többi processzt
kezeli (indítja, leállítja, stb.) és csak egy van belőle. Hozzáfér a rendszer erőforrásaihoz,
viszont nem tölt be vagy dolgoz fel web tartalmat.
\subsubsection{Render Process}
A renderelő motor egy nagyon összetett és bonyolult szoftver komponens. Szinte lehetetlen
olyat implementálni, ami sosem hibázik és/vagy omlik össze \cite{bib:chromium-multi-process}.
Ezért érdemes az egymástól független oldalak renderelését egymástól független
processzekben végrehajtani. Amennyiben egy Render Process összeomlik, arról a
Browser Process értesül és az oldal helyett az \ref{fig:sad-tab} ábrán látható,
úgynevezett, ``sad tab'' értesítést jeleníti meg.
\begin{figure}[h]
\centering
\includegraphics[scale=0.8]{sad-tab}
\caption{
\label{fig:sad-tab}
Sad Tab
}
\end{figure}
Mivel a Chromiumban a renderelésért a Blink felel, ezért az is a Render Processben fut.
A Blink az, ami közvetlenül feldolgozza a webes tartalmat, ezért jellemzően a
Render Processt sandboxban futtatják, így a potenciálisan kártékony webes kódok nem
férhetnek hozzá a rendszer erőforrásaihoz vagy más betöltött webes tartalomhoz.
A Chromiumban különböző parancssori kapcsolókkal is beállítható processz modellek
vannak definiálva \cite{bib:chromium-process-models}:
\begin{description}
\item[Process-per-site-instance]
Minden \textit{site}\footnote{Site alatt olyan weboldalak csoportját értjük, amelyek
közös beregisztrált domain néven osztoznak} külön processz.
Ha ugyanaz a site kétszer van megnyitva, akkor az is két külön processz lesz.
\item[Process-per-site]
Különböző site-ok külön processzbe kerülnek. Az előzővel ellentétben, ha egy site
kétszer van megnyitva, akkor azok közös processzbe kerülnek.
\item[Process-per-tab]
Minden tab külön processz. Több tab kerülhet közös processzbe, ha függnek egymástól.
\item[Single Process]
A ``hagyományos'', egy-processzes modell. Nincs külön Render Process. A rendering
a Browser Processben, külön szálon (thread) történik.
\end{description}
\noindent
Alapértelmezetten a \textit{Process-per-site-instance} modellt használja a Chromium.
Ettől függetlenül azonban előfordulhat, hogy több site is osztozik, ugyanazon a processzen.
Erre vagy akkor van szükség amikor két site hivatkozik scriptből egymásra (függnek
egymástól), vagy amikor a futó Render Processek száma elér egy korlátot.
\subsubsection{Plugin Process}
A pluginok okozzák a legtöbb problémát egy böngésző stabilitásának szempontjából. A plugint
egy harmadik fél készíti, ezért a Chromiumnak nincs befolyása afelett, hogy milyen
erőforrásokat használ. Biztonsági és stabilitási megfontolásból érdemes a pluginokat nem
a Browser Processben futtatni. A legtöbb plugin azonban nem futhat sandbox környezetben,
mivel olyan képességekkel bővítik a böngészőt, amelyekhez szükség van hozzáférésre a rendszer
erőforrásaihoz. Ezen megszorítás miatt a Render Process nem jöhet számításba, így új
processz típusra van szükség, ami a Plugin Process \cite{bib:chromium-plugins}.
\subsubsection{GPU Process}
A renderelés a Render Processben történik, viszont ez a processz sandboxban fut és ezért
nem küldhet parancsokat GPU-nak. Hardveres gyorsítás esetén a compositingot és a rajzolást
egy külön, nem sandbox környezetben futó processzben\footnote{A Chromium úgy is
konfigurálható, hogy a GPU Process feladatát a Browser Process lássa el} kell elvégezni.
Erre a célra szánt processz típus a GPU Process \cite{bib:chromium-gpu}.
\subsection{Chromium Content Module}
A Content Module a Chromium az a része, ami megvalósítja az előző fejezetben bemutatott
multi-processz architektúrát \cite{bib:chromium-content-module}. Itt van még megvalósítva az
összes támogatott web platform funkcionalitás (például: HTML5, WebRTC, WebGL, stb.), illetve
a hardveres GPU gyorsítás is. Böngészőalkalmazás specifikus funkcionalitások nem részei a
Content Module-nak. Lényegében csak olyan funkciókat implementál ami a web tartalom
megjelenítéséhez\footnote{\textit{content} = web tartalom} szükséges.
Ezekre a legtöbb böngészőt integráló alkalmazásnak szüksége van.
Az opcionális böngésző funkcionalitásokat a beágyazó
alkalmazásnak\footnote{Egy a Chromium Content Module-t beágyazó alkalmazás például a Chrome}
kell implementálnia, viszont egyes funkciók szorosan kötődhetnek a Content Module-hoz,
így szükség van egy interfészre is, amin keresztül a funkciók megvalósíthatóak és
testreszabhatóak a beágyazó alkalmazásban anélkül, hogy a Chromium forráskódját módosítani
kellene. Ez az interfész a Chromium Content API \cite{bib:chromium-content-api}.
\subsubsection{Chromium Content API}
A Content API megtervezésekor a WebKit API-t vették alapul, hogy a WebKit fejlesztők
könnyebben áttérhessenek. A Content API \textit{unstable}, ami azt jelenti, hogy az minden
új kiadásban változhat, ezért az azt használó alkalmazást is minden Chromium frissítés után
nagy valószínűséggel változtatni kell.
A Content Module a beágyazó alkalmazást interfészeken (Delegate, Observer)
és callback függvényeken keresztül értesíti az eseményekről, változásokról (például,
hol tart a web oldal letöltése vagy sikeres volt-e a letöltés) vagy éppen
kér le adatokat (például, kell-e megjeleníteni hiba üzenetet, ha nem sikerül letölteni egy
oldalt). Az ilyen interfészek metódusainak törzse üres a Content Module-ban, ezeket a
beágyazó alkalmazásnak kell megvalósítania és a Content Module hívja meg őket szükség esetén.
Vannak továbbá olyan interfészek is, amelyeket a Content Module valósít meg. Ezek jellemzően
olyan funkciókat implementálnak, amelyeket a Content Module lát el, viszont a modulon
kívül kell használni. Ilyen funkciók például az oldal betöltése (\texttt{LoadURLWithParams()})
vagy a betöltött oldal URL-jének lekérdezése (\texttt{GetVisibleURL()}). Ezeket a funkciókat
nem ajánlott a Content Module-on kívül felül definiálni.
\subsubsection{Chromium Content Shell}
\begin{figure}[h]
\centering
\includegraphics[scale=0.40]{content-shell}
\caption{
\label{fig:content-shell}
Content Shell
}
\end{figure}
Az \ref{fig:content-shell} ábrán látható alkalmazás a Content Shell. Ez a lehető
legegyszerűbb böngészőalkalmazás, ami a Content API-ra épül. Arra használják, hogy a
Content Module-t és a Blinket tesztelhessék, debuggolhassák anélkül, hogy egy teljes
böngészőalkalmazást (például Chrome) le kellene fordítani.
\subsection{Felépítés}
Az eddigiek alapján a Chromiumot 3 rétegre oszthatjuk fel:
\begin{description}
\item[Chrome]
Felhasználói felület (UI) és böngészőalkalmazás funkciók
(például: böngészési előzmények, könyvjelzők, favicon, stb.)
\item[Content]
Ez a réteg valósítja meg a multi-processz architektúrát,
felel a web platform funkciókért és a hardveres GPU gyorsításért.
\item[Blink]
Webes tartalom feldolgozása és renderelése. A V8 JavaScript motor a
Blinken keresztül érhető el és közös processzben futnak.
\end{description}
A \ref{fig:chromium-architecture} ábra mutatja, hogyan is állnak össze a Chromium rétegei.
A Blink böngészőmotor ``WebKit'' elnevezéssel van jelölve.
A legfelső réteg a Chrome, helyére a saját beágyazó alkalmazás kerül.
\begin{figure}[ht]
\centering
\includegraphics[scale=0.6]{chromium-architecture}
\caption{
\label{fig:chromium-architecture}
Chromium Architecture \cite{bib:chromium-content-module}
}
\end{figure}
\subsection{Release}
Egy Chromium release verzió száma 4 részből tevődik össze:
\begin{verbatim}
MAJOR.MINOR.BUILD.PATCH
\end{verbatim}
A dolgozatomban a főverzió számra (\texttt{MAJOR}) hivatkozok.
A Chromium közösség előre tervezett menetrend szerint 1-1.5 havonta vált főverzió számot
(ad ki új release-t).
Dolgozatom készítése idején az 51-es verziójú volt a legfrissebb stabil kiadás.
Az itt leírtak erre a verzióra vonatkoznak.
\section{Qt}
A Qt egy nyílt forrású, cross-platform alkalmazás keretrendszer \cite{bib:qt-wiki-about-qt}.
Úgy ahogy a Chromium, úgy a Qt is elérhető napjaink legnépszerűbb desktop és mobil operációs
rendszerein. Ez a keretrendszer nyújt C++ függvénykönyvtárakat (library), bindingokat más
programozási nyelvekhez (például: Python, Java), saját deklaratív programozási nyelvet (QML),
saját integrált fejlesztői környezetet (QtCreator), saját build rendszert (qmake) és
kiterjesztéseket is a C++ programozási nyelvhez (például signal--slot modell).
\subsection{Történeti áttekintés}
\subsubsection{1995-2000}
A Qt első verzióját 1995-ben adta ki a Trolltech \cite{bib:qt-wiki-qt-history}. Akkor még a
projekt egy cross-platform GUI fejlesztői keretrendszernek indult. Pár évvel később
(1998-ban), jelent meg a KDE (K Desktop Environment) első verziója, amely Qt-re épült. A KDE
egyhamar az egyik legnépszerűbb Linuxos asztali környezetté nőtte ki magát és talán ennek
tudható be a Qt mai napig tartó népszerűsége is. A Qt eszköztára az évek során fokozatosan
bővült. Új API-k jelentek meg adatbázis kezeléshez (SQL), hálózati programozáshoz, multimédiás
alkalmazások készítéséhez, XML dokumentumok feldolgozásához stb.
\subsubsection{2000-2008}
2000-ben jelent meg a Qt-ra épülő Qt/Embedded keretrendszer Linuxos beágyazott eszközökre.
Ezzel az új technológiával a Qt meg is jelent az első okos telefonokon (2003: Motorola A760)
és a korabeli PDA-kon. 2006-ban a Trolltech kiadta saját fejlesztésű mobil telefonját
Greenphone néven.
\subsubsection{2008-2011}
Talán a Trolltech beágyazott platformokon és mobil telefonokon szerzett tapasztalata
miatt került arra sor, hogy 2008-ban, az akkori egyik vezető mobiltelefon gyártó -- a Nokia --
felvásárolta a céget. A következő pár évben a fejlesztés még inkább a mobil eszközök
felé tolódott el. Ezekben az években azokon a területeken, amelyek nem voltak érintettek a
mobil platformok által, jóformán nem is történt fejlesztés.
2010-ben kiadott 4.7-es verzióban két nagyon fontos újítás (teljesen új komponens) jelent meg:
a QtWebKit és a QtDeclarative.
A WebKit az Apple által fejlesztett nyílt forrású böngészőmotor. A Qt erre építette saját
böngészőmotorját, a QtWebKitet. A QtWebKit a WebKittel szemben Qt-s API-val rendelkezik és az
alacsony szintű műveleteket is -- mint a hálózatkezelés vagy a tartalom kirajzolása -- a Qt
végzi. A WebKit maga is 2 régi KDE-s projekre épül: a KHTML-re (WebCore) és a
KJS-re (JavaScriptCore). A sors iróniája, hogy amikor 2001-ben az Apple fejlesztői forkolták
ezeket a projekteket a céljuk éppen az volt, hogy egy a Qt-tól független új böngészőmotort
alkossanak.
Az új verzió másik fontos újítása a Qt Quick keretrendszer és a QML nyelv (QtDeclarative)
megjelenése volt. A QML egy új deklaratív programozási nyelv, a Qt Quick pedig egy
eszközkészletet nyújtott hozzá. Ezek segítségével a Qt új lehetőségeket nyitott grafikus
felhasználói felületek megvalósítására. Ez az új technológia a mobil fejlesztés szempontjából
jelentős előrelépés volt. A legnagyobb előnye (a könnyű használhatóságot és a gyors
fejlesztési ciklust nem számítva), hogy mobil alkalmazás felhasználói felületének
lefejlesztéséhez nincs szükség szimulátorra, hiszen a QML-ben írt alkalmazás
platformfüggetlen és ugyanúgy fut/néz ki desktopon mint mobilon.
\subsubsection{2011-2013}
2011 elején a Nokia szerződést kötött a Microsofttal. A Nokia készülékek elsődleges
platformja a Windows Phone lett, így a Nokia elkezdte fokozatosan leépíteni a
szoftver kutatás-fejlesztés részlegét. 2012-re a Qt teljes egészében a Digia
tulajdonába került.
A 2012-es év pozitív változást is hozott, az év végén megjelent a Qt 5.0-ás verziója.
Az új verzió API-ja nem sokban tér a 4-estől, így az új API szinte teljesen kompatibilis
maradt a régivel. Az igazán fontos változás a Qt kód struktúrájában történt.
A 4-es verzióban a kódot már modulokra bontották, hogy a Qt-s alkalmazások méretét
csökkentsék azzal, hogy a nem használt modulokat (gyakorlatilag függvénykönyvtárakat) nem
linkelik az alkalmazáshoz.
Az 5-ös verzióban a fejlesztők tovább mentek: a keretrendszert több,
kisebb modulra bontották és az összetartozó modulokat közös repositoryba helyezték
(komponensek vagy alprojektek). Ezzel megszűnt a 4-es verzió ``egy-repositorys'' modellje
és így a modulok/komponensek egymástól függetlenül is kiadhatóvá, verziózhatóvá váltak.
Az új projektek/modulok saját repositoryait a \texttt{qt5} top-level repository gyűjti össze,
amely hivatkozásokat (git submodule) tartalmaz a alprojektek repositoryjaira.
Az 5-ös verzió másik újítása Qt Quick2 modul volt. A Qt Quick első verziója (Qt Quick1) a
\texttt{QGraphicsView}-ra épül, ami szoftveres renderelést használ a megjelenítéshez.
Ez a megoldás lassú, ráadásul widget függőséggel is jár (Qt Widgets modul).
A Qt Quick2 API-ja kompatibilis maradt a Qt Quick1-el, viszont teljesen újraírták.
Megszűnt a widget függőség mivel ezentúl a Qt Quick2 saját Qt Quick Scene Graph-ot valósít
meg. Ez a scene graph Open GL ES 2.0-ra vagy Open GL 2.0-ra épül, így a renderelés a GPU-n
történik. Ez a megoldás sokkal gyorsabb, viszont nem támogatott olyan platformokon, ahol
nem elérhető az Open GL 2 vagy újabb verziója.
2013-ban a Qt fejlesztői úgy döntenek szakítanak a WebKittel és, hogy böngésző motor
API-jukat ezentúl a Chromium felé építik \cite{bib:qt-blog-introducing-qtwebengine}.
Az új komponenst Qt WebEngine-nek hívják és 5.4-es verzióban jelent meg először.
\subsubsection{2014-napjainkig}
2014-ben a Qt részlege kivált a Digia-ból és létrejött a \textit{The Qt Company},
mint a Digia leányvállalata. A kiválás oka, hogy a Qt üzleti logikája és piaca eltér a
Digia-étól, ezért másfajta vezetésre, fejlesztésre és befektetési tervre van szükség.
Ez a folyamat még 2016-ban is tart és terv szerint 2016 májusában a The Qt Company megjelenik
a tőzsdén is \cite{bib:qt-about-us}.
A Qt hányattatásai ellenére még ma is töretlen népszerűségnek örvend és talán az egyik
legjobb elérhető C++ alkalmazás keretrendszer a piacon. Ezt bizonyítja,
hogy több, napjainkban is népszerű és széles körben elterjedt alkalmazás is a
Qt keretrendszerre épít. Mint például Skype, Google Earth, VirtualBox,
a VLC média lejátszó és a Spotify is.
\subsection{Modulok és Komponensek}
A 4-es Qt verzióban megtörtént az első lépés a modularizáció felé: minden modul külön
függvénykönyvtárként jelenik meg, a korábbi egyetlen Qt függvénykönyvtár helyett.
Ennek előnye, hogy a fejlesztőnek nem kell olyan modulokat az alkalmazásához linkelnie,
amit nem is használ.
\begin{figure}[h]
\centering
\includegraphics[scale=.66]{qt-repos-and-modules}
\caption{
\label{fig:qt-repos-and-modules}
Qt repository-k és modulok
}
\end{figure}
Az 5-ös Qt verzióban kiterjesztették a modularizációt a projekt struktúrájára is. A projekt
többé nem egy nagy közös repository, hanem több önálló repositoryból áll össze, melyeket
a modulok szerint választottak szét. Ennek a modellnek több előnye is van: a moduloknak
saját verzió számuk lehet, ezért a Qt release-től függetlenül is kiadhatóak. Fejlesztés
szempontjából a buildelés és tesztelés rugalmasabb és gyorsabb lett, hiszen változás esetén
csak a modult és annak függőségeit kell újra buildelni.
Qt 5-ben a modulokat két kategóriába sorolják: \textbf{Qt Essentials} és
\textbf{Qt Add-Ons} \cite{bib:qt-doc-qtmodules}.
Az Essential modulok nyújtják a Qt alap funkcionalitását, amit a legtöbb Qt-s alkalmazás
használ. Ezeknek a moduloknak működniük kell az összes támogatott platformon, az 5-ös
főverzión belül a bináris és az API kompatibilitás garantált.
Az Add-on modulok nem általános célú, opcionális modulok. Nem garantált, hogy minden
támogatott platformon működnek és az egyes verziók sem biztos, hogy kompatibilisak egymással.
A kifutó Qt modulok (például Qt Script) is a az Add-ons kategóriába kerülnek addig, amíg
véglegesen el nem távolítják őket. A QtWebEngine moduljai is Add-onok, mivel nem általános
célúak, a legtöbb alkalmazásnak nincs szüksége böngésző funkciókra.
Ha egy Qt-s alkalmazás használ egy Qt modult, akkor azt annak a projekt fájljában meg kell
adni:
\begin{lstlisting}[title=app.pro]
QT += network widgets qml quick
\end{lstlisting}
Ez alól kivétel a Qt Core és a Qt GUI modul. A Qt Core modult
minden Qt-s alkalmazás használja, ezért azt a Qt build rendszere implicit linkeli.
Ebben a modulban vannak megvalósítva a Qt típusok és adatszerkezetek, a Qt specifikus nyelvi
elemek és makrók (például: \texttt{Q\_OBJECT}, \texttt{signals}, \texttt{slots}),
smart pointerek, stb. A Qt GUI\footnote{A Qt GUI modulról bővebben a \ref{sec:qt-gui}
fejezetben lesz szó.} modulra a grafikus felhasználói felület megvalósításához van szükség.
A Core modulhoz hasonlóan implicit linkelődik az alkalmazáshoz viszont ez már letiltható, ha
a következő sort adjuk a projekt fájlhoz:
\begin{lstlisting}[title=app.pro]
QT -= gui
\end{lstlisting}
Ahogy a Qt-s alkalmazások, használnak egy Qt-s modult, úgy a Qt-s modulok is függhetnek
egymástól. Az alkalmazáséhoz hasonlóan, a modul projekt fájljában is jelölni kell a
függőséget. Továbbá ez a függőség komponensek közötti függőséget is jelent, hogy ha
a hivatkozott modul egy másik repository-ban van. A komponens függőségeit a
\texttt{sync.profile} scriptben kell felsorolni:
\begin{lstlisting}[title=sync.profile]
%dependencies = (
"qtbase" => "",
"qtdeclarative" => "",
"qtxmlpatterns" => "",
"qtquickcontrols" => "",
"qtwebchannel" => "",
);
\end{lstlisting}
Habár a QtBase komponens minden más komponens függősége, azt explicit meg kell adni.
Az \ref{fig:qtwebengine-dependencies} ábra mutatja, hogy a fenti \texttt{sync.profile} script
alapján a QtWebEngine függőségei hogyan alakulnak.
\begin{figure}[ht]
\centering
\includegraphics[scale=.6]{qtwebengine-dependencies}
\caption{
\label{fig:qtwebengine-dependencies}
QtWebEngine függőségei
}
\end{figure}
\subsection{GUI}
\label{sec:qt-gui}
A Qt keretrendszer grafikus felhasználói felületek (GUI) megvalósítására gazdag
eszközkészletet kínál a fejlesztők számára. A Qt GUI modul \cite{bib:qt-doc-qt-gui} az,
amely alacsony szintű API-t nyújt 2D (rasztergrafika) és 3D (OpenGL API) rajzoláshoz,
esemény kezeléshez, képek és szövegek megjelenítéséhez.
Egy grafikus felület megvalósításához nem érdemes közvetlenül a Qt GUI modul
alacsony színtű API-ját használni. A Qt nyújt magasabb szintű, Qt GUI-ra épülő API-kat is
\cite{bib:qt-doc-user-interfaces}. Jelenleg két egymástól eltérő megközelítést is támogat
a Qt felhasználói felületek megvalósítására. A klasszikusat a \textbf{Widget},
míg a modern megközelítést a \textbf{Quick} API teszi elérhetővé.
\subsubsection{Widget}
A widget API-n \cite{bib:qt-doc-qt-widgets} keresztül ``hagyományos'' felhasználói
felületeket lehet megvalósítani, melyeknek megjelenítéséhez a Qt a futtató operációs
rendszer stílusát adja (\textit{native look'n'feel}). A widgetek olyan statikus GUI elemek,
amelyekből desktop alkalmazások grafikus felülete felépül. Információt jelenítenek meg és
felhasználói eseményekre reagálhatnak. Ilyen Qt widget elemek például:
gomb (\texttt{QButton}), címke (\texttt{QLabel}), görgetősáv (\texttt{QScrollBar}), stb.
Az a widget, aminek nincs szülője, az az ablak (\texttt{QWindow})
A Qt beépített widgetjei a \textbf{Qt Widgets} modulból elérhetőek, de saját widgetek is
készíthetőek. A widgeteket és azok tartalmát a \texttt{QGraphicsView} jeleníti meg. A rajzolás
szoftveresen történik, nincs hardveres gyorsítás.
A Qt Widgets modul a widgeteken kívül tartalmaz API-t a widgetek megjelenítésének
testreszabására (\texttt{QStyle}) és beépített stílusokat is natív megjelenéshez különböző
platformokon. A widgetek elrendezésére a modul \texttt{QLayout} osztályai használhatóak.
A widget alapú GUI-t első sorban C++ API-n keresztül lehet felépíteni, de a Qt
keretrendszer tartalmaz egy Qt Designer elnevezésű alkalmazást is, aminek segítségével,
akár programozási ismeret nélkül össze lehet állítani a egy felhasználói felületet.
A Qt Designer a widgeteket fastruktúrába rendezi és XML formátumban tárolja egy \texttt{.ui}
kiterjesztésű fájlban. Az XML fájlból a User Interface Compiler (uic) generál buildelhető
C++ forrás állományt.
\subsubsection{Quick}
Az új Quick technológia segítségével modern megjelenésű, dinamikus elemekből felépített,
``fluid'' GUI-t lehet összeállítani. Megvalósítás ``deklaratív módszerrel'' történik, ami
magasabb szintű, mint a widget API esetében használatos imperatív paradigma: nem azt kell
leprogramozni, hogyan legyen megjelenítve a GUI, hanem azt, hogy hogyan nézzen ki
(mint például a HTML esetében). A technológia használatához alapvetően 2 modulra van
szükség: \textbf{Qt QML}-re és a \textbf{Qt Quick}-re\footnote{Mindkét modul a QtDeclarative
projekt része}.
A Qt egy saját nyelvet nyújt a deklaratív programozáshoz, ez a QML (Qt Modeling Language)
\cite{bib:qt-doc-qt-qml}. A QML nyelv a Qt QML modulon keresztül válik elérhetővé. A modul
rendelkezik C++ és QML API-val is, hogy a QML nyelv saját típusokkal és funkciókkal bővíthető
legyen. A Quick GUI akár ezen a C++ API-n keresztül is megvalósítható, de erre a célra
sokkal inkább a QML nyelv használata ajánlott.
A QML nyelv ``JSON-szerű'' szintaxissal írja le a UI komponensek hierarchiáját és
kapcsolatait. A QML programot egy külön erre a célra fejlesztett JavaScript motor dolgozza
fel és hajtja végre, ez a v4. Ezáltal lehetővé válik, hogy a UI kódja akár futásidőben is
dinamikusan változtatható legyen. JavaScript kód szabadon hozzáadható a QML forráshoz, így
akár logikát is meg lehet valósítani a QML programon belül. JavaScript kód használatánál
érdemes csak az eseménykezelésre szorítkozni és a többi vezérlést a Qt QML modul C++ API-ján
keresztül C++ nyelven megvalósítani.
Habár a Qt QML modul rendelkezésünkre bocsájtja a QML deklaratív nyelvet, az még
nem rendelkezik olyan elemekkel, amelyekből össze lehetne állítani egy grafikus felületet.
Előre gyártott GUI elemeket a \textbf{Qt Quick} és a \textbf{Qt QuickControls} modulok
szolgálgatják \cite{bib:qt-doc-qt-quick}. Ezekben majdnem minden elem megtalálható, mint ami
widget API-ban, sőt még több is. További lehetőség nyílik a felület elemeinek animálására
Qt Quick API-ján keresztül. A Qt Quick C++ API-ját használva pedig saját
\texttt{QQuickItem}-ek hozhatóak létre, melyek a Qt QML C++ API-ján keresztül QML típusként
regisztrálhatóak be a QML nyelvbe.
A Qt Quick modul felel a Quick GUI elemek megjelenítéséért és kirajzolásáért is.
Korábban (Qt Quick1) a rajzolás ugyanúgy történt, mint a widget esetén: az elemek a
\texttt{QGraphicsView}-ra voltak kirajzolva. Ez a megoldás lassú, különösen, ha egy folyton
változó dinamikus felhasználói felületről beszélünk. A jelenleg is használt Qt Quick verzióban
(Qt Quick2) jelent meg a Qt Quick Scene Graph \cite{bib:qt-doc-qt-quick-scene-graph}.
A Qt Quick Scene Graph a Qt Quick modul része, ezért nem használható önállóan, viszont van
publikus API-ja. A scene graph a UI elemeiből épített fa struktúra, amelyet aztán a modul
OpenGL ES 2.0 vagy OpenGL 2.0 API-n keresztül megjelenít. Emiatt a Quick technológia nem
használható olyan platformokon, ahol nem érhető el legalább az OpenGL 2.0 API.
\subsection{Web}
A Qt keretrendszerben nem a QtWebEngine az egyetlen komponens/modul ami a
webhez, web alkalmazásokhoz nyújt API-t.
\subsubsection{QtWebKit}
A QtWebKit a nyílt forrású WebKit böngésző motor portja. A WebKit API felé két fajta Qt-s
API-t implementál: C++ API-t a Widget alkalmazásokba való beágyazáshoz és QML/Quick API-t a
Quick alkalmazásokhoz. A C++ API szinkron, mivel a single-process architektúrájú WebKit
API-ra (WebKit1) épül. Ezzel szemben a Quick integrációt lehetővé tevő QML API aszinkron,
mert az már a multi-process WebKit2-re épül.
A QtWebKit a Qt 4.7-es verziójában jelent meg. A Chromium--WebKit szétválás után a
fejlesztése leállt és csak karbantartási munkálatokat végeztek rajta. A Qt 5.5-ös kiadásban
már elavultnak (deprecated) számít az 5.6-os verzióból már a bináris csomagokat is
eltávolították, csak QtWebKit forráskódja érhető el. A QtWebKit leváltására a Chromiumra
épülő QtWebEngine-t hozták be.
\subsubsection{QtWebView}
A QtWebKit sosem volt támogatott mobil platformokon (Embedded Linuxon igen) és ez jelenleg
hivatalosan igaz a QtWebEngine-re is. Azonban, a mobil platformok (például: Android, iOS,
WinRT) biztosítanak natív API-t (WebView) a webes tartalmak megjelenítésére. Biztonsági
megfontolásból más módon a mobil alkalmazások nem is férhetnének hozzá web tartalomhoz.
A QtWebView komponens/modul \cite{bib:qt-doc-qt-webview} ezeket a natív API-kat fedi el
(wrapper) és implementál felettük egységes, Qt API-t. Amennyiben nincs elérhető (vagy
támogatott) web API a platformon, akkor a QtWebEngine-t próbálja használni (fallback).
A QtWebView-nak csak QML/Quick API-ja van.
\subsubsection{QtWebSockets}
A WebSocket egy olyan protokoll, amely kétirányú kommunikációt biztosít a web felett.
A kommunikáció kliens és szerver között történik. A legtöbb modern böngésző integrálja a
WebSocket klienst. A QtWebSockets \cite{bib:qt-doc-qt-websockets} C++ és QML/Quick API-t
biztosít mind WebSocket kliens és szerver megvalósításához.
\subsubsection{QtWebChannel}
A QtWebChannel komponens/modul \cite{bib:qt-doc-qt-webchannel} a Qt 5.4-es verziójában jelent
meg. Olyan alkalmazások esetében, amelyek beépített HTML tartalmat jelenítenek meg szükség
lehet olyan megoldásra, amelynek segítségével a WebView-ban futó webalkalmazás
(JavaScript/HTML) és a natív alkalmazás (QML/C++) kommunikálni tud
\cite{bib:kdab-qt-webchannel}.
A single-process QtWebKit widget API esetén ennek megvalósítása nem jelentett különösebb
problémát, viszont egy multi-process architektúrára épülő motor (WebKit2 vagy Chromium)
a megvalósítás már sokkal bonyolultabb. Erre a problémára nyújt megoldást a QtWebChannel.
A QtWebChannel segítségével egy \textit{Qt MetaObject}-et (\texttt{QObject}) lehet
``meghirdetni'' szerver oldalon, a kliens oldal pedig ezt a MetaObject-et tudja használni.
A komponens szerver oldalra nyújt QML és C++, a kliens oldalra pedig JavaScript API-t.
A kliens oldalon megjelenő JavaScript objektum a szerver oldali Qt MetaObject másolata. A két
objektum szinkronizálva van, a property változtatások és a Qt-s szignálok mindkét oldalon
megjelennek.
Ez úgy valósul meg, hogy a QtWebChannel szerializálja Qt MetaObject-et majd átküldi
a kliensnek. A kliens oldali API a szerializált Qt MetaObject-ből JavaScript
object-et gyárt, amely képes kommunikálni az eredeti object-el. A kommunikáció történhet
QtWebSockets segítségével, de akár IPC-n keresztül is.
\subsection{Release}
Egy Qt release verzió száma 3 részből tevődik össze:
\begin{verbatim}
MAJOR.MINOR.PATCH
\end{verbatim}
A dolgozatomban bemutatott fejlesztések mind az 5-ös főverzióban (\texttt{MAJOR})
jelentek meg. Ahol ez egyértelmű feltüntetem az alverzió számot is (\texttt{MINOR}).
A Qt közösség előre tervezett menetrend szerint fél évente vált alverzió számot (ad ki új
release-t). Dolgozatom készítése idején a Qt 5.6 a legfrissebb stabil kiadás, viszont egyes
bemutatott funkcionalitások, majd csak a Qt 5.7-ben lesznek elérhetőek.
\section{QtWebEngine}
A QtWebEngine \cite{bib:qt-doc-qtwebengine-overview} váltotta le a QtWebKitet a Qt
keretrendszer 5.4-es verziójában. A célja megegyezik a QtWebKitével: webes tartalom
integrálása és manipulálása Qt alkalmazásban. A QtWebEngine a Chromiumra épül, pontosabban a
Chromium Content Module unstable API-ja -- Chromium Content API -- felé implementál egy
stable API-t. Az \ref{fig:chromium-architecture} ábra alapján, a Chrome böngésző alkalmazás
helyére a Chromium \textit{stack} tetejére a QtWebEngine kerül és az lesz a Chromium Content
Module-t beágyazó ``alkalmazás''\footnote{QtWebEngine esetén inkább ``beépítő''
függvénykönvytárról van szó, mintsem alkalmazásról}.
A QtWebEngine fejlesztői forkolták a Chromiumot és ennek a forknak a karbantartása jelentős
mennyiségű munkát jelent a fejlesztőknek. Körülbelül 6 hetente jelenik meg új Chromium
verzió aminek változik az API-ja. Minden új verzió tartalmazhat biztonsági javításokat is,
amelyeket a Chromium fejlesztői nem backportolnak korábbi verziókba\footnote{A Chromiumnak
nincs LTS (Long Term Support) verziója}, ezért a rendszeres frissítésekre szükség van.
A biztonsági javítások, amikor ez megoldható \textit{cherry-pickelve} vannak a QtWebEngine
Chromium forkjába.
A QtWebEngine legnagyobb részét a Chromium fork forráskódja teszi ki, habár sok
nem használt Chromium komponens eltávolításra került (például a Chrome böngésző alkalmazás).
Viszont egyes ``backend'' komponensek, amelyek lecserélhetőek voltak QtWebKitben Qt modulokra,
már nem cserélhetőek le a Chromiumban. Ilyen például a Chromium \textit{network library}.
A web elemek kirajzolását viszont a Qt végzi. A mailbox texture azonosítók segítségével a
QtWebEngine hozzáfér a Chrome Compositor által összeállított textúrákhoz, amelyek a
megosztott OpenGL contexten vannak tárolva.
A textúrákból a QtWebEngine épít scene graph fát (\texttt{QSGNode} tree), amit majd a
Qt Quick Scene Graph rajzol ki. Emiatt, a Chromiumban a GPU process ki van kapcsolva,
mert a GPU-t a Qt használja, ami a Browser process-ben fut (\texttt{switches:kInProcessGPU}).
A scene graph függőség miatt a QtWebEngine nem működik olyan környezetben, ahol nincs
OpenGL ES 2.0 vagy OpenGL 2.0. Ez igaz a QtWebEngine widget API-jára is, mivel a web tartalom
kirajzolásának megvalósítása közös, így a Qt WebEngine Widgets modul sem működik Qt Quick
nélkül.
A QtWebEngine tartalmazza a QtWebEngine Processt és 3 modult: a Qt WebEngine és a
Qt WebEngine Widgets rendre a Quick és Widget API-kat valósítják meg. A Qt WebEngine Core
modul tartalmazza a Chromium forkot és QtWebEngine funkcionalitások közös megvalósítását,
amin a Quick és a Widget API-k osztoznak. A QtWebEngine felépítését a
\ref{fig:qtwebengine-architecture} ábra mutatja.
\begin{figure}[ht]
\centering
\includegraphics[scale=0.75]{qtwebengine-architecture}
\caption{
\label{fig:qtwebengine-architecture}
QtWebEngine Architecture \cite{bib:qt-doc-webengine-overview}
}
\end{figure}
\subsection{Process}
A QtWebEngine Process \cite{bib:qt-doc-qt-webengine-process} a Chromium Render Processt
bővíti ki és csomagolja magába. Különálló program saját belépési ponttal (\texttt{main()}
függvénnyel), amit a Browser Process indít el. Önálló fordítási egység, de a hozzátartozó kód
a QtWebEngine Core modulban található. Ez a processz felel a web tartalom megjelenítésért
(Blink) és a JavaScript kódok végrehajtásáért (V8). A processz OS X-en és Linuxon sandboxban
fut, Windowson a sandbox környezet még (Qt 5.7) nem támogatott.
\subsection{Core}
A Qt WebEngine Core modul \cite{bib:qt-doc-qt-webengine-core} tartalmazza a Chromium forkot
és implementálja a Chromium Content API interfészeit. Belső (\textit{internal}) API-ja elfedi
a publikus API-k (Widget, Quick) elől a Chromium Content API-t, így a publikus API-knak
nincsenek közvetlen Chromium függőségeik. A publikus API-k számára közös adapter interfészt
(\texttt{WebContentsAdapterClient}) definiál, amit a publikus API-nak kell megvalósítania.
A modul része a Qt Quick Scene Graph integráció is: ő hozza létre a Chromiumból
kinyert textúrákból a scene graph node-okat (\texttt{QSGNode}) és épít belőle fát a
megjelenítésre (compositing). Továbbá itt van megvalósítva a Browser Process és a Qt WebEngine
Process inicializációja (\texttt{WebEngineContext}), a QtWebEngine beállításainak továbbítása
a Chromium felé (\texttt{WebEngineSettings}), \textit{controller} osztályok az API specifikus
dialog ablakok megvalósításához (például \texttt{JavaScriptDialogController}) és még sok minden
más.
A Qt WebEngine Core modul függősége a Qt WebChannel modul. A WebChannel modulra azért van
szükség, hogy a publikus API-t használva tetszőleges, saját Qt-s objektum elérhető legyen a
weboldal (vagy webalkalmazás) számára. Ezáltal a fejlesztő hibrid alkalmazásokat hozhat létre,
melyekben a QtWebEngine-nel megjelenített weboldalak, kommunikálhatnak a QtWebEngine-t
beágyazó alkalmazással. A Qt WebChannel Qt WebSockets-re épülő backendjét a Qt WebEngine Core
cseréli le úgy, hogy a kommunikáció a Chromium IPC felett történjen. A \textit{web channel}-t
a Core modul regisztrálja be a V8\footnote{A V8 a Chromium JavaScript motorja} API-n keresztül
Qt WebEngine Process (Render Process) JavaScript contextjébe.