Sonsuzdöngü Blog Sonsuzdongu Thu, 07 Nov 2024 22:05:43 +0000 Zend_Feed_Writer 1.12.0 (http://framework.zend.com) http://www.sonsuzdongu.com/ WebP ve NGINX small-light ile daha performanslı siteler Mon, 17 Oct 2016 20:14:17 +0000 http://www.sonsuzdongu.com/blog/webp-ve-nginx-small-light-ile-daha-performansli-siteler http://www.sonsuzdongu.com/blog/webp-ve-nginx-small-light-ile-daha-performansli-siteler yuxel@sonsuzdongu.com (Osman Yüksel) Osman Yüksel

Web'de en çok kullanılan PNG ve JPEG resim formatları. Neredeyse tüm tarayıcılar ve cihazlar tarafından desteklenmeleri, bir çok resim işleme aracı tarafından düzenlenebilmeleri bu iki formatı bu günlere getirdi. Ancak bu resim formatlarının sıkıştırma algoritmaları eski olduğu için genellikle boyutları çok yüksek olabiliyor. Bu resim formatlarını optimize etmek için bir çok araç var. WebP'den önce bu tip araçlar kullanarak bu resimleri optimize edip sunuyorduk.


WebP, Google'ın 2010 yılında, açık bir standart olarak duyurduğu çok benzer kalitelerde %45'lere kadar daha az boyutta sıkıştırma sağlayan bir format. Optimize edilmiş JPG ve PNG formatlarından bile %10-%30 arasında daha düşük boyutta resimler üretebiliyorsunuz. Şu anda Chrome, Opera ve Android tarayıcılarda kullanılabiliyor.


WebP ile, kaliteden biraz ödün vererek, %90'lara varan sıkıştırmalar yapmanız mümkün. Bu da bizim için %90 daha hızlı yüklenen siteler demek oluyor!


WebP kullanımı, normal resim formatları kullanımından çok farklı değil. Gimp veya Photoshop gibi bir araçla, resmi WebP formatında kaydetmeniz yeterli. sonrasında

<img src="dosya-adi.webp">
şeklinde kullanmaya başlayabilirsiniz.


Tabii yukarıda bahsettiğim gibi, bunu sadece desteklenen tarayıcılar için yapmanız gerekiyor. WebP destekleyen tarayıcılar, isteklerde "Accept" header'ı olarak "image/webp" içeren bir header gönderiyor.


accept:image/webp,image/*,*/*;q=0.8

gibi. Kodunuzda "eğer bu header varsa webp, yoksa jpg yükle" gibi çok basit bir koşul ile, pazar payı yaklaşık %50 olan yukarıdaki tarayıcıları kullanan kullanıcılara çok daha hızlı bir deneyim sağlayabilirsiniz.

WebP hakkında, detaylı bir incelemeyi David Walsh'un şuradaki yazısında (ingilizce) bulabilirsiniz.


"Elimizdeki tüm resimleri webp'ye çevirip, kodumuzu 'eğer accept header'ı varsa webp, yoksa png sun' şeklinde güncellemeden bunu yapmanın bir yolu yok mu?" diye sorduğunuzu duyar gibiyim;


Burada da imdadımıza, kadim dostumuz NGINX ve onun yancısı Small Light yetişiyor. Small Light, sitesinde de belirtiği gibi, NGINX için, dinamik olarak resim manipülasyonu yapabildiğiniz bir modül. Resmi resize etmekten, crop etmeye, bulanıklaştırmaktan, kalitesini düşürmeye gibi bir çok işlemi yapabilmenizi sağlıyor.


Örneğin, bir resminiz var, ve bunun 300x300'lük thumbnail'larını oluşturmak istiyorsanız yapmanız gereken tek şey, small light'lı nginx sunucunuza

http://sunucu/resim.jpg?cw=300&ch=300
gibi bir parametre geçmek. Small Light bunun gibi bir çok parametre destekliyor.


Bunlardan birisi de "of" komutu. Bu da format dönüşümleri yapmanızı sağlıyor.

http://sunucu/resim.jpg?of=png
dediğinizde, jpg olan resminiz artık PNG olarak sunulmaya başlıyor örneğin.


Tabii ki, small light'ın webp desteği de mevcut. Kısaca yapmanız gereken. eğer accept header'ında webp desteği varsa resimlerinizin sonuna ?of=webp eklemek.


Bunu bir adım daha ileri götürüp, kodda herhangi bir koşul denetimi yapmadan bunu yapmanın da yolları var elbette. Sonuçta kadim dostumuz NGINX istekleri karşılayan sunucu olduğu için, accept header kontrolünü ona yaptırabilir, eğer webp destekleniyorsa small light kullanarak webp sunmasını sağlayabilirsiniz.


Böylece kodda yapmanız gereken hiçbir değişiklik olmayacak. Siz yine

<img src="http://resim-sunucunuz/foo.jpg">
olarak istek yapacaksınız. Tarayıcınız NGINX destekliyorsa size foo.jpg dosyasını webp olarak sunacak.


Small Light'ın güzelliklerini çok basitçe göstermek için bir Docker imajı oluşturduk. https://github.com/sonsuzdongu/ngx_small_light


git clone https://github.com/sonsuzdongu/ngx_small_light.git
cd ngx_small_light
docker build -t sonsuzdongu/ngx_small_light .
docker run \
    --rm \
    -it \
    --name ngx \
    -p 80:80 \
    -p 8080:8080 \
    -p 8090:8090 \
    -v `pwd`/html:/opt/nginx/html/ \
    sonsuzdongu/ngx_small_light

Bunu yaptığınızda, örnek depo içindeki html klasöründeki resimlerin webp olarak nasıl sunulduğunu görmek için http://127.0.0.1 adresini ziyaret etmeniz yeterli


WebP ile Performanslı Web


Optimize edilmemiş 2mb'lık bayrak.png dosyasının, 44KB olarak sunulduğunu görünce baya sevinmişsinizdir :) Neredeyse aynı kalitede resim ve %90'dan daha az bir boyut.


Bu yazıyı, yazarken Hürriyet Ürün Ekibi'nin paylaştığı Mobil Web Yenileme Süreci - Zorluklar ve Çözümler yazısına denk geldim. Yazıda, Hürriyet mobil web'in yenilenme sürecinden ve bu süreçte yaptıkları performans iyileştirmelerinden bashediyorlardı. "Acaba webp de entegre etmişler mi" diye kısaca bir inceledim, ancak gördüğüm kadarıyla WebP implementasyonun hala yapmamışlar.


Ben de hazırladığım docker imajındaki kod ile, Hürriyet'in sitesinde i.hurimg.com'dan sunulan resimleri, small light ile proxy'ledim.


Yukarıdaki videoda da görüleceği gibi,

  • Hürriyet'in sitesi 7 saniye civarı bir sürede yükleniyor.
  • Sayfadaki resimlerin toplam boyutu 5MB
  • Sayfadaki en yüksek boyutlu resim 305KB boyutunda bir PNG dosyası.

Nginx Small Light ile proxy ettiğimde ise

  • Sayfanın yüklenme hızı 7 saniyeden 4 saniyeye
  • Yüklenen resim miktarı 5MB'dan 1.3MB'a düştü.
  • 305KB'lık resim dosyası da 25KB'a düştü.

Böyle bir performans kazanımını koda hiç dokunmadan kazanabildik. Sadece i.hurimg.com'u kendi kurduğum, hiç optimize edilmemiş nginx small light'a proxy'ledim.


WebP, garip bir şekilde hala çok fazla kullanılmasa da, harcayacağınız ufak bir emek karşısında size kazandıracağı performans görülmeye değer olacaktır.


Not: Small Light'ın tüm parametrelerini açık bırakmak sitenize DDOS atakları yapılmasını sağlayabilir. cw=300&ch=300 nasıl 300 pixellik thumbnail oluşturuyorsa bu parametreler cw=10000&ch=12312321 gibi değerler de olabilir. Kısaca, bu parametrelerden hangilerine izin veriyorsanız sunucu tarafında bunları sınırlamanız önerilir. Ayrıca, small light her istekte bu işlemleri tekrar yapacağı için nginx proxy cache gibi bir modül ile istekleri cache'lemeniz de tavsiye edilir.

]]>
PHPKonf 2016 Her sene, önceki senelerden daha iyiye giden, başta PHP dünyasından olmak üzere çok değerli konuşmacı ve yüzlerce ilgili katılımcı ile artık baya baya dünya çapında olan bir etkinliğimiz var artık: PHPKonf.


]]>
Sat, 16 Apr 2016 10:14:22 +0000 http://www.sonsuzdongu.com/blog/phpkonf-2016 http://www.sonsuzdongu.com/blog/phpkonf-2016 yuxel@sonsuzdongu.com (Osman Yüksel) Osman Yüksel Her sene, önceki senelerden daha iyiye giden, başta PHP dünyasından olmak üzere çok değerli konuşmacı ve yüzlerce ilgili katılımcı ile artık baya baya dünya çapında olan bir etkinliğimiz var artık: PHPKonf.


PHPKonf 2016


Bu sene 3.cüsü düzenlenen, PHPKonf, İstanbul PHP Topluluğu'nun çabaları ile yapılan, bölgedeki en "güçlü" etkinliklerden. İstanbul PHP, her ay düzenlediği meetup'ları, senede bir düzenlediği PHPKonf ile süslemeye devam ediyor.



PHP ve web geliştirme dünyasına yön veren bir çok şirketten bir çok önemli konuşmacı var bu sene.

  • En çok kullanılan PHP framework'lerinden Symfony'yi geliştiren SensioLabs'in ortaklarından ve Symfony baş geliştiricisi Fabien Potencier, nam-ı diğer "fabpot"
  • Microsoft'dan PHP'nin Windows sürümünden sorumlu Pierre Joye
  • En çok kullanılan PHP ORM'lerinden Doctrine'in geliştiriclerinden Marco Pivetta
  • En çok kullanılan bir başka framework olan Yii Framework geliştiricilerinden Alexander Makarov
bu sene konuşma yapacak 44 konuşmacıdan sadece 4'ü.



Etkinlikte sadece PHP yok elbet;
günümüzde, geliştirme ortamları için artık neredeyse endüstri standardı olmuş "Docker"'dan, "insan kaynakları"na, "kod kalitesi"nden, "realtime web uygulamaları"na, "güvenlik"ten, "çevik yazılım geliştirme süreçleri"ne bir çok konu; Türkiye'nin en güzel geliştirici podcast'lerinden DevPod ve Kadın Yazılımcı panelleri de etkinlikte sizleri bekliyor.



Sponsorları arasında olduğumuz bu etkinlikte yerinizi almak için https://istanbulphp-phpkonf2016.eventbrite.com/ adresinden biletinizi almanız yeterli.



Bu arada unutmadan;

Elegan elegan ruby/python yazarsın ama cenazene php gelir

]]>
Tarayıcılar Nasıl Çalışır - Modern web tarayıcıların perde arkası [Çeviri] tarayıcıları incelemeyle başladım. Tarayıcılar temelde web kaynaklarını bizlere göstermekle görevli yazılımlardı ancak alt tarafta neler döndüğünü merak ediyordum. Bununla ilgili olarak How Browsers Work: Behind the scenes of modern web browsers makalesini okudum. Aşağıda da bu belgeyi çevirdim. ]]> Mon, 10 Nov 2014 12:30:27 +0000 http://www.sonsuzdongu.com/blog/tarayicilar-nasil-calisir-modern-web-tarayicilarin-perde-arkasi-cevirisi http://www.sonsuzdongu.com/blog/tarayicilar-nasil-calisir-modern-web-tarayicilarin-perde-arkasi-cevirisi mustafa.hasturk@yandex.com (Mustafa Hastürk) Mustafa Hastürk tarayıcıları incelemeyle başladım. Tarayıcılar temelde web kaynaklarını bizlere göstermekle görevli yazılımlardı ancak alt tarafta neler döndüğünü merak ediyordum. Bununla ilgili olarak How Browsers Work: Behind the scenes of modern web browsers makalesini okudum. Aşağıda da bu belgeyi çevirdim.
Çevirmen: Mustafa Hastürk

Önsöz

Bu kapsamlı belge Webkit ve Gecko'nun iç yapılarının araştırmasını içermektedir. İsrailli geliştirici Tali Garsiel uzun zaman ve emek harcayarak tarayıcıların kaynak kodlarını okumuş ve tarayıcıların iç yapısı ve çalışma mekanizması incelemiştir.

Kendisi şöyle bir not düşmüş:

IE'ın zamanlarında %90 gibi bir oranda hakimiyet sürerken tarayıcılara bir kapalı kutu olarak bakılıyor ve saygı duyuluyordu. Fakat şimdi, pazar payı yarıdan fazla olan açık kaynaklı tarayıcılarla birlikte tarayıcı çekirdeklerinin altında ne olduğuna bakarak orada ne olduğunu görmek için tam sırası. Daha doğrusu milyonlarca C++ kodunun içinde ne olduğunu...

Tali araştırmalarını kendi sitesinde yayınladı fakat hepimiz biliyoruz ki daha fazla okuyucu kitlesini hak ediyor. Bu yüzden de çalışmayı düzenleyip burada yeniden yayınladık.

Bir web geliştiricisi olarak tarayıcı işlemlerinin iç yapısını öğrenmek bize daha iyi kararlar vermeyi ve geliştirmenin arkasındaki en iyi pratikleri bilmemizi sağlar. Bu belge oldukça uzun bir belge iken tüm detayları öğrenmek için biraz zaman harcamanızı öneriyoruz. Garanti ediyoruz ki harcadığınız zamana değecek.

Ayrıca Tali Garsiel'in bu konu hakkındaki konuşmasını Vimeo üzerinden http://vimeo.com/44182484 adresinden takip izleyebilirsiniz.

Giriş

Web tarayıcıları çok geniş çevrede kullanılan yazılımlardır. Bu el kitapçığı boyunca web tarayıcılarının arka planında neler döndüğünü ve nasıl çalıştığını anlatacağım. Tarayıcının adres çubuğuna google.com yazdığınızda taki ekranınıza Google yazısı gelinceye kadar neler döndüğüne bakacağız .

Bahsedeceğimiz Tarayıcılar

Bu günlerde masaüstünde kullanılan beş ana tarayıcı şunlardır. Opera, Chrome, Firefox, Safari ve Internet Explorer. Mobil platformda ise ana tarayıcılar Android Browser, iPhone, Opera Mini ve Opera Mobile, UC Browser. Bu tarayıcıların bir çoğu Webkit i temel alıyor. Açık kaynak tarayıcılar olan Chrome, Firefox ve Safari (kısmen de olsa) den örnekler vereceğim.

StatCounter istatistiklerine göre tarayıcıların kullanım oranlarını resimden görebilirsiniz.

İstatistikler

Tarayıcıların Ana İşlevselliği

Tarayıcının ana görevi bizim seçtiğimiz web kaynağını, sunucuya istek yaparak ve tarayıcının penceresinde bize göstererek sunmaktır. Kaynak genellikle bir HTML belgesi iken PDF, görüntü veya farklı bir içerik tipi de olabilir. Kaynağın konumu kullanıcı tarafından URI (Uniform Resource Identifier = Uniform Kaynak Tanımlayıcı) kullanılarak belirtilir.

Tarayıcı yorumlama ve HTML dosyalarının görüntülenmesinin yolu HTML ve CSS beyannamelerinde belirtilmiştir. Bu beyannameler W3C organizasyonu tarafından sürdürülmektedir ve bu organizasyon webin standartlarını oluşturmaktadır. Yıllardır tarayıcılar bu beyannamenin sadece belli bir kısmına uydular ve kendi uzantılarını geliştirdiler. Bunlar web yaratıcıları için ciddi uyumluluk sorunlarına neden oldu. Bugün ise bir çok tarayıcı bu beyannameye az veya çok şekilde uyuyorlar.

Tarayıcılar genel olarak çeşitli kullanıcı arayüzlerine sahipler. Bu genel arayüzler arasında;

  • Adres (URI) girmek için kullanılacak bir adres çubuğu
  • İleri ve geri butonları
  • Yer imleri seçeneği
  • Geçerli belgeyi yenilemek veya durdurmak için gerekli yenileme ve durdurma butonları
  • Ana sayfaya gitmek için kullanılacak ana sayfa butonu

yer almaktadır.

Gariptir ki tarayıcıların kullanıcı arayüzleri herhangi bir resmi beyanname ile belirtilmemiştir. Bu arayüzler uzun yıllar süren, şekillenen iyi deneyimler ile meydana gelmektedir ve tarayıcılar birbirlerini taklit ederek / esinlenerek ilerlemektedirler. HTML5 beyannamesi, tarayıcıların sahip olması gerektiği herhangi bir UI yani kullanıcı arayüzü tanımlamaz fakat bazı ortak elemanları listeler. Bunların arasında; adres çubuğu, durum çubuğu ve araç çubuğu yer alır. UI yani kullanıcı arayüzü elemanları arasında tabi ki de tarayıcıya özgü elemanlar da vardır. Örneğin Opera Browser'ın Discover yani keşfet arayüzü gibi.

Tarayıcının Yüksek Seviyeli Yapısı

Tarayıcının ana bileşenleri;

  1. Kullanıcı arayüzü: Adres çubuğu, ileri-geri butonu, yer imleri menüsü gibi elemanları içerir.

  2. Tarayıcı motoru:: Rendering motoru ile kullanıcı arayüzü (UI) arasında sıraya koyma aksiyonlarını denetler.

  3. Rendering motoru:: İstek yapılmış içeriği görüntülemekten sorumludur. Örnek vermek gerekirse istek yapılmış içerik bir HTML ise rendering engine HTML ve CSS i çözümleri, ayrıştırır (parse) ve çözümlenmiş, ayrıştırılmış içeriği ekranda görüntüler.

  4. Ağ iletişimi: ağ (network) çağrıları örneğin HTTP istekleri için kullanılır. Platform bağımsız arayüzün arkasında farklı platformlar için farklı uygulamar kullanılır.

  5. UI Arka Uç: (UI backend) Combo boxes ve pencereler gibi basit grafiksel araçları çizmek için kullanılır. Bu arka uç (backend) platforma özel olmayan genel bir arayüz ortaya çıkarır

  6. JavaScript Yorumlayıcı: JavaScript kodlarını ayrıştırmak, çözümlemek (parse) ve çalıştırmak için kullanılır.

  7. Veri Belleği: (data storage) Bu bir süreklilik katmanıdır. Tarayıcı verilerin hepsini lokal olarak depolamaya ihtiyaç duyabilir. Çerezler (cookies) gibi. Ayrıca tarayıcılar farklı depolama mekanizmalarını da desteklerler. localStorage, IndexedDB, WebSQL ve FileSystem gibi.

Tarayıcı bileşenleri

Rendering (Oluşturma) Motoru

Rendering motorunun sorumluluğu tam olarak rendering yani oluşturmak. Rendering istek yapılmış içeriği ekranda görüntülemektir.

Varsayılan olarak rendering motoru HTML, XML belgelerinin yanı sıra resimleri görüntüleyebilir. Ayrıca eklentiler ve uzantılar sayesi ile diğer tip verileri görüntüleyebilir. Örneğin bir pdf eklentisi ile pdf dökümanları tarayıcı içerisinde görüntülenebilir. Fakat biz bu bölümde ana kullanım durumuna odaklanacağız. Ana kullanım durumumuz CSS ile biçimlenmiş HTML belgeleri ve resimleri görüntülemek.

Rendering Motorları

