drawing-item.cpp revision 7674bbcd155943a9c273cd0d21542fbfe6efdc6c
403N/A * Canvas item belonging to an SVG drawing element. 403N/A * Krzysztof KosiĆski <tweenk.pl@gmail.com> 403N/A * Copyright (C) 2011 Authors 403N/A * Released under GNU GPL, read the file 'COPYING' for more information 403N/A // All of the blend modes are implemented in Cairo as of 1.10. // For a detailed description, see: * SVG drawing item for display. * This was previously known as NRArenaItem. It represents the renderable * portion of the SVG document. Typically this is created by the SP tree, * in particular the show() virtual function. * @section ObjectLifetime Object lifetime * Deleting a DrawingItem will cause all of its children to be deleted as well. * This can lead to nasty surprises if you hold references to things * which are children of what is being deleted. Therefore, in the SP tree, * you always need to delete the item views of children before deleting * the view of the parent. Do not call delete on things returned from show() * - this will cause dangling pointers inside the SPItem and lead to a crash. * Use the corresponing hide() method. * Outside of the SP tree, you should not use any references after the root node //if (!_children.empty()) { // g_warning("Removing item with children"); // remove from the set of cached items and delete cache // remove this item from parent's children list // due to the effect of clearChildren(), this only happens for the top-level deleted item // we cannot call setClip(NULL) or setMask(NULL), // because that would be an endless loop // initially I wanted to return NULL if we are a clip or mask child, // but the previous behavior was just to return the parent regardless of child type /// Returns true if item is among the descendants. Will return false if item == this. if (i ==
this)
return true;
// This ensures that _markForUpdate() called on the child will recurse to this item // Because _markForUpdate recurses through ancestors, we can simply call it // on the just-added child. This has the additional benefit that we do not // rely on the appended child being in the default non-updated state. // We set propagate to true, because the child might have descendants of its own. // See appendChild for explanation /// Delete all regular children of this item (not mask or clip). // prevent children from referencing the parent during deletion // this way, children won't try to remove themselves from a list // from which they have already been removed by clear_and_dispose /// Set the incremental transform for this item // mark the area where the object was for redraw. //if( isolation != 0 ) std::cout << "isolation: " << isolation << std::endl; //if( blend_mode != 0 ) std::cout << "setBlendMode: " << blend_mode << std::endl; /// This is currently unused * Enable / disable storing the rendering in memory. * Calling setCached(false, true) will also remove the persistent status /// Move this item to the given place in the Z order of siblings. /// Does nothing if the item has no parent. * Update derived data before operations. * The purpose of this call is to recompute internal data which depends * on the attributes of the object, but is not directly settable by the user. * Precomputing this data speeds up later rendering, because some items * Currently this method handles updating the visual and geometric bounding boxes * in pixels, storing the total transformation from item space to the screen * and cache invalidation. * @param area Area to which the update should be restricted. Only takes effect * if the bounding box is known. * @param ctx A structure to store cascading state. * @param flags Which internal data should be recomputed. This can be any combination * @param reset State fields that should be reset before processing them. This is * a means to force a recomputation of internal data even if the item * considers it up to date. Mainly for internal use, such as * propagating bunding box recomputation to children when the item's // Set reset flags according to propagation status // TODO this might be wrong // we have up-to-date bbox // compute which elements need an update // this needs to be called before we recurse into children /* Remember the transformation matrix */ // update _bbox and call this function for children // for masking, we need full drawbox of mask // Update cache score for this item // remove old score information // if _cacheRect() is empty, a negative score will be returned from _cacheScore(), // so this will not execute (cache score threshold must be positive) /* Update cache if enabled. * General note: here we only tell the cache how it has to transform * during the render phase. The transformation is deferred because * after the update the item can have its caching turned off, * e.g. because its filter was removed. This way we avoid tempoerarily * using more memory than the cache budget */ if (
_visible &&
cl) {
// never create cache for invisible items // this takes care of invalidation on transform // Destroy cache for this item - outside of canvas or invisible. // The opposite transition (invisible -> visible or object // entering the canvas) is handled during the render phase // now that we know drawbox, dirty the corresponding rect on canvas // unless filtered, groups do not need to render by themselves, only their members guint r = 0, g = 0, b = 0;
// the operation of unpremul -> luminance-to-alpha -> multiply by alpha // is equivalent to luminance-to-alpha on premultiplied color values // original computation in double: r*0.2125 + g*0.7154 + b*0.0721 guint32 ao = r*
109 + g*
366 + b*
37;
// coeffs add up to 512 return ((
ao +
256) <<
15) &
0xff000000;
// equivalent to ((ao + 256) / 512) << 24 * This method submits the drawing opeartions required to draw this item * to the supplied DrawingContext, restricting drawing the specified area. * This method does some common tasks and calls the item-specific rendering * function, _renderItem(), to render e.g. paths or bitmaps. * @param flags Rendering options. This deals mainly with cache control. // stop_at is handled in DrawingGroup, but this check is required to handle the case // where a filtered item with background-accessing filter has enable-background: new // If we are invisible, return immediately // TODO convert outline rendering to a separate virtual function // carea is the area to paint // render from cache if possible // There is no cache. This could be because caching of this item // was just turned on after the last update phase, or because // we were previously outside of the canvas. // if our caching was turned off after the last update, it was already // deleted in setCached() // determine whether this shape needs intermediate rendering. // this item needs an intermediate rendering if: /* How the rendering is done. * Clipping, masking and opacity are done by rendering them to a surface * and then compositing the object's rendering onto it with the IN operator. * The object itself is rendered to a group. * Opacity is done by rendering the clipping path with an alpha * value corresponding to the opacity. If there is no clipping path, * the entire intermediate surface is painted with alpha corresponding // Short-circuit the simple case. // We also use this path for filter background rendering, because masking, clipping, // filters and opacity do not apply when rendering the ancestors of the filtered // iarea is the bounding box for intermediate rendering // Note 1: Pixels inside iarea but outside carea are invalid // (incomplete filter dependence region). // Note 2: We only need to render carea of clip and mask, but // expand carea to contain the dependent area of filters. // 1. Render clipping path with alpha = opacity. // Since clip can be combined with opacity, the result could be incorrect // for overlapping clip children. To fix this we use the SOURCE operator // instead of the default OVER. // 2. Render the mask if present and compose it with the clipping path + opacity. // Convert mask's luminance to alpha // 3. Render object itself // Note that because the object was rendered to a group, // the internals of the filter need to use cairo_get_group_target() // instead of cairo_get_target(). // 5. Render object inside the composited mask + clip // 6. Paint the completed rendering onto the base context (or into cache) // the call above is to clear a ref on the intermediate surface held by ct // intersect with bbox rather than drawbox, as we want to render things outside // of the clipping path as well // just render everything: item, clip, mask // First, render the object itself // render clip and mask, if any // render clippath as an object, using a different color // render mask as an object, using a different color * Rasterize the clipping path. * This method submits drawing operations required to draw a basic filled shape * of the item to the supplied drawing context. Rendering is limited to the * given area. The rendering of the clipped object is composited into * the result of this call using the IN operator. See the implementation * of render() for details. // don't bother if the object does not implement clipping (e.g. DrawingImage) // rasterize the clipping path // The item used as the clipping path itself has a clipping path. // Render this item's clipping path onto a temporary surface, then composite it // with the item using the IN operator * Get the item under the specified point. * Searches the tree for the first item in the Z-order which is closer than * @a delta to the given point. The pick should be visual - for example * an object with a thick stroke should pick on the entire area of the stroke. * @param delta Maximum allowed distance from the point * @param sticky Whether the pick should ignore visibility and sensitivity. * When false, only visible and sensitive objects are considered. * When true, invisible and insensitive objects can also be picked. // Sometimes there's no BBOX in state, reason unknown (bug 992817) // I made this not an assert to remove the warning g_warning(
"Invalid state when picking: STATE_BBOX = %d, STATE_PICK = %d",
// ignore invisible and insensitive items unless sticky // pick inside clipping path; if NULL, it means the object is clipped away there * Marks the current visual bounding box of the item for redrawing. * This is called whenever the object changes its visible appearance. * For some cases (such as setting opacity) this is enough, but for others * _markForUpdate() also needs to be called. // TODO: this function does too much work when a large subtree // dirty the caches of all parents * Marks the item as needing a recomputation of internal data. * This mechanism avoids traversing the entire rendering tree (which could be vast) * on every trivial state changed in any item. Only items marked as needing * an update (having some bits in their _state unset) will be traversed * during the update call. * The _propagate variable is another optimization. We use it to specify that * all children should also have the corresponding flags unset before checking * whether they need to be traversed. This way there is one less traversal * of the tree. Without this we would need to unset state bits in all children. * With _propagate we do this during the update call, when we have to recurse // If we actually reset anything in state, recurse on the parent. // If nothing changed, it means our ancestors are already invalidated // up to the root. Do not bother recursing, because it won't change anything. // Also do this if we are the root item, because we have no more ancestors * Process information related to the new style. * This function is something of a hack to avoid creating an extra class in the hierarchy * which would differ from DrawingItem only by having a _style member. * This is mainly to the benefit of DrawingGlyphs, which use the style of their parent. * This should probably be refactored some day, possibly by creating the relevant class * or creating a more complex data model in DrawingText and removing DrawingGlyphs, * which would cause every item to have a style. // no filter set for this group * Compute the caching score. * Higher scores mean the item is more aggresively prioritized for automatic * caching by Inkscape::Drawing. // a crude first approximation: // the basic score is the number of pixels in the drawbox // this is multiplied by the filter complexity and its expansion // area_enlarge never shrinks the rect, so the result of intersection below // if the object is clipped, add 1/2 of its bbox pixels // if masked, add mask score //g_message("caching score: %f", score); }
// end namespace Inkscape c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :