blob: beb574f5d4a6c352bb49321cbf7df3a73303d9c0 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mock_spinel.h"
#include <float.h>
#include <limits.h>
#include "spinel/spinel_opcodes.h"
namespace mock_spinel {
///
/// Context
///
const Path *
Context::pathFor(spn_path_t handle)
{
if (handle.handle < paths_.size())
return &paths_[handle.handle];
else
return nullptr;
}
const Raster *
Context::rasterFor(spn_raster_t handle)
{
if (handle.handle < rasters_.size())
return &rasters_[handle.handle];
else
return nullptr;
}
spn_result_t
Context::reset()
{
paths_.clear();
rasters_.clear();
return SPN_SUCCESS;
}
spn_result_t
Context::status(spn_status_t const * status) const
{
return SPN_SUCCESS;
}
spn_result_t
Context::createPathBuilder(spn_path_builder_t * path_builder)
{
PathBuilder * builder = new PathBuilder(this);
*path_builder = builder->toSpinel();
return SPN_SUCCESS;
}
spn_result_t
Context::createRasterBuilder(spn_raster_builder_t * raster_builder)
{
RasterBuilder * builder = new RasterBuilder(this);
*raster_builder = builder->toSpinel();
return SPN_SUCCESS;
}
spn_result_t
Context::createComposition(spn_composition_t * composition)
{
Composition * comp = new Composition(this);
*composition = comp->toSpinel();
return SPN_SUCCESS;
}
spn_result_t
Context::cloneComposition(spn_composition_t composition, spn_composition_t * clone)
{
Composition * copy = Composition::fromSpinel(composition)->clone();
*clone = copy->toSpinel();
return SPN_SUCCESS;
}
spn_result_t
Context::createStyling(uint32_t layers_count, uint32_t cmds_count, spn_styling_t * styling)
{
Styling * styl = new Styling(this, layers_count, cmds_count);
*styling = styl->toSpinel();
return SPN_SUCCESS;
}
spn_result_t
Context::retainPaths(const spn_path_t * ids, uint32_t count)
{
return SPN_SUCCESS;
}
spn_result_t
Context::releasePaths(const spn_path_t * ids, uint32_t count)
{
return SPN_SUCCESS;
}
spn_result_t
Context::retainRasters(const spn_raster_t * ids, uint32_t count)
{
return SPN_SUCCESS;
}
spn_result_t
Context::releaseRasters(const spn_raster_t * ids, uint32_t count)
{
return SPN_SUCCESS;
}
spn_result_t
Context::render(const spn_render_submit_t *)
{
ASSERT_MSG(false, "Unimplemented");
return SPN_ERROR_CONTEXT_LOST;
}
// Called from the path and raster builders to add a new path or raster instance
// and return its Spinel handle.
spn_path_t
Context::installPath(Path && path)
{
uint32_t handle = static_cast<uint32_t>(paths_.size());
paths_.push_back(std::move(path));
return { handle };
}
spn_raster_t
Context::installRaster(Raster && raster)
{
uint32_t handle = static_cast<uint32_t>(rasters_.size());
rasters_.push_back(std::move(raster));
return { handle };
}
///
/// Path builder
///
spn_result_t
PathBuilder::flush()
{
return SPN_SUCCESS;
}
spn_result_t
PathBuilder::begin()
{
return reset();
}
spn_result_t
PathBuilder::end(spn_path_t * path)
{
*path = context_->installPath(std::move(path_));
return SPN_SUCCESS;
}
spn_result_t
PathBuilder::reset()
{
path_.data.clear();
return SPN_SUCCESS;
}
spn_result_t
PathBuilder::moveTo(float x, float y)
{
Path::MoveTo element = {
.x = x,
.y = y,
};
path_.add(element);
return SPN_SUCCESS;
}
spn_result_t
PathBuilder::lineTo(float x, float y)
{
Path::LineTo element = {
.x = x,
.y = y,
};
path_.add(element);
return SPN_SUCCESS;
}
spn_result_t
PathBuilder::quadTo(float cx, float cy, float x, float y)
{
Path::QuadTo element = {
.cx = cx,
.cy = cy,
.x = x,
.y = y,
};
path_.add(element);
return SPN_SUCCESS;
}
spn_result_t
PathBuilder::cubicTo(float c1x, float c1y, float c2x, float c2y, float x, float y)
{
Path::CubicTo element = {
.c1x = c1x,
.c1y = c1y,
.c2x = c2x,
.c2y = c2y,
.x = x,
.y = y,
};
path_.add(element);
return SPN_SUCCESS;
}
spn_result_t
PathBuilder::ratQuadTo(float cx, float cy, float x, float y, float w)
{
Path::RatQuadTo element = {
.cx = cx,
.cy = cy,
.x = x,
.y = y,
.w = w,
};
path_.add(element);
return SPN_SUCCESS;
}
spn_result_t
PathBuilder::ratCubicTo(
float c1x, float c1y, float c2x, float c2y, float x, float y, float w1, float w2)
{
Path::RatCubicTo element = {
.c1x = c1x,
.c1y = c1y,
.c2x = c2x,
.c2y = c2y,
.x = x,
.y = y,
.w1 = w1,
.w2 = w2,
};
path_.add(element);
return SPN_SUCCESS;
}
///
/// Raster builder
///
spn_result_t
RasterBuilder::flush()
{
return SPN_SUCCESS;
}
spn_result_t
RasterBuilder::begin()
{
raster_.clear();
return SPN_SUCCESS;
}
spn_result_t
RasterBuilder::end(spn_raster_t * raster)
{
*raster = context_->installRaster(std::move(raster_));
raster_.clear();
return SPN_SUCCESS;
}
spn_result_t
RasterBuilder::add(spn_path_t const * paths,
spn_transform_weakref_t * transform_weakrefs,
spn_transform_t const * transforms,
spn_clip_weakref_t * clip_weakrefs,
spn_clip_t const * clips,
uint32_t count)
{
for (uint32_t nn = 0; nn < count; ++nn)
{
RasterPath rpath = {
.path_id = paths[nn].handle,
.transform = { 1., 0., 0., 0., 1., 0., 0., 0. }, // identity
.clip = { 0., 0., FLT_MAX, FLT_MAX },
};
if (transforms)
rpath.transform = transforms[nn];
if (clips)
rpath.clip = clips[nn];
raster_.push_back(std::move(rpath));
}
return SPN_SUCCESS;
}
///
/// Composition
///
Composition *
Composition::clone()
{
Composition * result = new Composition(context_);
result->prints_.assign(prints_.begin(), prints_.end());
return result;
}
spn_result_t
Composition::place(spn_raster_t const * rasters,
spn_layer_id const * layer_ids,
spn_txty_t const * txtys,
uint32_t count)
{
for (uint32_t nn = 0; nn < count; ++nn)
{
RasterPrint print = {
.raster_id = rasters[nn].handle,
.layer_id = layer_ids[nn],
.translation = { 0, 0 },
};
if (txtys)
print.translation = txtys[nn];
prints_.push_back(std::move(print));
}
return SPN_SUCCESS;
}
spn_result_t
Composition::seal()
{
return SPN_SUCCESS;
}
Composition::LayerMap
Composition::computeLayerMap() const
{
Composition::LayerMap result;
for (const RasterPrint & print : prints_)
result[print.layer_id].push_back(&print);
return result;
}
spn_result_t
Composition::unseal()
{
return SPN_SUCCESS;
}
spn_result_t
Composition::reset()
{
prints_.clear();
return SPN_SUCCESS;
}
spn_result_t
Composition::getBounds(uint32_t bounds[4]) const
{
ASSERT_MSG(false, "Unimplemented");
return SPN_ERROR_CONTEXT_LOST;
}
spn_result_t
Composition::setClip(const uint32_t clip[4])
{
// Ignored for now.
return SPN_SUCCESS;
}
///
/// Styling
///
spn_result_t
Styling::seal()
{
return SPN_SUCCESS;
}
spn_result_t
Styling::unseal()
{
return SPN_SUCCESS;
}
spn_result_t
Styling::reset()
{
groups_.clear();
return SPN_SUCCESS;
}
spn_result_t
Styling::groupAllocId(spn_group_id * group_id)
{
*group_id = groups_.size();
groups_.push_back(StylingGroup());
return SPN_SUCCESS;
}
spn_result_t
Styling::groupAllocEnterCommands(spn_group_id group_id, uint32_t count, spn_styling_cmd_t ** cmds)
{
ASSERT_MSG(group_id < groups_.size(), "Invalid group id");
StylingCommands & commands = groups_[group_id].begin_commands;
commands.resize(count);
if (cmds)
{
*cmds = count ? commands.data() : nullptr;
}
return SPN_SUCCESS;
}
spn_result_t
Styling::groupAllocLeaveCommands(spn_group_id group_id, uint32_t count, spn_styling_cmd_t ** cmds)
{
ASSERT_MSG(group_id < groups_.size(), "Invalid group id");
StylingCommands & commands = groups_[group_id].end_commands;
commands.resize(count);
if (cmds)
{
*cmds = count ? commands.data() : nullptr;
}
return SPN_SUCCESS;
}
spn_result_t
Styling::groupAllocLayerCommands(spn_group_id group_id,
spn_layer_id layer_id,
uint32_t count,
spn_styling_cmd_t ** cmds)
{
ASSERT(group_id < groups_.size());
StylingCommands & commands = groups_[group_id].layer_commands[layer_id];
commands.resize(count);
if (cmds)
{
*cmds = count ? commands.data() : nullptr;
}
return SPN_SUCCESS;
}
spn_result_t
Styling::groupAllocParents(spn_group_id group_id, uint32_t count, spn_group_id ** parents)
{
// We don't deal with parents for now because our demos don't use them.
ASSERT_MSG(count == 0, "TODO: Implement styling group parents");
return SPN_SUCCESS;
}
spn_result_t
Styling::groupSetRangeLo(spn_group_id group_id, spn_layer_id layer_lo)
{
ASSERT(group_id < groups_.size());
groups_[group_id].layer_lo = layer_lo;
return SPN_SUCCESS;
}
spn_result_t
Styling::groupSetRangeHi(spn_group_id group_id, spn_layer_id layer_hi)
{
ASSERT(group_id < groups_.size());
groups_[group_id].layer_hi = layer_hi;
return SPN_SUCCESS;
}
//
// Spinel
//
void
Spinel::rgbaToCmds(const float rgba[4], spn_styling_cmd_t cmds[2])
{
uint8_t r8 = (uint8_t)(255 * rgba[0]);
uint8_t g8 = (uint8_t)(255 * rgba[1]);
uint8_t b8 = (uint8_t)(255 * rgba[2]);
uint8_t a8 = (uint8_t)(255 * rgba[3]);
cmds[0] = ((uint32_t)r8 << 24) | ((uint32_t)g8 << 16) | ((uint32_t)b8 << 8) | a8;
cmds[1] = 0;
}
void
Spinel::cmdsToRgba(const spn_styling_cmd_t cmds[2], float rgba[4])
{
uint8_t r8 = (uint8_t)(cmds[0] >> 24);
uint8_t g8 = (uint8_t)(cmds[0] >> 16);
uint8_t b8 = (uint8_t)(cmds[0] >> 8);
uint8_t a8 = (uint8_t)(cmds[0] >> 0);
rgba[0] = r8 / 255.;
rgba[1] = g8 / 255.;
rgba[2] = b8 / 255.;
rgba[3] = a8 / 255.;
}
void
spn_styling_layer_fill_rgba_encoder(spn_styling_cmd_t * cmds, float const rgba[4])
{
cmds[0] = SPN_STYLING_OPCODE_COLOR_FILL_SOLID;
Spinel::rgbaToCmds(rgba, cmds + 1);
}
void
Spinel::encodeCommandFillRgba(spn_styling_cmd_t * cmds, const float rgba[4])
{
cmds[0] = SPN_STYLING_OPCODE_COLOR_FILL_SOLID;
Spinel::rgbaToCmds(rgba, cmds + 1);
}
void
Spinel::encodeCommandBackgroundOver(spn_styling_cmd_t * cmds, float const rgba[4])
{
cmds[0] = SPN_STYLING_OPCODE_COLOR_ACC_OVER_BACKGROUND;
Spinel::rgbaToCmds(rgba, cmds + 1);
}
spn_result_t
Spinel::createContext(spn_context_t * context)
{
Context * c = new Context();
*context = c->toSpinel();
return SPN_SUCCESS;
}
} // namespace mock_spinel