Farklı tarayıcılar farklı rendering motorları kullanmaktadırlar.
- Chrome ve Opera (15. sürümden itibaren) Blink (WebKit'in çatallanmış hali)
- Internet Explorer Trident,
- Firefox Gecko,
- Safari WebKit
kullanmaktadırlar.

WebKit ilk zamanlar Linux platformu için oluşturulmuş açık kaynak bir rendering motorudur ve Apple tarafından Mac ve Windows platformunu desteklemek için değiştirilmiştir. Daha ayrıntılı bilgi için webkit.org'a bakılabilir.

Ana Akış

Rendering motoru istek yapılmış belgenin içeriklerini ağ katmanından alacaktır. Bu işlem genellikle 8kB ile gerçekleşecektir.

Rendering motorunun temel akış diyagramı resimde görüldüğü gibidir.

Rendering Motoru Temel Akış Diyagramı

Rendering motoru HTML belgesini çözümlemeye başlayacak ve belgedeki elementleri içerik ağacı olarak adlandırılan ağaçta yer alan DOM düğümlerine çevirecek. Motor aynı zamanda hem harici CSS dosyalarını, hem de satır içi stilleri çözümlemeye başlayacak. HTML de bulunan görsel talimatlarla birlikte bulunan tasarım bilgileri başka bir ağacı oluşturmak için kullanılacak. Bu ağaç ise render ağacı

Render ağacı, boyut ve renk gibi görsel nitelikler içeren dikdörtgenler içerir. Bu dikdörtgenler ekranda görüntülenmek üzere düzgün sıradadırlar.

Render ağacının inşası sonrası anahat düzeni (layout) süreci takip edilir. Bunun anlamı verilen her düğüm tam olarak ekranda görüntüleneceği sıradaki konumda bulunur. Bir sonraki aşama ise boyamadır (painting). Render ağacı işlenecek ve her bir düğüm UI arka uc (backend) katmanı kullanılarak boyanacaktır.

Tüm bunların kademeli bir süreç olduğunu anlamak önemlidir. Daha iyi bir kullanıcı deneyimi için, render motoru, içeriği olabildiğince çabuk bir şekilde ekranda görüntülemeye çalışacaktır. Render ağacının inşası ve tasarım düzeninden önce tüm HTML in çözümlenmesini beklemeyecektir. İçeriğin bir bölümü, düğer içerikler ağ üzerinden gelirken ve süreç devam ederken işlenecek ve ekranda görüntülenecektir.

Ana Akış Örnekleri

Şekil: Webkit Ana Akışı
Webkit Ana Akışı

Şekil: Gecko Ana Akışı Mozilla nın Gecko Render Rotorunun Ana Akışı

Yukarıda ki iki akış diyagramlarına bakarak Webkit ve Gecko nun nispeten farklı terminolojilere sahip olduğunu görebilirsiniz. Ancak temelde akış aynıdır.

Gecko, görsel biçimlendirilmiş elementlerin ağacını "Frame Tree, Çerçeve ağacı" olarak adlandırıyor. Her element bir çerçeve. Webkit ise "Render Tree, render ağacı" terimini kullanıyor ve bu render nesnelerinden oluşuyor. Webkit elementleri yerleştirmek için "layout" terimini kullanıyor iken Gecko bunu "reflow" olarak adlandırıyor. "Attachment" Webkit'in DOM düğümlerine bağlanmak ve render ağaçlarını oluşturmak için kullandığı görsel bilgi için kullandığı bir terim. Burada ki ikincil anlamsal fark ise Gecko'nun HTML ve DOM ağacı arasında ekstra bir katmana sahip olması. Bu "content sink, içerik alış noktası" olarak adlandırılıyor ve DOM elementlerini oluşturmak için fabrika görevi üstleniyor. Bu akışın her parçasından bahsedeceğim.

Parsing-general

Çözümleme (parsing) rendering motorunun içindeki çok önemli bir işlem olduğundan bu konuyu daha derinden değineceğiz. Kısa bir giriş ile çözümleme sürecine başlayalım.

Belgeyi çözümlemenin anlamı kodun kullanabileceği bir yapıya dönüştürmektir. Çözümleme işleminin sonucu genellikle, belgenin yapısını temsil eden düğümlerin ağacıdır. Bu genellikle parse tree, çözümleme ağacı veya syntax tree, sözdizimi ağacı olarak adlandırılır.

Örnek vermek gerekirse 2 + 3 - 1 bu ifadenin çözümlenmiş (parsing) hali aşağıdaki ağacı döndürür.

Şekil: **Matematiksel İfadenin Düğüm Ağacı Mathematical Expression Tree Node

Dilbilgisi

Sözdizimsel analiz belgenin yazılmış olduğu dil ve formatın yazım kurallarını temel alır. Çözümleme yapabileceğimiz her format kelime öbeği ve yazım kuralları olan belirleyici bir dilbilgisine sahip olmalıdır. Bu context free grammar olarak adlandırılır. İnsanların kullandığı diller bunun gibi değildir ve bu yüzden geleneksel çözümleme teknikleri ile çözümlenemezler.

Parser–Lexer Kombinasyonu

Sözdizimsel analiz (parsing) iki alt işleme ayrılabilir: sözcüksel analiz (lexical analysis) ve sözdizim analizi (syntax analysis).

Sözcüksel analiz girdileri, sembollere parçalama işlemidir. Semboller (tokens) dilin söz dağarcığıdır: geçerli (valid) yapım bloklarının koleksiyonudur.Bu semboller, insanların kullandığı dillerde sözlüklerde o dil için görülen kelimelerden meydana gelecektir.

Sözdizim analizi ise o dildeki sözdizimsel kuralların uygulanışıdır.

Genellikle çözümleyiciler yapılacak olan işi iki bileşene ayırırlar. Lexer (bazen tokenizer olarak da adlandırılır) girdileri geçerli sembollere (tokens) parçalama işinden sorumludur. Parser belgenin yapısını dilin sözdizimi kurallarına göre analiz ederek parse tree inşa etmekten sorumludur. Lexer boşluk karakteri ve satır sonları gibi alakasız karakterleri nasıl sıyıracağını / ayıracağını / çıkaracağını bilir.

Şekil: Kaynak Belgeden Parse Ağacına

from source document to parse trees

Sözdizimsel analiz yinelemeli bir süreçtir. Parser genellikle lexer a yeni token olup olmadığını sorar ve bu token ile birlikte bir sözdizimi eşleştirmeye çalışır. Eğer bir eşleşme olursa o düğüm parse ağacına eklenir ve parser bir sonraki token ı bekler.

Eğer bir eşleşme bulunamaz ise parser o tokunu saklar ve eşleşecek olan token bulana kadar yeni token bekler. Herhangi bir kural eşleşmesi olmaz ise parser bir istisna (exception) fırlatır. Bunun anlamı belge geçerli değildir ve sözdizimi hataları içerir.

Çeviri (Translation)

Bir çok durum için parse tree son ürün değildir. Sözdizimsel analiz (parsing) genellikle giriş dökümanını farklı bir formata dönüştürme de kullanılır. Örnek olarak derleme (compilation). Kaynak kodu makine koduna derleyen derleyici (compiler), ilk çözümlemede parse tree ye daha sonra da ağacı makine koduna dönüştürür.

Compilation Flow

Sözdizimsel Analiz Örneği

Şekil 5 e göre matematiksel ifadeden bir parse ağacı inşa ettik. Basit matematiksel bir dil ifade edelim ve çözümleme/sözdizimsel analiz (parse) sürecini görelim.

Kelime hazinesi: Bizim yarattığımız dil tam sayıları, artı ve eksi işaretini içeriyor.

Sözdizimi: 1. Dilin oluşturduğu bloklar ifadeler, terimler ve işlemlerdir. 2. Dilimiz herhangi sayıda ifade içereiblir. 3. Terimler işlemler ile bir araya gelerek ifadeleri oluştururlar. 4. İşlemler artı veya eksidir. 5. Terimler bir tamsayı veya ifadedir.

Bu girişi analiz edelim. 2 + 3 -1 İlk alt sözcük 2 dir ve kural beşe göre bu bir ifadedir. Devamı ise 2 + 3 dür ve bu da kural 3 ile eşleşir. Bir sonraki eşleşme girişin son isabeti olmalıdır. 2 + 3 - 1 bir ifadedir çünkü biz çoktan 2 + 3 ün bir terim olduğunu biliyoruz. Elimizde bir sonraki terimi bir işlem ile birleştiren bir terim bulunmaktadır. 2 + + herhangi bir kural ile eşleşmediği için geçersiz bir giriş olacaktır.

Sözdizimi ve Kelime Dağarcığı için Format Tanımı

Kelime dağarcığı genellikle Düzenli İfadeler ile ifade edilir.

Örneğin bizim dilimiz aşağıdaki gibi tanımlanmış olsun:

Gördüğünüz gibi tamsayılar düzenli ifadeler olarak tanımlanmıştır.

Sözdizimi BNF olarak adlandırılan bir formatta tanımlanır. Bizim dilimiz böyle tanımlanacaktır.

BNF

Eğer dilbilgisi context free grammar olarak tanımlandı ise o dil regular parser lar ile çözümlenebilir. Context free grammar ın sezgisel tanımı ise; tamamen BNF ile ifade edilebilen dilbilgisidir. Format tanımını için: İçerikten-bağımsız Dilbilgisi - Vikipedia

Ayrıştırıcı/Çözümleyicinin Tipleri

İki tip çözümleyici vardır: Yukarıdan aşağı çözümleyici, aşağıdan yukarı çözümleyici. Yukarıdan aşağı çözümleyicinin sezgisel açıklanışı, sözdizimin yüksek seviyeli yapısını inceleyerek eşleşen bir kural bulmaya çalışır. Aşağıdan yukarı çözümleyici ise girişi alır ve adım adım sözdizimi kuralına döüştürür ve düşük seviyeden yüksek seviyeye çözümler.

İki farklı çözümleyicinin bizim örneğimizi nasıl ayrıştıracağına bakalım.

top-down çözümleyici en yüksek kuraldan ifadeyi çözümlemeye başlar. 2 + 3 ü bir ifade olarak tanımlar. Daha sonra bu 2 + 3 -1 in bir ifade olduğunu tanımlar. Tanımlamanın süreci aşama aşamadır ancak her zaman yüksek seviyeden başlanır.

bottom-up çözümleyici girişi bir kural eşleşmesi bulana kadar tarayacaktır. Eşleşen girişi kural ile değiştirecektir. Bu girişin sonu gelene kadar devam edecektir. Kısmen eşleşmiş olan ifadeler çözümleyicinin yığınında saklanır.

stack

Bu tip bottom-up çözümleyiciler shift-reduce parser olarak adlandırılır. Çünkü giriş sağa doğru kaydırılır (ilk girişi gösteren ve sağa doğru kayan bir pointer düşünülebilir) ve aşamaları olarak sözdizimi kuralına indirgenir.

Otomatik Olarak Çözümleyici Üretmek

Ayrıştırıcı oluşturan araçlar vardır. Bu araçları dilin sahip olduğu dilbilgisi (kelime dağarcığı + sözdizimi) ile beslersiniz ve onlar çalışan ayrıştırıcı üretirler. Çözümleyici üretmek çözümleme sürecini derin olarak anlamaktan geçer ve el ile optimize olmuş bir çözümleyici oluşturmak kolay değildir. Bu yüzden çözümleyici oluşturucular çok kullanışlıdır.

Webkit iyi bilinen iki çözümleyici üretici kullanmaktadır. Flex lexer oluşturmak için ve Bison ise ayrıştırıcı (parser) oluşturmak içindir. Flex girişleri tokenların düzenli ifade tanımlarını içeren bir dosyadır. Bison un girişleri ise BNF formatında tanımlanmış dilin sözdizimi kurallarıdır.

HTML Çözümleyici

HTML çözümleyicinin görevi HTML işaretlerini çözümleyerek parse treeye çevirmektir.

HTML Gramer Tanımı

HTML in dil ve sözdizimi özellikleri W3C tarafından oluşturulan spesifikasyonlarda tanımlanmıştır.

İçerik Bağımsız Değildir

Çözümleme tanıtımında gördüğümüz gibi, dilbilgisi sözdizimi usulen BNF gibi bir format kullanılarak tanımlanabilir.

Ne yazık ki geleneksel tüm çözümleme konuları HTML’e uygulanmaz.(Bunlardan sadece eğlence olsun diye bahsetmedim. CSS ve Javascript konularında kullanılacaklar). HTML, basitçe derleyicilerin ihtiyacı olan bağlamdan bağımsız bir dilbilgisi olarak tanımlanamaz.

HTML-DTD (Document Type Definition)’yi tanımlamak için resmi bir format vardır. Fakat bu format içerikten bağımsız bir dilbilgisi değildir.

Bu ilk bakışta tuhaf gözükebilir. HTML, XML’e oldukça yakındır. Birçok XML çözümleyici mevcuttur. HTML-XHTML in bir XML varyasyonu vardır. Peki büyük fark nerededir?

Fark şuradadır. HTML’in yaklaşımı daha hoşgörülüdür. Belirli etiket (tag) leri(Sonradan kapalı bir şekilde eklenen), bazen başlangıç ve bitiş etiketlerini ihmal etmenize olanak sağlar. XML’in katı ve zahmetli sintaksının aksine bütün olarak hafif bir sintaksı vardır.

Küçük görünen bu detay birçok fark yaratır. Diğer yandan bu detay HTML’in neden çok popüler olduğunun ana sebebidir. HTML sizin hatalarınızı affeder ve böylece web yazarlarının hayatını kolaylaştırır. Buna karşılık, resmi bir şekilde yazmayı zorlaştırır. Özetleyecek olursak, HTML’in grameri içerikten bağımsız olduğundan dolayı, geleneksel derleyiciler tarafından kolaylıkla çözümlenemez. HTML, XML derleyicileri tarafından çözümlenemez.

HTML DTD

HTML’in tanımı DTD formatının içinde saklıdır. Bu format SGML ailesinden gelen dilleri tanımlamak için kullanılır. Yine bu format tüm izin verilmiş elemanlar, bu elemanların davranışları ve hiyerarşisi için açıklamalar içerir. Daha önceden gördüğümüz üzere, HTML DTD içerik bağımsız bir gramer oluşturmaz.

DTD’nin birkaç çeşidi vardır. Kuralcı olan mod sadece spesifikasyonlara uymaktadır. Diğer modlar ise geçmiş tarayıcılar tarafından kullanılan işaretlemeler için destek sağlamaktadır. Buradaki amaç eski içerikler için geriye dönük uyumluluk sağlamaktır. Güncel kuralcı DTD’ye ulaşmak için:

DOM

Çözümleme ağacı(Parse Tree) DOM elemanlarının ve özellik düğümleri(attribute nodes) nin bir ağacıdır. “Document Object Model” in kısaltılmış halidir. DOM’un bize görünen yüzü, bir HTML dökümanının ve HTML arayüz elemanlarının nesne olarak sunumudur. Tıpkı Javascript’ te olduğu gibi. Bu ağacın kökü ise döküman nesnesidir.

DOM’un neredeyse işaretleme elemanlarıyla birebir ilişkisi vardır. Örneğin,

Yukarıdaki biçim aşağıdaki DOM ağacı şekiline çevrilebilir.

dom-tree

HTML’de olduğu gibi, DOM’un da özellikleri W3C tarafından belirlenmiştir. İncelemek için www.w3.org/DOM/DOMTR. DOM, dökümanların içeriklerini değiştirmek için oluşturulmuş genel bir şartnamedir. Ayrıca HTML’in spesifik elemanlarını tanımlayan bir modüldür. HTML’in tanımlarına ulaşmak için: .

Çözümleme ağacı(parse tree) DOM düğümlerini içerir derken, bu ağacın DOM arayüzlerinden bir tanesini implement eden elemanlardan kurulduğunu söyleyebiliriz. Tarayıcılar, tarayıcı tarafından dahili olarak kullanılan diğer özelliklere sahip somut implementasyonlar içerirler.

Çözümleme Algoritması

Bir önceki bölümde gördüğümüz üzere, bir HTML dosyası baştan aşağı ya da sondan başa tarama yapan sıradan derleyiciler tarafından derlenemez. Bunun nedenleri şunlardır:

  1. Affedici yapıya sahip bir dil olması.
  2. Tarayıcıların çok iyi bilinen geçersiz HTML durumlarına karşı geleneksel hata toleranslarının olması.
  3. Derleme aşaması yeniden girişlidir. Diğer dillerde kaynak kod derleme aşamasında değişmezken HTML’de dinamik kod (document.write() çağrıları içeren script elemanları gibi) ekstra işaretler ekleyebilir. Yani derleme aşaması girdiyi değiştirir.

Sıradan derleme teknikleri işe yaramayacağından dolayı tarayıcılar kendi derleyicilerini oluşturlar. Derleme algoritması HTML5 spesifikasyonlarında detaylı bir şekilde tanımlanmıştır. Bu algoritma 2 aşamadan oluşur: sembollere ayırma ve ağaç oluşumu.

Sembollere ayırma görevi, girdiyi sembollere çözümleyen sözlüksel analiz(lexical analysis) dir. Bu semboller HTML içindeki başlangıç, bitiş etiketleri, özellik(attribute) isimleri ve değerleridir.

Sembollere ayıran mekanizma sembolü tanır, onu ağaç oluşturucusuna verir ve bir sonraki karakteri bir sonraki sembolü tanımak üzere kullanır. Bu işlem girdinin sonuna kadar tekrarlanır.

Şekil: HTML Çözümleme Akışı HTML parsing flow (taken from HTML5 spec)

Sembollere Ayırma Algoritması (The Tokenization Algorithm)

Sembollere ayırma algoritmanın çıktısı bir HTML sembolüdür. Bu algoritma bir durum makinesi(state machine) olarak ifade edilir. Her durum bir ya da daha fazla karakter girdisi kullanır ve bir sonraki durumu o karakterlere göre günceller. Karar mekanizması, mevcut sembollere ayırma durumu ve ağaç oluşumu durumu tarafından etkilenir. Bu mevcut duruma bağlı olarak, kullanılan aynı karakter bir sonraki doğru durum için farklı sonuçlar verir anlamı taşır. Bu algoritma, tam olarak tanımının yapılabilmesi açısından çok kompleksdir. Bu yüzden çalışma prensibini anlamamız açısından basit bir örnek incelemek bize yardımcı olacaktır.

Aşağıdaki HTML kodu temel bir sembollerine ayrıştırma örneğidir:

Başlangıç durumu “Veri durumu(Data state)”dur. ‘<’ karakteriyle karşılaşıldığında, durum(state) “etiket açık durumu(tag open state)” olarak değişir. A-z arasında bir karakter kullanmak “etiket sembolünü başlat (start tag token)” oluşumuna yol açar ve bu durum “etiket ismi durumu(tag name state)”na dönüşür. Bu durum ‘>’ karakteri kullanılıncaya kadar aynı kalır. Her karakter yeni sembol ismine eklenir. Yukarıdaki durumda oluşturulan sembol bir html sembolüdür.

‘>’ ile birlikte etiket tamamlandığında, mevcut olan sembol ifade edilmiş olur ve durum(state) yine “Veri durumu (Data state)” olarak değişir. <body> etiketi de aynı aşamalardan geçerek işlem görür. Şimdiye kadar html ve body etiketleri ifade edilmiş oldu. Şimdi tekrar “Veri durumu (Data state)” ndayız. “Hello world” ifadesindeki H karakteri bir oluşuma ve karakter sembolünü ifade etmeye yol açar, ve bu </body> etiketindeki < karakterine ulaşılıncaya kadar devam eder.”Hello world” ifadesindeki her karakter için bir karakter sembolü ifade edeceğiz.

Şu an “etiket açık durumu (tag open state)” ndayız. ‘/’ girdisini kullanmak “etiket sonu sembolü(end tag token)” oluşumuna yol açar ve bu durum “etiket ismi durumu(tag name state)”na dönüşür. İlk aşamada olduğu gibi ‘>’ sembolüyle karşılaşılıncaya kadar bu durumda kalırız. Bu sembolle karşılaştıktan sonra yeni etiket ifade edilecektir. Daha sonra da “Veri durumu(Data state)” na geri döneriz. </html> girdisi ise önceki durumdaki gibi işlenecektir.

Şekil: Girileri Sınıflandırma Örneği Tokenizing the example input

Ağaç Yapısı Algoritması(Tree Construction Algorithm)

Çözümleyici oluşturulduğunda döküman nesnesi de oluşturulur. Ağaç oluşumu sürecinde, kökünde döküman bulunan DOM tree modifiye edilir ve elemanlar bu ağaca eklenir. Bu ağaçtaki sembollerine ayırıcı tarafından tanımlanan her bir düğüm ağaç oluşturucusu tarafından işlenecektir. Her bir düğüm için şartname, hangi DOM elemanının o düğümle ilişkili olduğunu tanımlar ve bu sembol için hangi DOM elemanının oluşturulacağını tanımlar. Elemanlar DOM ağacına ve açık elemanların yığınına eklenir. Bu yığın uyumsuz ve kapatılmamış etiketleri doğru bir şekilde yapmak için kullanılır. Bu algoritma ayrıca durum makinesi olarak tanımlanır. Bu durum insertion modes olarak adlandırılır.

Örnek bir giriş için ağacın yapı sürecine bakalım:

Ağacın yapım aşaması girdisi, işaretleme kademesindendan gelen işaret dizisidir. İlk düğüm initial mode dur. html token almak before html durumuna geçmesine ve bu durumda yeniden işlenmesine neden olacaktır. Bu durum root Document objesine eklenecek olan HTMLHtmlElement elemanı oluşmasına neden olacaktır.

Durum before head e geçilecektir. Body token alınmış olur. Body token y eniden işlenir, HTMLBodyElement oluşturulur, yerleştirilir ve durum in body ye aktarılır.

"Hello world" kelime grubunun karakter tokenları şimdi alınır. İlki oluşmasına ve Text düğümünün eklenmesine neden olur ve diğer karakterler bu düğüme eklenir.

Body end tokenın alınması after body moduna geçilmesine neden olur. Şimdi bizi after after body moduna geçirecek olan html bitiş etiketini alacağız. Dosya sonu tokenı almak çözümleme işlemini bitirecektir.

Şekil: Örnek HTML in Ağaç Yapısı Örneğin Ağaç Yapısı

Çözümleme Bittiğindeki Aksiyonlar

Bu aşamada tarayıcı belgeyi etkileşimli olarak işaretleyecek ve çözümleme scriptini deferred modda çalıştıracaktır: bu mod belge çözümlemesi tamamlandıktan sonra çalıştırılmalıdır. Belgenin durumu tamamlanmış (complete) olarak ayarlanacaktır ve load eventi başlatılacaktır.

Ayrıca HTML5 şartnamesindeki full ağaç yapılandırma ve tokenization algoritmasına bakabilirsiniz.

Tarayıcıların Hata Toleransı

Hiçbir zaman HTML sayfalarında geçersiz söz dizimi hatası almazsınız. Tarayıcılar geçersiz içeriği düzeltir ve devam ederler.

Aşağıdaki HTML kodu örnek olarak alalım:

Error Tolerance Kodu

Bu koda bakarak çok fazla kural ihlali (geçersiz mytag, yanlış iç içe geçmiş p ve div etiketi ve daha fazlası) almam gerekiyor ancak tarayıcı bunu düzgün gösteriyor ve herhangi bir hta verip şikayet etmiyor. Burada yazarın yapmış olduğu birçok HTML hatası düzeltiliyor.

Hata idaresi tarayıcılarda pek bi tutarlıdır fakat kesinlikle HTML şartnamesinin bir parçası değildir. Tıpkı yer imleri, ileri/geri butonları gibi tarayıcıların uzun yıllar süren geliştirme süreçlerinden biridir. Birçok sitede yer alan ve bilinen geçersiz HTML yapıları vardır. Tarayıcılar bunları belirli bir standarda uygun olarak diğer tarayıcılar ile birlikte düzeltmeye çalışır.

HTML5 şartnamesi bu gerekliliklerden birazını tanımlar. (Webkit HTML parser sınıfının başında bu durumu çok güzel bir şekilde özetlemektedir.)

Birkaç Webkit hata toleransı örneğine bakalım:

<br> yerine </br>

Bazı siteler <br> yerine </br> tagını kullanmaktadır. IE ve Firefox ile uyumlu olması için Webkit bunu <br> olarak işler. Kod:

br tag

Unutmayın hata idaresi içseldir. Kullanıcıya herhangi birşey sunulmaz.

Başıboş (Stray) Tablo

Başıboş tablo; bir tablo içindeki başka bir tablodur. Ancak tablonun hücresi içinde değildir.

Örnek olarak; stray table 1

Webkit hiyerarşiyi iki alt tablo olarak ayırır. Sibling Tables

Kod: Başıboş Tablo Kodu

Webkit geçerli elemanın içeriği için yığın kullanmaktadır. İçerdeki tabloyu dış tablonun dışına almaktadır. Bu şekilde tablolar artık kardeş olacaktır.

İç içe Form Elementleri

Kullanıcının başka bir form içinden form eklemesi durumunda ikinci form göz ardı edilir.

Kod:

Nested Form Elements

Çok Derin Etiket Hiyerarşisi

İç içe geçmiş aynı tipteki etiketlerden maksimum olarak 20 tanesi geçerlidir ve diğerleri göz ardı edilmektedir.

Deep Tag Hierarchy

Yanlış Yerleştirilmiş body veya html Bitiş Etiketi

Tarayıcı hiçbir zaman html veya body etiketini kapatmıyor.

Yanlış Yerleştirilmiş Bitiş Etiketleri

CSS Çözümleme

Girişteki çözümleme sürecini hatırlıyor musunuz? HTMl in aksine CSS içerik bağımsız dilbilgisi (context free grammar) dir ve girişte tanımlanan çözümleyici tipleri ile çözümlenebilir. Gerçek şu ki CSS şartnamesi CSS in sözlüksel (lexical) ve sözdizimi (syntax) dilbilgisini tanımlar.

Birkaç örneğe bakalım: Sözlüksel dilbisi (vocabulary) her token için düzenli ifadeler ile tanımlanır.

css için düzenli ifade

ident identifier için bir kısaltmadır tıpkı sınıf isimleri gibi. name ise element id sidir. # ile gösterilir.

Sözdizimi dilbilgisi BNF içinde tanımlanır.

css parsing bnf

Açıklama: Kural kümesi bu yapıdadır.

ruleset

div.error ve a.error seçicilerdir. Köşeli parantez içerisinde görülen parça kural kümesi (ruleset) tarafından uygulanacak olan kuralları içerir. Bu yapı usulen şöyle tanımlanır:

ruleset definition

Bunun anlamı ruleset seçici veya virgül ve boşluk ile ayrılmış belli sayıdaki opsiyonel seçicidir. Ruleset köşeli parantez ve onların içinde tanım veya belli bir sayıdaki virgül ile ayrılmış opsiyonel tanımları içerir. declaration ve selector takip eden BNF içinde tanımlanacaktır.

Webkit CSS Çözümleyici

Webkit CSS dilbilgisi dosyalarından otomatik olarak çözümleyici oluşturmak için Flex ve Bison çözümleyici oluşturucularını kullanır. Ayrıştırıcı (parser) girişinden hatırlayacağınız üzere, Bison, aşağıdan yukarı shift-reduce ayrıştırıcı (parser) oluşturur. Firefox manuel olarak yazılmış yukarıdan aşağı ayrıştırıcı kullanır. Her iki durumda da CSS dosyaları StyleSheet objelerine dönüştürülür. Her obje CSS kurallarını içerir. CSS kural objesi seçici ve bildirim nesnelerini içerir ve diğer objeler CSS dilbilgisi ile ilişkilendirilir.

Parsing CSS

Scriptlerin ve Stil Sayfalarının İşlenişinin Düzeni

Scriptler

Web modeli senkronik olarak yapılır. Geliştirici scriptin çözümlenmiş olmasını bekler ve çözümleyici <script> tagına ulaştığında scriptin çabucak çalıştırılmasını ister. Dosyanın çözümlenmesi scriptin işlenmesinin bitmesiyle durur. Script dışardan geliyorsa bu durumda kaynak ağdan alınmalı - bu işlemler aynı anda yapılır, kaynak alındığında çözümleme durur. Bu model uzun yıllar boyunca kullanıldı, ayrıca HTML4 ve 5 için özel olarak kullanıldı. Geliştirici scripte "defer" özelliğini katabilir, bu durum dosya çözümlemesini durdurmaz ve dosyanın çözümlenmesinden sonra işlenmesini sağlar. HTML5 "scripti asyncronous olarak işartle" seçeneğini ekler ve script başka bir birimle çözümlenir ve işlenir.

Teorik Sözdizimsel Analiz (Parsing)

Webkit ve Firefox bu optimizasyonu yaparlar. Scripti işlerken, diğer birim dosyanın kalanını çözümler ve ağdan hangi kaynakların yüklenmesi gerektiğini bulur ve onları yükler. Bu şekilde kaynaklar paralel bağlantıyla yüklenebilir ve genel hız gelişir. Not: speculative çözümleyiciler sadece dış kaynaklı referansları çözümler "external scripts, style sheets and images" gibi: DOM tree yi modife etmez, onu ana çözümleyici çözümler.

Stil Sayfaları

Diğer taraftan stil sayfalarının (style sheets) farklı modelleri var. Style sheet ler DOM tree yi değiştirmediğine göre konsept olarak onları beklemenin ve dosya çözümlemesini durdurulmasının anlamı yok. Script in dosya çözümleme aşamasındayken stil hakkında bilgi istemesiyle ilgili bir durum var. Eğer stil yüklenmediyse ve hala çözümlenmediyse script yanlış cevaplar alır ve bu açıkça birçok probleme neden olur. Bu aslında geneldışı görülen ama sıkça görülen bi durumdur. Style sheet hala yükleniyor ve çözümleniyorsa firefox tüm script leri kilitler. Webkit, sheetleri sadece yüklenmemiş stil sheetler tarafından etkilenmiş olabilen belirli stil özelliklerine erişmeye çalışırken kilitler.

Render Ağaç İnşası

DOM ağacı oluşturulurken, tarayıcı diğer ağacı oluşturur, render ağacını. Bu ağaç görsel elementleri onların gösterileceği şekilde sıraya koyar. Bu, dosyanın görsel bir sunumudur. Bu ağacın amacı içerikleri doğru sırada paint edebilmektir. Firefox render ağacındaki elementleri "frames" diye adlandırır. Webkit "renderer" ya da "render object" terimlerini kullanır. Renderer kendini ve çocuklarını nasıl tasarlayacağını ve paint edeceğini bilir. Webkit in RenderObject sınıfı, renderer lerin ana sınıfı, şu tanımlamaları izler:

RenderObject Class

CSS2 şartnamesinde söylendiği gibi, her renderer genellikle düğümüün CCS kutusuna tekabül eden rectangular alanı temsil eder. Burda, genişlik, yükseklik ve durum gibi geometrik bilgiler bulunur.

Kutu tipi, node la ilişkili olan "stil özellikleri" nin "display" değeri tarafından etkilenir. ( style computation seçeneğine bak). Display özelliğine göre, buradaki Webkit kodunu, DOM node u için hangi renderer in oluşturulması gerektiğine karar verirken görüyoruz.

RenderObject Switch-Case

Element tipi şu şekilde de ele alınabilir: mesela, form kontrol ve masalarının özel frame leri vardır. Webkit te eğer element özel renderer oluşturmak istiyorsa createRenderer( ) metodunu aşırı sürer. Renderer lar içinde geometrik bilgi olmayan stil objelere işaret ederler.

DOM Ağacına İlişkin Render Ağacı

Renderer'lar DOM elemanlarına karşılık gelir, ama bu ilişki birebir değildir. Görsel olmayan DOM öğeleri render ağacında yerleştirilmeyecektir, buna “head” elemanı örnektir. Aynı zamanda görüntülenen değeri “none” atanan öğeler ağaçta gözükmeyecektir (oysa “saklı” görünümlü öğeler ağaçta gözükecektir).

Bazı görsel nesnelere karşılık gelen DOM elemanları bulunur. Bunlar genellikle tek bir dikdörtgen çizimiyle tanımlanamayacak, karmaşık yapılı elemanlardır. Örneğin, “select” öğesi 3 elemana sahiptir: biri görüntüleme alanı için, biri açılır liste kutusu için, biri de buton için. Ayrıca genişliğin bir satır için yeterli olmaması sebebiyle, yazı birkaç satıra bölümlendiğinde, yeni satırlar ekstra renderer'lar olarak eklenecektir.

Çoklu renderer'lara bir diğer örnek bölünmüş HTML'dir. CSS belirlemelerine göre, bir satıriçi eleman, ya sadece blok elemanları, ya da sadece satıriçi elemanları içermelidir. Karışık içerik durumunda, kimliği belirsiz blok renderer'ları, satıriçi elemanları sarmalayacak şekilde yaratılmış olur.

Bazı render nesneleri DOM düğümlerine karşılık gelir fakat ağaçta aynı yerde değildir. Float'lar ve mutlak konumlandırılmış elemanlar yerleşim akışının dışındadır, ağacın farklı bir kısmına yerleşir, ve gerçek çerçeveye eşleştirilirler. Yer tutucu çerçeve olması gereken yerdedir.

Şekil: Render ağacı ve ilişkili DOM ağacı (3.1). “Viewport” ilk kapsama bloğudur. WebKit'te bir “RenderView” nesnesi olacaktır.

Ağacı Oluşturma Akışı

Firefox'ta sunum, DOM güncellemeleri için dinleyici olarak kayıtlıdır. Sunum, çerçeve yaratma görevini FrameConstructor'a verir. Constructor stili çözümler (bkz. stil hesaplama) ve çerçeve yaratır.

WebKit'te stili çözümleme ve renderer yaratma işlemi “attachment” olarak adlandırılır. Her DOM düğümünün “attach” metodu vardır. Attachment eş zamanlıdır, DOM ağacına düğüm ilavesi için yeni düğümün “attach” metodu çağrılır.

html ve body etiketlerinin işlenmesi, render ağacı kökünün yapımında sonuçlanır. Kök render nesnesi, CSS belirlemesinin kapsama bloğu tanımlamasına benzer: en üst blok diğer tüm blokları içerir. Onun boyutları görünüm alanıdır: tarayıcı penceresi alan boyutlarını görüntüler. Firefox onu ViewPortFrame, ve WebKit onu RenderView olarak adlandırır. Bu, dökümanın işaret ettiği render nesnesidir. Ağacın geri kalanı DOM düğüm yerleşimi ile yapılandırılır.

İşleme modeli üzerinde CSS2 belirlemesi ne bakınız.

Stil Hesaplama

Render ağacını inşa etme, her bir render nesnesinin görsel özelliklerini hesaplamayı gerektirir. Bu, her bir elemanın stil özelliklerini hesaplamayla yapılır.

Stil, çeşitli kökenlerin stil sayfalarını, HTML'deki satıriçi stil elemanlarını ve görsel özellikleri içerir (“bgcolor” özelliği gibi). Sonradan, eşleşen CSS stil özelliklerine çevrilir.

Stil sayfalarının kökenleri tarayıcının varsayılan stil sayfalarıdır. Stil sayfaları, sayfa yazarı ve kullanıcı stil sayfaları tarafından sağlanır – bunlar tarayıcı kullanıcıları tarafından sağlanan stil sayfalarıdır (tarayıcılar size favori stillerinizi tanımlama izni verir. Mesela bu Firefox'ta; stil sayfası “Firefox Profile” klasörüne yerleştirilerek yapılır).

Stil hesaplama birkaç zorluk getirir:

  1. Stil verisi çok geniş bir yapıdır, sayısız stil özelliği tutar, bu bellek sorunlarına neden olabilir.

  2. Her bir eleman için eşleşen kuralları bulmak, eğer en iyi şekle getirilmediyse performans sorunlarına sebep olabilir. Her elemanın eşleşenini bulmak için tüm kurallar listesinin içinden geçmek zor bir görevdir. Karmaşık yapılı olabilen seçiciler, umut verici görünen ama nafile olduğu kanıtlanmış bir eşleşme sürecinin başlamasına yol açabilir.

Mesela aşağıdaki bileşik seçici:

  div div div div{
    ...
  }
  

<div>'e uygulanan kurallar, onun 3 div'in soyundan geldiğini ifade eder. Verilen bir <div> elemanı için bu kuralın uygulanıp uygulanmadığına bakmak istediğinizi varsayın. Kontrol için ağaçtan belli bir yol seçersiniz. Sadece iki div'in olduğunu ve bunun kurala uymadığını bulmak için düğüm ağacının içinden geçmeye ihtiyaç duyabilirsiniz. Sonra mecburen ağaçtaki diğer yolları denersiniz.

  1. Kurallar hiyerarşisini tanımlayan, oldukça karmaşık ve katlı kuralları kapsayan kuralları uygulamak.

Tarayıcıların bu sorunlarla nasıl yüzleştiğini görelim:

Stil Verisini Paylaşma

WebKit düğümleri, kaynağını stil nesnelerinden alır (RenderStyle). Bazı durumlarda düğümler bu nesneleri paylaşabilir. Düğümler kardeş veya kuzenlerdir, ve:

  1. Elemanlar aynı fare durumunda olmalıdır (örneğin biri :hover durumunda değilken diğeri de olamaz)
  2. Hiçbir elemanın id'si olmamalıdır
  3. Etiket isimleri eşleşmelidir
  4. Sınıf özellikleri eşleşmelidir
  5. Haritalanmış özellik kümesi tamamıyla aynı olmalıdır
  6. Link durumları eşleşmelidir
  7. Odaklanma durumları eşleşmelidir
  8. Hiçbir eleman özellik seçicilerden etkilenmemelidir. Etkilenme; seçicinin de dahil olduğu herhangi bir konumdaki bir özellik seçiciyi kullanan bir seçici eşleşmesi bulundurma olarak tanımlanır.
  9. Elemanlarda hiç satıriçi stil özelliği olmamalıdır
  10. Kullanımda olan kardeş seçiciler hiç olmamalıdır. Herhangi bir kardeş seçiciyle karşılaşıldığında WebCore basitçe genel şalteri indirir, ve sunulmakta olan tüm döküman için stil paylaşımını devre dışı bırakır. Buna + seçicisi ve :first-child, :last-child gibi seçiciler dahildir.

Firefox Kural Ağacı

Firefox'un daha basit stil hesaplamak için iki eksta ağacı bulunur: kural ağacı ve stil bağlam ağacı. WebKit'in de ayrıca stil nesneleri vardır ama onlar stil bağlam ağacındaki gibi ağaçta bulunmazlar, sadece DOM düğümü ilgili stili işaret eder.

Şekil: Firefox Stil Bağlam Aracı

Stil bağlamları bitiş değerleri içerir. Bu değerler, tüm eşleşme kuralları düzgün sırayla uygulanarak ve mantıksaldan somut değerlere dönüştürme işlemleri yapılarak hesaplanır. Örneğin, mantıksal değer ekranın bir yüzde oranıysa, hesaplanacak ve mutlak birimlere çevrilecektir. Kural ağacı fikri ise, gerçekten zekicedir. Bu değerlerin düğümler arasında tekrar hesaplanmadan paylaşılması olanağını sağlar. Bu aynı zamanda bellek alanı kurtarır.

Eşlenmiş tüm kurallar bir ağaçta tutulur. Ağaçtaki alt düğümler daha yüksek önceliğe sahiptir. Ağaç, bulunmuş kural eşleşmeleri için tüm yolları içerir. Kuralları tutma işi tembelce yapılır. Ağaç, her düğümü için en başta hesaplanmaz, sadece düğüm stilinin hesaplanmasına ihtiyaç duyulduğunda, hesaplanmış yollar ağaca eklenir.

Maksat, ağaç yollarını, sözlükteki kelimeler gibi görmektir. Aşağıdaki kural ağacını önceden hesaplamış olduğumuzu düşünelim:

Diyelim ki içerik ağacındaki başka bir eleman için kuralları eşleştirmemiz gerekiyor, ve bulduğumuz eşleşmiş kurallar sırasıyla B-E-I. Ağaçta bu yolumuz şimdiden bulunuyor, çünkü zaten A-B-E-I-L yolunda hesap yapmıştık. Şimdi yapacak daha az işimiz kaldı.

Ağacın bizi nasıl işten kurtardığını görelim.

Yapı İçine Bölme

Stil içerikleri yapıların içinde bölünür. Bu yapılar, sınır veya renk gibi kesin bir kategori için stil bilgilerini içerir. Yapı içerisindeki tüm özellikler ya kalıtımsaldır (inherited) yada değildir. Kalıtımsal özellikler, element tarafından tanımlanmadığında ebeveyn den miras kalan özelliktir. Kalıtımsal olmayan özellikler ( **reset** özellik olarak adlandırılır) eğer tanımlanmadı ise varsayılan değeri kullanır.

Ağaç, tüm yapıyı ağaç içinde cacheleyerek bize yardım eder. (hesaplanmış sonuç değerlerini de içerir) Amaç şu ki, eğer bottom node struct için tanım sağlamazsa upper node taki ön belleğe alınmış struct kullanılabilir.

Kural Ağacını (Rule Tree) Kullanarak Stil İçeriklerini Hesaplama

Belli bir eleman için stil içeriği hesaplanırken, ilk olarak kural ağacının yolu(path) hesaplanır veya varolan biri kullanırız. Daha sonra yeni stil içeriğimizdeki yapıları doldurmak için, kuralları yola uygulamaya başlarız. Yolun alt düğümünde başlar – yüksek önceliğe sahip olan bir düğüm (genellikle en özel seçiçici)- ve yapı dolana kadar ağaç döndürülür. Bu kural düğümü yapısı için hiçbir belirtim yoksa, o zaman büyük ölçüde optimize edebiliriz – tamamen ve başitçe belirtime işaret eden düğümü bulana kadar ağaçta yukarı çıkarız –bu en iyi optimizaysondur – tüm yapı paylaşılır. Hesaplama son değerleri ve bellek kaydedilir.

Eğer kismi tanım bulursak yapı dolana kadar ağaçta yukarı çıkarız.

Eğer yapımız için hiçbir tanım bulamazsak , bu durumda yapı “inherit(miras)” tiplidir, yapının parentını context ağacında gösteririz. Bu durumda ayrıca paylaşılan yapılarda başardık. Eğer sıfırlama yapısıysa varsayılan değerler kullanılır.

Eğer en beliri düğüm değerlerini eklerse, gerçek değerlere dönüştürmek için fazladan hesaplamalar yapmalıyız. Saha sonra, ağac düğümlerinde sonucu önyükleriz ve böylelikler çocuk düğümler (children) tarafından kullanabiliriz.

Bu durumda, bir eleman aynı ağaç düğümüne işaret eden bir kardeşe veya bir erkek kardeşe sahiptir ve tüm yapı içeriği aralarında paylaşılır.

Bir örnek inceleyelim: Aşağıdaki HTML parçasına sahip olduğumuzu varsayalım.

<html> 
   <body> 
        <div class="err" id="div1"> 
           <p> this is a <span class="big"> big error </span> this is also a <span class="big"> very big error</span> error </p> </div> 
           <div class="err" id="div2">another error
        </div> 
    </body> 
</html>
  

Aşağıdaki kurallarımız olsun.

3

Basitleştirmek için yalnızca iki yapıyı doldurmamız gerektiğini varsayalım : renk yapısı ve margin yapısı. Renk yapısı yalnızca bir eleman içerir : rengi. Margin yapısı 4 tarafı içerir.

Sonuç kural ağacı aşağıdaki gibi gözükür ( Düğümler, düğüm isimleriyle işaretlenir: O noktada kural sayısını işaret eder):

Şekil: Kural Ağacı

İçerik ağacı ise şu şekilde görülür (Düğüm isimleri: kural düğümünü işaret eder):

Şekil: İçerik Ağacı

HTML’i ikinci bir div’e ayırdığımızı varsayalım. Bu düğüm için stil içeriğini oluşturmız ve stil yapısını doldurmamız gerekecektir.

Kuralları birleştireceğiz ve <div> için birleştirilen kuralların 1,2 ve olduğunu fark edeceğiz. Bunun anlamı, bu yolun ağaçta önceden var olduğu ve bizim bunu kullanabileceğimizdir ve sadece kural 6 için bir düğüm eklememiz gerekecek (kural ağacında düğüm F). Stil içeriğini oluşturacağız ve içerik ağacına yerleştireceğiz. Yeni stil içeriği kural ağacında düğüm Fyi gösterecektir.

Şimdi stil yapısını doldurmamız gerekecek. Margin yapısını doldurarak başlayacağız. Son kural düğümü (F) margin yapısına eklenmediği sürece, ağaçta, bir önceki eklenen düğümde önblleğe alınmış hesaplı yapı bulana kadar yukarı çıkabiliriz ve kullanabiliriz. Margin kuralında en üst seviye düğüm olarak B’yi bulacağız.

Renk yapısı için bir tanımlamaya sahibiz, bu nedenle önbelleğe alınmış yapıyı kullanamayız. Renk yalnızca bir niteliğe sahip olduğu sürece diğer nitelikleri doldurmak için aaçta yukarı gidemeyiz. Son değeri hesaplayacapız (RGB’den stringe döndürmek gibi ) ve düğümdeki hesaplanan yapıyı önbelleğe alacağız.

İkinci <span> elemanı üzerinde çalışmak kolaydır. Kuralları birleştireceğiz ve kural G’yi gösterdiği sonucuna varacağız, bir önceki span gibi. Aynı düğümü gösteren kardeşler olduğu sürece, tüm stil içeriğini paylaşacağız ve bir önceki span’ın içeriğini göstereceğiz.

İnherit kurallar içeren yapı için önbelleğe alma context ağacında yapılır (renk özelliği aslında inherittir, ancak Firefox sıfırlama gibi davranır ve kural ağacında önbelleğe alır)

Örneğin, eğer bir paragrafta font için kural eklersek:

  p {font-family: Verdana; font size: 10px; font-weight: bold}
  

Context ağacındaki div elemanının çocuğu olan paragraf elemanı, kendi üst elemanıyla aynı font yapısını paylaşabilir. Bu, paragraf için belirli bir font özelliği olmadığında gerçekleşir.

WebKit’te, kural ağacına sahip olmayan, birleştirilmiş tanımlamalar dört kez döndürülür. İlkinde, önemli olmayan yüksek öncelikli özellikler uygulanır (özellikler ilk olarak uygulanmalı çünkü diğerleri ona bağlıdır), daha sonra yüksek öncelikli önemli, normal öncelikli önemsiz, normal öncelikli önemli kurallar uygulanır. Bunun anlamı, özellikler doğru kademeli sıra ile birkaç kez görüntülenerek çözülür. Sonuncular kazanır.

Özetle: Stil nesnelerini paylaşmak (tamamını yada bir bölümünü) aşağıdaki stil hesaplama zorluklarından 1(Style) ve 3(Applying ) numaralı problemleri çözer. Firefox kural ağacı ayrıca özellikleri doğru sırada uygulamaya yardımcı olur.

Stil Şablonlarının Sıralaması

Stil özelliğinin bildirilmesi birden fazla stil şablonunda olabileceği gibi, aynı şablon içerisinde birden fazla geçebilir. Bunun anlamı şudur ki kuralların uygulanış sırası çok önemlidir. Bu cascade sıralaması olarak adlandırılır. CSS2 şartnamesine göre cascade sıralaması düşükten yükseğe doğru:

  1. Tarayıcı bildirimleri
  2. Kullanıcı normal bildirimleri
  3. Geliştirici normal bildirimleri
  4. Geliştirici önemli bildirimleri
  5. Kullanıcı önemli bildirimleri

Tarayıcı bildirimleri düşük öneme sahiptir ve kullanıcı eğer bildirim önemli olarak işaretlenmiş ise geliştiriciyi ezebilir. Aynı sıralamadaki bildirimler specificity tarafından sıralanır. HTML in görsel öznitelikleri eşleşen CSS bildirimlerine dönüştürülür. Bu geliştirici kuralı gibi yapılır ve düşük önceliğe sahiptir.

Specificity (Özel Etken Oranı / Özgüllük)

Seçicilerin specificity leri CSS2 şartnamesinde aşağıdaki gibi tanımlanmıştır.

  • a= Eğer seçili kuralı ile değil de style özniteliği ile bildirim varsa 1, aksi taktirde 0.
  • b= Seçicide yer alan ID özniteliğinin (attribute) sayısı
  • c= Seçicide yer alan sözde sınıfların (pseudo) ve özniteliklerin sayısı
  • d= Seçicide yer alan sözde elementlerin ve element isimlerinin sayısı

Bu dört a-b-c-d numaranın birleşimi bize specificity verir.

İhtiyacımız olan sayı tabanı bu kategoriler içerisindeki en büyük numara belirler. Örneğin a=14 ise hexadecimal taban kullanabiliriz.

Birkaç örnek:

  *             {}  /* a=0 b=0 c=0 d=0 -&gt; specificity = 0,0,0,0 */
  li            {}  /* a=0 b=0 c=0 d=1 -&gt; specificity = 0,0,0,1 */
  li:first-line {}  /* a=0 b=0 c=0 d=2 -&gt; specificity = 0,0,0,2 */
  ul li         {}  /* a=0 b=0 c=0 d=2 -&gt; specificity = 0,0,0,2 */
  ul ol+li      {}  /* a=0 b=0 c=0 d=3 -&gt; specificity = 0,0,0,3 */
  h1 + *[rel=up]{}  /* a=0 b=0 c=1 d=1 -&gt; specificity = 0,0,1,1 */
  ul ol li.red  {}  /* a=0 b=0 c=1 d=3 -&gt; specificity = 0,0,1,3 */
  li.red.level  {}  /* a=0 b=0 c=2 d=1 -&gt; specificity = 0,0,2,1 */
  #x34y         {}  /* a=0 b=1 c=0 d=0 -&gt; specificity = 0,1,0,0 */
  style=""          /* a=1 b=0 c=0 d=0 -&gt; specificity = 1,0,0,0 */
  
Kuralların Sıralanması

Kurallar eşleştirildikten sonra, cascade kurallarına göre sıralanırlar. Webkit küçük listeler için bubble sort, büyük listeler için ise merge sort kullanmaktadır. Webkit sıralama işlemini kurallar için > operatörünü ezerek (override) uygulamaktadır.

  static bool operator >(CSSRuleData>; r1, CSSRuleData>; r2)
  {
      int spec1 = r1.selector()->;specificity();
      int spec2 = r2.selector()->;specificity();
      return (spec1 == spec2) : r1.position() >; r2.position() : spec1 >; spec2;
  }
  
#### Kademeli Süreç Webkit, bütün yüksek seviyeli stil şablonları yüklendi ise (@imports dahil) işaretlemek için bayrakları kullanır. Eklendiği zaman tam olarak yüklenmemiş stiller varsa yer tutucular kullanılır ve belgede işaretlenir ve stil şablonu yüklendiğinde yeniden hesaplanacaktır.

Tasarım Düzeni (Layout)

Renderer oluşturulduğunda ve ağaca eklendiğinde o, bir pozisyona ve boyuta sahip olmaz. Bu pozisyon ve boyut değerlerinin hesaplanması tasarım düzeni (layout)” ve reflow olarak adlandırılır.

HTML tasarım düzeni modeli tabanlı bir akış kullanır. Buradan, akışın çoğu zamanında, tek bir geçişte geometrik hesaplaması yapmasının mümkün olduğu anlamı çıkar. Akıştan sonraki elementler, akıştan önceki elementlerin geometrisinin etkilemez. Bu yüzden tasarım düzeni döküman boyunca soldan sağa ve yukarıdan aşağıya ilerleyebilir. HTML tablolarının bir geçişten fazlasına ihtiyaç duyabilmesi gibi istisnalar bulunur.

Kordinat sistemi kök çerçeveyle ilgilidir. Üst ve sol kordinatlar kullanılır.

Tasarım düeni tekrarlı bir işlemdir. HTML dökümanının <html> elementine karşılık gelen kök renderer’da başlar. Tasarım düzeni, ihtiyacı olan her renderer’ın geometrik bilgilerinin hesaplanması, çerçeve hiyerarşisinin hepsi ya da bazısı boyunca tekrarlanan bir şekilde devam eder.

Kök renderer’ın pozisyonu (0,0)’dır ve onun boyutları tarayıcı penceresinin görüş alanı,-görünen kısmı kadardır.

Tüm renderer’lar tasarım düzeni ve reflow metoduna sahiptir. Her renderer, tasarım düzenine ihtiyaç duyan çoçuklarının tasarım düzeni metodunu çalıştırır.

Dirty Bit Sistemi

Her küçük değişiklik için tam bir tasarım düzeni yapılmadığı zaman, tarayıcılar Dirty Bit sistemini kullanırlar.

İşaretleri değiştirlen ya da ekleme yapılan renderer ve dirty gibi çocuklar tasarım düzenine ihtiyaç duyarlar.

İki tane etiket bulunur: Dirty ve tasarım düzenine ihtiyaç duyan en az bir çocuğa sahip olan renderer’ın kendisinin onaylıyor olmasına rağmen çocuklarının dirty olmasıdır.

Dirty Bit: Memory’de bulunan veya cache’de bulunan CPU tarafından değiştirilmiş ama disk üzerine yazılmamış bitin adıdır.

Global ve Artan Tasarım Düzeni

Global tasarım düzeni için, tasarım düzeni bütün render ağacında etki gösterebilir. Bu, şu sonuçlar gibi olabilir:

  1. Yazı boyutunun (Font Size) değişmesi gibi, bütün render’ı etkileyen global bir biçim(style) değişimi.

  2. Boyutlandırılan bir ekranın görüntüsündeki değişimin sonuçları gibi.

Tasarım düzeni artan olabilir. Sadece Dirty Renderer’lar hazırlanmış olacaktır.(Bu, ekstra tasarım düzenine ihtiyaç duyacak bazı hasarlara neden olabilir). Artan tasarım düzeni, renderer’lar dirty olduğunda eş zamansız bir şekilde tetiklenir. Örneğin; DOM ağacına eklendiğinde ve şebekeden ekstra içerik geldikten sonra, yeni renderer’lar render ağacına eklendiğinde.

![](/data/upload/hbw/incremental layout–only dirty.png)

Eş Zamanlı ve Eş Zamansız Tasarım Düzeni

Artan tasarım düzeni eş zamansız yapılır. Firefox, artan tasarım düzenleri için, “reflow komutlarını” sıralar ve bir çalıştırıcı program bu komutların icra yığınlarını çalıştırmaya başlar. WebKit ayrıca, artan tasarım düzenini baştan sonra çalıştıran bir zamanlayıcıya sahiptir.(Dirty renderer’lar bu tasarım düzeni dışındadır.)

Scriptler ofsetHeight gibi artan tasarım düzenini eş zamansız başlatabilen biçim(style) bilgilerini talep eder(ister).

Global tasarım düzeni genellikle eş zamansız olarak başlatılacak.

Bazen tasarım düzeni, değiştirilen kayan durumlar gibi, bazı özelliklerinden dolayı ilk tasarım düzeninden sonra geri çağırma olarak başlatılır.

WebKit: Web tarayıcılarına web sayfalarını işlemesine izin vermek için tasarlanmış bir tarayıcı motorudur.

Optimizasyonlar

Tasarım düzeni “Yeniden Boyutlandırma” yapılarak veya renderer pozisyonunda (ve boyutlanmamış) bir değişiklik yapılarak başlatıldığında, o render’ların boyutları ön bellekten (cache) alınır ve tekrar hesaplanmaz.

Bazı durumlarda, sadece bir alt ağaç değiştirildiğinde tasarım düzeni kökten başlatılmaz. Bu değişim yerel olduğunda ve etrafındakileri etkilemediği durumlarda olabilir (yazı alanına yazı girilmesi gibi). Aksi halde her tuş basımında tasarım düzeninin kökten başlatılması tetiklenecektir.

Tasarım Düzeni Süreci

Tasarım düzeni genellikle aşağıdaki kalıplara sahiptir:

  1. Ata renderer kendi genişliğini belirler.

  2. Ata render çocukları kontol eder ve :

    1. Çocuk renderer’a yer verir. (kendi x-y kümesinde)
    1. İhtiyaç duyulduğunda çocuk tasarım düzenini çağırır. -Dirty olanlar için, ya da global tasarım düzeninde olduğumuzda ya da çocukların boylarını hesaplayan diğer bazı sebepler için.

  3. Ata, çocukların toplanan boylarını, kenarlara olan uzaklıklarını ve mesafesi kendisinde belirlenmiş olan doldurma boyutunu kullanır. - Bu, ata renderer’ın atası aracılığıyla kullanılacaktır.

  4. Tasarım düzeninin yanlış olan dirty bit’i ayarlanır.

Firefox tasarım düzenine bir parametre olarak state nesnesini (nsHTMLReflowState) kullanır (reflow olarak belirlenir). Diğerlerini arasında bu durum ataların genişiliğini kapsar. Firefox tasarım düzeninin çıktısı “metrics” (ölçüme uygun) bir nesnedir (nsHTMLReflowMetrics). O, yüksekliği hesaplanmış renderer’ı içerektir.

Genişlik Hesaplama

Renderer’ın genişliği; konteynır bloklarının genişliğinin, rendererın sahip olduğu “width” özellikli biçiminin, marjinlerinin ve sınırlarının kullanılmasıyla hesaplanır.

Örneğin; aşağıdaki divin genişliği:

width calculation div

Aşağıdaki gibi WebKit aracılıyla hesaplanaca k (RenderBox sınıfının calcWidth metodu):

  • Konteynır genişliği, sıfır ve konteynırın mevcut genişliğinin (availableWidth) maximum boyutu arasındadır. Bu durumda mevcut genişliklik, aşağıda hesaplanan içerik genişliği kadardır.

width calc 2th pic

clientWidth ve clientHeight, sınır ve kaydırma çubuğu haricindeki bir nesnenin içerisini yansıtır.

  • Elementlerin genişliği, “width” biçimiyle nitelendirilir. Bu genişlik konteynır genişliğinin yüzdesinin hesaplanmasıyla mutlak bir değer olarak belirlenecektir.

  • Yatay sınırlar ve doldurmalar(padding) bu anda hesaplanır.

Buraya kadar olan kısım, “tercih edilen genişlik” hesaplamarıydı. Şimdi, maksimum ve minimum genişlikler hesaplanacaktır.

Eğer tercih edilen genişlik maksimum genişlikten daha büyükse, maksimum genişlik kullanılır. Eğer minimum genişlikten (en küçük bölünmez birim) daha küçükse, o zaman minimum genişlik kullanılır.

Bahsedilen değerler, tasarım düzeninin ihtiyaç duyduğu durumda ön belleğe alınır, fakat genişlik değeri değişmez.

Satır Sonlandırma

Tasarım düzeninin ortasındaki bir renderer, durdurulma ihtiyacı olduğuna karar verdiğinde, renderer durur ve sonlandırılması gereken tasarım düzeninde atasına yayılır. Ata render ekstra renderlar yaratır ve o, onlarda tasarım düzeni çağırır.

Çizim (Painting)

Çizim aşamasında render ağacında geçiş yapılır ve içeriği ekranda görüntülemek için renderın paint() yöntemi çağrılır. Çizim user interface altyapı bileşenini kullanır.

Global ve Artımlı

Layout gibi, çizim de global –tüm ağaç çizimi- ya da artımlı olabilir. Artımlı çizimde, renderların bazıları tüm ağacı etkilemeyecek şekilde değiştirilir. Değiştirilen render, ekrandaki rectangle’yi geçersiz kılar. Bu işletim sisteminde “kirli bölge” görülmesine ve “çizim” olayı oluşturulmasına neden olur. İşletim sistemi bunu akıllıca yapar ve birden fazla bölgede birleştirir. Chrome’da bu daha karmaşıktır çünkü render ana işlemden farklı bir işlemdedir. Chrome bazı ölçülerde işletim sistemini taklit eder. Sunu bu olayları dinler ve mesajı kök rendera devreder. İlişkili rendera ulaşılıncaya kadar ağaçta geçiş yapılır.Kendisini (ve genellikle çocuklarını) yeniden .izecektir.

Çizim Sırası

CSS2, çizim sırasını tanımlar. Bu gerçekte yığın içeriğindeki hangi elemanın yükleneceğinin sırasıdır. Yığınlar, arkadan öne doğru çizildiğinden, sıra çizimi etkiler. Blok renderın yığınlanma sırası şu şekildedir:

  • Arkaplan rengi
  • Arkaplan resmi
  • Kenarlık
  • Çocuklar
  • Anahat

Firefox Görüntü Listesi

Firefox render ağacına gider ve çizim rectanglesi için görüntüleme listesi oluşturur. Bu, rectangle için doğru çizim sırasında ilgili renderları içerir (renderın arka planı, kenarlıkları vs.). Bu şekilde, ağaç, tüm arkaplanları, sonra tüm resimleri, sonra da kenarlıkları vb.. yeniden çizmek için birkaç kez yerine yalnızca bir kez geçilmeye ihtiyaç duyacaktır.

Firefox, tamamen opak öğelerinde altında kalan elementler gibi gizlenecek öğeleri eklemeyerek işlemleri optimize eder.

WebKit Dikdörtgen Depolama

Yeniden çizimden önce. WebKit, Bitmap gibi eski rectangle’leri kaydeder. Sonra sadece yeni ve eski rectangle arasında farkı çizer.

Dinamik Değişiklikler

Tarayıcılar bir değişikliğe yanıt olarak minimum muhtemel eylemler gerçekleştirmeye çalışır. Bu nedenle bir öğenin rengini değiştirmek sadece öğenin yeniden çizilmesine neden olur. Öğe pozisyonundaki değişiklikler öğenin, cocuklarının ve muhtemel kardeşlerinin yeniden çizimine ve düzenine neden olur. Bir DOM düğümü eklemek, nodun yeniden çizimine ve düzenine neden olur. HTML font boyutunun değiştirilmesi gibi büyük değişiklikler, önbellekleri geçersiz kılar ve tüm ağaç yeniden düzenlenir ve çizilir.

Rendering Motorlarının İş Parçacıkları (Threads)

Rendering motorları tek iş parçacığından(threads) oluşur. Network işlemleri hariç, neredeyse her şey tek iş parçacığından meydana gelir. Firefox ve Safari’de, bu tarayıcının ana iş parçacığıdır. Chrome’da, ana iş parçacığının tab işlemidir.

Network işlemleri bir çok paralel iş parçacığıyla gerçekleşebilir. Paralel bağlantı sayısı sınırlıdır (genellikle 2- 6 bağlantı).

Olay Döngüsü (Event Loop)

Tarayıcı ana iş parcacığı bir olay döngüsüdür. İşlemi canlı tutan bir sonsuz döngüdür. Bir olay için bekler (Düzenleme ve çizme işlemi gibi) ve onları işler. Aşağıdaki Firefox’un ana olay döngüsü kodudur.

Event Loop

CSS2 Görsel Model

Kanvas

CSS2 şartnamesine göre kanvas terimi tarayıcının çizdiği içerikte “Biçimlendirme yapısının renderlandığı alan”ı tanımlar. Kanvas alanı her boyut için sınsuzdur ancak tarayıcı görüntüleme çerçevesinin boyutuna dayalı bir başlangıç genişliği seçer.

www.w3.org/TR/CSS2/zindex.html 'e göre kanvas, içinde başka bir kanvas içeriyorsa şeffaftır, içermiyorsa kanvasa tarayıcıda tanımlanan renk verilir.

CSS Kutu Modeli

CCS kutu modeli, doküman ağacındaki bir eleman için oluşturulan ve sanal formatlama modeline göre ortaya konulan dikdörtgen kutuları tanımlar.

Her kutu içerik alanına (yazı, resim vs..) ve isteğe bağlı çevresindeki dolgu, kenarlık ve kenar boşluğu alanına sahiptir.

CSS2 Kutu Modeli

Her düğüm 0..n gibi kutuları üretir.

Tüm elemanlar oluşturulacak kutu tipini ytanımlayan “display” özelliğine sahiptir. Örnek olarak:

after css2 box model

Varsayılan inline seçeneğidir ancak tarayıcı stil sayfasında varsayılan ayarlanabilir. Örneğin : div elemanı için varsayılan display blocktur. Varsayılan stil sayfası örneklerini burada bulabilirsiniz.

www.w3.org/TR/CSS2/sample.html

Konumlandırma Şeması

3 şema vardır.

  1. Normal: Nesne, dökümandaki yerine göre konumlandırılır. Bu render ağacındaki yerinin DOM ağacındaki yeri gibi olduğu ve kutu tipi ve boyutlara göre düzenlendiği anlamına gelir.
  2. Float: nesne ilk olarak normal akışı gibi düzenlenir. Sonra olabildiğince sağa ya da sola kaydırılır.
  3. Absolute: Nesne render ağacında, DOM ağacında olduğundan farklı şekilde konumlandırılır.

Konumlandırma şemaları “position” özelliği “float” niteliği tarafından ayarlanır. - static ve relative normal akışa neden olurabsolute and fixed cause absolute positioning - absolute ve fixed kesin konumlandırmaya neden olur.

Static pozisyonda tanımlanan pozisyon yoktur ve varsayılan pozisyon kullanılır. Diğer şemalarda, pozisyon tanımlanır: top, bottom, left, right.

Kutu düzenleme aşağıdakiler tarafından tanımlanır:

  • Kutu Tipi
  • Kutu Boyutu
  • Konumlandırma Şeması
  • Ekran boyuru, resim boyutu gbi harici bilgiler

Kutu Tipi

Block Kutu: Bir blok oluşturur. Tarayıcı penceresinde kendi dikdörtgeni vardır.

Şekil: Block Kutu

Inline Kutu: Kendi bloğu yoktur ancak içeren bir blok içindedir.

Şekil: İnline Kutu

Bloklar birbiri ardına dikey şekilde biçimlendirilir. Inline ise yatay biçimlendirilir.

Şekil: Blok ve İnline Formatı

Inline kutuları bir satır içerisine ya da satır kutularının içerisine konulur. Satırların uzunluğu, kutular tabana hizalandığında –yani bir elemanın alt kısmı daha sonra başka bir kutunun bir alt alanına hizalandığında, en azından en uzun kutu kadar uzun olmalıdır ancak daha da uzun olabilir. Eğer genişlik yeterince uzun değilse, inline kutular birkaç satıra konulacaktır. Genellikle bir paragrafta böyle olur.

Şekil: Satırlar

Konumlandırma

Relative

Olağan biçimde yerleştirilir ve sonra gerekli delta tarafından taşınır.

Şekil: Relative Positioning

Floats

Float kutu bir satırın soluna veya sağına kaydırılır. İlgiç özelliği şudur: Diğer kutular etrafından akar.

  <p>
    <img style="float: right" src="images/image.gif" width="100" height="100">
    Lorem ipsum dolor sit amet, consectetuer...
  </p>
  

Şu şekilde görülür:

Absolute and fixed

Layout(Tasarım Düzeni) normal akışından bağımsız olarak tanımlanır. Eleman, normal akışa katılmaz. Boyutları bulunduğu kaba göredir. Fixed’da, kab görüntü alanı kadardır.

Şekil: Fixed Position

Not: Döküman kaydırıldığında sabit kutu hareket etmeyecektir.

Katmanlı Gösterim

Z-index css özelliği tarafından belirlenir. Bir kutunun üçüncü boyutu temsil eder: "z ekseni" boyunca konumunu.

Kutular yığınlara ayrılır (Yığın içeriği de denir). Her yığın içinde arkadaki elmanlar ilk olarak çizilir ve elemanı kullanıcıya daha yakına doğru doğru ilerletir. Örtüşme durumda en öndeki eleman, eski elemanı gizler. Yığınları z-index özelliğine göre sıralanır. "Z-index" özelliği ile kutular yerel bir yığın oluşturur. Görüntüleme çerçevesi dış yığına sahiptir.

Örneğin:

  <style type="text/css">
	div {
	  position: absolute;
	  left: 2in;
	  top: 2in;
	}
  </style>

  <p>
      <div 
	  style="z-index: 3;background-color:red; width: 1in; height: 1in">
      </div>
      <div
	  style="z-index: 1;background-color:green;width: 2in; height: 2in;">
      </div>
  </p>
  

Sonuç şu şekildedir:

Kırmızı div yeşil biçimlendirmeden önde olduğu halde ve regular akış içinde önce çizilmesine rağmen z-index özelliği daha yüksektir bu yüzden root kutusu tarafından düzenlenen yığınında daha ileri tutulur.

]]>
SASS'a Giriş Mon, 14 Jul 2014 19:53:49 +0000 http://www.sonsuzdongu.com/blog/sass-a-giris http://www.sonsuzdongu.com/blog/sass-a-giris kalendernesrin@gmail.com (Nesrin Kalender) Nesrin Kalender

