blob: 6a08d7a8cff907e4220b3a49e04f96af37934e26 [file] [log] [blame]
// Copyright 2023 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cgen
import (
"fmt"
"strings"
)
func insertBasePixConvSubmoduleYcckC(buf *buffer) error {
src := embedBasePixConvSubmoduleYcckC.Trim()
prefix, suffix := "", ""
const insertPatchPixconv = "// ¡ INSERT patch_pixconv\n\n"
if i := strings.Index(src, insertPatchPixconv); i < 0 {
return fmt.Errorf("internal error: could not find %q", insertPatchPixconv)
} else {
prefix, suffix = src[:i], src[i+len(insertPatchPixconv):]
}
stripCFuncBangComments(buf, prefix)
// ----
const dstIterEtcSansX = "" +
"size_t dst_stride = dst->private_impl.planes[0].stride;\n" +
"uint8_t* dst_iter =\n" +
" dst->private_impl.planes[0].ptr + (dst_stride * ((size_t)y));\n"
const dstIterEtcWithX = "" +
"size_t dst_stride = dst->private_impl.planes[0].stride;\n" +
"uint8_t* dst_iter =\n" +
" dst->private_impl.planes[0].ptr + (dst_stride * ((size_t)y)) + (4 * ((size_t)x));\n"
const dstIterPlusEq4 = "" +
"dst_iter += 4;\n"
const setColorU32AtOld = "" +
"wuffs_base__pixel_buffer__set_color_u32_at(dst, x, y, color);\n"
const setColorU32AtNew = "" +
"wuffs_base__poke_u32le__no_bounds_check(dst_iter, color);\n"
// ----
patches := []struct {
funcNameLines []string
patchMap map[string]string
}{{
[]string{
"wuffs_base__pixel_swizzler__swizzle_ycc__bgrx__hv11(\n",
"wuffs_base__pixel_swizzler__swizzle_ycc__rgbx__hv11(\n",
},
map[string]string{},
}, {
[]string{
"wuffs_base__pixel_swizzler__swizzle_ycc__general__triangle_filter(\n",
"wuffs_base__pixel_swizzler__swizzle_ycc__bgrx__triangle_filter(\n",
"wuffs_base__pixel_swizzler__swizzle_ycc__rgbx__triangle_filter(\n",
},
map[string]string{
"// ¡ dst_iter = etc\n": dstIterEtcWithX,
"// ¡ dst_iter += 4\n": dstIterPlusEq4,
setColorU32AtOld: setColorU32AtNew,
},
}, {
[]string{
"wuffs_base__pixel_swizzler__swizzle_ycc__general__box_filter(\n",
"wuffs_base__pixel_swizzler__swizzle_ycc__bgrx__box_filter(\n",
"wuffs_base__pixel_swizzler__swizzle_ycc__rgbx__box_filter(\n",
},
map[string]string{
"// ¡ dst_iter = etc\n": dstIterEtcSansX,
"// ¡ dst_iter += 4\n": dstIterPlusEq4,
setColorU32AtOld: setColorU32AtNew,
},
}}
// ----
for _, p := range patches {
oldFuncNameLine := p.funcNameLines[0]
funcSrc, err := extractCFunc(src, "static void //\n"+oldFuncNameLine)
if err != nil {
return err
}
for _, newFuncNameLine := range p.funcNameLines[1:] {
if err := patchCFunc(buf, funcSrc, oldFuncNameLine, newFuncNameLine, p.patchMap); err != nil {
return err
}
}
}
stripCFuncBangComments(buf, suffix)
return nil
}
func extractCFunc(src string, start string) (string, error) {
if i := strings.Index(src, start); i < 0 {
goto fail
} else {
src = src[i:]
}
if i := strings.Index(src, "\n}\n"); i < 0 {
goto fail
} else {
return src[:i+3], nil
}
fail:
return "", fmt.Errorf("internal error: could not extractCFunc %q", start)
}
func stripCFuncBangComments(buf *buffer, s string) {
for {
const slashEtc = "// ¡"
i := strings.Index(s, slashEtc)
if i < 0 {
break
}
// Extend forwards past (including) the next '\n'.
j := i + len(slashEtc)
for ; (j < len(s)) && (s[j] != '\n'); j++ {
}
if j < len(s) {
j++
}
// Extend backwards up to (but excluding) the previous '\n'.
for ; (i > 0) && (s[i-1] != '\n'); i-- {
}
// Collapse multiple '\n's.
if (i >= 2) && (s[i-2] == '\n') {
for ; (j < len(s)) && (s[j] == '\n'); j++ {
}
}
buf.writes(s[:i])
s = s[j:]
}
buf.writes(s)
}
func patchCFunc(buf *buffer, src string, oldFuncNameLine string, newFuncNameLine string, patchMap map[string]string) error {
m := cloneStringStringMap(patchMap)
m[oldFuncNameLine] = newFuncNameLine
if strings.Contains(newFuncNameLine, "swizzle_ycc__rgbx__") {
m["wuffs_base__color_ycc__as__color_u32( //\n"] =
"wuffs_base__color_ycc__as__color_u32_abgr(\n"
}
buf.writes("// Generated by internal/cgen/patch_pixconv.go\n")
for src != "" {
line := ""
if i := strings.IndexByte(src, '\n'); i < 0 {
return fmt.Errorf("internal error: patchCFunc failed to find '\n'")
} else {
line, src = src[:i+1], src[i+1:]
}
key, indent := line, ""
for i := 0; ; i++ {
if i == len(line) {
key, indent = "", line
break
} else if line[i] != ' ' {
key, indent = line[i:], line[:i]
break
}
}
val, ok := m[key]
if !ok {
if !isCFuncComment(line) {
buf.writes(line)
}
continue
}
indentCFunc(buf, indent, val)
if !strings.Contains(key, "¡ BEGIN") {
continue
}
// Extend forwards past (including) the next '\n'.
j := strings.Index(src, "¡ END ")
if j < 0 {
return fmt.Errorf("internal error: patchCFunc failed to find \"¡ END\"")
}
for ; (j < len(src)) && (src[j] != '\n'); j++ {
}
if j < len(src) {
j++
}
src = src[j:]
}
buf.writes("\n")
return nil
}
func isCFuncComment(s string) bool {
for ; (len(s) > 0) && (s[0] <= ' '); s = s[1:] {
}
return (len(s) >= 2) && (s[0] == '/') && (s[1] == '/')
}
func indentCFunc(buf *buffer, indent string, s string) {
for s != "" {
line := ""
if i := strings.IndexByte(s, '\n'); i < 0 {
line, s = s, ""
} else {
line, s = s[:i+1], s[i+1:]
}
buf.writes(indent)
buf.writes(line)
}
}
func cloneStringStringMap(m map[string]string) map[string]string {
ret := map[string]string{}
for k, v := range m {
ret[k] = v
}
return ret
}