blob: 15372de07652fa8b55d29d188e7d6a3fce63f6cb [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can
* be found in the LICENSE file.
*
*/
//
//
//
#include "path_builder.h"
#include "context.h"
//
//
//
skc_err
skc_path_builder_retain(skc_path_builder_t path_builder)
{
++path_builder->refcount;
return SKC_ERR_SUCCESS;
}
skc_err
skc_path_builder_release(skc_path_builder_t path_builder)
{
SKC_ASSERT_STATE_ASSERT(SKC_PATH_BUILDER_STATE_READY,path_builder);
path_builder->release(path_builder->impl);
return SKC_ERR_SUCCESS;
}
//
// PATH BODY
//
skc_err
skc_path_begin(skc_path_builder_t path_builder)
{
SKC_ASSERT_STATE_TRANSITION(SKC_PATH_BUILDER_STATE_READY,
SKC_PATH_BUILDER_STATE_BUILDING,
path_builder);
// init path builder counters
path_builder->line .rem = 0;
path_builder->quad .rem = 0;
path_builder->cubic.rem = 0;
// begin the path
path_builder->begin(path_builder->impl);
return SKC_ERR_SUCCESS;
}
skc_err
skc_path_end(skc_path_builder_t path_builder, skc_path_t * path)
{
SKC_ASSERT_STATE_TRANSITION(SKC_PATH_BUILDER_STATE_BUILDING,
SKC_PATH_BUILDER_STATE_READY,
path_builder);
// update path header with proper counts
path_builder->end(path_builder->impl,path);
return SKC_ERR_SUCCESS;
}
//
// PATH SEGMENT OPS
//
static
void
skc_path_move_to_1(skc_path_builder_t path_builder,
float x0, float y0)
{
path_builder->curr[0].x = x0;
path_builder->curr[0].y = y0;
path_builder->curr[1].x = x0;
path_builder->curr[1].y = y0;
}
static
void
skc_path_move_to_2(skc_path_builder_t path_builder,
float x0, float y0,
float x1, float y1)
{
path_builder->curr[0].x = x0;
path_builder->curr[0].y = y0;
path_builder->curr[1].x = x1;
path_builder->curr[1].y = y1;
}
skc_err
skc_path_move_to(skc_path_builder_t path_builder,
float x0, float y0)
{
skc_path_move_to_1(path_builder,x0,y0);
return SKC_ERR_SUCCESS;
}
skc_err
skc_path_close(skc_path_builder_t path_builder)
{
//
// FIXME -- CLARIFY WHY SUBTLE AUTO-CLOSE BEHAVIORS _DON'T BELONG_
// IN THE SKIA COMPUTE LAYER
//
// OR, BETTER YET, GET RID OF THIS FUNC ENTIRELY
//
return SKC_ERR_NOT_IMPLEMENTED;
}
skc_err
skc_path_line_to(skc_path_builder_t path_builder,
float x1, float y1)
{
if (path_builder->line.rem == 0) {
path_builder->new_line(path_builder->impl);
}
--path_builder->line.rem;
*path_builder->line.coords[0]++ = path_builder->curr[0].x;
*path_builder->line.coords[1]++ = path_builder->curr[0].y;
*path_builder->line.coords[2]++ = x1;
*path_builder->line.coords[3]++ = y1;
skc_path_move_to_1(path_builder,x1,y1);
return SKC_ERR_SUCCESS;
}
skc_err
skc_path_quad_to(skc_path_builder_t path_builder,
float x1, float y1,
float x2, float y2)
{
if (path_builder->quad.rem == 0) {
path_builder->new_quad(path_builder->impl);
}
--path_builder->quad.rem;
*path_builder->quad.coords[0]++ = path_builder->curr[0].x;
*path_builder->quad.coords[1]++ = path_builder->curr[0].y;
*path_builder->quad.coords[2]++ = x1;
*path_builder->quad.coords[3]++ = y1;
*path_builder->quad.coords[4]++ = x2;
*path_builder->quad.coords[5]++ = y2;
skc_path_move_to_2(path_builder,x2,y2,x1,y1);
return SKC_ERR_SUCCESS;
}
skc_err
skc_path_quad_smooth_to(skc_path_builder_t path_builder,
float x2, float y2)
{
float const x1 = path_builder->curr[0].x * 2.0f - path_builder->curr[1].x;
float const y1 = path_builder->curr[0].y * 2.0f - path_builder->curr[1].y;
return skc_path_quad_to(path_builder,x1,y1,x2,y2);
}
skc_err
skc_path_cubic_to(skc_path_builder_t path_builder,
float x1, float y1,
float x2, float y2,
float x3, float y3)
{
if (path_builder->cubic.rem == 0) {
path_builder->new_cubic(path_builder->impl);
}
--path_builder->cubic.rem;
*path_builder->cubic.coords[0]++ = path_builder->curr[0].x;
*path_builder->cubic.coords[1]++ = path_builder->curr[0].y;
*path_builder->cubic.coords[2]++ = x1;
*path_builder->cubic.coords[3]++ = y1;
*path_builder->cubic.coords[4]++ = x2;
*path_builder->cubic.coords[5]++ = y2;
*path_builder->cubic.coords[6]++ = x3;
*path_builder->cubic.coords[7]++ = y3;
skc_path_move_to_2(path_builder,x3,y3,x2,y2);
return SKC_ERR_SUCCESS;
}
skc_err
skc_path_cubic_smooth_to(skc_path_builder_t path_builder,
float x2, float y2,
float x3, float y3)
{
float const x1 = path_builder->curr[0].x * 2.0f - path_builder->curr[1].x;
float const y1 = path_builder->curr[0].y * 2.0f - path_builder->curr[1].y;
return skc_path_cubic_to(path_builder,x1,y1,x2,y2,x3,y3);
}
//
// FIXME -- add rational quad and cubic support and move primitives
// like ellipse into an adapter. They do *not* belong in the core API.
//
skc_err
skc_path_ellipse(skc_path_builder_t path_builder,
float cx, float cy,
float rx, float ry)
{
//
// FIXME -- we can implement this with rationals later...
//
//
// Approximate a circle with 4 cubics:
//
// http://en.wikipedia.org/wiki/B%C3%A9zier_spline#Approximating_circular_arcs
//
skc_path_move_to_1(path_builder, cx, cy + ry);
#define KAPPA_FLOAT 0.55228474983079339840f // moar digits!
float const kx = rx * KAPPA_FLOAT;
float const ky = ry * KAPPA_FLOAT;
skc_err err;
err = skc_path_cubic_to(path_builder,
cx + kx, cy + ry,
cx + rx, cy + ky,
cx + rx, cy);
if (err)
return err;
err = skc_path_cubic_to(path_builder,
cx + rx, cy - ky,
cx + kx, cy - ry,
cx, cy - ry);
if (err)
return err;
err = skc_path_cubic_to(path_builder,
cx - kx, cy - ry,
cx - rx, cy - ky,
cx - rx, cy);
if (err)
return err;
err = skc_path_cubic_to(path_builder,
cx - rx, cy + ky,
cx - kx, cy + ry,
cx, cy + ry);
return err;
}
//
//
//