SASS, CSS yazarken işlerimizi kolaylaştıran teknolojilerden bir tanesi. Genelde SASS denince akla LESS gelir. Aynı işi yapan ve birbirine çok benzeyen bu iki teknoloji arasındaki fazla fark yok fakat yine de http://css-tricks.com/SASS-vs-less/ adresine bir gözatın derim. (Not: winner kısmı sürekli update ediliyor.)

Sass normalde CSS yazarken kullanamadığımız özellikleri bize sağlıyor. Genel olarak css yazarken vaktimizi alan noktalara Sass çözüm getiriyor. Prefixleri bir property için her kullanımda tekrarlamak yerine bir kez tanımlamak vakitten kazandırıyor. Birazdan bahsedeceğim değişkenler ile projedeki en çok kullanılan renk kodlarını isimlendirebiliriz ve bir rengi tek seferde değiştirebiliriz.

Yukarıda bahsettiğim gibi Sass sayesinde değişken tanımlayabiliyoruz böylece projedeki belli başlı renk kodlarımızı kendi değişken isimlerimiz ile kullanabiliyoruz. Herhangi bir renk kodu değişiminde tek yerden kolayca değiştirebiliyoruz. İç içe yazım şekli sayesinde tekrar tekrar selector isimleri yazmıyoruz. Mixins ile prefixleri tekrar tekrar yazmak yerine sadece bir kez tanımlıyoruz ve gerektiği yerden include ile çağırarak değerimizi giriyoruz. Değişken tanımlama, iç içe yazım tarzı, extend miras alma diyebiliriz ve son olarak mixin bu maddeleri birazdan başlık başlık inceleyeceğiz.

