Skip to content

Commit

Permalink
[WIP] Refactor Java2d backend
Browse files Browse the repository at this point in the history
`frame.canvas()` now returns a `Resource[IO, Canvas]`, to manage the
resources a `Canvas` can control. Additionally, for the Java2d backend:

- Clear separation between Swing / Java threads and Cats Effect
components, makes reasoning easier
- Better concurrency control avoids deadlock
- Better resource management shutdowns cleanly when it should
- Miscellaneous simplifications

Still to be done:

- Remove debugging statements
- Simplify `Reified` representation
  • Loading branch information
Noel Welsh authored and Noel Welsh committed Sep 21, 2024
1 parent 9c79e8b commit c913596
Show file tree
Hide file tree
Showing 79 changed files with 717 additions and 325 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ jobs:

dependency-submission:
name: Submit Dependencies
if: github.event_name != 'pull_request'
if: github.event.repository.fork == false && github.event_name != 'pull_request'
strategy:
matrix:
os: [ubuntu-latest]
Expand Down
1 change: 1 addition & 0 deletions .scalafix.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ rules = [
]
OrganizeImports.removeUnused = false
OrganizeImports.coalesceToWildcardImportThreshold = 5
OrganizeImports.targetDialect = Scala3
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

- Fix monospaced font rendering on SVG (by `@kulsoom2003`)

- Complete reworking of Java2D backend to remove race conditions and manage resources correctly.


## 0.23.0 26-Jul-2024

Expand Down
5 changes: 3 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ ThisBuild / developers := List(
tlGitHubDev("noelwelsh", "Noel Welsh")
)

// true by default, set to false to publish to s01.oss.sonatype.org
ThisBuild / tlSonatypeUseLegacyHost := true
ThisBuild / sonatypeCredentialHost := xerial.sbt.Sonatype.sonatypeLegacy

lazy val scala3 = "3.3.3"

