fix layerdrawable/transitiondrawable/gradientdrawable's memleak

This commit is contained in:
houzh 2023-11-26 22:50:06 +08:00
parent 5bfce08c8e
commit 5339af05cb
14 changed files with 132 additions and 74 deletions

View File

@ -13,18 +13,6 @@
using namespace Cairo;
namespace cdroid {
struct Assets::COMPLEXCOLOR {
int icolor;
ColorStateList*colors;
COMPLEXCOLOR(int c) {
icolor=c;
colors=nullptr;
}
COMPLEXCOLOR(ColorStateList*c) {
colors=c;
}
};
Assets::Assets() {
mNextAutofillViewId=100000;
}
@ -34,12 +22,10 @@ Assets::Assets(const std::string&path):Assets() {
}
Assets::~Assets() {
for(auto it = mColors.begin() ; it != mColors.end() ; it++) {
if(it->second->colors) {
delete it->second->colors;
}
for(auto cls:mStateColors){
delete cls.second;
}
mColors.clear();
mStateColors.clear();
for(auto it=mResources.begin(); it!=mResources.end(); it++) {
delete it->second;
@ -102,10 +88,10 @@ void Assets::parseItem(const std::string&package,const std::vector<std::string>&
LOGV("%s=%s",name.c_str(),value.c_str());
} else if(tag0.compare("color")==0) {
const std::string name=atts[0].getString("name");
std::unique_ptr<COMPLEXCOLOR>cl(new COMPLEXCOLOR(Color::parseColor(value)));
uint32_t color = Color::parseColor(value);
LOGV("%s:color/%s:%s",package.c_str(),name.c_str(),value.c_str());
mColors.insert(std::pair<const std::string,std::unique_ptr<COMPLEXCOLOR>>
(package+":color/"+name,std::unique_ptr<COMPLEXCOLOR>(std::move(cl))));
mColors.insert(std::pair<const std::string,uint32_t>
(package+":color/"+name,color));
} else if(tag0.compare("string")==0) {
const std::string name= atts[0].getString("name");
const std::string key = package+":string/"+name;
@ -183,10 +169,9 @@ int Assets::addResource(const std::string&path,const std::string&name) {
pak->forEachEntry([this,package,&count](const std::string&res) {
if((res.size()>6)&&TextUtils::startWith(res,"color")) {
LOGV("LoadKeyValues from:%s ...",res.c_str());
std::string resid=package+":"+res.substr(0,res.find(".xml"));
std::unique_ptr<COMPLEXCOLOR>cl(new COMPLEXCOLOR(ColorStateList::inflate(this,resid)));
mColors.insert(std::pair<const std::string,std::unique_ptr<COMPLEXCOLOR>>
(resid,std::unique_ptr<COMPLEXCOLOR>(std::move(cl))));
std::string resid = package+":"+res.substr(0,res.find(".xml"));
ColorStateList*cls = ColorStateList::inflate(this,resid);
mStateColors.insert(std::pair<const std::string,ColorStateList*>(resid,cls));
}
return 0;
});
@ -382,7 +367,25 @@ Drawable* Assets::getDrawable(const std::string&fullresid) {
//wrap png to drawable,make app develop simply
if(resname[0]=='#'||resname[1]=='x'|| resname[1]=='X'){
LOGV("color %s",fullresid.c_str());
return new ColorDrawable(Color::parseColor(resname));
d = new ColorDrawable(Color::parseColor(resname));
mDrawables.insert(std::pair<std::string,std::weak_ptr<Drawable::ConstantState>>(fullresid,d->getConstantState()));
return d;
}
if(resname.find("color/")!=std::string::npos){
auto itc = mColors.find(fullresid);
auto its = mStateColors.find(fullresid);
if(itc!=mColors.end()){
const uint32_t cc = (uint32_t)getColor(fullresid);
LOGE("%s use colors as drawable",fullresid.c_str());
d = new ColorDrawable(cc);
mDrawables.insert(std::pair<std::string,std::weak_ptr<Drawable::ConstantState>>(fullresid,d->getConstantState()));
return d;
} else if(its!=mStateColors.end()){
LOGE("%s use colorstatelist as drawable",fullresid.c_str());
d = new StateListDrawable(*its->second);
mDrawables.insert(std::pair<std::string,std::weak_ptr<Drawable::ConstantState>>(fullresid,d->getConstantState()));
return d;
}
}
if(resname.find("attr/")!=std::string::npos) {//for reference resource
@ -425,7 +428,7 @@ int Assets::getColor(const std::string&refid) {
name = AttributeSet::normalize(pkg,name);
auto it = mColors.find(name);
if(it != mColors.end()) {
return it->second->icolor;
return it->second;
} else if((refid[0]=='#')||refid.find(':')==std::string::npos) {
return Color::parseColor(refid);
} else if(refid.find("color/")==std::string::npos) { //refid is defined as an color reference
@ -440,24 +443,35 @@ ColorStateList* Assets::getColorStateList(const std::string&fullresid) {
std::string pkg,name = fullresid;
parseResource(name,nullptr,&pkg);
name = AttributeSet::normalize(pkg,name);
auto it = mColors.find(name);
if( (it == mColors.end()) && (name.empty()==false)) {
auto itc= mColors.find(name);
auto its = mStateColors.find(name);
if(fullresid.compare("#313431")==0)
LOGI("");
if( its!=mStateColors.end())
return its->second;
else if(itc != mColors.end()){
ColorStateList* cls = ColorStateList::valueOf(itc->second);
mStateColors.insert(std::pair<const std::string,ColorStateList*>(fullresid,cls));
return cls;
}else if( (itc == mColors.end()) && (name.empty()==false) ) {
size_t slashpos = fullresid.find("/");
if((fullresid[0]=='#')||(slashpos==std::string::npos) ) {
int color = Color::parseColor(fullresid);
return ColorStateList::valueOf(color);
if( (fullresid[0]=='#') || (slashpos==std::string::npos) ) {/*digital colors*/
const int color = Color::parseColor(fullresid);
ColorStateList* cls = ColorStateList::valueOf(color);
mStateColors.insert(std::pair<const std::string,ColorStateList*>(fullresid,cls));
return cls;
}
if(slashpos==std::string::npos ) {
if( slashpos==std::string::npos ) {/*for color wolrds*/
std::string realName;
parseResource(fullresid,&realName,nullptr);
realName = mTheme.getString(realName);
it = mColors.find(realName);
itc = mColors.find(realName);
if(itc != mColors.end()){
ColorStateList* cls = ColorStateList::valueOf(itc->second);
mStateColors.insert(std::pair<const std::string,ColorStateList*>(fullresid,cls));
return cls;
}
}
}
if(it != mColors.end()) {
LOGV("%s type=%s",fullresid.c_str(),(it->second->colors?"color":"colorstatelist"));
if(it->second->colors)return new ColorStateList(*it->second->colors);
else return ColorStateList::valueOf(it->second->icolor);
} else if(fullresid.find("attr")!=std::string::npos) {
size_t slashpos=fullresid.find("/");
std::string name = fullresid.substr(slashpos+1);

View File

@ -21,8 +21,8 @@ private:
std::map<const std::string,std::weak_ptr<Drawable::ConstantState>>mDrawables;
std::map<const std::string,class ZIPArchive*>mResources;
std::map<const std::string,AttributeSet>mStyles;
struct COMPLEXCOLOR;
std::map<const std::string,std::unique_ptr<COMPLEXCOLOR>>mColors;
std::map<const std::string,uint32_t>mColors;
std::map<const std::string,ColorStateList*>mStateColors;
const std::string parseResource(const std::string&fullresid,std::string*res,std::string*ns)const;
void parseItem(const std::string&package,const std::vector<std::string>&tag,std::vector<AttributeSet>atts,const std::string&value);
ZIPArchive*getResource(const std::string & fullresid, std::string* relativeResid,std::string*package)const;

View File

@ -8,7 +8,7 @@
#include <map>
#include <cdtypes.h>
#include <cdlog.h>
#include <unistd.h>
namespace cdroid{
@ -30,6 +30,9 @@ ColorStateList::ColorStateList(const std::vector<std::vector<int>>&states,const
onColorsChanged();
}
ColorStateList::~ColorStateList(){
}
void ColorStateList::dump()const{
std::ostringstream oss;
for(int i=0;i<mColors.size();i++){
@ -102,6 +105,10 @@ int ColorStateList::getDefaultColor()const{
return mDefaultColor;
}
const std::vector<std::vector<int>>& ColorStateList::getStates()const{
return mStateSpecs;
}
void ColorStateList::onColorsChanged(){
int defaultColor = Color::RED;//DEFAULT_COLOR;
bool isOpaque = true;
@ -144,7 +151,7 @@ ColorStateList*ColorStateList::valueOf(int color){
return new ColorStateList(EMPTY,colors);
}
const std::vector<int> ColorStateList::getColors()const{
const std::vector<int>& ColorStateList::getColors()const{
return mColors;
}
@ -157,7 +164,7 @@ bool ColorStateList::hasState(int state)const{
return false;
}
struct ColorsParserData{
ColorStateList colors;
ColorStateList* colors;
Context*ctx;
std::string package;
};
@ -170,7 +177,9 @@ static void startElement(void *userData, const XML_Char *name, const XML_Char **
std::vector<int>states;
int color = cd->ctx->getColor(atts.getString("color"));
StateSet::parseState(states,atts);
cd->colors.addStateColor(states,color);
if(cd->colors==nullptr)
cd->colors = new ColorStateList();
cd->colors->addStateColor(states,color);
}
}
@ -180,6 +189,7 @@ ColorStateList*ColorStateList::fromStream(Context*ctx,std::istream&stream,const
XML_Parser parser = XML_ParserCreateNS(nullptr,' ');
ColorsParserData cd;
cd.ctx = ctx;
cd.colors = nullptr;
XML_SetUserData(parser,&cd);
XML_SetElementHandler(parser, startElement, nullptr/*endElement*/);
do {
@ -193,9 +203,7 @@ ColorStateList*ColorStateList::fromStream(Context*ctx,std::istream&stream,const
}
} while(!done);
XML_ParserFree(parser);
if(cd.colors.getColors().size())
return new ColorStateList(cd.colors);
return nullptr;
return cd.colors;
}
ColorStateList*ColorStateList::inflate(Context*ctx,const std::string&resname){

View File

@ -26,8 +26,10 @@ public:
ColorStateList();
ColorStateList(const ColorStateList&other);
ColorStateList(const std::vector<std::vector<int>>&states,const std::vector<int>&colors);
~ColorStateList();
int addStateColor(const std::vector<int>&stateSet,int color);
int getDefaultColor()const override;
const std::vector<std::vector<int>>& getStates()const;
bool isOpaque()const;
bool isStateful()const override;
bool hasFocusStateSpecified()const;
@ -38,7 +40,7 @@ public:
int getChangingConfigurations()const;
int getColorForState(const std::vector<int>&stateSet, int defaultColor)const;
const std::vector<int>getColors()const;
const std::vector<int>& getColors()const;
bool hasState(int state)const ;
void dump()const;
static ColorStateList*valueOf(int color);

View File

@ -45,10 +45,10 @@ GradientDrawable::GradientState::GradientState(const GradientState& orig) {
mGradient = orig.mGradient;
mAngle = orig.mAngle;
mOrientation = orig.mOrientation;
mSolidColors = orig.mSolidColors;
mSolidColors = orig.mSolidColors ? new ColorStateList(*orig.mSolidColors):nullptr;
mGradientColors = orig.mGradientColors;
mPositions = orig.mPositions;
mStrokeColors = orig.mStrokeColors;
mStrokeColors = orig.mStrokeColors?new ColorStateList(*orig.mStrokeColors):nullptr;
mStrokeWidth = orig.mStrokeWidth;
mStrokeDashWidth = orig.mStrokeDashWidth;
mStrokeDashGap = orig.mStrokeDashGap;
@ -71,7 +71,7 @@ GradientDrawable::GradientState::GradientState(const GradientState& orig) {
mUseLevelForShape = orig.mUseLevelForShape;
mOpaqueOverBounds = orig.mOpaqueOverBounds;
mOpaqueOverShape = orig.mOpaqueOverShape;
mTint = orig.mTint;
mTint = orig.mTint?new ColorStateList(*orig.mTint):nullptr;
mTintMode = orig.mTintMode;
//mThemeAttrs = orig.mThemeAttrs;
mAttrSize = orig.mAttrSize;
@ -87,6 +87,12 @@ GradientDrawable::GradientState::GradientState(const GradientState& orig) {
}
}
GradientDrawable::GradientState::~GradientState(){
delete mTint;
delete mStrokeColors;
delete mSolidColors;
}
void GradientDrawable::GradientState::setDensity(int targetDensity) {
if (mDensity != targetDensity) {
const int sourceDensity = mDensity;
@ -152,7 +158,10 @@ void GradientDrawable::GradientState::setShape( int shape) {
void GradientDrawable::GradientState::setSolidColors(ColorStateList*colors) {
mGradientColors.clear();
mSolidColors = colors;
delete mSolidColors;
mSolidColors = nullptr;
if(colors)
mSolidColors = new ColorStateList(*colors);
computeOpacity();
}
@ -191,9 +200,12 @@ void GradientDrawable::GradientState::computeOpacity() {
mOpaqueOverBounds = mShape == RECTANGLE && mRadius <= 0 && mRadiusArray.size()==0;
}
void GradientDrawable::GradientState::setStroke(int width,/*@Nullable*/ColorStateList*colors, float dashWidth,float dashGap) {
void GradientDrawable::GradientState::setStroke(int width,ColorStateList*colors, float dashWidth,float dashGap) {
mStrokeWidth = width;
mStrokeColors = colors;
delete mStrokeColors;
mStrokeColors = nullptr;
if(colors)
mStrokeColors = new ColorStateList(*colors);
mStrokeDashWidth = dashWidth;
mStrokeDashGap = dashGap;
computeOpacity();
@ -265,7 +277,7 @@ void GradientDrawable::updateLocalState() {
auto cls = state->mStrokeColors;
strokeStateColor = cls->getColorForState(currentState,0);
}
setStroke(state->mStrokeWidth,state->mStrokeColors,state->mStrokeDashWidth,state->mStrokeDashGap);
setStroke(state->mStrokeWidth,strokeStateColor,state->mStrokeDashWidth,state->mStrokeDashGap);
}
state->computeOpacity();
}

View File

@ -87,6 +87,7 @@ private:
GradientState();
GradientState(Orientation orientation, const std::vector<int>&gradientColors);
GradientState(const GradientState& orig);
~GradientState();
void setDensity(int targetDensity);
bool hasCenterColor()const;
void applyDensityScaling(int sourceDensity, int targetDensity);

View File

@ -204,13 +204,13 @@ LayerDrawable::LayerDrawable(const std::vector<Drawable*>&drawables)
refreshPadding();
}
LayerDrawable::LayerState* LayerDrawable::createConstantState(LayerState* state){
return new LayerState(state, this);
std::shared_ptr<LayerDrawable::LayerState> LayerDrawable::createConstantState(LayerState* state){
return std::make_shared<LayerState>(state, this);
}
LayerDrawable::LayerDrawable(std::shared_ptr<LayerState>state){
mMutated = false;
mLayerState.reset(createConstantState(state.get()));
mLayerState = createConstantState(state.get());
if (mLayerState->mChildren.size()) {
ensurePadding();
refreshPadding();
@ -936,7 +936,7 @@ Drawable* LayerDrawable::getFirstNonNullDrawable()const{
Drawable*LayerDrawable::mutate(){
if (!mMutated && Drawable::mutate() == this) {
mLayerState=std::make_shared<LayerState>(createConstantState(mLayerState.get()),nullptr);
mLayerState = createConstantState(mLayerState.get());
for (auto child:mLayerState->mChildren) {
Drawable*dr=child->mDrawable;
if (dr != nullptr) {

View File

@ -74,7 +74,7 @@ private:
ChildDrawable* createLayer(Drawable* dr);
Drawable*getFirstNonNullDrawable()const;
protected:
virtual LayerState* createConstantState(LayerState* state);
virtual std::shared_ptr<LayerState> createConstantState(LayerState* state);
void onBoundsChange(const Rect& bounds)override;
bool onLevelChange(int level)override;
bool onStateChange(const std::vector<int>& state)override;

View File

@ -1,4 +1,5 @@
#include <drawables/statelistdrawable.h>
#include <drawables/colordrawable.h>
#include <cdtypes.h>
#include <cdlog.h>
namespace cdroid{
@ -42,6 +43,16 @@ StateListDrawable::StateListDrawable(){
setConstantState(state);
}
StateListDrawable::StateListDrawable(const ColorStateList&cls){
auto state=std::make_shared<StateListState>(nullptr,this);
setConstantState(state);
const std::vector<int>&colors = cls.getColors();
const std::vector<std::vector<int>>& states = cls.getStates();
for(int i=0;i<states.size();i++){
addState(states[i],new ColorDrawable(colors[i]));
}
}
StateListDrawable::StateListDrawable(std::shared_ptr<StateListState>state){
std::shared_ptr<StateListState>newState =std::make_shared<StateListState>(state.get(), this);
setConstantState(newState);

View File

@ -25,6 +25,7 @@ protected:
void setConstantState(std::shared_ptr<DrawableContainerState>state)override;
public:
StateListDrawable();
StateListDrawable(const ColorStateList&);
void addState(const std::vector<int>&stateSet,Drawable*drawable);
bool isStateful()const override{return true;}
bool hasFocusStateSpecified()const override;

View File

@ -8,6 +8,9 @@ namespace cdroid{
#define TRANSITION_RUNNING 1
#define TRANSITION_NONE 2
/*TransitionDrawable::TransitionState::TransitionState(const Context*ctx,const AttributeSet&atts){
}*/
TransitionDrawable::TransitionState::TransitionState(TransitionState* orig, TransitionDrawable* owner)
:LayerState::LayerState(orig,owner){
}
@ -17,10 +20,15 @@ Drawable*TransitionDrawable::TransitionState::newDrawable(){
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
TransitionDrawable::TransitionDrawable(){
mAlpha=0;
mCrossFade =false;
mTransitionState=TRANSITION_NONE;
TransitionDrawable::TransitionDrawable()
:LayerDrawable(std::make_shared<TransitionState>(nullptr,this)){
}
TransitionDrawable::TransitionDrawable(Context*ctx,const AttributeSet&atts)
:LayerDrawable(std::make_shared<TransitionState>(nullptr,this)){
mAlpha = 0;
mCrossFade = false;
mTransitionState = TRANSITION_NONE;
}
TransitionDrawable::TransitionDrawable(const std::vector<Drawable*>drawables)
@ -37,8 +45,8 @@ TransitionDrawable::TransitionDrawable(std::shared_ptr<TransitionState> state)
mTransitionState=TRANSITION_NONE;
}
LayerDrawable::LayerState* TransitionDrawable::createConstantState(LayerState* state){
return new TransitionState((TransitionState*) state, this);
std::shared_ptr<LayerDrawable::LayerState> TransitionDrawable::createConstantState(LayerState* state){
return std::make_shared<TransitionState>((TransitionState*) state, this);
}
void TransitionDrawable::startTransition(int durationMillis) {
@ -138,7 +146,7 @@ void TransitionDrawable::draw(Canvas&canvas){
}
Drawable*TransitionDrawable::inflate(Context*ctx,const AttributeSet&atts){
return new TransitionDrawable();
return new TransitionDrawable(ctx,atts);
}
}

View File

@ -21,8 +21,10 @@ private:
TransitionState(TransitionState* orig, TransitionDrawable* owner);
Drawable*newDrawable()override;
};
TransitionDrawable(std::shared_ptr<TransitionState> state);
LayerDrawable::LayerState* createConstantState(LayerState* state)override;
std::shared_ptr<LayerDrawable::LayerState> createConstantState(LayerState* state)override;
TransitionDrawable(Context*,const AttributeSet&);
public:
TransitionDrawable();
TransitionDrawable(const std::vector<Drawable*>drawables);
@ -32,7 +34,7 @@ public:
bool isCrossFadeEnabled()const;
void setCrossFadeEnabled(bool enabled);
void draw(Canvas&canvas)override;
static Drawable*inflate(Context*ctx,const AttributeSet&atts);
static Drawable*inflate(Context*ctx,const AttributeSet&atts);
};
}

View File

@ -16,13 +16,12 @@ private:
typedef std::map<const std::string,const std::string>STYLEMAPPER;
static INFLATERMAPPER& getInflaterMap();
static STYLEMAPPER& getStyleMap();
protected:
View* inflate(const std::string&package,std::istream&stream,ViewGroup*root,bool attachToRoot,AttributeSet*);
public:
static LayoutInflater*from(Context*context);
static ViewInflater getInflater(const std::string&);
static bool registerInflater(const std::string&name,const std::string&,ViewInflater fun);
const std::string getDefaultStyle(const std::string&name)const;
View* inflate(const std::string&package,std::istream&stream,ViewGroup*root,bool attachToRoot,AttributeSet*);
View* inflate(const std::string&resource,ViewGroup* root, bool attachToRoot=true,AttributeSet*atts=nullptr);
};

View File

@ -1640,7 +1640,7 @@ void TextView::setTextColor(int color){
void TextView::setTextColor(ColorStateList* colors){
if((colors!=nullptr)&&(colors!=mTextColor)){
delete mTextColor;
mTextColor = colors;
mTextColor = new ColorStateList(*colors);
updateTextColors();
}
}
@ -1681,7 +1681,7 @@ void TextView::setHintTextColor(int color){
void TextView::setHintTextColor(ColorStateList* colors){
if(colors!=nullptr){
delete mHintTextColor;
mHintTextColor=colors;
mHintTextColor = new ColorStateList(*colors);
updateTextColors();
}
}
@ -1704,7 +1704,7 @@ void TextView::setLinkTextColor(int color){
void TextView::setLinkTextColor(ColorStateList* colors){
if(colors){
delete mLinkTextColor;
mLinkTextColor=colors;
mLinkTextColor = new ColorStateList(*colors);
updateTextColors();
}
}