SASS'ı bilgisayarınızda bulunan işletim sistemine göre değişik şekillerde kurabilirsiniz. http://sass-lang.com/install adresinde farklı platformlar için kurulum yönergeleri bulunmaktadır.

SASS yazarken karşınıza iki adet dosya uzantısı gelecektir. Bir .scss bir de .sass. İkisi arasındaki fark yazım tarzıdır. Siz tamamen alışkanlık ve arzunuza göre yazabilirsiniz. Ayrıca komut satırından uzantıları birbirine convert edebiliyorsunuz.

# Convert SASS to SCSS
$ sass-convert style.SASS style.scss

# Convert SCSS to SASS
$ sass-convert style.scss style.SASS 

Ayrıca yazdığınız style.scss dosyanızın css çıktısını alabilmek için komut satırından;

sass --watch /dosyayolu/style.scss
komutunu çalıştırmanız yeterli. Bu şekilde build ettiğinizde nested tipinde çıktı alırsınız.

Diğer çıktı tipleri compact, compressed ve expanded'dır. Çıktı tipini değiştirmek için;
sass --watch style.scss:style.css --style expanded
yani --style çıktıtipi komutunu eklemeniz yeterlidir.

Eğer http://sass-lang.com/ adresine site değiştirilmeden önce girseydiniz karşınızda 4 madde görecektiniz. Bunlar yukarıda da sıraladığımız en temel maddeler; Nesting, Variables, Mixin'ler, Extend.

