<div class="gmail_quote">On Sat, Sep 26, 2009 at 1:33 PM, Boudewijn Rempt <span dir="ltr">&lt;&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="im">On Friday 25 September 2009, Dmitry Kazakov wrote:<br>
&gt; What is done in the patch.<br>
&gt;<br>
&gt;<br>
&gt; 1) Now all the layers apply their own masks in a uniform way.<br>
&gt;<br>
&gt; How it was before:<br>
&gt; Every type of layer (paint, adjustment,etc) had it&#39;s own<br>
&gt; updateProjection() function. And EVERY layer implemented it&#39;s own<br>
&gt; cycle of applying masks. No need to say that they all differed. And<br>
&gt; most of them was broken, because they didn&#39;t take into account<br>
&gt; need/change rects of filters inside masks (at best).<br>
&gt;<br>
&gt; How it is now:<br>
&gt; updateProjection() and ALL the stuff about masks AND projections is<br>
&gt; moved to KisLayer. Specialized layer can operate with only a few<br>
&gt; functions those are not connected with a projection much. Every child<br>
&gt; can overload these functions:<br>
&gt;<br>
&gt; original() - returns a paint device where the layer stores it&#39;s<br>
&gt; image. NOTE: This is not the same with projection() as the latter one<br>
&gt; includes original() with all the masks applied.<br>
<br>
</div>So, that&#39;s what used to be called paintDevice(), right? I don&#39;t think the<br>
rename adds much clarity.<br></blockquote><div><br>No. Well, &quot;not always&quot;. <br><br>paintDevice() - is a device where tools are painting on, e.g. selections of the adjustment layers.<br><br>paintDevice() and original() are the same for KisPaintLayer as the picture we paint on and a picture we show on a screen are the same.<br>
But this is not right for KisSelectionBasedLayer (and it&#39;s child KisAdjustmentLayer). We paint on it&#39;s selection() paint device, but show on screen filtered image. That&#39;s why it has these methods:<br><br>KisPaintDeviceSP KisSelectionBasedLayer::original() const<br>
{<br>    return m_d-&gt;paintDevice;<br>}<br>KisPaintDeviceSP KisSelectionBasedLayer::paintDevice() const<br>{<br>    return m_d-&gt;selection-&gt;getOrCreatePixelSelection();<br>}<br> <br></div><div><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="im">
&gt; repaintOriginal() - called by updateProjection when original should be<br>
&gt; repainted.<br>
&gt;<br>
&gt; OPTIONAL:<br>
&gt; A layer CAN (not should) overload:<br>
&gt;<br>
&gt; needProjection() - if a layer needs an always-in-memory projection<br>
&gt; (e.g. KisPaintLayer needs one for indirect painting)<br>
&gt;<br>
&gt; copyOriginalToProjection() - used in couple with the previous one. A<br>
&gt; layer can enhance original during painting on a projection<br>
&gt; (e.g. indirect painting, see KisPaintDevice&#39;s method)<br>
&gt;<br>
&gt;<br>
&gt; This all means that a KisLayer&#39;s child shouldn&#39;t do any work to create<br>
&gt; a projection. It&#39;s created by KisLayer in a deferred way (when masks<br>
&gt; are present)<br>
<br>
</div>Ok, that&#39;s clear.<br>
<div class="im"><br>
&gt; Masks application strategy changed too (and quite much).<br>
&gt; Now changeRect()/needRect() functions are part of KisNode. And before<br>
&gt; application of a mask-stack we first get to know what need rect we<br>
&gt; want to copy from original() device.<br>
&gt;<br>
&gt; Rect calculating algorithm is quite overwhelming. It&#39;s implemented in<br>
&gt; two functions: masksChangeRect and masksNeedRect.<br>
&gt; First we get a change rect of a DESTINATION PROJECTION with a first<br>
&gt; function in a bottom-up(!) way. Then we calculate needRects for all<br>
&gt; the masks in a top-down(!) way with a second function, and by the end<br>
&gt; of this process we get a rect that we should copy from original()<br>
&gt; device to a temporary device for applying filters.<br>
<br>
</div>That sounds good.<br>
<div class="im"><br>
&gt; BUGFIX:<br>
&gt; This part of a patch fixes a bug with a blur-filter-mask. In current<br>
&gt; version  you simply you get a slack if you paint on a layer with<br>
&gt; blur-mask present (i&#39;m not sure you can check it up now, because<br>
&gt; blur-filter has an internal bug - it writes the result to the source<br>
&gt; instead of destination).<br>
<br>
</div>That&#39;s impossible, the src paint device is const.</blockquote><div>Btw, const KisSharedPtr does not mean that the object is constant too. That is a bug of shared pointers that we used to discuss on irc, don&#39;t know whether it has already been fixed. Has it?<br>
 </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"> I just checked the blur<br>
filter and it doesn&#39;t touch the src paint device.<br></blockquote><div><br>Yes, i can&#39;t reproduce it either now. I&#39;ll take a look at it. I always get empty dst device. Maybe the reason is that i pass it NULL selection?<br>
 </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div><div></div><div class="h5"><br>
&gt; 2) The second task for this patch was to unify adjustment and<br>
&gt; generator layers. The point is, they both use selections, that means<br>
&gt; they both should work in the same way.<br>
&gt;<br>
&gt; How it was before:<br>
&gt; KisAdjustmentLayer and KisGeneratorLayer had code duplications for<br>
&gt; selections stuff.<br>
&gt;<br>
&gt; How it is now:<br>
&gt; All the selection-related stuff is moved to a separate class -<br>
&gt; KisSelectionBasedLayer. Both problematic classes are derived from this<br>
&gt; base class. Speaking truly, KisAdjustmentLayer class has very few code<br>
&gt; inside now.<br>
&gt;<br>
&gt; BUGFIX:<br>
&gt; Selections on selection based layers was not working at all<br>
&gt; before. Now the the code applies selections (if you manage to<br>
&gt; create one ;) (see * for more)) to the layers well.<br>
&gt;<br>
&gt;<br>
&gt; 3) The third task was to clean masks classes. We had much code<br>
&gt; duplication there too. Most duplications and misuses was connected to<br>
&gt; selections (again).<br>
&gt;<br>
&gt; How it was before:<br>
&gt; KisFilterMaks, KisGeneratorMask, KisTransparencyMask - they all had<br>
&gt; their own implementation<br>
&gt;<br>
&gt; How it is now:<br>
&gt; All the selection-related stuff is moved to KisMask class. Here is an<br>
&gt; extract form a commit message:<br>
&gt;<br>
&gt;     Refactoring for masks<br>
&gt;<br>
&gt;     Now masks utilize selections in a uniform way. KisMask is the only<br>
&gt;     place that knows anything about mask&#39;s selection[0]. It&#39;s descendant&#39;s<br>
&gt; do<br>
&gt;     very simple task, they just decorate the rect with the desired<br>
&gt;     effect[1]. The task made by KisTransparencyMask fell back to even more<br>
&gt;     trivial routine - it just needs to copy source image to destination,<br>
&gt;     without any modifications[2].<br>
&gt;<br>
&gt;     Another significant change accumulated by this commit is a small<br>
&gt;     cleanup of KisMaskManager. There are still many FIXME&#39;s for it. The<br>
&gt;     most annoying is code duplication [3] of KActions for masks.<br>
&gt;<br>
&gt;     [0] - KisMask::apply()<br>
&gt;     [1] - virtual KisMask::decorateRect()<br>
&gt;     [2] - KisTransparencyMask::decorateRect()<br>
&gt;     [3] - KisMaskManager&#39;s actions for mask functions are duplicated in<br>
&gt;     KisLayerBox.<br>
&gt;<br>
&gt; As you can see, this commit accumulates some cleanups for<br>
&gt; KisMaskManager too. Most of them remove code duplications and uniform<br>
&gt; the code. More than that [and this is the only place where i worry<br>
&gt; about the patch] this fix adds a new method(!) to KoDocument. It&#39;s<br>
&gt; called undoLastCommand() - that is an equivalent to a user-undo<br>
&gt; command. It is added to be able to cancel creation of an filter mask<br>
&gt; in case a user presses &#39;Cancel&#39; button in a creation dialog. Please<br>
&gt; review this change!<br>
&gt;<br>
&gt; BUGFIXES:<br>
&gt; - cancelling creation of the filter mask now do not break undo stack<br>
&gt; - selections (see *) on filter masks work well now<br>
&gt;<br>
<br>
</div></div>Ok -- I think you should apply this patch, if all unittests still run.</blockquote><div><br>Well, the build and they run. But there are some fails. Most of them are connected to a design.<br><br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
 The two<br>
