1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkScanPriv_DEFINED
9#define SkScanPriv_DEFINED
10
11#include "SkPath.h"
12#include "SkScan.h"
13#include "SkBlitter.h"
14
15// controls how much we super-sample (when we use that scan convertion)
16#define SK_SUPERSAMPLE_SHIFT    2
17
18class SkScanClipper {
19public:
20    SkScanClipper(SkBlitter* blitter, const SkRegion* clip, const SkIRect& bounds,
21                  bool skipRejectTest = false, bool boundsPreClipped = false);
22
23    SkBlitter*      getBlitter() const { return fBlitter; }
24    const SkIRect*  getClipRect() const { return fClipRect; }
25
26private:
27    SkRectClipBlitter   fRectBlitter;
28    SkRgnClipBlitter    fRgnBlitter;
29#ifdef SK_DEBUG
30    SkRectClipCheckBlitter fRectClipCheckBlitter;
31#endif
32    SkBlitter*          fBlitter;
33    const SkIRect*      fClipRect;
34};
35
36void sk_fill_path(const SkPath& path, const SkIRect& clipRect,
37                  SkBlitter* blitter, int start_y, int stop_y, int shiftEdgesUp,
38                  bool pathContainedInClip);
39
40// blit the rects above and below avoid, clipped to clip
41void sk_blit_above(SkBlitter*, const SkIRect& avoid, const SkRegion& clip);
42void sk_blit_below(SkBlitter*, const SkIRect& avoid, const SkRegion& clip);
43
44template<class EdgeType>
45static inline void remove_edge(EdgeType* edge) {
46    edge->fPrev->fNext = edge->fNext;
47    edge->fNext->fPrev = edge->fPrev;
48}
49
50template<class EdgeType>
51static inline void insert_edge_after(EdgeType* edge, EdgeType* afterMe) {
52    edge->fPrev = afterMe;
53    edge->fNext = afterMe->fNext;
54    afterMe->fNext->fPrev = edge;
55    afterMe->fNext = edge;
56}
57
58template<class EdgeType>
59static void backward_insert_edge_based_on_x(EdgeType* edge) {
60    SkFixed x = edge->fX;
61    EdgeType* prev = edge->fPrev;
62    while (prev->fPrev && prev->fX > x) {
63        prev = prev->fPrev;
64    }
65    if (prev->fNext != edge) {
66        remove_edge(edge);
67        insert_edge_after(edge, prev);
68    }
69}
70
71// Start from the right side, searching backwards for the point to begin the new edge list
72// insertion, marching forwards from here. The implementation could have started from the left
73// of the prior insertion, and search to the right, or with some additional caching, binary
74// search the starting point. More work could be done to determine optimal new edge insertion.
75template<class EdgeType>
76static EdgeType* backward_insert_start(EdgeType* prev, SkFixed x) {
77    while (prev->fPrev && prev->fX > x) {
78        prev = prev->fPrev;
79    }
80    return prev;
81}
82
83// Check if the path is a rect and fat enough after clipping; if so, blit it.
84static inline bool TryBlitFatAntiRect(SkBlitter* blitter, const SkPath& path, const SkIRect& clip) {
85    SkRect rect;
86    if (!path.isRect(&rect)) {
87        return false; // not rect
88    }
89    if (!rect.intersect(SkRect::Make(clip))) {
90        return true; // The intersection is empty. Hence consider it done.
91    }
92    SkIRect bounds = rect.roundOut();
93    if (bounds.width() < 3 || bounds.height() < 3) {
94        return false; // not fat
95    }
96    blitter->blitFatAntiRect(rect);
97    return true;
98}
99
100#endif
101