Nesting

Nesting ile iç içe bir yazım şekli elde edebiliyoruz.Bu sayede tekrar tekrar selector isimleri yazmaktan kurtuluyorsunuz. Örneğin:

CSS:
ul{}
ul li {}
ul li a{}

SASS:
ul {
    li{
        a{}
    }
}
şeklinde yazabilirsiniz.

Değişken tanımlama

Variables değişken tanımlamamızı sağlıyor. Bir projedeki herhangi bir rengi sadece tek seferde değişken tanımından kolayca değiştirebiliyoruz. Örnekleyecek olursak;

$my-color: #C61C6F;
body {
    color: $my-color;
}

Mixin'ler

Mixin'ler bize değer döndürüyor. Genelde prefixlerle karşımıza çıkan mixin için güzel bir mixin library var Bourbon adında http://www.sametaydemir.com/bourbon-sass-mixin-kutuphanesi/ linkinde Samet Aydemir’in yazısında detaylarını bulabilirsiniz. Mixinler ile prefixleri tekrar tekrar yazmak yerine bir kere tanımladıktan değerleri girip prefixlerle tanımlamayı sağlayabiliyoruz.



Mixin örneği verecek olursak;

@mixin border-radius($radius) {
    -webkit-border-radius: $radius;
    -moz-border-radius: $radius;
    -ms-border-radius: $radius;
    -o-border-radius: $radius;
    border-radius: $radius;
}
.box { @include border-radius(10px); }

