line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
###################################################################################################
|
2
|
|
|
|
|
|
|
# Copyright 2013/2014 by Marcel Greter
|
3
|
|
|
|
|
|
|
# This file is part of OCBNET-WebSprite (GPL3)
|
4
|
|
|
|
|
|
|
####################################################################################################
|
5
|
|
|
|
|
|
|
package OCBNET::WebSprite;
|
6
|
|
|
|
|
|
|
####################################################################################################
|
7
|
|
|
|
|
|
|
our $VERSION = '1.0.2';
|
8
|
|
|
|
|
|
|
####################################################################################################
|
9
|
|
|
|
|
|
|
|
10
|
4
|
|
|
4
|
|
40711
|
use Carp;
|
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
327
|
|
11
|
4
|
|
|
4
|
|
20
|
use strict;
|
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
121
|
|
12
|
4
|
|
|
4
|
|
19
|
use warnings;
|
|
4
|
|
|
|
|
11
|
|
|
4
|
|
|
|
|
118
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
####################################################################################################
|
15
|
|
|
|
|
|
|
|
16
|
4
|
|
|
4
|
|
2757
|
use OCBNET::CSS3;
|
|
4
|
|
|
|
|
177488
|
|
|
4
|
|
|
|
|
119
|
|
17
|
4
|
|
|
4
|
|
1209
|
use OCBNET::Image;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
use OCBNET::WebSprite::Fit;
|
20
|
|
|
|
|
|
|
use OCBNET::WebSprite::Edge;
|
21
|
|
|
|
|
|
|
use OCBNET::WebSprite::Corner;
|
22
|
|
|
|
|
|
|
use OCBNET::WebSprite::Canvas;
|
23
|
|
|
|
|
|
|
use OCBNET::WebSprite::Sprite;
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
use OCBNET::CSS3::Styles::Margin;
|
26
|
|
|
|
|
|
|
use OCBNET::CSS3::Styles::Padding;
|
27
|
|
|
|
|
|
|
use OCBNET::CSS3::Styles::Background;
|
28
|
|
|
|
|
|
|
use OCBNET::CSS3::Styles::References;
|
29
|
|
|
|
|
|
|
use OCBNET::CSS3::DOM::Comment::Options;
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
use OCBNET::CSS3::Regex::Base qw(unwrapUrl wrapUrl);
|
32
|
|
|
|
|
|
|
use OCBNET::CSS3::Regex::Numbers qw(fromPx toPx);
|
33
|
|
|
|
|
|
|
use OCBNET::CSS3::Regex::Background qw(fromPosition);
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# load function from core module
|
36
|
|
|
|
|
|
|
use List::MoreUtils qw(uniq);
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
####################################################################################################
|
39
|
|
|
|
|
|
|
# Constructor - not much going on
|
40
|
|
|
|
|
|
|
####################################################################################################
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub new
|
43
|
|
|
|
|
|
|
{
|
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# get arguments
|
46
|
|
|
|
|
|
|
my ($pkg) = @_;
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# create object
|
49
|
|
|
|
|
|
|
my $obj = {
|
50
|
|
|
|
|
|
|
# init array
|
51
|
|
|
|
|
|
|
'sprites' => [],
|
52
|
|
|
|
|
|
|
# init hash
|
53
|
|
|
|
|
|
|
'spritesets' => {}
|
54
|
|
|
|
|
|
|
};
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# bless into package
|
57
|
|
|
|
|
|
|
bless $obj, $pkg;
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
}
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
####################################################################################################
|
62
|
|
|
|
|
|
|
# helper to accept various input sources
|
63
|
|
|
|
|
|
|
# will finally return a css stylesheet object
|
64
|
|
|
|
|
|
|
####################################################################################################
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
my $parseCSS = sub
|
67
|
|
|
|
|
|
|
{
|
68
|
|
|
|
|
|
|
# check first if the data is already in desired format
|
69
|
|
|
|
|
|
|
return $_[0] if UNIVERSAL::isa($_[0], "OCBNET::CSS3::Stylesheet");
|
70
|
|
|
|
|
|
|
# data was probably a string containing css
|
71
|
|
|
|
|
|
|
return OCBNET::CSS3::Stylesheet->new->parse($_[0]) unless ref $_[0];
|
72
|
|
|
|
|
|
|
# data was probably a string reference containing css
|
73
|
|
|
|
|
|
|
return OCBNET::CSS3::Stylesheet->new->parse(${$_[0]}) if ref $_[0] eq "SCALAR";
|
74
|
|
|
|
|
|
|
# otherwise we got some invalid data type
|
75
|
|
|
|
|
|
|
Carp::confess "invalid input data";
|
76
|
|
|
|
|
|
|
};
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
####################################################################################################
|
79
|
|
|
|
|
|
|
# method to find exactly equal sprite
|
80
|
|
|
|
|
|
|
####################################################################################################
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub findSprite
|
83
|
|
|
|
|
|
|
{
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# get arguments
|
86
|
|
|
|
|
|
|
my ($self, $config) = @_;
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# disable specific warning
|
89
|
|
|
|
|
|
|
no warnings 'uninitialized';
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# try all known sprites to find equivalent
|
92
|
|
|
|
|
|
|
foreach my $sprite (@{$self->{'sprites'}})
|
93
|
|
|
|
|
|
|
{
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# skip if any of the attributes differ
|
96
|
|
|
|
|
|
|
next if $sprite->{'filename'} ne $config->{'filename'};
|
97
|
|
|
|
|
|
|
next if $sprite->{'size-x'} ne $config->{'size-x'};
|
98
|
|
|
|
|
|
|
next if $sprite->{'size-y'} ne $config->{'size-y'};
|
99
|
|
|
|
|
|
|
next if $sprite->{'repeat-x'} ne $config->{'repeat-x'};
|
100
|
|
|
|
|
|
|
next if $sprite->{'repeat-y'} ne $config->{'repeat-y'};
|
101
|
|
|
|
|
|
|
next if $sprite->{'enclosed-x'} ne $config->{'enclosed-x'};
|
102
|
|
|
|
|
|
|
next if $sprite->{'enclosed-y'} ne $config->{'enclosed-y'};
|
103
|
|
|
|
|
|
|
next if $sprite->{'position-x'} ne $config->{'position-x'};
|
104
|
|
|
|
|
|
|
next if $sprite->{'position-y'} ne $config->{'position-y'};
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# found a sprite
|
107
|
|
|
|
|
|
|
return $sprite;
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
}
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# nothing found
|
112
|
|
|
|
|
|
|
return undef;
|
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
}
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
####################################################################################################
|
117
|
|
|
|
|
|
|
# method is responsible to write spritesets to the disk
|
118
|
|
|
|
|
|
|
# overload this method if you want to implement it different
|
119
|
|
|
|
|
|
|
####################################################################################################
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub writer
|
122
|
|
|
|
|
|
|
{
|
123
|
|
|
|
|
|
|
# get input arguments
|
124
|
|
|
|
|
|
|
my ($self, $path, $data, $opt) = @_;
|
125
|
|
|
|
|
|
|
# load module optionally
|
126
|
|
|
|
|
|
|
require File::Slurp;
|
127
|
|
|
|
|
|
|
# store path to opt if it is an array
|
128
|
|
|
|
|
|
|
push @{$opt}, $path if ref $opt eq "ARRAY";
|
129
|
|
|
|
|
|
|
# write the image to the disk (passed data is a scalar ref)
|
130
|
|
|
|
|
|
|
File::Slurp::write_file $path, { binmode => ':raw' }, $data;
|
131
|
|
|
|
|
|
|
}
|
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
####################################################################################################
|
134
|
|
|
|
|
|
|
# method is responsible to read images from the disk
|
135
|
|
|
|
|
|
|
# overload this method if you want to implement it different
|
136
|
|
|
|
|
|
|
####################################################################################################
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub reader
|
139
|
|
|
|
|
|
|
{
|
140
|
|
|
|
|
|
|
# get input arguments
|
141
|
|
|
|
|
|
|
my ($self, $path) = @_;
|
142
|
|
|
|
|
|
|
# load module optionally
|
143
|
|
|
|
|
|
|
require File::Slurp;
|
144
|
|
|
|
|
|
|
# read the file from the disk
|
145
|
|
|
|
|
|
|
File::Slurp::read_file($path, { binmode => ':raw' });
|
146
|
|
|
|
|
|
|
}
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
####################################################################################################
|
149
|
|
|
|
|
|
|
# main method to create spritesets
|
150
|
|
|
|
|
|
|
####################################################################################################
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub create
|
153
|
|
|
|
|
|
|
{
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# get input arguments
|
156
|
|
|
|
|
|
|
my ($self, $data, $opt) = @_;
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# convert data to stylesheet
|
159
|
|
|
|
|
|
|
my $css = &{$parseCSS}($data);
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# put all blocks in a flat array
|
162
|
|
|
|
|
|
|
my @blocks = ($css, $css->blocks);
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# this will process all and each sub block
|
165
|
|
|
|
|
|
|
for (my $i = 0; $i < scalar(@blocks); $i ++)
|
166
|
|
|
|
|
|
|
{ push @blocks, $blocks[$i]->blocks; }
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# remove possible duplicates
|
169
|
|
|
|
|
|
|
@blocks = uniq @blocks;
|
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# process to setup canvas
|
172
|
|
|
|
|
|
|
foreach my $block (@blocks)
|
173
|
|
|
|
|
|
|
{
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# check if this comment is meant for us
|
176
|
|
|
|
|
|
|
next unless $block->option('sprite-image');
|
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# get parsed options collection
|
179
|
|
|
|
|
|
|
my $options = $block->options;
|
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# check if this comment is meant for us
|
182
|
|
|
|
|
|
|
next unless $options->get('sprite-image');
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# check if the sprite image has an associated id
|
185
|
|
|
|
|
|
|
die "sprite image has no id" unless $options->get('css-id');
|
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# get the id of this spriteset
|
188
|
|
|
|
|
|
|
my $id = $block->option('css-id');
|
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# pass debug mode from config to options
|
191
|
|
|
|
|
|
|
$options->{'debug'} = $self->{'config'}->{'debug'};
|
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# create a new canvas object to hold all sprites
|
194
|
|
|
|
|
|
|
my $canvas = OCBNET::WebSprite::Canvas->new(undef, $options);
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# add canvas to global hash object
|
197
|
|
|
|
|
|
|
$self->{'spritesets'}->{$id} = $canvas;
|
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# associate canvas with block
|
200
|
|
|
|
|
|
|
$block->{'canvas'} = $canvas;
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# store the id for canvas
|
203
|
|
|
|
|
|
|
$canvas->{'id'} = $id;
|
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
}
|
206
|
|
|
|
|
|
|
# EO each block
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# filter out all unqiue selectors from each css blocks
|
209
|
|
|
|
|
|
|
my @selectors = grep { $_->type eq 'selector' } @blocks;
|
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# now process each selector and setup references
|
212
|
|
|
|
|
|
|
foreach my $selector (@selectors)
|
213
|
|
|
|
|
|
|
{
|
214
|
|
|
|
|
|
|
# find the block where the sprite-image is declared
|
215
|
|
|
|
|
|
|
# if there is no such block, the selector is not a sprite
|
216
|
|
|
|
|
|
|
my $block = $selector->find('option', 'sprite-image') || next;
|
217
|
|
|
|
|
|
|
# check if selector is not a canvas itself and sprite has css-id
|
218
|
|
|
|
|
|
|
if (! $selector->{'canvas'} && (my $id = $block->option('css-id')))
|
219
|
|
|
|
|
|
|
{
|
220
|
|
|
|
|
|
|
# connect the references spriteset to this selector
|
221
|
|
|
|
|
|
|
$selector->{'canvas'} = $self->{'spritesets'}->{$id};
|
222
|
|
|
|
|
|
|
}
|
223
|
|
|
|
|
|
|
}
|
224
|
|
|
|
|
|
|
# EO each selector
|
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# now process each selector and setup sprites
|
227
|
|
|
|
|
|
|
foreach my $selector (@selectors)
|
228
|
|
|
|
|
|
|
{
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# check if this selector block has a background
|
231
|
|
|
|
|
|
|
next unless $selector->style('background-image');
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# get associated spriteset canvas
|
234
|
|
|
|
|
|
|
my $canvas = $selector->{'canvas'} || next;
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# fill sprite config
|
237
|
|
|
|
|
|
|
my $config = {
|
238
|
|
|
|
|
|
|
# connect spriteset
|
239
|
|
|
|
|
|
|
# needed for reader
|
240
|
|
|
|
|
|
|
'spriteset' => $self,
|
241
|
|
|
|
|
|
|
# pass debug mode from config
|
242
|
|
|
|
|
|
|
# will draw funky color backgrounds
|
243
|
|
|
|
|
|
|
'debug' => $self->{'config'}->{'debug'},
|
244
|
|
|
|
|
|
|
# get the filename from the url (must be "normalized")
|
245
|
|
|
|
|
|
|
'filename' => unwrapUrl($selector->style('background-image')),
|
246
|
|
|
|
|
|
|
# the size the sprite is actually shown in (from css styles)
|
247
|
|
|
|
|
|
|
'size-x' => fromPx($selector->style('background-size-x')) || undef,
|
248
|
|
|
|
|
|
|
'size-y' => fromPx($selector->style('background-size-y')) || undef,
|
249
|
|
|
|
|
|
|
# set repeat options to decide where to ditribute
|
250
|
|
|
|
|
|
|
'repeat-x' => $selector->style('background-repeat-x') || 0,
|
251
|
|
|
|
|
|
|
'repeat-y' => $selector->style('background-repeat-y') || 0,
|
252
|
|
|
|
|
|
|
# set enclosed options to decide where to ditribute
|
253
|
|
|
|
|
|
|
'enclosed-x' => fromPx($selector->style('width') || 0) || 0,
|
254
|
|
|
|
|
|
|
'enclosed-y' => fromPx($selector->style('height') || 0) || 0,
|
255
|
|
|
|
|
|
|
# set position/align options to decide where to ditribute
|
256
|
|
|
|
|
|
|
'position-x' => fromPosition($selector->style('background-position-x') || 0),
|
257
|
|
|
|
|
|
|
'position-y' => fromPosition($selector->style('background-position-y') || 0)
|
258
|
|
|
|
|
|
|
};
|
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# try to find already loaded sprite
|
261
|
|
|
|
|
|
|
my $sprite = $self->findSprite($config);
|
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# or create a new sprite and setup most options
|
264
|
|
|
|
|
|
|
$sprite = OCBNET::WebSprite::Sprite->new($config) unless $sprite;
|
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# add sprite to collection
|
267
|
|
|
|
|
|
|
push @{$self->{'sprites'}}, $sprite;
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# store sprite object on selector
|
270
|
|
|
|
|
|
|
$selector->{'sprite'} = $sprite;
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# and also store the selector on the sprite
|
273
|
|
|
|
|
|
|
$sprite->{'selector'} = $selector;
|
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# add sprite to canvas
|
276
|
|
|
|
|
|
|
$canvas->add($sprite);
|
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
}
|
279
|
|
|
|
|
|
|
# EO each selector
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# do the work on every spriteset
|
282
|
|
|
|
|
|
|
$_->optimize foreach $self->spritesets;
|
283
|
|
|
|
|
|
|
$_->distribute foreach $self->spritesets;
|
284
|
|
|
|
|
|
|
$_->finalize foreach $self->spritesets;
|
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# call write with our file writer
|
287
|
|
|
|
|
|
|
my $written = $self->write($opt);
|
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# now process each selector and setup sprites
|
290
|
|
|
|
|
|
|
foreach my $selector (@selectors)
|
291
|
|
|
|
|
|
|
{
|
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# new styles
|
294
|
|
|
|
|
|
|
my %styles;
|
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# selector has a canvas, this means the spriteset
|
297
|
|
|
|
|
|
|
# has been declares within this block, so render it
|
298
|
|
|
|
|
|
|
# check this directly and not with the object method
|
299
|
|
|
|
|
|
|
# this way we will really only check the local block
|
300
|
|
|
|
|
|
|
if ($selector->{'canvas'})
|
301
|
|
|
|
|
|
|
{
|
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
# get canvas directly from selector block
|
304
|
|
|
|
|
|
|
# this means that the spriteset was defined
|
305
|
|
|
|
|
|
|
# inline and not in referenced selector block
|
306
|
|
|
|
|
|
|
my $canvas = $selector->{'canvas'};
|
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# get the url of the spriteset image
|
309
|
|
|
|
|
|
|
my $url = $canvas->{'options'}->get('url');
|
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# find block that has sprite-image obtion declared
|
312
|
|
|
|
|
|
|
if (my $block = $selector->find('option', 'sprite-image'))
|
313
|
|
|
|
|
|
|
{
|
314
|
|
|
|
|
|
|
# add background image to the selector if
|
315
|
|
|
|
|
|
|
# sprite-image has been declared on this selector
|
316
|
|
|
|
|
|
|
# or the sprite-image was declared on the stylesheet
|
317
|
|
|
|
|
|
|
if ($block eq $selector || $block->isa('Stylesheet'))
|
318
|
|
|
|
|
|
|
{
|
319
|
|
|
|
|
|
|
$styles{'background-image'} = wrapUrl($url);
|
320
|
|
|
|
|
|
|
$styles{'background-repeat'} = 'no-repeat';
|
321
|
|
|
|
|
|
|
}
|
322
|
|
|
|
|
|
|
}
|
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# remove all background styles from selector
|
325
|
|
|
|
|
|
|
$selector->clean(qr/background(?:\-[a-z0-9])*/);
|
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
};
|
328
|
|
|
|
|
|
|
# EO each selector
|
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# check if this selector is configured for a sprite
|
331
|
|
|
|
|
|
|
if ($selector->{'sprite'})
|
332
|
|
|
|
|
|
|
{
|
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
# get the sprite for selector
|
335
|
|
|
|
|
|
|
my $sprite = $selector->{'sprite'};
|
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
# spriteset canvas of block
|
338
|
|
|
|
|
|
|
my $canvas = $selector->{'canvas'};
|
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# get the url of the spriteset image
|
341
|
|
|
|
|
|
|
my $url = $canvas->{'options'}->get('url');
|
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
# get the sprite position within set
|
344
|
|
|
|
|
|
|
my $offset = $sprite->offset;
|
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
# get position offset vars
|
347
|
|
|
|
|
|
|
my $offset_x = $offset->{'x'};
|
348
|
|
|
|
|
|
|
my $offset_y = $offset->{'y'};
|
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
# assertion that the values are defined
|
351
|
|
|
|
|
|
|
die "no sprite x" unless defined $offset_x;
|
352
|
|
|
|
|
|
|
die "no sprite y" unless defined $offset_y;
|
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# get pre-caluculated position in spriteset
|
355
|
|
|
|
|
|
|
my $spriteset_x = $sprite->{'position-x'};
|
356
|
|
|
|
|
|
|
my $spriteset_y = $sprite->{'position-y'};
|
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
# assertion that the values are defined
|
359
|
|
|
|
|
|
|
die "no spriteset x" unless defined $spriteset_x;
|
360
|
|
|
|
|
|
|
die "no spriteset y" unless defined $spriteset_y;
|
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
# calculate the axes for background size
|
363
|
|
|
|
|
|
|
my $background_w = toPx($canvas->width / $sprite->scaleX);
|
364
|
|
|
|
|
|
|
my $background_h = toPx($canvas->height / $sprite->scaleY);
|
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# align relative to the top and relative to the left
|
367
|
|
|
|
|
|
|
$spriteset_y = toPx($spriteset_y - ($offset_y + $sprite->paddingTop) / $sprite->scaleY) if $sprite->alignTop;
|
368
|
|
|
|
|
|
|
$spriteset_x = toPx($spriteset_x - ($offset_x + $sprite->paddingLeft) / $sprite->scaleX) if $sprite->alignLeft;
|
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# assertion that the actual background position is always a full integer
|
371
|
|
|
|
|
|
|
warn "spriteset_x is not an integer $spriteset_x" unless $spriteset_x =~ m/^(?:\-?[0-9]+px|top|left|right|bottom)$/i;
|
372
|
|
|
|
|
|
|
warn "spriteset_y is not an integer $spriteset_y" unless $spriteset_y =~ m/^(?:\-?[0-9]+px|top|left|right|bottom)$/i;
|
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# check if sprite was distributed
|
375
|
|
|
|
|
|
|
# if it has no parent it means the
|
376
|
|
|
|
|
|
|
# sprite has not been included yet
|
377
|
|
|
|
|
|
|
unless ($sprite->{'parent'})
|
378
|
|
|
|
|
|
|
{
|
379
|
|
|
|
|
|
|
# check for debug mode on canvas or sprite
|
380
|
|
|
|
|
|
|
if ($canvas->{'debug'} || $sprite->{'debug'})
|
381
|
|
|
|
|
|
|
{
|
382
|
|
|
|
|
|
|
# make border dark red and background lightly red
|
383
|
|
|
|
|
|
|
$styles{'border-color'} = 'rgba(96, 0, 0, 0.875)';
|
384
|
|
|
|
|
|
|
$styles{'background-color'} = 'rgba(255, 0, 0, 0.125)';
|
385
|
|
|
|
|
|
|
}
|
386
|
|
|
|
|
|
|
}
|
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
# sprite was distributed
|
389
|
|
|
|
|
|
|
else
|
390
|
|
|
|
|
|
|
{
|
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
# add shorthand styles for sprite sizing and position
|
393
|
|
|
|
|
|
|
$styles{'background-size'} = join(' ', $background_w, $background_h);
|
394
|
|
|
|
|
|
|
$styles{'background-position'} = join(' ', $spriteset_x, $spriteset_y);
|
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
# add repeating if sprite has it configured
|
397
|
|
|
|
|
|
|
if ($sprite->isRepeatX && $sprite->isFlexibleX)
|
398
|
|
|
|
|
|
|
{ $styles{'background-repeat'} = 'repeat-x'; }
|
399
|
|
|
|
|
|
|
if ($sprite->isRepeatY && $sprite->isFlexibleY)
|
400
|
|
|
|
|
|
|
{ $styles{'background-repeat'} = 'repeat-y'; }
|
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
# remove all background styles from selector
|
403
|
|
|
|
|
|
|
$selector->clean(qr/background(?:\-[a-z0-9])*/);
|
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
}
|
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
}
|
408
|
|
|
|
|
|
|
# EO if has sprite
|
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
# do we have new styles
|
411
|
|
|
|
|
|
|
if (scalar %styles)
|
412
|
|
|
|
|
|
|
{
|
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
# render the selector bodies
|
415
|
|
|
|
|
|
|
my $body = $selector->body;
|
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
# find the first indenting to reuse it
|
418
|
|
|
|
|
|
|
my $indent = $body =~ m/^([ ]*)\S/m ? $1 : ' ';
|
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
# get the traling whitespace on last line
|
421
|
|
|
|
|
|
|
my $footer = $body =~ s/([ ]*)$// ? $1 : '';
|
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
# add some debugger statements into css
|
424
|
|
|
|
|
|
|
$selector->{'footer'} .= "\n" . $indent . ";/* \\/ added by WebSprite \\/ */\n";
|
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# add these declarations to the footer to be included within block
|
427
|
|
|
|
|
|
|
$selector->{'footer'} .= sprintf "%s%s: %s;\n", $indent, $_, $styles{$_} foreach keys %styles;
|
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# add some debugger statements into css
|
430
|
|
|
|
|
|
|
$selector->{'footer'} .= $indent . "/* /\\ added by WebSprite /\\ */\n";
|
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
# append traling whitespace again
|
433
|
|
|
|
|
|
|
$selector->{'footer'} .= $footer;
|
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
}
|
436
|
|
|
|
|
|
|
# EO if has styles
|
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
}
|
439
|
|
|
|
|
|
|
# EO each selector
|
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
# css stylesheet
|
442
|
|
|
|
|
|
|
return $css;
|
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
}
|
445
|
|
|
|
|
|
|
# EO create
|
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
# write out all spritesets within stylesheet
|
449
|
|
|
|
|
|
|
# ***************************************************************************************
|
450
|
|
|
|
|
|
|
sub write
|
451
|
|
|
|
|
|
|
{
|
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
# get passed arguments
|
454
|
|
|
|
|
|
|
my ($self, $opt) = @_;
|
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
# status variable
|
457
|
|
|
|
|
|
|
# info about all writes which is
|
458
|
|
|
|
|
|
|
# used to optimize files afterwards
|
459
|
|
|
|
|
|
|
my %written;
|
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
# write all registered spritesets
|
462
|
|
|
|
|
|
|
foreach my $canvas ($self->spritesets)
|
463
|
|
|
|
|
|
|
{
|
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
# get name of the canvas
|
466
|
|
|
|
|
|
|
my $id = $canvas->{'id'};
|
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
# get the css options for canvas
|
469
|
|
|
|
|
|
|
# they are gathered from block comments
|
470
|
|
|
|
|
|
|
my $options = $canvas->{'options'};
|
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
# parse sprite image option and add to options for later use
|
473
|
|
|
|
|
|
|
$options->set('url', unwrapUrl($options->get('sprite-image')));
|
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
# assertion that we have gotten some usefull url to store the image
|
476
|
|
|
|
|
|
|
die "no sprite image defined for <$id>" unless $options->get('url');
|
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
# call layout on canvas
|
479
|
|
|
|
|
|
|
$canvas->layout;
|
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
# draw image and check for success
|
482
|
|
|
|
|
|
|
if (my $image = $canvas->draw)
|
483
|
|
|
|
|
|
|
{
|
484
|
|
|
|
|
|
|
# set the output format
|
485
|
|
|
|
|
|
|
$image->Set(magick => 'png');
|
486
|
|
|
|
|
|
|
# cal image to binary object
|
487
|
|
|
|
|
|
|
my $blob = $image->ImageToBlob();
|
488
|
|
|
|
|
|
|
# get the filename to store image
|
489
|
|
|
|
|
|
|
my $file = $options->get('url');
|
490
|
|
|
|
|
|
|
# call method (can be overriden)
|
491
|
|
|
|
|
|
|
$self->writer($file, $blob, $opt);
|
492
|
|
|
|
|
|
|
}
|
493
|
|
|
|
|
|
|
# couldn't draw the image
|
494
|
|
|
|
|
|
|
else
|
495
|
|
|
|
|
|
|
{
|
496
|
|
|
|
|
|
|
# throw a error message, maybe we could
|
497
|
|
|
|
|
|
|
# extend this a bit to be more verbose
|
498
|
|
|
|
|
|
|
die "canvas could not be drawn";
|
499
|
|
|
|
|
|
|
}
|
500
|
|
|
|
|
|
|
# EO if drawn
|
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
}
|
503
|
|
|
|
|
|
|
# EO each spriteset
|
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
# return status variable
|
506
|
|
|
|
|
|
|
return \%written;
|
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
}
|
509
|
|
|
|
|
|
|
# EO sub write
|
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
####################################################################################################
|
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# return all spritesets in list context
|
514
|
|
|
|
|
|
|
sub spritesets { values %{$_[0]->{'spritesets'}} }
|
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
####################################################################################################
|
517
|
|
|
|
|
|
|
####################################################################################################
|
518
|
|
|
|
|
|
|
1; |