Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_layer_style_projection_plane.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include "kis_global.h"
13#include "kis_psd_layer_style.h"
14
16#include "kis_ls_satin_filter.h"
20#include "kis_projection_leaf.h"
22#include "kis_painter.h"
23#include "kis_ls_utils.h"
25#include "krita_utils.h"
26
28{
30
35
38 KisLayer *sourceLayer = 0;
39
40
42 bool canHaveChildNodes = false;
43 bool dependsOnLowerNodes = false;
44
45 void initSourcePlane(KisLayer *sourceLayer) {
47 sourceProjectionPlane = sourceLayer->internalProjectionPlane();
48 canHaveChildNodes = sourceLayer->projectionLeaf()->canHaveChildLayers();
49 dependsOnLowerNodes = sourceLayer->projectionLeaf()->dependsOnLowerNodes();
50 this->sourceLayer = sourceLayer;
51 }
52
55 result << stylesBefore;
56 result << stylesOverlay;
57 result << strokeStyle;
58 result << stylesAfter;
59 return result;
60 }
61
62 bool hasOverlayStyles() const {
63 Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, stylesOverlay) {
64 if (!plane->isEmpty()) return true;
65 }
66
67 return false;
68 }
69
70 bool hasKnockoutStyles() const {
71 Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, stylesBefore) {
72 if (!plane->knockoutBlower()->isEmpty()) return true;
73 }
74
75 Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, stylesAfter) {
76 if (!plane->knockoutBlower()->isEmpty()) return true;
77 }
78
79 if (!strokeStyle->knockoutBlower()->isEmpty()) return true;
80
81 return false;
82 }
83
86 const QRect &rect,
87 KisPaintDeviceSP originalClone);
88};
89
101
103 : m_d(new Private)
104{
105 m_d->initSourcePlane(sourceLayer);
106 m_d->style = clonedStyle;
107
109 m_d->style = toQShared(new KisPSDLayerStyle());
110 }
111
112 Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, rhs.m_d->stylesBefore) {
113 m_d->stylesBefore << toQShared(new KisLayerStyleFilterProjectionPlane(*plane, sourceLayer, m_d->style));
114 }
115
116 Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, rhs.m_d->stylesAfter) {
117 m_d->stylesAfter << toQShared(new KisLayerStyleFilterProjectionPlane(*plane, sourceLayer, m_d->style));
118 }
119
120 Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, rhs.m_d->stylesOverlay) {
121 m_d->stylesOverlay << toQShared(new KisLayerStyleFilterProjectionPlane(*plane, sourceLayer, m_d->style));
122 }
123
124 m_d->strokeStyle.reset(new KisStrokeLayerStyleFilterProjectionPlane(*rhs.m_d->strokeStyle, sourceLayer, m_d->style));
125}
126
127// for testing purposes only!
129 : m_d(new Private)
130{
131 init(sourceLayer, layerStyle);
132}
133
135{
137 m_d->initSourcePlane(sourceLayer);
138 m_d->style = style;
139
140 {
144 m_d->stylesBefore << toQShared(dropShadow);
145 }
146
147 {
151 m_d->stylesAfter << toQShared(outerGlow);
152 }
153
154 {
157 stroke->setStyle(new KisLsStrokeFilter(), style);
158 m_d->strokeStyle.reset(stroke);
159 }
160
161 {
164 bevelEmboss->setStyle(new KisLsBevelEmbossFilter(), style);
165 m_d->stylesAfter << toQShared(bevelEmboss);
166 }
167
168 {
169 KisLayerStyleFilterProjectionPlane *patternOverlay =
172 m_d->stylesOverlay << toQShared(patternOverlay);
173 }
174
175 {
176 KisLayerStyleFilterProjectionPlane *gradientOverlay =
179 m_d->stylesOverlay << toQShared(gradientOverlay);
180 }
181
182 {
186 m_d->stylesOverlay << toQShared(colorOverlay);
187 }
188
189 {
192 satin->setStyle(new KisLsSatinFilter(), style);
193 m_d->stylesOverlay << toQShared(satin);
194 }
195
196 {
200 m_d->stylesOverlay << toQShared(innerGlow);
201 }
202
203 {
207 m_d->stylesOverlay << toQShared(innerShadow);
208 }
209}
210
214
220
221QRect KisLayerStyleProjectionPlane::recalculate(const QRect& rect, KisNodeSP filthyNode, KisRenderPassFlags flags)
222{
223 KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef();
224 QRect result = rect;
225
226 if (m_d->style->isEnabled()) {
227 result = sourcePlane->recalculate(stylesNeedRect(rect), filthyNode, flags);
228
229 Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) {
230 plane->recalculate(rect, filthyNode, flags);
231 }
232 } else {
233 result = sourcePlane->recalculate(rect, filthyNode, flags);
234 }
235
236 return result;
237}
238
239void KisLayerStyleProjectionPlane::Private::applyComplexPlane(KisPainter *painter,
241 const QRect &rect,
242 KisPaintDeviceSP originalClone)
243{
244 if (plane->isEmpty()) return;
245
246 if (!plane->knockoutBlower()->isEmpty()) {
247 KisCachedPaintDevice::Guard d1(originalClone, cachedPaintDevice);
248 KisPaintDeviceSP mergedStyle = d1.device();
249 mergedStyle->makeCloneFromRough(originalClone, rect);
250
251 KisPainter overlayPainter(mergedStyle);
252 plane->apply(&overlayPainter, rect);
253 plane->knockoutBlower()->apply(painter, mergedStyle, rect);
254
255 } else {
256 plane->apply(painter, rect);
257 }
258}
259
261{
262 KisLayerProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef();
263
264 if (m_d->style->isEnabled()) {
265 if (m_d->hasOverlayStyles() || m_d->hasKnockoutStyles()) {
266 KisCachedPaintDevice::Guard d1(painter->device(), m_d->cachedPaintDevice);
267 KisPaintDeviceSP originalClone = d1.device();
268 originalClone->makeCloneFromRough(painter->device(), rect);
269
270 Q_FOREACH (const KisLayerStyleFilterProjectionPlaneSP plane, m_d->stylesBefore) {
271 m_d->applyComplexPlane(painter, plane, rect, originalClone);
272 }
273
274 KritaUtils::ThresholdMode sourceThresholdMode =
275 !m_d->strokeStyle->isEmpty() ?
276 m_d->strokeStyle->sourcePlaneOpacityThresholdRequirement() :
278
279 if (m_d->hasOverlayStyles()) {
280 KisCachedSelection::Guard s1(m_d->cachedSelection);
281 KisSelectionSP knockoutSelection = s1.selection();
282 KisLsUtils::selectionFromAlphaChannel(m_d->sourceLayer->projection(), knockoutSelection, rect);
283
284 KisCachedPaintDevice::Guard d2(painter->device(), m_d->cachedPaintDevice);
285 KisPaintDeviceSP sourceProjection = d2.device();
286 sourceProjection->makeCloneFromRough(painter->device(), rect);
287
288 {
289 KisPainter overlayPainter(sourceProjection);
290 sourcePlane->applyMaxOutAlpha(&overlayPainter, rect, KritaUtils::ThresholdMaxOut);
291
292 Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesOverlay) {
293 plane->apply(&overlayPainter, rect);
294 }
295 }
296
297 KritaUtils::thresholdOpacityAlpha8(knockoutSelection->pixelSelection(), rect, sourceThresholdMode);
298
300 blower.setKnockoutSelection(knockoutSelection);
301 blower.apply(painter, sourceProjection, rect);
302
303 blower.resetKnockoutSelection();
304 } else {
305 sourcePlane->applyMaxOutAlpha(painter, rect, sourceThresholdMode);
306 }
307
308 if (!m_d->strokeStyle->isEmpty()) {
309 m_d->applyComplexPlane(painter, m_d->strokeStyle, rect, originalClone);
310 }
311
312 Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, m_d->stylesAfter) {
313 m_d->applyComplexPlane(painter, plane, rect, originalClone);
314 }
315 } else {
316 Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesBefore) {
317 plane->apply(painter, rect);
318 }
319
320 sourcePlane->apply(painter, rect);
321
322 Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesAfter) {
323 plane->apply(painter, rect);
324 }
325 }
326 } else {
327 sourcePlane->apply(painter, rect);
328 }
329}
330
332{
334 KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef();
335
336 if (m_d->style->isEnabled()) {
337 Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) {
338 list << plane->getLodCapableDevices();
339 }
340
341 list << sourcePlane->getLodCapableDevices();
342 } else {
343 list << sourcePlane->getLodCapableDevices();
344 }
345
346 return list;
347}
348
350{
358 QRect needRect = rect;
359
360 const bool adjustmentAboveDirty = m_d->dependsOnLowerNodes &&
362
363 if (m_d->style->isEnabled() && adjustmentAboveDirty) {
365 }
366
367 KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef();
368 needRect = sourcePlane->needRect(needRect, pos);
369
370 return needRect;
371}
372
374{
375 KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef();
376 QRect layerChangeRect = sourcePlane->changeRect(rect, pos);
377 QRect changeRect = layerChangeRect;
378
379 if (m_d->style->isEnabled() && !layerChangeRect.isEmpty()) {
380 Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) {
381 changeRect |= plane->changeRect(layerChangeRect, KisLayer::N_ABOVE_FILTHY);
382 }
383 }
384
385 return changeRect;
386}
387
389{
390 KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef();
391 QRect accessRect = sourcePlane->accessRect(rect, pos);
392
393 if (m_d->style->isEnabled()) {
394 Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) {
395 accessRect |= plane->accessRect(rect, KisLayer::N_ABOVE_FILTHY);
396 }
397 }
398
399 return accessRect;
400}
401
403{
411 QRect needRect = rect;
412
413 if (m_d->style->isEnabled()) {
415 }
416
417 KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef();
418 needRect = sourcePlane->needRectForOriginal(needRect);
419
420 return needRect;
421}
422
424{
425 KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef();
426 QRect rect = sourcePlane->tightUserVisibleBounds();
427
428 Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) {
429 rect |= plane->tightUserVisibleBounds();
430 }
431
432 return rect;
433}
434
436{
437 KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef();
438 QRect rect = sourcePlane->looseUserVisibleBounds();
439
440 Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) {
441 rect |= plane->looseUserVisibleBounds();
442 }
443
444 return rect;
445}
446
448{
449 QRect needRect = rect;
450
451 Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) {
452 needRect |= plane->needRect(rect, KisLayer::N_ABOVE_FILTHY);
453 }
454
455 return needRect;
456}
QPointF s1
void setStyle(KisLayerStyleFilter *filter, KisPSDLayerStyleSP style)
void setKnockoutSelection(KisSelectionSP selection)
void apply(KisPainter *painter, KisPaintDeviceSP mergedStyle, const QRect &rect) const
void makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect)
KisPaintDeviceSP device
StrokeStyle strokeStyle
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
QSharedPointer< T > toQShared(T *ptr)
void selectionFromAlphaChannel(KisPaintDeviceSP srcDevice, KisSelectionSP dstSelection, const QRect &srcRect)
void thresholdOpacityAlpha8(KisPaintDeviceSP device, const QRect &rect, ThresholdMode mode)
KisPaintDeviceSP device() const
QRect changeRect(const QRect &rect, KisLayer::PositionToFilthy pos) const override
QRect needRectForOriginal(const QRect &rect) const override
KisPaintDeviceList getLodCapableDevices() const override
void apply(KisPainter *painter, const QRect &rect) override
static KisAbstractProjectionPlaneSP factoryObject(KisLayer *sourceLayer)
QRect stylesNeedRect(const QRect &rect) const
QVector< KisLayerStyleFilterProjectionPlaneSP > allStyles() const
KisStrokeLayerStyleFilterProjectionPlaneSP strokeStyle
QVector< KisLayerStyleFilterProjectionPlaneSP > stylesOverlay
void applyComplexPlane(KisPainter *painter, KisLayerStyleFilterProjectionPlaneSP plane, const QRect &rect, KisPaintDeviceSP originalClone)
QRect needRect(const QRect &rect, KisLayer::PositionToFilthy pos) const override
QVector< KisLayerStyleFilterProjectionPlaneSP > stylesAfter
QRect recalculate(const QRect &rect, KisNodeSP filthyNode, KisRenderPassFlags flags) override
void init(KisLayer *sourceLayer, KisPSDLayerStyleSP layerStyle)
QVector< KisLayerStyleFilterProjectionPlaneSP > stylesBefore
QRect accessRect(const QRect &rect, KisLayer::PositionToFilthy pos) const override
virtual KisLayerProjectionPlaneSP internalProjectionPlane() const
Definition kis_layer.cc:815
KisPSDLayerStyleSP layerStyle
Definition kis_layer.cc:171
KisProjectionLeafSP projectionLeaf
Definition kis_node.cpp:93
PositionToFilthy
Definition kis_node.h:58
@ N_ABOVE_FILTHY
Definition kis_node.h:59
@ N_FILTHY
Definition kis_node.h:61
The KisPSDLayerStyle class implements loading, saving and applying the PSD layer effects.
KisPixelSelectionSP pixelSelection