九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
WebKit源碼分析系列之(1) html5 canvas
關(guān)閉
關(guān)閉

WebKit源碼分析系列之(一) html5 canvas
如今html5概念炒的很是火熱,其中不乏標(biāo)志性的tags,其中video算一個(gè),把Adobe憋的不行,收購PhoneGap等系列的活動(dòng)以應(yīng)對(duì)html5之強(qiáng)勢(shì)
兩大不開源的公司Apple Adobe誰都不服氣,以目前的勢(shì)頭看Apple走的更加深遠(yuǎn)些,閑話少說,我們說說今天的tag主角canvas
我們知道flash開發(fā)的時(shí)候,有專門畫點(diǎn)畫線的函數(shù),有這樣的接口對(duì)于開發(fā)小游戲,是相當(dāng)方便,而且還可以制作出很炫的視覺效果,下面的幾個(gè)鏈接
就是canvas應(yīng)用
http://media.chikuyonok.ru/ambilight/
http://www.2cto.com/zz/201206/135837.html

canvas這么牛,倒是如何實(shí)現(xiàn)的那?
從樣式上看canvas也只是一個(gè)普通的html標(biāo)簽(在webkit上還沒有專門擴(kuò)展過html那,找個(gè)時(shí)間實(shí)踐下,哈哈)
下面我們看一個(gè)簡(jiǎn)單的canvas應(yīng)用舉例:
<!DOCTYPE HTML>
<html>
<body>
<canvas id="myCanvas">your browser does not support the canvas tag </canvas>
<script type="text/javascript">
var canvas=document.getElementById('myCanvas');
var ctx=canvas.getContext('2d');
ctx.fillStyle='#FF0000';
ctx.fillRect(0,0,80,100);
</script>
</body>
</html>
我們做個(gè)簡(jiǎn)單的分析
<canvas id="myCanvas">your browser does not support the canvas tag </canvas>
典型的html語言的語法
這個(gè)辦法的顯示其實(shí)很簡(jiǎn)單,就是如果是不支持的tags,那么“your browser does not support the canvas tag”就是作為字符串進(jìn)行處理了,
如果是支持該tags的情況下,這一段文字是不會(huì)去處理的,這個(gè)方式通常作為判斷瀏覽器是否支持某個(gè)標(biāo)簽,例如在優(yōu)酷或者土豆網(wǎng)站對(duì)瀏覽器的支持
<video src="video.ogg">
   <object data="videoplayer.swf" type="application/x-shockwave-flash">
     <param name="movie" value="video.swf"/>
   </object>
</video>
就是說在支持video的狀態(tài)下,使用video標(biāo)簽播放,在不支持狀態(tài)下,使用Adobe flash
好了繼續(xù)分析網(wǎng)頁內(nèi)容
var canvas=document.getElementById('myCanvas');
var ctx=canvas.getContext('2d');
第一句很好理解,就是取到canvas實(shí)例對(duì)象
canvas.getContext('2d')
這句話得到畫板句柄,根據(jù)傳入的類型進(jìn)行返回不同實(shí)例,普通的操作是2D方式,如果涉及到3D操作傳入experimental-webgl或者webkit-3d參數(shù),這樣在網(wǎng)頁上就可以執(zhí)行3D的動(dòng)作
ctx.fillStyle='#FF0000';
ctx.fillRect(0,0,80,100);
這兩句話就是具體繪制操作,畫個(gè)紅色矩形
不要小瞧這兩句話,意味著在網(wǎng)頁里面可以隨便進(jìn)行畫點(diǎn)畫線,一些絢麗操作的通道就開啟了
上層邏輯的分析,基本上就是這種情況了。
下面進(jìn)入底層的分析流程:
對(duì)于最基礎(chǔ)的HTMLCanvasElement類的實(shí)例化,就先不做過多的分析了,直接分析底層
canvas.getContext('2d');這個(gè)函數(shù)的實(shí)現(xiàn)流程

CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, CanvasContextAttributes* attrs)
{
    // A Canvas can either be "2D" or "webgl" but never both. If you request a 2D canvas and the existing
    // context is already 2D, just return that. If the existing context is WebGL, then destroy it
    // before creating a new 2D context. Vice versa when requesting a WebGL canvas. Requesting a
    // context with any other type string will destroy any existing context.
    
    // FIXME - The code depends on the context not going away once created, to prevent JS from
    // seeing a dangling pointer. So for now we will disallow the context from being changed
    // once it is created.
    if (type == "2d") {
        if (m_context && !m_context->is2d())
            return 0;
        if (!m_context) {
            bool usesDashbardCompatibilityMode = false;
#if ENABLE(DASHBOARD_SUPPORT)
            if (Settings* settings = document()->settings())
                usesDashbardCompatibilityMode = settings->usesDashboardBackwardCompatibilityMode();
#endif
            m_context = adoptPtr(new CanvasRenderingContext2D(this, document()->inQuirksMode(), usesDashbardCompatibilityMode));
#if USE(IOSURFACE_CANVAS_BACKING_STORE) || (ENABLE(ACCELERATED_2D_CANVAS) && USE(ACCELERATED_COMPOSITING))
            if (m_context) {
                // Need to make sure a RenderLayer and compositing layer get created for the Canvas
                setNeedsStyleRecalc(SyntheticStyleChange);
            }
#endif
        }
        return m_context.get();
    }
#if ENABLE(WEBGL)    
    Settings* settings = document()->settings();
    if (settings && settings->webGLEnabled()
#if !PLATFORM(CHROMIUM) && !PLATFORM(GTK)
        && settings->acceleratedCompositingEnabled()
#endif
        ) {
        // Accept the legacy "webkit-3d" name as well as the provisional "experimental-webgl" name.
        // Once ratified, we will also accept "webgl" as the context name.
        if ((type == "webkit-3d") ||
            (type == "experimental-webgl")) {
            if (m_context && !m_context->is3d())
                return 0;
            if (!m_context) {
                m_context = WebGLRenderingContext::create(this, static_cast<WebGLContextAttributes*>(attrs));
                if (m_context) {
                    // Need to make sure a RenderLayer and compositing layer get created for the Canvas
                    setNeedsStyleRecalc(SyntheticStyleChange);
                }
            }
            return m_context.get();
        }
    }
#else
    UNUSED_PARAM(attrs);
#endif
    return 0;
}
代碼很多我們只是分析針對(duì)2D的情況
OwnPtr<CanvasRenderingContext> m_context;
m_context = adoptPtr(new CanvasRenderingContext2D(this, document()->inQuirksMode(), usesDashbardCompatibilityMode));
這個(gè)操作是我們要拿到畫布的句柄,實(shí)際上所有的操作都是圍繞這個(gè)函數(shù)展開的
我們具體追蹤一下CanvasRenderingContext類型實(shí)例對(duì)象如何進(jìn)行簡(jiǎn)單的畫點(diǎn)畫線操作
我們先不去看這個(gè)m_context如何去實(shí)現(xiàn),我們先看看如何使用的過程
ctx.fillRect(0,0,80,100);看看這個(gè)函數(shù)內(nèi)部包的什么我們感興趣的寶貝
下面是在c++層函數(shù)實(shí)現(xiàn)
void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
{
    if (!validateRectForCanvas(x, y, width, height))
        return;

    GraphicsContext* c = drawingContext();
    if (!c)
        return;
    if (!state().m_invertibleCTM)
        return;

    // from the HTML5 Canvas spec:
    // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing
    // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing
    Gradient* gradient = c->fillGradient();
    if (gradient && gradient->isZeroSize())
        return;

    FloatRect rect(x, y, width, height);

    c->fillRect(rect);
    didDraw(rect);
}
這個(gè)函數(shù)我們只關(guān)心三行
GraphicsContext* c = drawingContext();
c->fillRect(rect);
didDraw(rect);

先看第一行,GraphicsContext* c到底是誰給的?
層層分解,估計(jì)下面的層次會(huì)讓腦細(xì)胞累死一部分
GraphicsContext* CanvasRenderingContext2D::drawingContext() const
{
    return canvas()->drawingContext();
}
看看drawingContext()怎么實(shí)現(xiàn)
GraphicsContext* HTMLCanvasElement::drawingContext() const
{
    return buffer() ? m_imageBuffer->context() : 0;
}
buffer()函數(shù)實(shí)現(xiàn)
ImageBuffer* HTMLCanvasElement::buffer() const
{
    if (!m_hasCreatedImageBuffer)
        createImageBuffer();
    return m_imageBuffer.get();
}
createImageBuffer()函數(shù)實(shí)現(xiàn)
void HTMLCanvasElement::createImageBuffer() const
{
    ASSERT(!m_imageBuffer);

    m_hasCreatedImageBuffer = true;

    FloatSize unscaledSize(width(), height());
    IntSize size = convertLogicalToDevice(unscaledSize);
    if (!size.width() || !size.height())
        return;

#if USE(IOSURFACE_CANVAS_BACKING_STORE)
    if (document()->settings()->canvasUsesAcceleratedDrawing())
        m_imageBuffer = ImageBuffer::create(size, ColorSpaceDeviceRGB, Accelerated);
    else
        m_imageBuffer = ImageBuffer::create(size, ColorSpaceDeviceRGB, Unaccelerated);
#else
    m_imageBuffer = ImageBuffer::create(size);
#endif
    // The convertLogicalToDevice MaxCanvasArea check should prevent common cases
    // where ImageBuffer::create() returns 0, however we could still be low on memory.
    if (!m_imageBuffer)
        return;
    m_imageBuffer->context()->scale(FloatSize(size.width() / unscaledSize.width(), size.height() / unscaledSize.height()));
    m_imageBuffer->context()->setShadowsIgnoreTransforms(true);
    m_imageBuffer->context()->setImageInterpolationQuality(DefaultInterpolationQuality);

#if USE(JSC)
    JSC::JSLock lock(JSC::SilenceAssertionsOnly);
    scriptExecutionContext()->globalData()->heap.reportExtraMemoryCost(m_imageBuffer->dataSize());
#endif
}

