cairo裁剪使用分析

工作中遇到一個調用cairo_clip之後,無法執行任何繪製的問題,在官方文檔裏面僅僅是對這一堆函數的簡單介紹。因此自己啃代碼研究無法繪製的具體原因。

首先貼出官方給出的一個簡單例子: 

cairo_arc (cr, 128.0, 128.0, 76.8, 0, 2 * M_PI);
cairo_clip (cr);

cairo_new_path (cr);  /* current path is not
                         consumed by cairo_clip() */
cairo_rectangle (cr, 0, 0, 256, 256);
cairo_fill (cr);

一步一步分析:

1、cairo_arc

      其實只是在cairo_t裏面創建了一個path對象。

2、cairo_clip

      在cairo_t裏面根據前面的path創建了一個clip對象,此函數的核心代碼如下:

cairo_clip_t *
_cairo_clip_intersect_path (cairo_clip_t       *clip,
			    const cairo_path_fixed_t *path,
			    cairo_fill_rule_t   fill_rule,
			    double              tolerance,
			    cairo_antialias_t   antialias)
{
    cairo_clip_path_t *clip_path;
    cairo_status_t status;
    cairo_rectangle_int_t extents;
    cairo_box_t box;

    if (_cairo_clip_is_all_clipped (clip))
	return clip;

    /* catch the empty clip path */
    if (_cairo_path_fixed_fill_is_empty (path))
	return _cairo_clip_set_all_clipped (clip);

    if (_cairo_path_fixed_is_box (path, &box)) {
	if (antialias == CAIRO_ANTIALIAS_NONE) {
	    box.p1.x = _cairo_fixed_round_down (box.p1.x);
	    box.p1.y = _cairo_fixed_round_down (box.p1.y);
	    box.p2.x = _cairo_fixed_round_down (box.p2.x);
	    box.p2.y = _cairo_fixed_round_down (box.p2.y);
	}

	return _cairo_clip_intersect_box (clip, &box);
    }
    if (_cairo_path_fixed_fill_is_rectilinear (path))
	return _cairo_clip_intersect_rectilinear_path (clip, path,
						       fill_rule, antialias);

    _cairo_path_fixed_approximate_clip_extents (path, &extents);
    if (extents.width == 0 || extents.height == 0)
	return _cairo_clip_set_all_clipped (clip);

    clip = _cairo_clip_intersect_rectangle (clip, &extents);
    if (_cairo_clip_is_all_clipped (clip))
	return clip;

    clip_path = _cairo_clip_path_create (clip);
    if (unlikely (clip_path == NULL))
	return _cairo_clip_set_all_clipped (clip);

    status = _cairo_path_fixed_init_copy (&clip_path->path, path);
    if (unlikely (status))
	return _cairo_clip_set_all_clipped (clip);

    clip_path->fill_rule = fill_rule;
    clip_path->tolerance = tolerance;
    clip_path->antialias = antialias;

    if (clip->region) {
	cairo_region_destroy (clip->region);
	clip->region = NULL;
    }

    clip->is_region = FALSE;
    return clip;
}

_cairo_path_fixed_fill_is_empty函數主要是判斷path是否爲空,如果爲空,則執行_cairo_clip_set_all_clipped 。

再來看看_cairo_clip_set_all_clipped 怎麼寫的:

static inline cairo_clip_t *
_cairo_clip_set_all_clipped (cairo_clip_t *clip)
{
    _cairo_clip_destroy (clip);
    return (cairo_clip_t *) &__cairo_clip_all;
}

所以,如果path爲空,cairo會直接直接返回全局cairo_clip_t對象。因此,調用cairo_clip之前,必須給cairo一個非空的path對象。

當path存在後,接下來就是創建一個clip了。

  1. 當傳入的path是通過cairo_rectangle創建的,這個範圍就是一個簡單的box,會執行_cairo_clip_intersect_box函數,並返回。
  2. 當傳入的path是通過cairo_arc創建的,則會走後面的流程,_cairo_clip_intersect_rectangle裏面所做的事情,其實本質上和_cairo_clip_intersect_box是一樣的。然後接下來,調用_cairo_clip_path_create,爲clip創建一個裁剪路徑。最後調用_cairo_path_fixed_init_copy,使用cairo_arc創建的路徑初始化裁剪路徑。

3、cairo_rectangle

     函數也是在cairo_t裏面新增一個path對象。

4、cairo_fill

      函數是cairo的實際繪製的函數。

cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
    cairo_status_t status;

    status = _cairo_gstate_get_pattern_status (gstate->source);
    if (unlikely (status))
	return status;

    if (gstate->op == CAIRO_OPERATOR_DEST)
	return CAIRO_STATUS_SUCCESS;

    if (_cairo_clip_is_all_clipped (gstate->clip))
	return CAIRO_STATUS_SUCCESS;
    。。。。
}

在繪製時,同樣會判斷上下文中的clip對象是否是全局默認的clip對象,如果是,則直接返回,之後的繪製流程不會再執行。後面的繪製過程,因筆者水平有限,就不再分析。

總結:

     調用cairo_clip之前,必須給一個非空的path,否則cairo_clip會直接使用全局clip對象,導致後面的繪製都不會執行。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章