really important things after this are:<br>
<br>
* fix projection<br></blockquote><div></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
* fix pyramid<br></blockquote><div><br>Well, i&#39;m going to write a todo list, so shortly now:<br><br>The refactoring will contain three patches.<br>1st: Fixes masks and introduces needRect/changeRect infrastructure for layers/masks.<br>
2nd: Creates bottom-up recursive update strategy that works with need/change rects<br>3rd: Using information, collected by new update strategy, creates an &quot;update scheduler&quot;, that ensures that no two threads use the same rect at the same time.<br>
<br>And only after the third patch projection will not have flickering anymore.<br>The pyramid (more exactly, KisCanvas2) will use the same scheduler for threading scaling.<br><br><br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="im">
&gt; 4) Cleaning selections infrastructure, made me create a benchmark for<br>
&gt; different selection application algorithms. This benchmark is placed<br>
&gt; in ./image/tests/kis_filter_selections_benchmark.cpp. I wrote about it<br>
&gt; already here.<br>
&gt;<br>
<br>
</div>Cool!<br>
<div class="im"><br>
&gt;<br>
&gt; *) Still present bugs:<br>
&gt;<br>
&gt; a) [the worst one] Painting on any alpha mask do not work because of<br>
&gt; alpha() colorspace issue i was described before in this maillist. You<br>
&gt; can paint if your mask is transparent, but the brush isn&#39;t. This is<br>
&gt; not an issue of an algorithm. This is an issue of the alpha()<br>
&gt; colorspace and the fact that we use brush&#39;s alpha channel for painting<br>
&gt; alpha image-channel (tha latter assumption is completely wrong(!)).<br>
&gt;<br>
&gt; Solution: Brush&#39;s dab should use grayscale colorspace during painting<br>
&gt; on alpha-mask/selection. KisSelection should use grayscale, or a<br>
&gt; special alpha_special() colorspace to work with grayscale channel of a<br>
&gt; dab.<br>
<br>
</div>This has been fixed by Cyrille :-).<br></blockquote><div><br>Not really =(<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<div class="im"><br>
&gt; b) Vector selection tools DO NOT work on masks (And i&#39;m not sure they<br>
&gt; work on adjustment layers). The reason of the first fact (i think) is<br>
&gt; that KisSelectionToolHelper class uses KisLayerSP type for internal<br>
&gt; storage of a paint device. It should be changed to KisNodeSP to fix<br>
&gt; that (of course alongside some other changes in logics of this class)<br>
<br>
</div>Yes, that&#39;s something that should be fixed. The original idea for selections<br>
was different from what we have now: I wanted to have no selection tools at<br>
all, and have the ordinary tools work on local selection masks and on the<br>
global selection, with the global selection appearing in the layerbox as a<br>
node. That would have made it possible, for instance, to drag any shape onto<br>
the selection. Of course, tools like select contiguous area (bucket fill) or<br>
select similar pixels would have to be implemented in a way that makes sense<br>
for both ordinary layers and selections.<br>
<br>
That is still my goal. The current state is not a release blocker, as far as I<br>
am concerned, we&#39;ll have to rethink selection handling anway. And restore the<br>
mask visualization, too :-).<br>
<div class="im"><br>
&gt; a),b) =&gt; c) There is no(!) way to paint on alpha-channels/masks<br>
&gt; currently. You simply CAN&#39;T change the mask you created.<br>
<br>
</div>Fixed by Cyrille :P And even before that fix, I could select areas on a mask<br>
using the filled circle or rectangle tool without problems other than the<br>
projection not being updated.<br></blockquote><div><br>Thanks to  the hack that used to invert selection&#39;s paintDevice. Now you have to use an eraser to make a mask transparent, as my patch applies alpha channel directly.<br>
<br>Sorry.<br>(i&#39;ve just find the way to make it transparent again! Eraser tool!) So i have to change the initial sentence: &quot;there IS way to paint on masks, but you have to use eraser/brush to hide/show). Selection tools still do not work, but that is disputable, whether they should work _after_ creation of the mask. <br>
<br>PS_#1:<br>btw, i spent two weeks, to get to know that &quot;Eraser&quot; tool makes the opposite operation to a brush _on selections_. How do you think, how much time will user spend on this? And how to explain him that &quot;the color of the brush makes no sense when painting on a mask&quot;?<br>
<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="im">
&gt; The only way to create a mask now is the following:<br>
&gt;     i) make a vector selection first<br>
&gt;     ii) create a  mask - it&#39;ll derive this selection for it&#39;s own<br>
&gt;<br>
&gt; [some minor bugs not dependent on the patch]<br>
&gt; d) Blur filter works wrong. It writes filtered image to the source<br>
&gt; device instead of the destination one<br>
<br>
</div>Gaussian or ordinary blur? In any case, I don&#39;t see that happening, given that<br>
the src paint device is const. And what happens in<br>
<br>
void KisBlurFilter::process()<br>
<br>
is<br>
<br>
    KisConvolutionPainter painter(dst, dstInfo.selection());<br>
    painter.applyMatrix(kernel, src, srcTopLeft, dstTopLeft, size,<br>
BORDER_REPEAT);<br>
<br>
so to me it looks as if the filter reads from src and writes to dst.<br></blockquote><div><br>Ok, i&#39;ll take a look at it. It doesn&#39;t work for me now. <br></div><div><br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="im">
&gt; e) Drag&amp;Drop is broken in KisLayerBox. Just try to change an order of<br>
&gt; masks with a mouse - you can easily lift it up above the root<br>
&gt; layer. Of course,  your next action will cause krita to crash.<br>
<br>
</div>Unfixable, this is a Qt problem.</blockquote><div>I don&#39;t think so. Doesn&#39;t it have an ability to control where we can drag an item to?<br><br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
 And we don&#39;t show the root layer by default,<br>