ImageBuffer::create(size) 函數(shù)實(shí)現(xiàn)
static PassOwnPtr<ImageBuffer> create(const IntSize& size, ColorSpace colorSpace = ColorSpaceDeviceRGB, RenderingMode renderingMode = Unaccelerated)
{
    bool success = false;
    OwnPtr<ImageBuffer> buf(new ImageBuffer(size, colorSpace, renderingMode, success));
    if (success)
        return buf.release();
        return 0;
}
ImageBuffer構(gòu)造函數(shù)實(shí)現(xiàn)
ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success)
    : m_data(size)
    , m_size(size)
{
    // GraphicsContext creates a 32bpp SkBitmap, so 4 bytes per pixel.
    if (!PlatformBridge::canSatisfyMemoryAllocation(size.width() * size.height() * 4))
        success = false;
    else {
        m_context.set(GraphicsContext::createOffscreenContext(size.width(), size.height()));
        success = true;
    }
}
終于找到了針對(duì)canvas的GraphicsContext,哈哈看看函數(shù)里面的操作,哈哈熟悉的skia操作
GraphicsContext* GraphicsContext::createOffscreenContext(int width, int height)
{
    PlatformGraphicsContext* pgc = new PlatformGraphicsContext();

    SkBitmap bitmap;

    bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
    bitmap.allocPixels();
    bitmap.eraseColor(0);
    pgc->mCanvas->setBitmapDevice(bitmap);

    GraphicsContext* ctx = new GraphicsContext(pgc)
;
    return ctx;
}
追蹤到這里實(shí)際上已經(jīng)接近尾聲了,畫筆的老祖宗都已經(jīng)找到,具體的操作都是在祖先的基礎(chǔ)上完成


我們用比較輕松的心態(tài)看下具體的繪制操作
void GraphicsContext::fillRect(const FloatRect& rect)
{
    SkPaint paint;

    m_data->setupPaintFill(&paint);

    extactShader(&paint,
                 m_state.fillPattern.get(),
                 m_state.fillGradient.get());

    GC2CANVAS(this)->drawRect(rect, paint);
}
GC2CANVAS這個(gè)是什么玩意,看一下
#define GC2CANVAS(ctx)  (ctx)->m_data->getPlatformGfxCtx()->mCanvas
哈哈,canvas,原來搞到祖先頭上了,
GC2CANVAS(this)->drawRect(rect, paint);這句話實(shí)際上就是調(diào)用skia的canvas進(jìn)行繪制矩形操作,
繪制操作完畢之后就進(jìn)行具體展現(xiàn)到屏幕上,
void HTMLCanvasElement::didDraw(const FloatRect& rect)
{
    m_copiedImage.clear(); // Clear our image snapshot if we have one.

    if (RenderBox* ro = renderBox()) {
        FloatRect destRect = ro->contentBoxRect();
        FloatRect r = mapRect(rect, FloatRect(0, 0, size().width(), size().height()), destRect);
        r.intersect(destRect);
        if (r.isEmpty() || m_dirtyRect.contains(r))
            return;

        m_dirtyRect.unite(r);
        ro->repaintRectangle(enclosingIntRect(m_dirtyRect));
    }

    HashSet<CanvasObserver*>::iterator end = m_observers.end();
    for (HashSet<CanvasObserver*>::iterator it = m_observers.begin(); it != end; ++it)
        (*it)->canvasChanged(this, rect);
}
函數(shù)就是做的這個(gè)事情,因?yàn)樗械牟僮鞫际窃跒g覽器上操作,因此最后還是要觸發(fā),webkit的顯示動(dòng)作(repaintRectangle)
今天講述的都是一些框架性的,至于具體如何觸發(fā)webkit的操作以及具體繪制過程(相當(dāng)復(fù)雜)以后會(huì)做更加詳細(xì)的分析

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
使用canvas完成幀動(dòng)畫(方向鍵控制行走的小人)
android 美化zxing二維碼掃描框
HTML5 Canvas的事件處理介紹
HTML5 canvas drawImage() 方法 縮放
仿瓜子二手車價(jià)格選擇控件
ScratchView:一步步打造萬能的 Android 刮獎(jiǎng)效果控件
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服