From a337bc28f9a2eebc0a34effb839d6cda5e1a35f6 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 26 Sep 2012 12:30:02 +0100 Subject: [PATCH] Reduce number of divs used by typical apps. Without this optimisation nil or 0x0 sized image slices in three part and nine part images result in useless empty divs. Eliminating these divs should improve performance and reduce memory usage. Although exact memory usage is hard to measure, in a large app the number of divs on screen went from 1012 to 984, a reduction of about 2.7%. --- AppKit/CPView.j | 281 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 222 insertions(+), 59 deletions(-) diff --git a/AppKit/CPView.j b/AppKit/CPView.j index b11599d32..570a5e965 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -987,32 +987,90 @@ var CPCurrentToolTip, } else { - var images = [[_backgroundColor patternImage] imageSlices]; + var images = [[_backgroundColor patternImage] imageSlices], + partIndex = 0; if (_backgroundType === BackgroundVerticalThreePartImage) { + var top = _DOMImageSizes[0] ? _DOMImageSizes[0].height : 0, + bottom = _DOMImageSizes[2] ? _DOMImageSizes[2].height : 0; + // Make sure to repeat the top and bottom pieces horizontally if they're not the exact width needed. - CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, _DOMImageSizes[0].height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width, size.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[2], size.width, _DOMImageSizes[2].height); + if (top) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width, top); + partIndex++; + } + if (_DOMImageSizes[1]) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width, size.height - top - bottom); + partIndex++; + } + if (bottom) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width, bottom); + } } else if (_backgroundType === BackgroundHorizontalThreePartImage) { + var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0, + right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0; + // Make sure to repeat the left and right pieces vertically if they're not the exact height needed. - CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], _DOMImageSizes[0].width, size.height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, size.height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[2], _DOMImageSizes[2].width, size.height); + if (left) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], left, size.height); + partIndex++; + } + if (_DOMImageSizes[1]) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width - left - right, size.height); + partIndex++; + } + if (right) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], right, size.height); + } } else if (_backgroundType === BackgroundNinePartImage) { - var width = size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, - height = size.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height; + var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0, + right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0, + top = _DOMImageSizes[0] ? _DOMImageSizes[0].height : 0, + bottom = _DOMImageSizes[6] ? _DOMImageSizes[6].height : 0, + width = size.width - left - right, + height = size.height - top - bottom; - CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height); + if (_DOMImageSizes[0]) + partIndex++; + if (_DOMImageSizes[1]) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, top); + partIndex++; + } + if (_DOMImageSizes[2]) + partIndex++; + if (_DOMImageSizes[3]) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], _DOMImageSizes[3].width, height); + partIndex++; + } + if (_DOMImageSizes[4]) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, height); + partIndex++; + } + if (_DOMImageSizes[5]) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], _DOMImageSizes[5].width, height); + partIndex++; + } + if (_DOMImageSizes[6]) + partIndex++; + if (_DOMImageSizes[7]) + { + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, _DOMImageSizes[7].height); + } } } } @@ -1584,17 +1642,18 @@ var CPCurrentToolTip, colorHasAlpha = colorExists && [_backgroundColor alphaComponent] < 1.0, supportsRGBA = CPFeatureIsCompatible(CPCSSRGBAFeature), colorNeedsDOMElement = colorHasAlpha && !supportsRGBA, - amount = 0; + amount = 0, + slices; if ([patternImage isThreePartImage]) { _backgroundType = [patternImage isVertical] ? BackgroundVerticalThreePartImage : BackgroundHorizontalThreePartImage; - amount = 3 - _DOMImageParts.length; + amount = 3; } else if ([patternImage isNinePartImage]) { _backgroundType = BackgroundNinePartImage; - amount = 9 - _DOMImageParts.length; + amount = 9; } else { @@ -1602,6 +1661,34 @@ var CPCurrentToolTip, amount = (colorNeedsDOMElement ? 1 : 0) - _DOMImageParts.length; } + // Prepare multipart image data and reduce number of required DOM parts by number of empty slices in the multipart image to save needless DOM elements. + if (_backgroundType === BackgroundVerticalThreePartImage || _backgroundType === BackgroundHorizontalThreePartImage || _backgroundType === BackgroundNinePartImage) + { + slices = [patternImage imageSlices]; + + // We won't need more divs than there are slices. + amount = MIN(amount, slices.length); + + for (var i = 0, count = slices.length; i < count; i++) + { + var image = slices[i], + size = [image size]; + + if (!size || (size.width == 0 && size.height == 0)) + size = nil; + + _DOMImageSizes[i] = size; + + // If there's a nil slice or a slice with no size, it won't need a div. + if (!size) + amount--; + } + + // Now that we know how many divs we really need, compare that to number we actually have. + amount -= _DOMImageParts.length; + } + + // Make sure the number of divs we have match our needs. if (amount > 0) { while (amount--) @@ -1643,70 +1730,148 @@ var CPCurrentToolTip, } else { - var slices = [patternImage imageSlices], - count = MIN(_DOMImageParts.length, slices.length), - frameSize = _frame.size; + var frameSize = _frame.size, + partIndex = 0; - while (count--) + for (var i = 0; i < slices.length; i++) { - var image = slices[count], - size = _DOMImageSizes[count] = image ? [image size] : _CGSizeMakeZero(); + var size = _DOMImageSizes[i]; - CPDOMDisplayServerSetStyleSize(_DOMImageParts[count], size.width, size.height); + if (!size) + continue; - _DOMImageParts[count].style.background = image ? "url(\"" + [image filename] + "\")" : ""; + var image = slices[i]; + + // // If image was nil, size should have been nil too. + // assert(image != nil); + + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], size.width, size.height); + + _DOMImageParts[partIndex].style.background = "url(\"" + [image filename] + "\")"; if (!supportsRGBA) { if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature)) - try { _DOMImageParts[count].style.removeAttribute("filter") } catch (anException) { } + try { _DOMImageParts[partIndex].style.removeAttribute("filter") } catch (anException) { } else - _DOMImageParts[count].style.opacity = 1.0; + _DOMImageParts[partIndex].style.opacity = 1.0; } + + partIndex++; } if (_backgroundType == BackgroundNinePartImage) { - var width = frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, - height = frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[6].height; + var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0, + right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0, + top = _DOMImageSizes[0] ? _DOMImageSizes[0].height : 0, + bottom = _DOMImageSizes[6] ? _DOMImageSizes[6].height : 0, + width = frameSize.width - left - right, + height = frameSize.height - top - bottom; - CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], width, _DOMImageSizes[0].height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[3], _DOMImageSizes[3].width, height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[4], width, height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height); + partIndex = 0; - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0); - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0); - CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0); - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[3], NULL, 0.0, _DOMImageSizes[1].height); - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[4], NULL, _DOMImageSizes[0].width, _DOMImageSizes[0].height); - CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[5], NULL, 0.0, _DOMImageSizes[1].height); - CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[6], NULL, 0.0, 0.0); - CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[7], NULL, _DOMImageSizes[6].width, 0.0); - CPDOMDisplayServerSetStyleRightBottom(_DOMImageParts[8], NULL, 0.0, 0.0); + if (_DOMImageSizes[0]) + { + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[partIndex], NULL, 0.0, 0.0); + partIndex++; + } + if (_DOMImageSizes[1]) + { + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[partIndex], NULL, left, 0.0); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, _DOMImageSizes[1].height); + partIndex++; + } + if (_DOMImageSizes[2]) + { + CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[partIndex], NULL, 0.0, 0.0); + partIndex++; + } + if (_DOMImageSizes[3]) + { + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[partIndex], NULL, 0.0, top); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], _DOMImageSizes[3].width, height); + partIndex++; + } + if (_DOMImageSizes[4]) + { + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[partIndex], NULL, left, top); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, height); + partIndex++; + } + if (_DOMImageSizes[5]) + { + CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[partIndex], NULL, 0.0, top); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], _DOMImageSizes[5].width, height); + partIndex++; + } + if (_DOMImageSizes[6]) + { + CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[partIndex], NULL, 0.0, 0.0); + partIndex++; + } + if (_DOMImageSizes[7]) + { + CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[partIndex], NULL, left, 0.0); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], width, _DOMImageSizes[7].height); + partIndex++; + } + if (_DOMImageSizes[8]) + { + CPDOMDisplayServerSetStyleRightBottom(_DOMImageParts[partIndex], NULL, 0.0, 0.0); + } } else if (_backgroundType == BackgroundVerticalThreePartImage) { - // Make sure to repeat the top and bottom pieces horizontally if they're not the exact width needed. - CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], frameSize.width, _DOMImageSizes[0].height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width, frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[2], frameSize.width, _DOMImageSizes[2].height); + var top = _DOMImageSizes[0] ? _DOMImageSizes[0].height : 0, + bottom = _DOMImageSizes[2] ? _DOMImageSizes[2].height : 0; - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0); - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, 0.0, _DOMImageSizes[0].height); - CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[2], NULL, 0.0, 0.0); + partIndex = 0; + + // Make sure to repeat the top and bottom pieces horizontally if they're not the exact width needed. + if (top) + { + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[partIndex], NULL, 0.0, 0.0); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], frameSize.width, top); + partIndex++; + } + if (_DOMImageSizes[1]) + { + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[partIndex], NULL, 0.0, top); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], frameSize.width, frameSize.height - top - bottom); + partIndex++; + } + if (bottom) + { + CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[partIndex], NULL, 0.0, 0.0); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], frameSize.width, bottom); + } } else if (_backgroundType == BackgroundHorizontalThreePartImage) { - // Make sure to repeat the left and right pieces vertically if they're not the exact height needed. - CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], _DOMImageSizes[0].width, frameSize.height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, frameSize.height); - CPDOMDisplayServerSetStyleSize(_DOMImageParts[2], _DOMImageSizes[2].width, frameSize.height); + var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0, + right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0; - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0); - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0); - CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0); + partIndex = 0; + + // Make sure to repeat the left and right pieces vertically if they're not the exact height needed. + if (left) + { + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[partIndex], NULL, 0.0, 0.0); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], left, frameSize.height); + partIndex++; + } + if (_DOMImageSizes[1]) + { + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[partIndex], NULL, left, 0.0); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], frameSize.width - left - right, frameSize.height); + partIndex++; + } + if (right) + { + CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[partIndex], NULL, 0.0, 0.0); + CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], right, frameSize.height); + } } } #endif @@ -3143,5 +3308,3 @@ var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView) return transform; }; - -