Son olarak Extend adında da anlaşılacağı üzere örneğin bir class özelliğini diğer bir classta tekrar tekrar tanımlamak yerine extend ile class ismini yazıyoruz ardından farklılaşmasını istediğimiz özellikleri belirliyoruz. Böylece aynı özellikleri tekrar eden birden fazla class yazmak zorunda kalmıyoruz onu çokluyoruz.


Örnek olarak;

.message {
    border: 1px solid #ccc;
    padding: 10px;
    color: #333;
}

.success {
    @extend .message;
    border-color: green;
}

.error {
    @extend .message;
    border-color: red;
}

.warning {
    @extend .message;
    border-color: yellow;
}

Sass'a basic bir giriş yapmış sayılırsınız. Daha fazlası için http://sass-lang.com/ adresini ziyaret edebilirsiniz. Ayrıca kurulum yapmadan deneyeyim bir diyorsanız http://sassmeister.com linkine göz atabilirsiniz.

]]>
FileZilla ile Continuous Integration Sat, 04 Jan 2014 18:25:26 +0000 http://www.sonsuzdongu.com/blog/filezilla-ile-continuous-integration http://www.sonsuzdongu.com/blog/filezilla-ile-continuous-integration yuxel@sonsuzdongu.com (Osman Yüksel) Osman Yüksel

1 Nisan

1. Kurulum

Öncelikle sisteminize FileZilla kurmalısınız ki bu çok önemli. Bunun için
apt-get install filezilla --foolsday
komutunu vermeniz gerekiyor. Sonrasında karşınıza şu şekilde bir ekran çıkacak.

1 Nisan

2. Kullanım

Bu ekranda üst tarafa şu şekilde banka kredi kartı bilgilerinizi yazarak uygulamanızın sürekli tümleştirme (continuous integration) methodolojine uygun olmasını sağlayabilirsiniz.

1 Nisan

FileZilla'nın güzellikleri saymakla bitmez. Bu yazıda ancak Continuous Integration bölümüne değinebildik.

Bir sonraki blog yazısında görüşmek üzere...]]>
Grunt İle Frontend İşlerinizi Otomatize Edin Efem, 1.5 aydır blog yazamasak da bu süre zarfında kod.io, Özgür Web Teknolojileri Günleri, Google DevFest ve Laravel Türkiye etkinliklerinde sponsor ve konuşmacı olarak görev aldık. Yine çeşitli insanlarla falan tanıştık. Bu telaşede de blog yazmayı biraz ihmal ettik, grunt ile bir geri dönüş yapalım dedik.

]]>
Sun, 19 Jan 2014 17:33:29 +0000 http://www.sonsuzdongu.com/blog/grunt-ile-frontend-islerinizi-otomatize-edin http://www.sonsuzdongu.com/blog/grunt-ile-frontend-islerinizi-otomatize-edin yuxel@sonsuzdongu.com (Osman Yüksel) Osman Yüksel Efem, 1.5 aydır blog yazamasak da bu süre zarfında kod.io, Özgür Web Teknolojileri Günleri, Google DevFest ve Laravel Türkiye etkinliklerinde sponsor ve konuşmacı olarak görev aldık. Yine çeşitli insanlarla falan tanıştık. Bu telaşede de blog yazmayı biraz ihmal ettik, grunt ile bir geri dönüş yapalım dedik.


Her ne kadar "kendizi çok da geliştirmeyin, belli bir yerde durun" diye ahkam kessem de bu deli sektör sizi bir şeyler öğrenmeye mecbur kılıyor. Bundan iki sene önceki "frontend developer" ile şu anki "frontend developer" tanımlamaları bile oldukça değişti. İki sene önce "eli HTML/CSS tutan adama" frontend developer derken, artık frontend developer dediğimiz kitle yavaş yavaş en azından bir JavaScript MVC framework bilen, less'dir stylus'dur bir css pre-processor bilen, jshint, csslint gibi araçlarla daha düzgün kod yazmaya özen gösteren, test falan yazan insanlar olmaya başladı.


Ama bu süreçte, bu organizmaların otomatize etmesi gereken işler oluşmaya başladı:

  • Hazırladığı css ve javascript dosyalarını jshint, csslint gibi araçlardan geçirme
  • Coffescript, less gibi pre-processor'lerle yazdığı kodları derleme
  • Yine bu dosyaları tek dosya haline getirme
  • Bu dosyaları sıkıştırma
  • Kullanılan resim dosyalarını sıkıştırma
  • ...

Bu tip araçlar için unix dünyasından aşina olduğumuz makefile'lar denendi önce. Bir çok kütüphane (jQuery vs) bu tip işler için makefile kullanıyordu. Yine bazı projelerde Java dünyasından aşina olduğumuz Ant veya Maven gibi araçlar kullanılıyordu. Ya da oturup kendi bash scriptlerimizi yazıyorduk.


Ben hala make varken neden "ant" gibi bir şey icad edip yazılımcılar olarak kendi topuğumuza sıktığımızı bile tam olarak anlamamışken bir grup geliştirici Grunt'ı duyurdu.


Grunt temelde; ant'ın veya makefile'ın yaptığı işi JavaScript ile, Nodejs modülleri ile yapan "Not Invented Here"a örnek gösterilecek(zaaa xd) başka bir "Task Runner". Ve maalesef günümüz "frontend developer"larının bilmesi gereken bir kavram haline geldi. (grunt olmasa da Gulp gibi başka bir task runner).

Kendisi de bir Nodejs modülü olan grunt, yukarıda saydığım tür işleri otomatize etmek, frontend developer'ların yaptığı çoğu hamaliyeye son vermek için oluşturuldu. Bunun yanında günümüz frontend developer'larının ihtiyacı haline gelen bir çok iş için (örneğin; resim dosyalarından sprite üretme) de hazır modüller sunuyor.

Grunt'ı kurmak için temelde 2 dosyaya ihtiyacınız var:

  1. package.json: aslında grunt için değil ama kullanacağımınız node modüllerinin bağımlılıkları için diyelim
  2. Gruntfile.js: make'in Makefile'ı, ant'ın build.xml'i varsa, grunt'ın da Gruntfile.js'i var

package.json dosyasınız eğer yoksa aşağıdaki gibi oluşturduktan sonra $ npm install komutunu vererek gerekli bağımlılıkları kurabilirsiniz.

{
  "name": "my-project-name",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.2",
    "grunt-contrib-jshint": "~0.6.3",
    "grunt-contrib-nodeunit": "~0.2.0",
    "grunt-contrib-uglify": "~0.2.2"
  }
}

Burada dilediğiniz Grunt plugin'inini http://gruntjs.com/plugins adresinden bulup ekleyebilirsiniz veya
npm install node-modülü-adı --save-dev
diyerek de package.json dosyasını güncelleyebilirsiniz.


Gruntfile.js dosyası da içinde bazı yapılandırma fonksiyonları ve parametreleri (kısaca JavaScript kodları) bulunan şunun gibi bir dosya:

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    // pluginlerin kendi configurasyon parametrelerini plugin'in sayfasından öğrenebilirsiniz
    uglify: { 
      options: {
        // grunt kendi içinde basit bir templating sistemiyle de geliyor
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      build: { // uglify:build taski de bu parametrelerle çalışıyormuş
        src: 'src/<%= pkg.name %>.js',
        dest: 'build/<%= pkg.name %>.min.js'
      }
    },
    
    clean: { // örneğin clean task'i public/static içindeki her şeyi siliyor
      public: ["public/static"] 
    },

  });

  // Burada yüklenecek grunt plugin'lerini ekliyoruz
  grunt.loadNpmTasks('grunt-contrib-uglify');

  // Burada da task'leri oluşturabiliyoruz
  // burada default task gidip  initConfig içindeki "uglify" taskini çalıştırıyormuş mesela
  grunt.registerTask('default', ['uglify']);
  
  // başka bir örnek aşağıdaki gibi olabilir
  // deploy'dan önce "clean" taski sonra da "uglfy" taski çalışıyor olabilir
  grunt.registerTask('deploy', ['clean',  'uglify']);

};

Bunları tanımladıktan sonra istersek teker teker config'deki task'lerin adını verebilir, istersek de register ettiğimiz diğer task'leri çalıştırabiliriz:
$ grunt 
$ grunt deploy
$ grunt uglify
$ grunt herhangi_bir_task


Otomatize edeceğiniz her frontend görevi için bir grunt modülü ekleyip, çoğu işteki hamaliyenizden kurtulabilir, daha maintain edilebilir frontend kodları yazabilirsiniz.


Frontend developer'ların, tasarımcıların ve hatta release manager'ların en çok seveceği grunt paketinden birisi de SpriteSmith.
SpriteSmith koyduğunuz ufak resimlerden, sprite'lar üretip bunların css'lerini üreten çok güzel bir araç. Bu sayede hem tasarımcı sprite dosyası oluşturmakla uğraşmıyor, hem frontend developer "bu resim hangi koordinattaydı, boyutu neydi" gibi şeylerle uğraşmmıyor, hem sprite dosyasında oluşan conflict'ler sonrası sürüm yöneticiniz ağlamıyor.

SpriteSmith ve bunun gibi bir çok hayat kurtaran eklenti için Grunt Plugin'lerini incelemeyi unutmayın

]]>
Corona İle Mobil Oyun Programlamaya Giriş ne yapsak nasıl yapsak nereye yönelsek diye. Ben web programlama ile ilgili bir şeyler beklerken Osman ile konuşmamız sonucunda, oyunlar hakkındaki ilgimi ve bu yöne yönelmememin daha doğru olacağını keşfettik. Hepimizin hayalidir biraz oyun yapmak değil mi? :) ]]> Sun, 20 Oct 2013 19:43:35 +0000 http://www.sonsuzdongu.com/blog/corona-ile-mobil-oyun-programlamaya-giris http://www.sonsuzdongu.com/blog/corona-ile-mobil-oyun-programlamaya-giris tariktanyeli20@hotmail.com (Tarık Tanyeli) Tarık Tanyeli ne yapsak nasıl yapsak nereye yönelsek diye. Ben web programlama ile ilgili bir şeyler beklerken Osman ile konuşmamız sonucunda, oyunlar hakkındaki ilgimi ve bu yöne yönelmememin daha doğru olacağını keşfettik. Hepimizin hayalidir biraz oyun yapmak değil mi? :)

Osman, Sonsuzdongü'nün içeride geliştirdiği ufak oyunu anlattı. Yardımları ve destekleriyle ben de Corona öğrenmeye başladım gözümüzü kapayıp.

Corona SDK nedir?

Corona SDK mobil cihazlar için 2D (iki boyutlu) oyun ve uygulama geliştirme platformudur. Windows üzerinde sadece Android, Mac üzerinde Android ve iOS aygıtlar için uygulama geliştirilebilir.

Geliştirmeleri Lua programlama dilinde yaptığınız oyunları test etmeniz için bir de simülatör sunuyor Corona.

Bunun yanında fizik kütüphanesi başta olmak üzere, telefon donanımına erişebileceğiniz (GPS, accelerometer), sosyal medya API'ları ile ödeme aracıları ile iletişim kurabileceğiniz bir çok kütüphane sunuyor.

Haydi kuralım!

Corona SDK şu anda Windows ve Mac için mevcut. Corona’nın sitesinden indirdiğimiz kurulum dosyasını çalıştırdıktan sonra yönergeleri takip ederek kurulumu tamamlıyoruz.

Masaüstünden "Corona Simulator"ü çalıştırdığımızda karşımıza bir kerelik onaylama penceresi çıkacak ve bizden kullanıcı adı (mail adresi) ve şifre isteyecek, eğer hala kayıt olmadıysanız "Register”"tuşuna basarak açılan sayfadan kaydımızı yapıyoruz ve bu bilgileri onay penceresine giriyoruz. Ve artık başlamak için hazırız.

Geliştirme için sevdiğiniz metin editörünü kullanabilirsiniz. Ben Notepad2 kullanıyorum.

Her proje içinde bir main.lua dosyası vardır kodumuzu bu dosya içine yazacağız.

Şimdi kendi yaptığım ilk uygulama uzerinden satır satır inceleyelim başlangıç olarak. Bu uygulamaya oyun denemez ama başlangıç için güzel bir zar uygulaması. Kısaca, telefonu salladığınızda zar atıyor ve ekranda sonucu gösteriyor.

Corona Zar

-- Basit Zar Uygulamasi
-- Statü Bar kaldırma
display.setStatusBar( display.HiddenStatusBar )

-- Ekrana "background" adında yeni bir resim yerleştirme
local background = display.newImage( "images/iphone4-wallpaper7s.jpg" )

-- dice adında yeni bir resim yerleştirme ve ekrandaki yerini belirleme
local dice = display.newImage( "images/Dice-1.png" )
dice.x = display.contentWidth/2; dice.y = display.contentHeight/2
 
-- Ses dosyasını yukleme. (Çalma değil)
local diceSound = audio.loadSound("diceroll.wav")

--Yeni bir "text" ekleme ve yerini belirleme
myText = display.newText("", display.contentWidth/2, 100, native.systemFont, 40)

-- accelerometer Event lerini dinleyen fonksiyonu
local function listener( event )
    -- Cihazın "shake" edildiğini kontrol eden if
    if event.isShake then
        
        -- Daha önce yüklediğimiz ses dosyasını oynatma
        audio.play( diceSound )
        
        -- Konsola cihazın "shake" edildiğini yazdırma
        print( "The device is being shaken!" )
		
		-- timerE fonksiyonu
		local function timerE(ev)
			-- 1-6 arası rastgele bir sayı belirleme
			x=math.random(6)
			-- dice resmini silme
			dice:removeSelf()
			-- x değişkenine gore yeni bir resim ekleme (..x.. ya dikkat)
			dice = display.newImage( "images/Dice-"..x..".png" ) 
			dice.x = display.contentWidth/2 dice.y = display.contentHeight/2 	
      
			-- konsola x i yazdırma
			print("Rolled"..x)
			
			-- Onceden bos olan text içerigini x değişkenine gore değiştirmek
			myText.text = "Rolled "..x
		end
    
		--timerE fonksiyonunun özellikleri, 100ms, 10 kere
		timer.performWithDelay( 100, timerE, 10 )
		
    end
 
    return true
end

-- cihazın shake özelligini dinleyen listener
Runtime:addEventListener("accelerometer", listener )

Satır satır incelemek gerekirse;

Satır 3: Bu tek satır kod ekranın üstündeki "Statü Bar" denilen seridi kaldırmaya yarıyor. (Pil durumu, saat vs. Gösteren bar)

Satır 6: Bu satırda background adında bir resim tanımlıyoruz (.png) parantez ve tırnak içine istediğimiz resmin adını uzantısını yazıyoruz. Eğer ayrı bir dosya içindeyse bunu da ekliyoruz. Bu bizim uygulamamızın arkaplanındaki resim olacak.

Satır 9: Aynen üstteki gibi bir resim ekliyoruz bu da bizim zar resmimiz.

Satır 10: Burada zar resmini ekran üzerinde istediğimiz kordinatları belirleyerek yerleştiriyoruz. dice.x, x kordinatını dice.y,y kordinatını gosteriyor.
Display.contentWidth/2 ekranın eninin yarısı anlamına geliyor. Digeri aynı şekilde boyun yarısı anlamına geliyor.