Expand Down Expand Up @@ -62,6 +61,8 @@ commands += Command.command("build") { state =>
lazy val css = taskKey[Unit]("Build the CSS")

lazy val commonSettings = Seq(
// This is needed when running examples
Compile / run / fork := true,
libraryDependencies ++= Seq(
Dependencies.munit.value,
Dependencies.munitScalaCheck.value
Expand Down
2 changes: 1 addition & 1 deletion canvas/src/main/scala/doodle/canvas/algebra/Path.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package doodle.canvas.algebra
import doodle.algebra.Algebra
import doodle.algebra.generic.*
import doodle.core.*
import doodle.core.{Transform as Tx}
import doodle.core.Transform as Tx

trait Path extends GenericPath[CanvasDrawing] {
self: Algebra { type Drawing[A] = Finalized[CanvasDrawing, A] } =>
Expand Down
2 changes: 1 addition & 1 deletion canvas/src/main/scala/doodle/canvas/algebra/Shape.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import doodle.algebra.Algebra
import doodle.algebra.generic.*
import doodle.core.ClosedPath
import doodle.core.Point
import doodle.core.{Transform as Tx}
import doodle.core.Transform as Tx

trait Shape extends GenericShape[CanvasDrawing] {
self: Algebra { type Drawing[A] = Finalized[CanvasDrawing, A] } =>
Expand Down
2 changes: 1 addition & 1 deletion canvas/src/main/scala/doodle/canvas/algebra/Text.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ package doodle.canvas.algebra
import doodle.algebra.Algebra
import doodle.algebra.generic.*
import doodle.core.BoundingBox
import doodle.core.Transform as Tx
import doodle.core.font.Font
import doodle.core.{Transform as Tx}
import org.scalajs.dom

trait Text extends GenericText[CanvasDrawing] {
Expand Down
5 changes: 3 additions & 2 deletions canvas/src/main/scala/doodle/canvas/effect/Canvas.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package doodle.canvas.effect

import cats.effect.IO
import cats.effect.Resource
import doodle.algebra.generic.Finalized
import doodle.canvas.Picture
import doodle.canvas.algebra.CanvasAlgebra
Expand Down Expand Up @@ -74,14 +75,14 @@ final case class Canvas(target: dom.Node, frame: Frame) {
}
}
object Canvas {
def fromFrame(frame: Frame): IO[Canvas] = {
def fromFrame(frame: Frame): Resource[IO, Canvas] = {
IO {
val target = dom.document.getElementById(frame.id)
if target == null then {
throw new java.util.NoSuchElementException(
s"Doodle Canvas could not be created, as could not find a DOM element with the requested id ${frame.id}"
)
} else Canvas(target, frame)
}
}.toResource
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
package doodle.canvas.effect

import cats.effect.IO
import cats.effect.Resource
import doodle.canvas.Algebra
import doodle.canvas.Picture
import doodle.effect.Renderer

object CanvasRenderer extends Renderer[Algebra, Frame, Canvas] {

def canvas(description: Frame): IO[Canvas] =
def canvas(description: Frame): Resource[IO, Canvas] =
Canvas.fromFrame(description)

def render[A](canvas: Canvas)(picture: Picture[A]): IO[A] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import cats.effect.IO
import cats.effect.unsafe.IORuntime
import doodle.algebra.Algebra
import doodle.algebra.Picture
import doodle.core.Base64 as B64
import doodle.core.format.Format
import doodle.core.{Base64 as B64}
import doodle.effect.Base64Writer
import doodle.effect.DefaultFrame

Expand Down
2 changes: 1 addition & 1 deletion core/shared/src/main/scala/doodle/algebra/Transform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ package doodle
package algebra

import doodle.core.Angle
import doodle.core.Transform as Tx
import doodle.core.Vec
import doodle.core.{Transform as Tx}

trait Transform extends Algebra {
def transform[A](img: Drawing[A], tx: Tx): Drawing[A]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import cats.Eval
import cats.Later
import cats.data.*
import doodle.core.BoundingBox
import doodle.core.{Transform as Tx}
import doodle.core.Transform as Tx

/** A [[Finalized]] represents an effect that, when run, produces all the
* information needed to layout an image (it "finalizes" all the information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ package generic

import cats.data.State
import doodle.core.*
import doodle.core.{Transform as Tx}
import doodle.core.Transform as Tx

import scala.annotation.tailrec

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ package generic

import cats.data.State
import doodle.core.BoundingBox
import doodle.core.{Transform as Tx}
import doodle.core.Transform as Tx

trait GenericShape[G[_]] extends Shape {
self: Algebra { type Drawing[A] = Finalized[G, A] } =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ package generic

import cats.data.State
import doodle.core.BoundingBox
import doodle.core.Transform as Tx
import doodle.core.font.Font
import doodle.core.{Transform as Tx}

trait GenericText[G[_]] extends Text {
self: Algebra { type Drawing[A] = Finalized[G, A] } =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package doodle
package algebra
package generic

import doodle.core.{Transform as Tx}
import doodle.core.Transform as Tx

trait GenericTransform[G[_]] extends Transform {
self: Algebra { type Drawing[A] = Finalized[G, A] } =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ package algebra
import cats.*
import cats.data.*
import cats.syntax.all.*
import doodle.core.{Transform as Tx}
import doodle.core.Transform as Tx

package object generic {
type ContextTransform = DrawingContext => DrawingContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ package effect
import cats.effect.IO
import doodle.algebra.Algebra
import doodle.algebra.Picture
import doodle.core.Base64 as B64
import doodle.core.format.Format
import doodle.core.{Base64 as B64}

/** The Base64Writer type represent the ability to encode an image as a Base64
* String in a given format.
Expand Down
3 changes: 2 additions & 1 deletion core/shared/src/main/scala/doodle/effect/Renderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package doodle
package effect

import cats.effect.IO
import cats.effect.Resource
import doodle.algebra.Algebra
import doodle.algebra.Picture

Expand All @@ -28,7 +29,7 @@ import doodle.algebra.Picture
trait Renderer[+Alg <: Algebra, Frame, Canvas] {

/** Construct a Canvas from a description. */
def canvas(description: Frame): IO[Canvas]
def canvas(description: Frame): Resource[IO, Canvas]

/** Render a picture to a Canvas. */
def render[A](canvas: Canvas)(picture: Picture[Alg, A]): IO[A]
Expand Down
2 changes: 1 addition & 1 deletion core/shared/src/main/scala/doodle/random.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import cats.Comonad
import cats.free.Free

import scala.annotation.tailrec
import scala.util.{Random as Rng}
import scala.util.Random as Rng

object random {
type Random[A] = Free[RandomOp, A]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package doodle
package syntax

import cats.effect.IO
import cats.effect.Resource
import cats.effect.unsafe.IORuntime
import doodle.algebra.Algebra
import doodle.algebra.Picture
Expand Down Expand Up @@ -79,15 +80,15 @@ trait AbstractRendererSyntax {
): IO[A] =
renderer
.canvas(frame.default)
.flatMap(canvas => drawWithCanvasToIO(canvas))
.use(canvas => drawWithCanvasToIO(canvas))

/** Create an effect that, when run, will draw the `Picture` using the given
* `Frame` options.
*/
def drawWithFrameToIO[Frame, Canvas](frame: Frame)(implicit
renderer: Renderer[Alg, Frame, Canvas]
): IO[A] =
renderer.canvas(frame).flatMap(canvas => drawWithCanvasToIO(canvas))
renderer.canvas(frame).use(canvas => drawWithCanvasToIO(canvas))

/** Create an effect that, when run, will draw the `Picture` on the given
* `Canvas`.
Expand All @@ -102,7 +103,7 @@ trait AbstractRendererSyntax {
implicit class RendererFrameOps[Frame](frame: Frame) {
def canvas[Alg <: Algebra, Canvas]()(implicit
renderer: Renderer[Alg, Frame, Canvas]
): IO[Canvas] =
): Resource[IO, Canvas] =
renderer.canvas(frame)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import doodle.algebra.Algebra
import doodle.algebra.Picture
import doodle.algebra.Transform
import doodle.core.Angle
import doodle.core.Transform as Tx
import doodle.core.Vec
import doodle.core.{Transform as Tx}

trait TransformSyntax {
implicit class TransformPictureOps[Alg <: Algebra, A](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import cats.instances.unit.*
import doodle.algebra.generic.*
import doodle.algebra.generic.reified.Reification
import doodle.algebra.generic.reified.Reified
import doodle.core.{Transform as Tx}
import doodle.core.Transform as Tx
import org.scalacheck.*

trait Generators extends doodle.core.Generators {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ package algebra
package generic

import cats.instances.unit.*
import org.scalacheck.Prop.*
import org.scalacheck.*
import org.scalacheck.Prop.*

object GenericAlgebraspec extends Properties("Generic algebra properties") {
implicit val algebra: TestAlgebra = TestAlgebra()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ package generic
import cats.implicits.*
import doodle.algebra.generic.reified.Reification
import doodle.core.BoundingBox
import doodle.core.{Transform as Tx}
import org.scalacheck.Prop.*
import doodle.core.Transform as Tx
import org.scalacheck.*
import org.scalacheck.Prop.*

object LayoutSpec extends Properties("Layout properties") {
val style = TestAlgebra()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ package generic

import cats.implicits.*
import doodle.algebra.generic.reified.Reification
import doodle.core.{Transform as Tx}
import org.scalacheck.Prop.*
import doodle.core.Transform as Tx
import org.scalacheck.*
import org.scalacheck.Prop.*

object SizeSpec extends Properties("Size properties") {
implicit val algebra: TestAlgebra = TestAlgebra()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ package doodle
package algebra
package generic

import org.scalacheck.Prop.*
import org.scalacheck.*
import org.scalacheck.Prop.*

object StyleSpec extends Properties("Style properties") {
val style = TestAlgebra()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ package doodle
package algebra
package generic

import org.scalacheck.Prop.*
import org.scalacheck.*
import org.scalacheck.Prop.*

object TextSpec extends Properties("Text properties") {
val algebra = TestAlgebra()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ package reified

import doodle.core.PathElement
import doodle.core.Point
import doodle.core.Transform as Tx
import doodle.core.font.Font
import doodle.core.{Transform as Tx}

sealed abstract class Reified extends Product with Serializable {
def transform: Tx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ package reified
import cats.data.WriterT
import doodle.algebra.generic.*
import doodle.core.*
import doodle.core.{Transform as Tx}
import doodle.core.Transform as Tx

trait ReifiedPath extends GenericPath[Reification] {
self: Algebra { type Drawing[A] = TestAlgebra.Drawing[A] } =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ package reified
import cats.data.WriterT
import doodle.algebra.generic.*
import doodle.core.Point
import doodle.core.{Transform as Tx}
import doodle.core.Transform as Tx

trait ReifiedShape extends GenericShape[Reification] {
self: Algebra { type Drawing[A] = TestAlgebra.Drawing[A] } =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ package reified
import cats.data.WriterT
import doodle.algebra.generic.*
import doodle.core.BoundingBox
import doodle.core.Transform as Tx
import doodle.core.font.Font
import doodle.core.{Transform as Tx}

trait ReifiedText extends GenericText[Reification] {
self: Algebra { type Drawing[A] = TestAlgebra.Drawing[A] } =>
Expand Down
2 changes: 1 addition & 1 deletion core/shared/src/test/scala/doodle/core/AngleSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
package doodle
package core

import org.scalacheck.Prop.*
import org.scalacheck.*
import org.scalacheck.Prop.*

object AngleSpec extends Properties("Angle properties") {
import doodle.arbitrary.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
package doodle
package core

import org.scalacheck.Prop.*
import org.scalacheck.*
import org.scalacheck.Prop.*

object ClosedPathSpec extends Properties("ClosedPath properties") {
import Generators.*
Expand Down
2 changes: 1 addition & 1 deletion core/shared/src/test/scala/doodle/core/ColorSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
package doodle
package core

import org.scalacheck.Prop.*
import org.scalacheck.*
import org.scalacheck.Prop.*

object ColorSpec extends Properties("Color properties") {
import doodle.arbitrary.*
Expand Down
Loading

0 comments on commit c913596

Please sign in to comment.