which helps.<br></blockquote><div><br>Sorry, &quot;above it&#39;s parent layer to the empty place with no parent&quot;<br><br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<div class="im"><br>
&gt; f) Curves filter DO NOT(!) work. I guess, there is some bug in<br>
&gt; KoColorTransformation as every curve works as a brightness/contrast<br>
&gt; curve instead of a channel curve. Just try it out!<br>
<br>
</div>I think Cyrille just fix that.<br>
<div class="im"><br>
&gt; [some design bugs]<br>
&gt; g) KisNodeManager::allowAsChild uses some silly string comparison<br>
&gt; algorithm. Why?! Every node has a specially designed method for this!<br>
<br>
</div>Because that predates the newer method? You have to realize that the Krita<br>
code is about 10 years old. You will find historical artefacts all over the<br>
place.<br></blockquote><div><br>Cleaning?<br><br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="im">
&gt; h) KActions for mask-manipulation functions are duplicated in<br>
&gt; KisMaskManager and in KisLayerBox. They must be moved to<br>
&gt; KisMaskManager.<br>
<br>
</div>No, they aren&#39;t. The gui in the layerbox defers to the nodemanager for the<br>
executions of the user actions.<br></blockquote><div><br>It breaks KAction paradigm. I&#39;ve written about it before.<br></div></div><br clear="all"><br>-- <br>Dmitry Kazakov<br>