Satır 13: Burada kullanacağımız zar sesini yüklüyoruz. Resimlerde yaptıgımız gibi tırnak içine ses dosyasının adını uzantısıyla birlikte yazıyoruz. (Sadece yüklüyoruz daha çalmıyoruz çalma işlemi ileride)

Satır 16: Bu satırda myText adında ekrana eklenecek yazıyı tanımlıyoruz. Şimdilik içi boş ekranda birşey gozukmeyecek. İlerde zar resmi değiştikçe yazıda değişecek. Ayrıca ekrandaki yerini, puntosunu ve yazı tipinide burada belirliyoruz.

Satır 19: Listener adında bir fonksiyon başlatıyoruz. Nerdeyse tüm işlemler burda yapılıyor. Bu listener ise, 55. satırdaki "accelerometer" event'ine bind oldu

Satır 21: Burda bir if var cihaz sallandığı anda buraya giriyoruz.

Satır 24: Bu satır daha önce 13. satırda yüklediğimiz ses dosyasını çalmaya yarıyor.

Satır 27: Konsola cihazın sallandığını yazdıran satır. Kontrol amaçlıdır yazılmasa da olur.

Satır 30: Burada timer fonksiyonunu yazmaya başlıyoruz. Zar resimleri değişirken her resmin arasına zaman eklemeye yarıyor. Eger bu şekilde kullanmazsak resimler cok hızlı değiştirginden değiştiklerini gormuyoruz sadece en son gelen resmi goruyoruz.

Satır 32: 1-6 arası rastgele bir rakam olusturup x’e atıyoruz.

Satır 34:Corona'da da olusturdugumuz resmin içerigini değiştiremiyoruz bu yuzden resmi değiştirmek için once o resmi kaldırıp daha sonra aynı yere yeni kullanmak istediğimiz resmi eklememiz gerekiyor. Bu satırda resmi kaldırıyoruz. Aslında bunun için sprite gibi daha güzel teknikler var ama ilk uygulamada bu resmi kaldırıp tekrar yerine koymak daha basit bir çözüm :)

Satır 36: Burada ise yeniden resim ekliyoruz. Eklenicek resmin adını x’e gore belirliyoruz. Dosyamızdaki resimler 1 resmi için Dice-1, 2 resmi için Dice-2 diye gittiği için tırnak içine x değişkenini koyarak ekrana uygun resmi ekliyoruz.

Satır 37: Eklenen resmin yerini belirliyoruz. Satır10’daki ile aynı ki resimler üstüste gelsin sanki resim değişiyormus gibi görünsün.

Satır 40: Rastgele seçilen x’i konsola yazdırıyor yine takip ve kontrol amaçlı bir satır.

Satır 43: Daha önce myText adında boş olarak yarattığımız yazının artık birşeyler gosterme zamanı geldi. Burada bu değişikliği yapıyoruz.

Satır 47: timerE fonksiyonunu cağırıyoruz. Kaç kere çağıracağımızı ve aralarındaki süreyi de burada ekliyoruz. Burada 100ms aralıklarla 10 kere çağırıyoruz.

Satır55: Onceden belirttiğim gibi 19. Satır için eklediğimiz event listener.

Oyunun tamamlanmış halini, https://github.com/sonsuzdongu/corona-dice adresindeki git deposuna gönderdim. Oradan oyunu daha detaylı inceleyebilirsiniz.

Ben de yeniyim elimden geldiğince başlangıç için satır satır anlatmaya çalıştım. Sürç-ü lisan ettiysek affola :)

"Eee adam gibi oyun nasıl yapacağız diyenler" biraz daha bekleyecek şimdilik bu öğrendiklerimizle pratik yapalım :)]]>
Sonsuzdöngü 1 Yaşında! Mon, 10 Jun 2013 20:10:17 +0000 http://www.sonsuzdongu.com/blog/sonsuzdongu-1-yasinda http://www.sonsuzdongu.com/blog/sonsuzdongu-1-yasinda yuxel@sonsuzdongu.com (Osman Yüksel) Osman Yüksel Döngü'den Çıkanlar "ben bu çocuğu doğuracağım" dediğimde Mustafa İleri de "ben de elimden gelen desteği veririm, çocuk ufaktan büyüyünce de mevcut işimden istifa ederim, beraber büyütürüz" demişti. Son 4 aydır da bilfiil elinden tuttu Sonsuzdöngü'nün, şirketin ortağı oldu. ]]> Mon, 09 Sep 2013 22:28:33 +0000 http://www.sonsuzdongu.com/blog/dongu-den-cikanlar http://www.sonsuzdongu.com/blog/dongu-den-cikanlar yuxel@sonsuzdongu.com (Osman Yüksel) Osman Yüksel "ben bu çocuğu doğuracağım" dediğimde Mustafa İleri de "ben de elimden gelen desteği veririm, çocuk ufaktan büyüyünce de mevcut işimden istifa ederim, beraber büyütürüz" demişti. Son 4 aydır da bilfiil elinden tuttu Sonsuzdöngü'nün, şirketin ortağı oldu.

Bu sürede bir de akıncıyı saflarımıza kattık. Fatih de 6 aydır bizimle beraber geliştirdi Sonsuzdöngü'yü.

11. ayın sonunda Mustafa, bazı kişisel sebeplerden dolayı ortaklıktan ayrılmaya karar verdi. O artık kendi yolunu çizecek.

Fatih'i ise bu süreçte, kendi yönetim beceriksizliğimizden kaynaklı, iyi kullanamadığımız için, danışmanlığını verdiğimiz başka bir şirkete *dış mihrak* olarak soktuk.

Ben, bundan sonra elimden geldiğince Sonsuzdöngü'yü adam edeceğim, sünnetini, düğününü göreceğim inşallah.

Sonsuzdongu, son 11 ayda, her ne kadar 3-5 tane açık kaynak projemiz olsa da genelde müşteri odaklı bir şirketti. Eğer becerebilirsem, bundan sonraki süreçte yeni akıncılar yetiştirip, şirketin kendi projelerini geliştirmeye daha fazla ağırlık vereceğim.

Mustafa'nın Sonsuzdongu blog'da yazdığı yazılar da isteği üzerine yayından kaldırıldı. Mustafa'nın yazılarına, http://www.mustafaileri.com/ adresindeki kişisel blog'undan erişebilirsiniz.]]>
Solr'a Giriş ve Solarium karmaşık konulardan birisi haline gelmiş durumda. Performans kaygınız varsa veya seçtiğiniz veritabanı motoru (InnoDB?) full text search desteklemiyorsa harici bir arama motoru kullanmanız gerekli. ]]> Wed, 09 Jan 2013 13:11:24 +0000 http://www.sonsuzdongu.com/blog/solr-a-giris-ve-solarium http://www.sonsuzdongu.com/blog/solr-a-giris-ve-solarium yuxel@sonsuzdongu.com (Osman Yüksel) Osman Yüksel karmaşık konulardan birisi haline gelmiş durumda. Performans kaygınız varsa veya seçtiğiniz veritabanı motoru (InnoDB?) full text search desteklemiyorsa harici bir arama motoru kullanmanız gerekli.

Solr ise "Lucene tabanlı arama motorları ailesi"nin bir üyesi. Lucene; temelde metin analizi, indexleme ve arama gibi temel işlevleri sunan bir Apache projesi. Solr ise, Lucene temelini kullanan, onun üstüne filtreleme, faceting(Türkçesi var mı acaba?), önbellekleme, dağıtık mimari desteği gibi şeyleri kolay yapılandırma dosyaları ile yönetebilmenizi ve bu verileri XML, JSON, Binary gibi çeşitli formatlarda almanızı sağlayan bir üst proje.

Solr Kurulumu

http://lucene.apache.org/solr/downloads.html adresinden Apache Solr'ın son sürümü (yazı hazırlanırken 4.4 sürümü vardı) indirebilirsiniz. Solr kaynak kodlarını indirebileceğiniz gibi içinde hazır örnek uygulamaların da olduğu bir paketi (solr-4.4.0.zip) indirebilirsiniz.

Çalıştırma

Askere gidenler bilir; önce yaparak öğretme diye bir şey vardır. Bir eğitimi detaylı anlatmadan önce bir kere gösterir, sonra detaylara geçersiniz. Burada da önce, mevcut örnek uygulamayı bir çalıştırıp, sonra Solr'ın bir kaç yapılandırma dosyasını anlatacağım.
Zip'i açtığınızda içinde bir örnek uygulama bulunmakta. Eğer Java Runtime Environment'ınız kurulu ise aşağıdaki komutlarla Solr'ı çalıştırabilirsiniz.
$ cd solr-4.4.0/example/
$ java -jar start.jar

Solr, öntanımlı olarak 8983 portunda çalışır. Tarayıcınızdan http://localhost:8983/solr/ adresini ziyaret ettiğinizde aşağıdaki gibi bir yönetim paneli arayüzü göreceksiniz. Sol altta da mevcut "collection"ları görebilirsiniz. Örnek collection'a tıkladığınızda da aşağıdaki gibi bir ekran göreceksiniz.

Solr admin

Şu anda hiç "döküman"ımız yok. Solr her şeyi bir "döküman" olarak saklar. Dökümanları veritabanındaki "row"lar olarak düşünebilirsiniz. Örnek solr uygulaması, "exampledocs" isimli bir dizinde bir çok hazır döküman bulunduruyor. Daha sonra bu dökümanlara ve şemalara deyineceğim ama önce "yaparak göstermek" açısından örnek dökümanları ekleyip basit bir kaç arama yapalım.

Örnek birkaç döküman eklemek için komut satırında
$ cd exampledocs 
$ java -jar post.jar *.xml
komutlarını verdiğinizde aşağıdaki gibi bir çıktı alacaksınız
SimplePostTool version 1.5
Posting files to base url http://localhost:8983/solr/update using content-type application/xml..
POSTing file gb18030-example.xml
POSTing file hd.xml
POSTing file ipod_other.xml
POSTing file ipod_video.xml
POSTing file manufacturers.xml
POSTing file mem.xml
POSTing file money.xml
POSTing file monitor2.xml
POSTing file monitor.xml
POSTing file mp500.xml
POSTing file sd500.xml
POSTing file solr.xml
POSTing file utf8-example.xml
POSTing file vidcard.xml
14 files indexed.
COMMITting Solr index changes to http://localhost:8983/solr/update..
Time spent: 0:00:00.268

http://localhost:8983/solr/#/collection1 adresindeki yönetim paneline tekrar döndüğünüzde artık döküman sayınızın artığını görebilirsiniz.

Test etmek için;

Bunun yanında, örnek uygulama içinde, velocity template'ları ile geliştirilmiş "basit bir e-ticaret arama sayfası" da bulunuyor: http://localhost:8983/solr/browse

Artık "yaparak gösterme" kısmını geride bıraktığımıza göre biraz derine inmenin vakti geldi.

solrconfig.xml

İlgili collection'ın "conf" dizini altında bulunan bu dosyada solr genel yapılandırma ayarları, yukarıdaki örneklerde "query", "select", "spell" gibi farklı adreslerde gördüğünüz, bazı öntanımlı değerleri verip bazı ayarları yapabileceğiniz "requestHandler"lar, isteğe dönen cevap tipini ayarlayabileceğiniz queryResponseWriter'ları tanımlayabilirsiniz. Örnek içindeki dosya şuradaki gibi: https://gist.github.com/anonymous/038d4c991297a9352e5a

schema.xml

Daha önce bahsettiğim gibi, solr'daki her kayıt bir "döküman". Schema.xml de bu "döküman"ı tanımlamamız gereken dosya. <fields> alanındaki her <field> relational database'lerden alışık olduğumuz "column"lara denk geliyor. Burada kabaca field'ımızın adı(name), solr aramalarında kullanılıp kullanılmayacağı(indexed), bulunan kayıtlarda cevaplar içinde dönüp dönmeyeceği(stored), birden çok değer alıp alamayacağı(multiValued) ve hangi tipte bir veri içereceği(type)ni belirttiğimiz alanları içerir.

Bunun yanında uniqueId'yi belirleyebileceğimiz, bazı wildcard'lı field adları ile dynamic field'lar belirleyebileceğimiz, birden çok alanı tek alanda birleştirip arama yapabileceğimiz(copy) tanımlamaları bu dosyada belirtiyoruz.

Ayrıca, buradaki veri tiplerinin de class tanımlamaları ve varsa aldığı parametreler bu dosyada tanımlanıyor. Örnek içindeki dosya da şuradaki gibi: https://gist.github.com/anonymous/fb851195ea33e0fae9a7

Kendi döküman tipinizi schema.xml dosyasında belirleyebilirsiniz.

PHP ve Solr

Solr temelde HTTP istekleri ile çalıştığı için, basitçe cURL istekleri ile veriyi alıp, responseWriter olarak da json kullanırsanız basitçe verileri decode edip PHP içinde array ve obje olarak kullanabilirsiniz. Örnek olarak yukarıdaki ilk örneği aşağıdaki gibi Object olarak kullanabilirsiniz PHP tarafında.
<?php 
$url = "http://localhost:8983/solr/collection1/query?q=*";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch));
curl_close ($ch);

var_dump($response);
Ama istekler çeşitlenmeye başladığında istek yapmanız gereken adres çok karmaşık bir hal lamaya başlayacak. Curl ile uğraşıp, url generate etmek istemiyorsanız da Solarium gibi daha "high level" bir kütüphane kullanabilirsiniz.

Solarium, sizin için, daha "anlaşılabilir" bir programlama arayüzü ile Solr istekleri yapmanızı ve bu istekleri "parse etmenizi" sağlıyor. Bunun yanında buffer'lı şekilde döküman ekleme gibi de bir çok güzellik sunuyor.

Solarium kurulum

Solarium'u projenize dahil etmek için birçok yol olsa da, en güzeli composer ile eklemek. composer.json dosyanıza aşağıdaki "require" satırını ekledikten sonra composer install demeniz yeterli.
{
    "require": {
        "solarium/solarium": "3.1.2"
    }
}

Veri ekleme

<?php

require __DIR__. '/vendor/autoload.php';                                                        

$config = array(
    'endpoint' => array(
        'localhost' => array(
            'host' => '127.0.0.1',
            'port' => 8983,
            'path' => '/solr/',
        )
    )
);

$client = new Solarium\Client($config);

$update = $client->createUpdate();

// dokumanı oluşturuyoruz
$doc = $update->createDocument();
$doc->id = 1;
$doc->name = "Sonsuzdongu";
$doc->cat = "Yazılım";

// sonra dokumani commit'liyoruz
$update->addDocument($doc);
$update->addCommit();

// ve update sorgusunu calistiriyoruz
$result = $client->update($update);

// artik dokumanimiz eklendi
var_dump($result);

Veri Filtreleme

<?php

require __DIR__. '/vendor/autoload.php';

$config = array(
    'endpoint' => array(
        'localhost' => array(
            'host' => '127.0.0.1',
            'port' => 8983,
            'path' => '/solr/',
        )
    )
);

$client = new Solarium\Client($config);                         
                                                                
$query = $client->createSelect();                               
                                                                
// filtre olustur
$query->createFilterQuery('name')->setQuery('name:sonsuzdongu');
                                                                
$resultSet = $client->select($query);                           
                      

echo 'Toplam: '.$resultSet->getNumFound(); 
                      
//sonuclari ekrana bas                                                                
foreach($resultSet as $result) {                                
    var_dump($result->name);                                    
}             
Gördüğünüz gibi Solarium ile cURL ile yaptığımızdan daha "semantik" şekilde sorguları çalıştırıp sonuçları alabiliyoruz. Solr ve Solarium'dan şimdilik bu kadar. ]]>