mirror of
https://github.com/penpot/penpot.git
synced 2025-05-31 23:01:37 +02:00
🎉 Add text stroke fills
This commit is contained in:
parent
b71b9edee7
commit
eddabc0d68
3 changed files with 54 additions and 15 deletions
|
@ -1,4 +1,4 @@
|
||||||
use skia_safe::{self as skia, Matrix, RRect, Rect};
|
use skia_safe::{self as skia, image, Matrix, RRect, Rect};
|
||||||
|
|
||||||
use crate::uuid::Uuid;
|
use crate::uuid::Uuid;
|
||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
@ -20,7 +20,7 @@ mod surfaces;
|
||||||
mod text;
|
mod text;
|
||||||
mod tiles;
|
mod tiles;
|
||||||
|
|
||||||
use crate::shapes::{modified_children_ids, Corners, Shape, StructureEntry, Type};
|
use crate::shapes::{modified_children_ids, Corners, Fill, Shape, StructureEntry, Type};
|
||||||
use gpu_state::GpuState;
|
use gpu_state::GpuState;
|
||||||
use options::RenderOptions;
|
use options::RenderOptions;
|
||||||
use surfaces::{SurfaceId, Surfaces};
|
use surfaces::{SurfaceId, Surfaces};
|
||||||
|
@ -362,7 +362,11 @@ impl RenderState {
|
||||||
text::render(self, &shape, ¶graphs, None, None);
|
text::render(self, &shape, ¶graphs, None, None);
|
||||||
|
|
||||||
for stroke in shape.strokes().rev() {
|
for stroke in shape.strokes().rev() {
|
||||||
let stroke_paints = shape.get_text_stroke_paint(&stroke);
|
let mut image: Option<image::Image> = None;
|
||||||
|
if let Fill::Image(image_fill) = &stroke.fill {
|
||||||
|
image = self.images.get(&image_fill.id()).cloned();
|
||||||
|
}
|
||||||
|
let stroke_paints = shape.get_text_stroke_paint(&stroke, image.as_ref());
|
||||||
let stroke_paragraphs = text_content
|
let stroke_paragraphs = text_content
|
||||||
.get_skia_stroke_paragraphs(&self.fonts.font_collection(), &stroke_paints);
|
.get_skia_stroke_paragraphs(&self.fonts.font_collection(), &stroke_paints);
|
||||||
shadows::render_text_drop_shadows(self, &shape, &stroke_paragraphs, antialias);
|
shadows::render_text_drop_shadows(self, &shape, &stroke_paragraphs, antialias);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use skia_safe::Image;
|
||||||
use skia_safe::{self as skia, paint::Paint};
|
use skia_safe::{self as skia, paint::Paint};
|
||||||
|
|
||||||
use crate::render::BlendMode;
|
use crate::render::BlendMode;
|
||||||
|
@ -812,7 +813,37 @@ impl Shape {
|
||||||
!self.fills.is_empty()
|
!self.fills.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_text_stroke_paint(&self, stroke: &Stroke) -> Vec<Paint> {
|
fn set_paint_fill(&self, paint: &mut Paint, fill: &Fill, image: Option<Image>) {
|
||||||
|
match fill {
|
||||||
|
Fill::Solid(SolidColor(color)) => {
|
||||||
|
paint.set_color(*color);
|
||||||
|
}
|
||||||
|
Fill::LinearGradient(gradient) => {
|
||||||
|
paint.set_shader(gradient.to_linear_shader(&self.selrect()));
|
||||||
|
}
|
||||||
|
Fill::RadialGradient(gradient) => {
|
||||||
|
paint.set_shader(gradient.to_radial_shader(&self.selrect()));
|
||||||
|
}
|
||||||
|
Fill::Image(image_fill) => {
|
||||||
|
if let Some(image) = image {
|
||||||
|
let position = (self.selrect().x(), self.selrect().y());
|
||||||
|
let sampling_options = skia::SamplingOptions::new(
|
||||||
|
skia::FilterMode::Linear,
|
||||||
|
skia::MipmapMode::Nearest,
|
||||||
|
);
|
||||||
|
let tile_modes = (skia::TileMode::Clamp, skia::TileMode::Clamp);
|
||||||
|
let mut matrix = skia::Matrix::default();
|
||||||
|
matrix.set_translate(position);
|
||||||
|
|
||||||
|
let shader = image.to_shader(tile_modes, sampling_options, &matrix);
|
||||||
|
paint.set_shader(shader);
|
||||||
|
paint.set_alpha(image_fill.opacity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_text_stroke_paint(&self, stroke: &Stroke, image: Option<&Image>) -> Vec<Paint> {
|
||||||
let mut paints = Vec::new();
|
let mut paints = Vec::new();
|
||||||
|
|
||||||
match stroke.kind {
|
match stroke.kind {
|
||||||
|
@ -827,9 +858,9 @@ impl Shape {
|
||||||
paint.set_blend_mode(skia::BlendMode::SrcATop);
|
paint.set_blend_mode(skia::BlendMode::SrcATop);
|
||||||
paint.set_anti_alias(true);
|
paint.set_anti_alias(true);
|
||||||
paint.set_stroke_width(stroke.width * 2.0);
|
paint.set_stroke_width(stroke.width * 2.0);
|
||||||
if let Fill::Solid(SolidColor(color)) = stroke.fill {
|
|
||||||
paint.set_color(color);
|
self.set_paint_fill(&mut paint, &stroke.fill, image.cloned());
|
||||||
}
|
|
||||||
paints.push(paint);
|
paints.push(paint);
|
||||||
}
|
}
|
||||||
StrokeKind::CenterStroke => {
|
StrokeKind::CenterStroke => {
|
||||||
|
@ -837,9 +868,9 @@ impl Shape {
|
||||||
paint.set_style(skia::PaintStyle::Stroke);
|
paint.set_style(skia::PaintStyle::Stroke);
|
||||||
paint.set_anti_alias(true);
|
paint.set_anti_alias(true);
|
||||||
paint.set_stroke_width(stroke.width);
|
paint.set_stroke_width(stroke.width);
|
||||||
if let Fill::Solid(SolidColor(color)) = stroke.fill {
|
|
||||||
paint.set_color(color);
|
self.set_paint_fill(&mut paint, &stroke.fill, image.cloned());
|
||||||
}
|
|
||||||
paints.push(paint);
|
paints.push(paint);
|
||||||
}
|
}
|
||||||
StrokeKind::OuterStroke => {
|
StrokeKind::OuterStroke => {
|
||||||
|
@ -848,9 +879,9 @@ impl Shape {
|
||||||
paint.set_blend_mode(skia::BlendMode::DstOver);
|
paint.set_blend_mode(skia::BlendMode::DstOver);
|
||||||
paint.set_anti_alias(true);
|
paint.set_anti_alias(true);
|
||||||
paint.set_stroke_width(stroke.width * 2.0);
|
paint.set_stroke_width(stroke.width * 2.0);
|
||||||
if let Fill::Solid(SolidColor(color)) = stroke.fill {
|
|
||||||
paint.set_color(color);
|
self.set_paint_fill(&mut paint, &stroke.fill, image.cloned());
|
||||||
}
|
|
||||||
paints.push(paint);
|
paints.push(paint);
|
||||||
|
|
||||||
let mut paint = skia::Paint::default();
|
let mut paint = skia::Paint::default();
|
||||||
|
|
|
@ -41,7 +41,7 @@ impl Gradient {
|
||||||
self.offsets.extend(offsets);
|
self.offsets.extend(offsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_linear_shader(&self, rect: &Rect) -> Option<skia::Shader> {
|
pub fn to_linear_shader(&self, rect: &Rect) -> Option<skia::Shader> {
|
||||||
let start = (
|
let start = (
|
||||||
rect.left + self.start.0 * rect.width(),
|
rect.left + self.start.0 * rect.width(),
|
||||||
rect.top + self.start.1 * rect.height(),
|
rect.top + self.start.1 * rect.height(),
|
||||||
|
@ -60,7 +60,7 @@ impl Gradient {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_radial_shader(&self, rect: &Rect) -> Option<skia::Shader> {
|
pub fn to_radial_shader(&self, rect: &Rect) -> Option<skia::Shader> {
|
||||||
let center = skia::Point::new(
|
let center = skia::Point::new(
|
||||||
rect.left + self.start.0 * rect.width(),
|
rect.left + self.start.0 * rect.width(),
|
||||||
rect.top + self.start.1 * rect.height(),
|
rect.top + self.start.1 * rect.height(),
|
||||||
|
@ -119,6 +119,10 @@ impl ImageFill {
|
||||||
pub fn id(&self) -> Uuid {
|
pub fn id(&self) -> Uuid {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn opacity(&self) -> u8 {
|
||||||
|
self.opacity
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue